Merge tag 'phy-for-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Mar 2022 21:49:15 +0000 (22:49 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Mar 2022 21:49:15 +0000 (22:49 +0100)
Vinod writes:

phy-for-5.18

  - New support:
        - Mediatek tphy support for MT8186
- Qualcomm usb phy support for sc8180x and sc8280xp
- Qualcomm ufs phy support for sc8180x and sc8280xp
- Qualcomm usb phy support for MSM8953
- Cadence D-Phy Rx support
- Sun4i support for USB phy
- Rockchip naneng combo phy support for RK3568
- Qualcomm eDP PHY for sc7280

  - Updates:
        - wake on support for Synopsis XHCI controllers
- Yamilify Qualcomm USB HS phy binding
- Charger detection support for TI tusb1210

* tag 'phy-for-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy: (53 commits)
  phy: qcom-qmp: add sc8280xp UFS PHY
  dt-bindings: phy: qcom,qmp: add sc8180x and sc8280xp ufs compatibles
  phy: qcom-snps: Add sc8280xp support
  dt-bindings: phy: qcom,usb-snps-femto-v2: Add sc8180x and sc8280xp
  dt-bindings: Revert "dt-bindings: soc: grf: add naneng combo phy register compatible"
  phy: dt-bindings: Add Cadence D-PHY Rx bindings
  phy: dt-bindings: cdns,dphy: add power-domains property
  phy: dt-bindings: Convert Cadence DPHY binding to YAML
  phy: cadence: Add Cadence D-PHY Rx driver
  dt-bindings: phy: renesas,usb2-phy: Document RZ/V2L phy bindings
  Revert "PCI: aardvark: Fix initialization with old Marvell's Arm Trusted Firmware"
  Revert "usb: host: xhci: mvebu: make USB 3.0 PHY optional for Armada 3720"
  Revert "ata: ahci: mvebu: Make SATA PHY optional for Armada 3720"
  phy: marvell: phy-mvebu-a3700-comphy: Add native kernel implementation
  phy: marvell: phy-mvebu-a3700-comphy: Remove port from driver configuration
  phy: phy-brcm-usb: fixup BCM4908 support
  dt-bindings: phy: mediatek,tphy: Add compatible for MT8192
  phy: ti: tusb1210: Add charger detection
  phy: ti: tusb1210: Add a delay between power-on and restoring the phy-parameters
  phy: ti: tusb1210: Drop tusb->vendor_specific2 != 0 check from tusb1210_power_on()
  ...

1560 files changed:
.mailmap
Documentation/ABI/stable/sysfs-driver-firmware-zynqmp
Documentation/ABI/testing/debugfs-driver-habanalabs
Documentation/ABI/testing/sysfs-bus-peci [new file with mode: 0644]
Documentation/ABI/testing/sysfs-class-power
Documentation/ABI/testing/sysfs-driver-aspeed-uart-routing
Documentation/ABI/testing/sysfs-driver-habanalabs
Documentation/accounting/psi.rst
Documentation/admin-guide/gpio/index.rst
Documentation/arm/marvell.rst
Documentation/arm64/silicon-errata.rst
Documentation/core-api/dma-attributes.rst
Documentation/cpu-freq/cpu-drivers.rst
Documentation/dev-tools/kselftest.rst
Documentation/dev-tools/kunit/usage.rst
Documentation/devicetree/bindings/arm/omap/omap.txt
Documentation/devicetree/bindings/gpio/delta,tn48m-gpio.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/sifive,gpio.yaml
Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.yaml
Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml
Documentation/devicetree/bindings/mfd/delta,tn48m-cpld.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/ti,j721e-system-controller.yaml
Documentation/devicetree/bindings/net/can/tcan4x5x.txt
Documentation/devicetree/bindings/net/qcom,ipa.yaml
Documentation/devicetree/bindings/nvmem/allwinner,sun4i-a10-sid.yaml
Documentation/devicetree/bindings/nvmem/fsl,layerscape-sfp.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/nvmem/sunplus,sp7021-ocotp.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/peci/peci-aspeed.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/peci/peci-controller.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/phy/ti,omap-usb2.yaml
Documentation/devicetree/bindings/pwm/pwm-sifive.yaml
Documentation/devicetree/bindings/reserved-memory/google,open-dice.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/reset/delta,tn48m-reset.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/riscv/sifive-l2-cache.yaml
Documentation/devicetree/bindings/sound/google,cros-ec-codec.yaml
Documentation/devicetree/bindings/soundwire/qcom,sdw.txt
Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
Documentation/devicetree/bindings/usb/ti,j721e-usb.yaml
Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml
Documentation/driver-api/driver-model/devres.rst
Documentation/driver-api/nvmem.rst
Documentation/filesystems/netfs_library.rst
Documentation/gpu/todo.rst
Documentation/hwmon/index.rst
Documentation/hwmon/peci-cputemp.rst [new file with mode: 0644]
Documentation/hwmon/peci-dimmtemp.rst [new file with mode: 0644]
Documentation/index.rst
Documentation/kernel-hacking/locking.rst
Documentation/peci/index.rst [new file with mode: 0644]
Documentation/peci/peci.rst [new file with mode: 0644]
Documentation/tools/index.rst [new file with mode: 0644]
Documentation/tools/rtla/common_hist_options.rst
Documentation/tools/rtla/common_osnoise_description.rst
Documentation/tools/rtla/index.rst [new file with mode: 0644]
Documentation/tools/rtla/rtla-osnoise-hist.rst
Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst
Documentation/userspace-api/ioctl/ioctl-number.rst
Documentation/virt/kvm/api.rst
Documentation/vm/page_table_check.rst
MAINTAINERS
Makefile
arch/arm/Kconfig
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/am335x-wega.dtsi
arch/arm/boot/dts/aspeed-g4.dtsi
arch/arm/boot/dts/aspeed-g5.dtsi
arch/arm/boot/dts/aspeed-g6.dtsi
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/imx23-evk.dts
arch/arm/boot/dts/imx6qdl-udoo.dtsi
arch/arm/boot/dts/imx7ulp.dtsi
arch/arm/boot/dts/meson.dtsi
arch/arm/boot/dts/meson8.dtsi
arch/arm/boot/dts/meson8b.dtsi
arch/arm/boot/dts/omap3-beagle-ab4.dts [new file with mode: 0644]
arch/arm/boot/dts/omap3-beagle.dts
arch/arm/boot/dts/spear320-hmi.dts
arch/arm/boot/dts/ste-ux500-samsung-skomer.dts
arch/arm/crypto/blake2s-shash.c
arch/arm/include/asm/assembler.h
arch/arm/include/asm/processor.h
arch/arm/include/asm/uaccess.h
arch/arm/mach-omap2/display.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-socfpga/Kconfig
arch/arm/probes/kprobes/Makefile
arch/arm64/Kconfig
arch/arm64/Kconfig.platforms
arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts
arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dtsi
arch/arm64/boot/dts/amlogic/meson-gx.dtsi
arch/arm64/boot/dts/amlogic/meson-sm1-bananapi-m5.dts
arch/arm64/boot/dts/amlogic/meson-sm1-odroid.dtsi
arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts
arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28.dts
arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
arch/arm64/boot/dts/freescale/imx8mq.dtsi
arch/arm64/boot/dts/freescale/mba8mx.dtsi
arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts
arch/arm64/boot/dts/ti/k3-j721s2.dtsi
arch/arm64/include/asm/cputype.h
arch/arm64/include/asm/el2_setup.h
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/stacktrace.c
arch/arm64/kernel/vdso/Makefile
arch/arm64/kvm/arm.c
arch/arm64/kvm/handle_exit.c
arch/arm64/kvm/hyp/exception.c
arch/arm64/kvm/hyp/include/hyp/switch.h
arch/arm64/kvm/hyp/pgtable.c
arch/arm64/kvm/hyp/vgic-v3-sr.c
arch/arm64/kvm/vgic/vgic-mmio.c
arch/arm64/kvm/vgic/vgic-v3.c
arch/arm64/mm/extable.c
arch/arm64/tools/cpucaps
arch/ia64/Kconfig
arch/ia64/pci/fixup.c
arch/mips/boot/dts/ingenic/ci20.dts
arch/mips/cavium-octeon/octeon-memcpy.S
arch/mips/include/asm/asm.h
arch/mips/include/asm/ftrace.h
arch/mips/include/asm/r4kcache.h
arch/mips/include/asm/unaligned-emul.h
arch/mips/kernel/mips-r2-to-r6-emul.c
arch/mips/kernel/r2300_fpu.S
arch/mips/kernel/r4k_fpu.S
arch/mips/kernel/relocate_kernel.S
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-n64.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/syscall.c
arch/mips/kvm/mips.c
arch/mips/kvm/vz.c
arch/mips/lib/csum_partial.S
arch/mips/lib/memcpy.S
arch/mips/lib/memset.S
arch/mips/lib/strncpy_user.S
arch/mips/lib/strnlen_user.S
arch/mips/loongson64/vbios_quirk.c
arch/parisc/include/asm/bitops.h
arch/parisc/include/asm/uaccess.h
arch/parisc/kernel/unaligned.c
arch/parisc/lib/iomap.c
arch/parisc/mm/init.c
arch/powerpc/include/asm/book3s/32/mmu-hash.h
arch/powerpc/include/asm/book3s/32/pgtable.h
arch/powerpc/include/asm/book3s/64/pgtable.h
arch/powerpc/include/asm/fixmap.h
arch/powerpc/include/asm/hw_irq.h
arch/powerpc/include/asm/kvm_book3s_64.h
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/include/asm/nohash/32/pgtable.h
arch/powerpc/include/asm/nohash/64/pgtable.h
arch/powerpc/include/asm/ppc-opcode.h
arch/powerpc/include/asm/syscall.h
arch/powerpc/include/asm/thread_info.h
arch/powerpc/kernel/head_book3s_32.S
arch/powerpc/kernel/interrupt_64.S
arch/powerpc/kernel/time.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_nested.c
arch/powerpc/lib/sstep.c
arch/powerpc/mm/book3s32/mmu.c
arch/powerpc/mm/kasan/book3s_32.c
arch/powerpc/mm/pgtable.c
arch/powerpc/net/bpf_jit_comp.c
arch/powerpc/net/bpf_jit_comp32.c
arch/powerpc/net/bpf_jit_comp64.c
arch/powerpc/perf/core-book3s.c
arch/riscv/Makefile
arch/riscv/configs/nommu_k210_sdcard_defconfig
arch/riscv/kernel/Makefile
arch/riscv/kernel/cpu-hotplug.c
arch/riscv/kernel/entry.S
arch/riscv/kernel/head.S
arch/riscv/kernel/sbi.c
arch/riscv/kernel/stacktrace.c
arch/riscv/kernel/trace_irq.c [new file with mode: 0644]
arch/riscv/kernel/trace_irq.h [new file with mode: 0644]
arch/riscv/kvm/vcpu.c
arch/riscv/kvm/vcpu_sbi_base.c
arch/riscv/mm/extable.c
arch/riscv/mm/init.c
arch/s390/Kconfig
arch/s390/configs/debug_defconfig
arch/s390/configs/defconfig
arch/s390/configs/zfcpdump_defconfig
arch/s390/hypfs/hypfs_vm.c
arch/s390/include/asm/uaccess.h
arch/s390/kernel/module.c
arch/s390/kernel/nmi.c
arch/s390/kvm/kvm-s390.c
arch/s390/lib/Makefile
arch/s390/lib/test_modules.c [new file with mode: 0644]
arch/s390/lib/test_modules.h [new file with mode: 0644]
arch/s390/lib/test_modules_helpers.c [new file with mode: 0644]
arch/x86/Kconfig
arch/x86/crypto/blake2s-shash.c
arch/x86/events/intel/core.c
arch/x86/events/intel/lbr.c
arch/x86/events/intel/pt.c
arch/x86/events/intel/uncore.c
arch/x86/events/intel/uncore.h
arch/x86/events/intel/uncore_discovery.c
arch/x86/events/intel/uncore_discovery.h
arch/x86/events/intel/uncore_snb.c
arch/x86/events/intel/uncore_snbep.c
arch/x86/events/perf_event.h
arch/x86/events/rapl.c
arch/x86/include/asm/bug.h
arch/x86/include/asm/kvm-x86-ops.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/svm.h
arch/x86/include/asm/xen/cpuid.h
arch/x86/include/asm/xen/hypervisor.h
arch/x86/include/uapi/asm/kvm.h
arch/x86/kernel/cpu/mce/amd.c
arch/x86/kernel/cpu/mce/intel.c
arch/x86/kernel/cpu/sgx/encl.c
arch/x86/kernel/cpu/sgx/main.c
arch/x86/kernel/fpu/regset.c
arch/x86/kernel/fpu/xstate.c
arch/x86/kernel/kvm.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/resource.c
arch/x86/kvm/cpuid.c
arch/x86/kvm/lapic.c
arch/x86/kvm/mmu/mmu.c
arch/x86/kvm/pmu.c
arch/x86/kvm/svm/avic.c
arch/x86/kvm/svm/nested.c
arch/x86/kvm/svm/sev.c
arch/x86/kvm/svm/svm.c
arch/x86/kvm/svm/svm.h
arch/x86/kvm/svm/svm_onhyperv.h
arch/x86/kvm/vmx/capabilities.h
arch/x86/kvm/vmx/evmcs.c
arch/x86/kvm/vmx/evmcs.h
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/vmcs12.c
arch/x86/kvm/vmx/vmcs12.h
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h
arch/x86/kvm/xen.c
arch/x86/pci/fixup.c
arch/x86/xen/enlighten_hvm.c
arch/x86/xen/enlighten_pv.c
arch/x86/xen/smp_pv.c
arch/x86/xen/vga.c
block/bfq-iosched.c
block/bio-integrity.c
block/blk-core.c
block/blk-ia-ranges.c
block/blk-map.c
block/blk-mq.c
block/elevator.c
block/fops.c
block/genhd.c
crypto/af_alg.c
crypto/algapi.c
crypto/api.c
crypto/blake2s_generic.c
drivers/Kconfig
drivers/Makefile
drivers/accessibility/speakup/speakup_audptr.c
drivers/accessibility/speakup/speakup_dectlk.c
drivers/accessibility/speakup/synth.c
drivers/acpi/Kconfig
drivers/acpi/arm64/iort.c
drivers/acpi/ec.c
drivers/acpi/processor_idle.c
drivers/acpi/sleep.c
drivers/acpi/tables.c
drivers/acpi/x86/s2idle.c
drivers/android/binder_alloc.c
drivers/ata/libata-core.c
drivers/ata/pata_hpt37x.c
drivers/ata/pata_platform.c
drivers/ata/sata_fsl.c
drivers/base/dd.c
drivers/base/power/wakeup.c
drivers/base/regmap/regmap-irq.c
drivers/block/loop.c
drivers/block/loop.h
drivers/block/mtip32xx/mtip32xx.c
drivers/block/rbd.c
drivers/block/xen-blkfront.c
drivers/bus/mhi/pci_generic.c
drivers/char/bsr.c
drivers/char/hpet.c
drivers/char/random.c
drivers/char/xilinx_hwicap/fifo_icap.c
drivers/char/xilinx_hwicap/xilinx_hwicap.c
drivers/clk/ingenic/jz4725b-cgu.c
drivers/clk/qcom/gcc-msm8994.c
drivers/clocksource/timer-ti-dm-systimer.c
drivers/comedi/drivers/das16.c
drivers/comedi/drivers/ni_routes.c
drivers/comedi/drivers/pcm3724.c
drivers/connector/cn_proc.c
drivers/counter/counter-core.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/qcom-cpufreq-hw.c
drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c
drivers/dio/dio.c
drivers/dma-buf/dma-heap.c
drivers/dma/at_xdmac.c
drivers/dma/ptdma/ptdma-dev.c
drivers/dma/sh/rcar-dmac.c
drivers/dma/sh/shdma-base.c
drivers/dma/stm32-dmamux.c
drivers/edac/altera_edac.c
drivers/edac/edac_mc.c
drivers/edac/xgene_edac.c
drivers/firmware/efi/efi.c
drivers/firmware/efi/libstub/arm64-stub.c
drivers/firmware/stratix10-svc.c
drivers/firmware/xilinx/zynqmp.c
drivers/fpga/dfl-pci.c
drivers/fsi/fsi-core.c
drivers/fsi/fsi-master-aspeed.c
drivers/fsi/fsi-occ.c
drivers/fsi/fsi-sbefifo.c
drivers/fsi/fsi-scom.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-aggregator.c
drivers/gpio/gpio-rockchip.c
drivers/gpio/gpio-sifive.c
drivers/gpio/gpio-sim.c
drivers/gpio/gpio-tegra186.c
drivers/gpio/gpio-tn48m.c [new file with mode: 0644]
drivers/gpio/gpiolib-cdev.c
drivers/gpio/gpiolib-sysfs.c
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c
drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
drivers/gpu/drm/amd/amdgpu/soc15.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c
drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c
drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c
drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c
drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.c
drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.c
drivers/gpu/drm/amd/display/dc/dml/dcn301/dcn301_fpu.h
drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_helpers.c
drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c
drivers/gpu/drm/amd/display/dc/inc/core_types.h
drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
drivers/gpu/drm/amd/display/dc/inc/resource.h
drivers/gpu/drm/amd/pm/amdgpu_pm.c
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.h
drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_ppt.c
drivers/gpu/drm/ast/ast_tables.h
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_uapi.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_gem_cma_helper.c
drivers/gpu/drm/drm_panel_orientation_quirks.c
drivers/gpu/drm/drm_privacy_screen.c
drivers/gpu/drm/drm_privacy_screen_x86.c
drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
drivers/gpu/drm/i915/Kconfig
drivers/gpu/drm/i915/display/intel_bw.c
drivers/gpu/drm/i915/display/intel_bw.h
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/display/intel_drrs.c
drivers/gpu/drm/i915/display/intel_fbc.c
drivers/gpu/drm/i915/display/intel_opregion.c
drivers/gpu/drm/i915/display/intel_overlay.c
drivers/gpu/drm/i915/display/intel_snps_phy.c
drivers/gpu/drm/i915/display/intel_tc.c
drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
drivers/gpu/drm/i915/gem/i915_gem_object_types.h
drivers/gpu/drm/i915/gem/i915_gem_pages.c
drivers/gpu/drm/i915/gem/i915_gem_ttm.c
drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c
drivers/gpu/drm/i915/gt/intel_gt.c
drivers/gpu/drm/i915/gt/intel_gt.h
drivers/gpu/drm/i915/gt/intel_gt_types.h
drivers/gpu/drm/i915/gt/uc/intel_guc.h
drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
drivers/gpu/drm/i915/gvt/gtt.c
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_mm.h
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_vma.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_pm.h
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/gpu/drm/i915/intel_uncore.c
drivers/gpu/drm/i915/intel_uncore.h
drivers/gpu/drm/imx/dcss/Kconfig
drivers/gpu/drm/kmb/kmb_plane.c
drivers/gpu/drm/mediatek/mtk_dsi.c
drivers/gpu/drm/msm/adreno/a6xx_gpu.c
drivers/gpu/drm/msm/adreno/adreno_device.c
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c
drivers/gpu/drm/msm/dsi/dsi.c
drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
drivers/gpu/drm/msm/hdmi/hdmi.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_gpu.c
drivers/gpu/drm/msm/msm_gpu.h
drivers/gpu/drm/msm/msm_gpu_devfreq.c
drivers/gpu/drm/mxsfb/mxsfb_kms.c
drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/radeon_uvd.c
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
drivers/gpu/drm/rockchip/rockchip_vop_reg.c
drivers/gpu/drm/tegra/Kconfig
drivers/gpu/drm/tegra/dpaux.c
drivers/gpu/drm/tegra/falcon.c
drivers/gpu/drm/vc4/vc4_crtc.c
drivers/gpu/drm/vc4/vc4_dsi.c
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/gpu/drm/vc4/vc4_hdmi.h
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/host1x/syncpt.c
drivers/greybus/svc.c
drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
drivers/hid/hid-apple.c
drivers/hid/hid-elo.c
drivers/hid/hid-ids.h
drivers/hid/hid-quirks.c
drivers/hid/i2c-hid/i2c-hid-of-goodix.c
drivers/hv/hv_balloon.c
drivers/hv/hv_utils_transport.c
drivers/hv/vmbus_drv.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/adt7470.c
drivers/hwmon/hwmon.c
drivers/hwmon/lm90.c
drivers/hwmon/nct6775.c
drivers/hwmon/ntc_thermistor.c
drivers/hwmon/peci/Kconfig [new file with mode: 0644]
drivers/hwmon/peci/Makefile [new file with mode: 0644]
drivers/hwmon/peci/common.h [new file with mode: 0644]
drivers/hwmon/peci/cputemp.c [new file with mode: 0644]
drivers/hwmon/peci/dimmtemp.c [new file with mode: 0644]
drivers/hwmon/pmbus/ir38064.c
drivers/hwmon/pmbus/pmbus_core.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-bcm2835.c
drivers/i2c/busses/i2c-brcmstb.c
drivers/i2c/busses/i2c-qcom-cci.c
drivers/iio/accel/bmc150-accel-core.c
drivers/iio/accel/fxls8962af-core.c
drivers/iio/accel/fxls8962af-i2c.c
drivers/iio/accel/fxls8962af-spi.c
drivers/iio/accel/fxls8962af.h
drivers/iio/accel/kxcjk-1013.c
drivers/iio/accel/mma9551.c
drivers/iio/accel/mma9553.c
drivers/iio/adc/ad7124.c
drivers/iio/adc/men_z188_adc.c
drivers/iio/adc/ti-tsc2046.c
drivers/iio/addac/ad74413r.c
drivers/iio/frequency/admv1013.c
drivers/iio/gyro/bmg160_core.c
drivers/iio/imu/adis16480.c
drivers/iio/imu/kmx61.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
drivers/iio/industrialio-buffer.c
drivers/iio/magnetometer/bmc150_magn.c
drivers/infiniband/core/cm.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/ucma.c
drivers/infiniband/hw/hfi1/ipoib.h
drivers/infiniband/hw/hfi1/ipoib_main.c
drivers/infiniband/hw/hfi1/ipoib_tx.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/qib/qib_sysfs.c
drivers/infiniband/sw/rdmavt/qp.c
drivers/infiniband/sw/siw/siw.h
drivers/infiniband/sw/siw/siw_qp_rx.c
drivers/infiniband/sw/siw/siw_verbs.c
drivers/infiniband/ulp/rtrs/rtrs-clt.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/input/input.c
drivers/input/mouse/psmouse-smbus.c
drivers/input/touchscreen/wm97xx-core.c
drivers/input/touchscreen/zinitix.c
drivers/iommu/amd/init.c
drivers/iommu/intel/irq_remapping.c
drivers/iommu/ioasid.c
drivers/iommu/iommu.c
drivers/iommu/omap-iommu.c
drivers/irqchip/irq-apple-aic.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-loongson-pch-msi.c
drivers/irqchip/irq-realtek-rtl.c
drivers/irqchip/irq-sifive-plic.c
drivers/md/dm.c
drivers/md/md.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/cardreader/alcor_pci.c
drivers/misc/cardreader/rtl8411.c
drivers/misc/cardreader/rts5209.c
drivers/misc/cardreader/rts5227.c
drivers/misc/cardreader/rts5228.c
drivers/misc/cardreader/rts5229.c
drivers/misc/cardreader/rts5249.c
drivers/misc/cardreader/rts5261.c
drivers/misc/cardreader/rtsx_pcr.c
drivers/misc/cardreader/rtsx_pcr.h
drivers/misc/eeprom/at25.c
drivers/misc/eeprom/ee1004.c
drivers/misc/fastrpc.c
drivers/misc/habanalabs/common/Makefile
drivers/misc/habanalabs/common/command_buffer.c
drivers/misc/habanalabs/common/command_submission.c
drivers/misc/habanalabs/common/debugfs.c
drivers/misc/habanalabs/common/device.c
drivers/misc/habanalabs/common/firmware_if.c
drivers/misc/habanalabs/common/habanalabs.h
drivers/misc/habanalabs/common/habanalabs_drv.c
drivers/misc/habanalabs/common/habanalabs_ioctl.c
drivers/misc/habanalabs/common/hwmgr.c [deleted file]
drivers/misc/habanalabs/common/irq.c
drivers/misc/habanalabs/common/memory.c
drivers/misc/habanalabs/common/mmu/mmu.c
drivers/misc/habanalabs/common/mmu/mmu_v1.c
drivers/misc/habanalabs/common/pci/pci.c
drivers/misc/habanalabs/common/sysfs.c
drivers/misc/habanalabs/gaudi/gaudi.c
drivers/misc/habanalabs/gaudi/gaudiP.h
drivers/misc/habanalabs/goya/goya.c
drivers/misc/habanalabs/goya/goyaP.h
drivers/misc/habanalabs/goya/goya_hwmgr.c
drivers/misc/habanalabs/include/common/cpucp_if.h
drivers/misc/habanalabs/include/common/hl_boot_if.h
drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h
drivers/misc/lkdtm/fortify.c
drivers/misc/mei/client.c
drivers/misc/mei/hw-me-regs.h
drivers/misc/mei/hw-me.c
drivers/misc/mei/init.c
drivers/misc/mei/pci-me.c
drivers/misc/ocxl/link.c
drivers/misc/open-dice.c [new file with mode: 0644]
drivers/misc/sgi-gru/grutables.h
drivers/misc/vmw_vmci/vmci_guest.c
drivers/mmc/core/block.c
drivers/mmc/core/sd.c
drivers/mmc/host/moxart-mmc.c
drivers/mmc/host/rtsx_pci_sdmmc.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sh_mmcif.c
drivers/mtd/devices/phram.c
drivers/mtd/mtdcore.c
drivers/mtd/nand/raw/Kconfig
drivers/mtd/nand/raw/brcmnand/brcmnand.c
drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/raw/ingenic/ingenic_ecc.c
drivers/mtd/nand/raw/qcom_nandc.c
drivers/mtd/parsers/qcomsmempart.c
drivers/mux/core.c
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_main.c
drivers/net/can/flexcan/flexcan-core.c
drivers/net/can/flexcan/flexcan.h
drivers/net/can/m_can/m_can.c
drivers/net/can/m_can/tcan4x5x-regmap.c
drivers/net/dsa/Kconfig
drivers/net/dsa/bcm_sf2.c
drivers/net/dsa/lan9303-core.c
drivers/net/dsa/lantiq_gswip.c
drivers/net/dsa/microchip/ksz_common.c
drivers/net/dsa/mt7530.c
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/dsa/ocelot/felix_vsc9959.c
drivers/net/dsa/ocelot/seville_vsc9953.c
drivers/net/dsa/qca/ar9331.c
drivers/net/ethernet/3com/typhoon.c
drivers/net/ethernet/8390/etherh.c
drivers/net/ethernet/amd/declance.c
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
drivers/net/ethernet/amd/xgbe/xgbe-pci.c
drivers/net/ethernet/aquantia/atlantic/aq_filters.c
drivers/net/ethernet/atheros/atl1c/atl1c_main.c
drivers/net/ethernet/broadcom/bgmac-platform.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
drivers/net/ethernet/broadcom/bnxt/bnxt_hwrm.c
drivers/net/ethernet/broadcom/bnxt/bnxt_hwrm.h
drivers/net/ethernet/broadcom/sb1250-mac.c
drivers/net/ethernet/cadence/macb_main.c
drivers/net/ethernet/faraday/ftgmac100.c
drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-flower.c
drivers/net/ethernet/freescale/fec_mpc52xx.c
drivers/net/ethernet/google/gve/gve.h
drivers/net/ethernet/google/gve/gve_adminq.c
drivers/net/ethernet/google/gve/gve_main.c
drivers/net/ethernet/google/gve/gve_rx.c
drivers/net/ethernet/google/gve/gve_rx_dqo.c
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
drivers/net/ethernet/i825xx/ether1.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/ibm/ibmvnic.h
drivers/net/ethernet/intel/e1000e/e1000.h
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_debugfs.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_register.h
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
drivers/net/ethernet/intel/ice/ice.h
drivers/net/ethernet/intel/ice/ice_common.c
drivers/net/ethernet/intel/ice/ice_eswitch.c
drivers/net/ethernet/intel/ice/ice_lag.c
drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
drivers/net/ethernet/intel/ice/ice_lib.c
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/ice/ice_protocol_type.h
drivers/net/ethernet/intel/ice/ice_ptp.c
drivers/net/ethernet/intel/ice/ice_switch.c
drivers/net/ethernet/intel/ice/ice_tc_lib.c
drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/litex/Kconfig
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
drivers/net/ethernet/marvell/octeontx2/af/cgx.c
drivers/net/ethernet/marvell/octeontx2/af/lmac_common.h
drivers/net/ethernet/marvell/octeontx2/af/mbox.h
drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h
drivers/net/ethernet/marvell/octeontx2/af/rpm.c
drivers/net/ethernet/marvell/octeontx2/af/rpm.h
drivers/net/ethernet/marvell/octeontx2/af/rvu.c
drivers/net/ethernet/marvell/octeontx2/af/rvu.h
drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en/qos.c
drivers/net/ethernet/mellanox/mlx5/core/en/rep/bond.c
drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.h
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/ct.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/mirred.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/mpls.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_mplsoudp.c
drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h
drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c
drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c
drivers/net/ethernet/mellanox/mlx5/core/esw/diag/bridge_tracepoint.h
drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
drivers/net/ethernet/mellanox/mlx5/core/lib/fs_chains.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlx5/core/port.c
drivers/net/ethernet/mellanox/mlx5/core/steering/dr_icm_pool.c
drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c
drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c
drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h
drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c
drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h
drivers/net/ethernet/microchip/lan966x/lan966x_mac.c
drivers/net/ethernet/microchip/lan966x/lan966x_main.c
drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c
drivers/net/ethernet/microchip/sparx5/sparx5_packet.c
drivers/net/ethernet/mscc/ocelot.c
drivers/net/ethernet/netronome/nfp/flower/cmsg.h
drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
drivers/net/ethernet/seeq/ether3.c
drivers/net/ethernet/smsc/smc911x.c
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c
drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
drivers/net/ethernet/ti/cpsw_priv.c
drivers/net/ethernet/tundra/tsi108_eth.c
drivers/net/ethernet/xilinx/ll_temac_main.c
drivers/net/hamradio/6pack.c
drivers/net/hamradio/yam.c
drivers/net/ieee802154/at86rf230.c
drivers/net/ieee802154/ca8210.c
drivers/net/ieee802154/mac802154_hwsim.c
drivers/net/ieee802154/mcr20a.c
drivers/net/ipa/ipa_power.c
drivers/net/ipa/ipa_power.h
drivers/net/ipa/ipa_uc.c
drivers/net/macsec.c
drivers/net/mctp/mctp-serial.c
drivers/net/mdio/mdio-aspeed.c
drivers/net/mdio/mdio-ipq4019.c
drivers/net/netdevsim/fib.c
drivers/net/phy/at803x.c
drivers/net/phy/broadcom.c
drivers/net/phy/marvell.c
drivers/net/phy/mediatek-ge.c
drivers/net/phy/phy_device.c
drivers/net/phy/sfp-bus.c
drivers/net/usb/ax88179_178a.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/cdc_mbim.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/ipheth.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/sr9700.c
drivers/net/usb/zaurus.c
drivers/net/veth.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
drivers/net/wireless/intel/iwlwifi/Kconfig
drivers/net/wireless/intel/iwlwifi/fw/acpi.c
drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
drivers/net/wireless/intel/iwlwifi/fw/api/filter.h
drivers/net/wireless/intel/iwlwifi/fw/api/rs.h
drivers/net/wireless/intel/iwlwifi/fw/file.h
drivers/net/wireless/intel/iwlwifi/fw/rs.c
drivers/net/wireless/intel/iwlwifi/iwl-csr.h
drivers/net/wireless/intel/iwlwifi/iwl-drv.c
drivers/net/wireless/intel/iwlwifi/mei/main.c
drivers/net/wireless/intel/iwlwifi/mei/net.c
drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/mvm/tx.c
drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
drivers/net/wireless/intel/iwlwifi/pcie/trans.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/xen-netback/xenbus.c
drivers/nvme/host/core.c
drivers/nvme/host/fabrics.c
drivers/nvme/host/fabrics.h
drivers/nvme/host/multipath.c
drivers/nvme/host/pci.c
drivers/nvme/host/rdma.c
drivers/nvme/host/tcp.c
drivers/nvmem/Kconfig
drivers/nvmem/Makefile
drivers/nvmem/core.c
drivers/nvmem/layerscape-sfp.c [new file with mode: 0644]
drivers/nvmem/meson-mx-efuse.c
drivers/nvmem/qfprom.c
drivers/nvmem/sunplus-ocotp.c [new file with mode: 0644]
drivers/nvmem/sunxi_sid.c
drivers/of/fdt.c
drivers/of/platform.c
drivers/of/unittest.c
drivers/parisc/ccio-dma.c
drivers/parisc/sba_iommu.c
drivers/pci/controller/cadence/pci-j721e.c
drivers/pci/controller/dwc/pcie-kirin.c
drivers/pci/controller/pci-hyperv.c
drivers/pci/controller/pci-mvebu.c
drivers/pci/controller/pcie-mt7621.c
drivers/pci/controller/vmd.c
drivers/pci/msi/irqdomain.c
drivers/pci/msi/legacy.c
drivers/pci/msi/msi.c
drivers/pci/pcie/portdrv_core.c
drivers/pci/quirks.c
drivers/peci/Kconfig [new file with mode: 0644]
drivers/peci/Makefile [new file with mode: 0644]
drivers/peci/controller/Kconfig [new file with mode: 0644]
drivers/peci/controller/Makefile [new file with mode: 0644]
drivers/peci/controller/peci-aspeed.c [new file with mode: 0644]
drivers/peci/core.c [new file with mode: 0644]
drivers/peci/cpu.c [new file with mode: 0644]
drivers/peci/device.c [new file with mode: 0644]
drivers/peci/internal.h [new file with mode: 0644]
drivers/peci/request.c [new file with mode: 0644]
drivers/peci/sysfs.c [new file with mode: 0644]
drivers/pinctrl/Makefile
drivers/pinctrl/bcm/Kconfig
drivers/pinctrl/bcm/pinctrl-bcm2835.c
drivers/pinctrl/intel/pinctrl-cherryview.c
drivers/pinctrl/intel/pinctrl-intel.c
drivers/pinctrl/intel/pinctrl-tigerlake.c
drivers/pinctrl/pinctrl-k210.c
drivers/pinctrl/pinctrl-microchip-sgpio.c
drivers/pinctrl/pinctrl-starfive.c
drivers/pinctrl/pinctrl-thunderbay.c
drivers/pinctrl/pinctrl-zynqmp.c
drivers/pinctrl/sunxi/pinctrl-sun50i-h616.c
drivers/platform/surface/Kconfig
drivers/platform/surface/surface3_power.c
drivers/platform/x86/amd-pmc.c
drivers/platform/x86/asus-tf103c-dock.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/intel/crystal_cove_charger.c
drivers/platform/x86/intel/int3472/tps68470_board_data.c
drivers/platform/x86/intel/speed_select_if/isst_if_common.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/touchscreen_dmi.c
drivers/platform/x86/x86-android-tablets.c
drivers/power/supply/bq256xx_charger.c
drivers/power/supply/cw2015_battery.c
drivers/pps/clients/pps-gpio.c
drivers/regulator/core.c
drivers/regulator/da9121-regulator.c
drivers/regulator/max20086-regulator.c
drivers/remoteproc/Kconfig
drivers/remoteproc/qcom_q6v5.c
drivers/reset/Kconfig
drivers/reset/Makefile
drivers/reset/reset-tn48m.c [new file with mode: 0644]
drivers/rpmsg/rpmsg_char.c
drivers/s390/cio/device.c
drivers/s390/scsi/zfcp_fc.c
drivers/scsi/3w-sas.c
drivers/scsi/53c700.c
drivers/scsi/bfa/bfad.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/elx/libefc/efc_els.c
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_nportdisc.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/myrs.c
drivers/scsi/pm8001/pm8001_hwi.c
drivers/scsi/pm8001/pm8001_sas.c
drivers/scsi/pm8001/pm80xx_hwi.c
drivers/scsi/pm8001/pm80xx_hwi.h
drivers/scsi/qedf/qedf_io.c
drivers/scsi/qedf/qedf_main.c
drivers/scsi/qedi/qedi_fw.c
drivers/scsi/scsi_scan.c
drivers/scsi/ufs/ufshcd-pltfrm.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshci.h
drivers/soc/aspeed/aspeed-lpc-ctrl.c
drivers/soc/mediatek/mtk-scpsys.c
drivers/soc/samsung/Kconfig
drivers/soundwire/bus.c
drivers/soundwire/intel.c
drivers/soundwire/intel_init.c
drivers/soundwire/qcom.c
drivers/soundwire/stream.c
drivers/spi/spi-bcm-qspi.c
drivers/spi/spi-meson-spicc.c
drivers/spi/spi-mt65xx.c
drivers/spi/spi-rockchip.c
drivers/spi/spi-stm32-qspi.c
drivers/spi/spi-stm32.c
drivers/spi/spi-uniphier.c
drivers/spi/spi-zynq-qspi.c
drivers/staging/fbtft/fb_st7789v.c
drivers/staging/fbtft/fbtft.h
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
drivers/target/iscsi/iscsi_target_tpg.c
drivers/tee/optee/core.c
drivers/tee/optee/ffa_abi.c
drivers/tee/optee/notif.c
drivers/tee/optee/optee_private.h
drivers/tee/optee/smc_abi.c
drivers/thermal/intel/int340x_thermal/int3400_thermal.c
drivers/thunderbolt/nvm.c
drivers/tty/n_gsm.c
drivers/tty/n_tty.c
drivers/tty/rpmsg_tty.c
drivers/tty/serial/8250/8250_gsc.c
drivers/tty/serial/8250/8250_of.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/8250/8250_pericom.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/sc16is7xx.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/stm32-usart.c
drivers/tty/vt/vt_ioctl.c
drivers/usb/cdns3/drd.c
drivers/usb/common/ulpi.c
drivers/usb/core/hcd.c
drivers/usb/core/port.c
drivers/usb/core/urb.c
drivers/usb/dwc2/core.h
drivers/usb/dwc2/drd.c
drivers/usb/dwc2/gadget.c
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/dwc3-xilinx.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/composite.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_sourcesink.c
drivers/usb/gadget/function/f_uac2.c
drivers/usb/gadget/function/rndis.c
drivers/usb/gadget/function/rndis.h
drivers/usb/gadget/legacy/raw_gadget.c
drivers/usb/gadget/udc/at91_udc.c
drivers/usb/gadget/udc/renesas_usb3.c
drivers/usb/gadget/udc/udc-xilinx.c
drivers/usb/host/xhci-plat.c
drivers/usb/host/xhci.c
drivers/usb/misc/usb251xb.c
drivers/usb/serial/ch341.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/option.c
drivers/usb/storage/unusual_devs.h
drivers/usb/typec/port-mapper.c
drivers/usb/typec/tcpm/tcpci.c
drivers/usb/typec/tcpm/tcpci.h
drivers/usb/typec/tcpm/tcpm.c
drivers/usb/typec/tipd/core.c
drivers/usb/typec/ucsi/ucsi_ccg.c
drivers/vhost/vsock.c
drivers/video/console/Kconfig
drivers/video/fbdev/core/bitblit.c
drivers/video/fbdev/core/fbcon.c
drivers/video/fbdev/core/fbcon.h
drivers/video/fbdev/core/fbcon_ccw.c
drivers/video/fbdev/core/fbcon_cw.c
drivers/video/fbdev/core/fbcon_rotate.h
drivers/video/fbdev/core/fbcon_ud.c
drivers/video/fbdev/core/fbmem.c
drivers/video/fbdev/core/tileblit.c
drivers/video/fbdev/hyperv_fb.c
drivers/video/fbdev/skeletonfb.c
drivers/w1/slaves/w1_therm.c
drivers/xen/pci.c
fs/9p/fid.c
fs/Kconfig
fs/Makefile
fs/binfmt_elf.c
fs/binfmt_misc.c
fs/btrfs/block-group.c
fs/btrfs/ctree.h
fs/btrfs/extent_map.c
fs/btrfs/extent_map.h
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/lzo.c
fs/btrfs/qgroup.c
fs/btrfs/send.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-checker.c
fs/btrfs/tree-log.c
fs/cachefiles/io.c
fs/ceph/caps.c
fs/ceph/file.c
fs/cifs/cifs_swn.c
fs/cifs/cifsacl.c
fs/cifs/cifsfs.c
fs/cifs/connect.c
fs/cifs/dfs_cache.c
fs/cifs/file.c
fs/cifs/fs_context.c
fs/cifs/fscache.c
fs/cifs/fscache.h
fs/cifs/inode.c
fs/cifs/sess.c
fs/cifs/smb1ops.c
fs/cifs/transport.c
fs/cifs/xattr.c
fs/configfs/dir.c
fs/devpts/inode.c
fs/erofs/data.c
fs/erofs/zdata.c
fs/erofs/zmap.c
fs/ext4/acl.c
fs/ext4/ext4.h
fs/ext4/ext4_jbd2.h
fs/ext4/extents.c
fs/ext4/fast_commit.c
fs/ext4/hash.c
fs/ext4/indirect.c
fs/ext4/inline.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/migrate.c
fs/ext4/namei.c
fs/ext4/orphan.c
fs/ext4/super.c
fs/ext4/sysfs.c
fs/ext4/xattr.c
fs/f2fs/dir.c
fs/f2fs/f2fs.h
fs/f2fs/hash.c
fs/f2fs/namei.c
fs/f2fs/recovery.c
fs/f2fs/super.c
fs/f2fs/sysfs.c
fs/file_table.c
fs/gfs2/file.c
fs/gfs2/glock.c
fs/io_uring.c
fs/iomap/buffered-io.c
fs/jbd2/commit.c
fs/jbd2/journal.c
fs/jbd2/transaction.c
fs/ksmbd/auth.c
fs/ksmbd/smb2pdu.c
fs/ksmbd/smb_common.c
fs/ksmbd/transport_rdma.c
fs/ksmbd/vfs.h
fs/libfs.c
fs/lockd/svcsubs.c
fs/namei.c
fs/namespace.c
fs/nfs/callback.h
fs/nfs/callback_proc.c
fs/nfs/callback_xdr.c
fs/nfs/client.c
fs/nfs/dir.c
fs/nfs/filelayout/filelayout.h
fs/nfs/filelayout/filelayoutdev.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs3proc.c
fs/nfs/nfs42proc.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4client.c
fs/nfs/nfs4namespace.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfs/sysfs.c
fs/nfsd/nfs3proc.c
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/trace.h
fs/nfsd/vfs.c
fs/nfsd/vfs.h
fs/notify/fanotify/fanotify_user.c
fs/ocfs2/stackglue.c
fs/ocfs2/suballoc.c
fs/overlayfs/copy_up.c
fs/proc/task_mmu.c
fs/quota/dquot.c
fs/super.c
fs/sync.c
fs/tracefs/inode.c
fs/udf/inode.c
fs/unicode/Kconfig
fs/unicode/Makefile
fs/xfs/xfs_aops.c
fs/xfs/xfs_bmap_util.c
fs/xfs/xfs_file.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_pnfs.c
fs/xfs/xfs_super.c
include/crypto/internal/blake2s.h
include/dt-bindings/clock/dra7.h
include/dt-bindings/reset/delta,tn48m-reset.h [new file with mode: 0644]
include/linux/ata.h
include/linux/blkdev.h
include/linux/bpf.h
include/linux/ceph/libceph.h
include/linux/ceph/messenger.h
include/linux/compiler.h
include/linux/cpufreq.h
include/linux/dma-mapping.h
include/linux/ethtool.h
include/linux/fb.h
include/linux/firmware/intel/stratix10-smc.h
include/linux/firmware/intel/stratix10-svc-client.h
include/linux/firmware/xlnx-zynqmp.h
include/linux/fs.h
include/linux/fsnotify.h
include/linux/hyperv.h
include/linux/if_vlan.h
include/linux/iomap.h
include/linux/jbd2.h
include/linux/kfence.h
include/linux/kvm_host.h
include/linux/libata.h
include/linux/lsm_hook_defs.h
include/linux/memcontrol.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/mux/consumer.h
include/linux/netdevice.h
include/linux/netfs.h
include/linux/nfs.h
include/linux/nfs_fs.h
include/linux/nfs_fs_sb.h
include/linux/nfs_xdr.h
include/linux/nvme-tcp.h
include/linux/nvmem-provider.h
include/linux/page_table_check.h
include/linux/peci-cpu.h [new file with mode: 0644]
include/linux/peci.h [new file with mode: 0644]
include/linux/perf_event.h
include/linux/pgtable.h
include/linux/pid_namespace.h
include/linux/psi.h
include/linux/psi_types.h
include/linux/quota.h
include/linux/rtsx_pci.h
include/linux/sched.h
include/linux/sched/task.h
include/linux/skbuff.h
include/linux/slab.h
include/linux/suspend.h
include/linux/sysctl.h
include/linux/trace_events.h
include/linux/usb/role.h
include/linux/vmw_vmci_defs.h
include/net/addrconf.h
include/net/ax25.h
include/net/bond_3ad.h
include/net/bonding.h
include/net/checksum.h
include/net/dsa.h
include/net/dst_metadata.h
include/net/ip.h
include/net/ip6_fib.h
include/net/ipv6.h
include/net/neighbour.h
include/net/netfilter/nf_tables.h
include/net/netfilter/nf_tables_offload.h
include/net/netns/ipv6.h
include/net/route.h
include/net/sock.h
include/net/tcp.h
include/sound/pcm.h
include/trace/events/fsi.h
include/trace/events/fsi_master_aspeed.h
include/trace/events/skb.h
include/trace/events/sunrpc.h
include/trace/perf.h
include/trace/trace_events.h
include/uapi/linux/cyclades.h [new file with mode: 0644]
include/uapi/linux/fsi.h
include/uapi/linux/kvm.h
include/uapi/linux/netfilter/nf_conntrack_common.h
include/uapi/linux/perf_event.h
include/uapi/linux/smc_diag.h
include/uapi/misc/habanalabs.h
include/uapi/sound/asound.h
include/uapi/xen/gntdev.h
include/xen/xenbus_dev.h
ipc/sem.c
kernel/async.c
kernel/audit.c
kernel/auditsc.c
kernel/bpf/bpf_lsm.c
kernel/bpf/btf.c
kernel/bpf/helpers.c
kernel/bpf/ringbuf.c
kernel/bpf/stackmap.c
kernel/bpf/syscall.c
kernel/bpf/trampoline.c
kernel/cgroup/cgroup-v1.c
kernel/cgroup/cgroup.c
kernel/cgroup/cpuset.c
kernel/configs/android-recommended.config
kernel/cred.c
kernel/dma/swiotlb.c
kernel/events/core.c
kernel/fork.c
kernel/locking/lockdep.c
kernel/module.c
kernel/module_decompress.c
kernel/power/main.c
kernel/power/process.c
kernel/power/snapshot.c
kernel/power/suspend.c
kernel/power/wakelock.c
kernel/printk/sysctl.c
kernel/rcu/tasks.h
kernel/sched/core.c
kernel/sched/core_sched.c
kernel/sched/fair.c
kernel/sched/membarrier.c
kernel/sched/pelt.h
kernel/sched/psi.c
kernel/seccomp.c
kernel/signal.c
kernel/stackleak.c
kernel/sys.c
kernel/trace/Kconfig
kernel/trace/ftrace.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_eprobe.c
kernel/trace/trace_events_hist.c
kernel/trace/trace_events_trigger.c
kernel/trace/trace_osnoise.c
kernel/trace/trace_probe.c
kernel/trace/trace_probe.h
kernel/trace/trace_selftest.c
kernel/ucount.c
lib/crypto/blake2s.c
lib/iov_iter.c
lib/sbitmap.c
lib/test_kasan.c
mm/debug_vm_pgtable.c
mm/gup.c
mm/hugetlb.c
mm/kfence/core.c
mm/kfence/kfence_test.c
mm/khugepaged.c
mm/kmemleak.c
mm/memblock.c
mm/memcontrol.c
mm/memory-failure.c
mm/mmap.c
mm/mprotect.c
mm/page_isolation.c
mm/page_table_check.c
mm/vmscan.c
net/8021q/vlan.h
net/8021q/vlan_dev.c
net/8021q/vlan_netlink.c
net/ax25/af_ax25.c
net/ax25/ax25_dev.c
net/ax25/ax25_route.c
net/bridge/br_multicast.c
net/bridge/br_vlan.c
net/bridge/netfilter/nft_reject_bridge.c
net/can/isotp.c
net/can/j1939/transport.c
net/ceph/ceph_common.c
net/ceph/messenger.c
net/ceph/messenger_v1.c
net/ceph/messenger_v2.c
net/core/drop_monitor.c
net/core/filter.c
net/core/neighbour.c
net/core/net-procfs.c
net/core/net-sysfs.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/dsa/dsa.c
net/dsa/dsa2.c
net/dsa/dsa_priv.h
net/dsa/master.c
net/dsa/port.c
net/dsa/tag_lan9303.c
net/ieee802154/nl802154.c
net/ipv4/af_inet.c
net/ipv4/fib_frontend.c
net/ipv4/fib_lookup.h
net/ipv4/fib_semantics.c
net/ipv4/fib_trie.c
net/ipv4/ip_output.c
net/ipv4/ipmr.c
net/ipv4/netfilter/Kconfig
net/ipv4/ping.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/udp_tunnel_nic.c
net/ipv6/addrconf.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_flowlabel.c
net/ipv6/ip6_offload.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6mr.c
net/ipv6/mcast.c
net/ipv6/netfilter/Kconfig
net/ipv6/netfilter/Makefile
net/ipv6/netfilter/nf_flow_table_ipv6.c [deleted file]
net/ipv6/route.c
net/mac80211/mlme.c
net/mctp/route.c
net/mpls/af_mpls.c
net/mptcp/mib.c
net/mptcp/mib.h
net/mptcp/pm.c
net/mptcp/pm_netlink.c
net/mptcp/protocol.h
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_netbios_ns.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_tables_api.c
net/netfilter/nf_tables_offload.c
net/netfilter/nft_byteorder.c
net/netfilter/nft_connlimit.c
net/netfilter/nft_ct.c
net/netfilter/nft_dup_netdev.c
net/netfilter/nft_exthdr.c
net/netfilter/nft_fwd_netdev.c
net/netfilter/nft_immediate.c
net/netfilter/nft_limit.c
net/netfilter/nft_payload.c
net/netfilter/nft_synproxy.c
net/netfilter/xt_socket.c
net/openvswitch/actions.c
net/packet/af_packet.c
net/rxrpc/call_event.c
net/rxrpc/output.c
net/sched/act_api.c
net/sched/act_ct.c
net/sched/cls_api.c
net/sched/sch_api.c
net/sched/sch_generic.c
net/sched/sch_htb.c
net/smc/af_smc.c
net/smc/smc.h
net/smc/smc_diag.c
net/smc/smc_pnet.c
net/smc/smc_pnet.h
net/socket.c
net/sunrpc/auth_gss/gss_generic_token.c
net/sunrpc/clnt.c
net/sunrpc/rpc_pipe.c
net/sunrpc/sysfs.c
net/sunrpc/xprtrdma/backchannel.c
net/sunrpc/xprtrdma/frwr_ops.c
net/sunrpc/xprtrdma/rpc_rdma.c
net/sunrpc/xprtrdma/transport.c
net/sunrpc/xprtrdma/verbs.c
net/sunrpc/xprtsock.c
net/tipc/crypto.c
net/tipc/link.c
net/tipc/monitor.c
net/tipc/name_distr.c
net/tipc/name_table.c
net/tipc/node.c
net/tipc/socket.c
net/vmw_vsock/af_vsock.c
net/wireless/core.c
samples/seccomp/dropper.c
scripts/Makefile
scripts/Makefile.extrawarn
scripts/kconfig/confdata.c
scripts/kconfig/preprocess.c
security/integrity/digsig_asymmetric.c
security/integrity/ima/ima_fs.c
security/integrity/ima/ima_policy.c
security/integrity/ima/ima_template.c
security/integrity/integrity_audit.c
security/security.c
security/selinux/ima.c
security/selinux/ss/conditional.c
sound/core/memalloc.c
sound/core/pcm_native.c
sound/hda/intel-sdw-acpi.c
sound/pci/hda/hda_auto_parser.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_realtek.c
sound/soc/amd/acp/acp-mach-common.c
sound/soc/amd/acp/acp-mach.h
sound/soc/amd/acp/acp-sof-mach.c
sound/soc/codecs/cpcap.c
sound/soc/codecs/hdmi-codec.c
sound/soc/codecs/lpass-rx-macro.c
sound/soc/codecs/max9759.c
sound/soc/codecs/rt5668.c
sound/soc/codecs/rt5682-i2c.c
sound/soc/codecs/rt5682.c
sound/soc/codecs/rt5682.h
sound/soc/codecs/rt5682s.c
sound/soc/codecs/tas2770.c
sound/soc/codecs/wcd938x.c
sound/soc/codecs/wm_adsp.c
sound/soc/fsl/pcm030-audio-fabric.c
sound/soc/generic/simple-card.c
sound/soc/intel/skylake/skl.c
sound/soc/mediatek/Kconfig
sound/soc/qcom/lpass-platform.c
sound/soc/qcom/qdsp6/q6apm-dai.c
sound/soc/soc-acpi.c
sound/soc/soc-ops.c
sound/soc/soc-pcm.c
sound/soc/sof/intel/hda.c
sound/soc/xilinx/xlnx_formatter_pcm.c
sound/usb/implicit.c
sound/usb/mixer.c
sound/usb/quirks-table.h
tools/arch/x86/include/asm/cpufeatures.h
tools/arch/x86/include/asm/msr-index.h
tools/arch/x86/include/uapi/asm/kvm.h
tools/bpf/resolve_btfids/Makefile
tools/bpf/runqslower/runqslower.bpf.c
tools/bpf/runqslower/runqslower.c
tools/bpf/runqslower/runqslower.h
tools/cgroup/memcg_slabinfo.py
tools/include/uapi/linux/kvm.h
tools/include/uapi/linux/lirc.h [deleted file]
tools/include/uapi/linux/perf_event.h
tools/include/uapi/linux/prctl.h
tools/include/uapi/sound/asound.h
tools/lib/perf/include/internal/cpumap.h
tools/lib/perf/include/perf/cpumap.h
tools/lib/perf/libperf.map
tools/lib/perf/mmap.c
tools/lib/perf/tests/test-cpumap.c
tools/lib/perf/tests/test-evlist.c
tools/lib/perf/tests/test-evsel.c
tools/lib/subcmd/subcmd-util.h
tools/objtool/check.c
tools/perf/builtin-ftrace.c
tools/perf/builtin-script.c
tools/perf/builtin-trace.c
tools/perf/tests/attr/README
tools/perf/tests/attr/test-record-graph-default
tools/perf/tests/attr/test-record-graph-default-aarch64 [new file with mode: 0644]
tools/perf/tests/attr/test-record-graph-fp
tools/perf/tests/attr/test-record-graph-fp-aarch64 [new file with mode: 0644]
tools/perf/tests/sigtrap.c
tools/perf/trace/beauty/prctl_option.sh
tools/perf/util/annotate.c
tools/perf/util/bpf-loader.c
tools/perf/util/bpf_counter_cgroup.c
tools/perf/util/cs-etm.c
tools/perf/util/data.c
tools/perf/util/evlist-hybrid.c
tools/perf/util/machine.c
tools/perf/util/map_symbol.h
tools/perf/util/perf_event_attr_fprintf.c
tools/perf/util/session.c
tools/perf/util/sort.c
tools/perf/util/stat-display.c
tools/perf/util/synthetic-events.c
tools/scripts/Makefile.include
tools/testing/kunit/kunit_kernel.py
tools/testing/kunit/run_checks.py
tools/testing/scatterlist/linux/mm.h
tools/testing/selftests/arm64/fp/sve-ptrace.c
tools/testing/selftests/bpf/prog_tests/timer_crash.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/test_sockmap_kern.h
tools/testing/selftests/bpf/progs/timer_crash.c [new file with mode: 0644]
tools/testing/selftests/bpf/test_lirc_mode2_user.c
tools/testing/selftests/clone3/clone3.c
tools/testing/selftests/cpufreq/main.sh
tools/testing/selftests/exec/Makefile
tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc
tools/testing/selftests/futex/Makefile
tools/testing/selftests/ir/ir_loopback.c
tools/testing/selftests/kselftest_harness.h
tools/testing/selftests/kvm/Makefile
tools/testing/selftests/kvm/include/kvm_util_base.h
tools/testing/selftests/kvm/include/x86_64/processor.h
tools/testing/selftests/kvm/lib/kvm_util.c
tools/testing/selftests/kvm/lib/x86_64/processor.c
tools/testing/selftests/kvm/x86_64/amx_test.c
tools/testing/selftests/kvm/x86_64/smm_test.c
tools/testing/selftests/lkdtm/config
tools/testing/selftests/memfd/memfd_test.c
tools/testing/selftests/mincore/mincore_selftest.c
tools/testing/selftests/mount_setattr/mount_setattr_test.c
tools/testing/selftests/net/ioam6_parser.c
tools/testing/selftests/net/mptcp/diag.sh
tools/testing/selftests/net/mptcp/mptcp_join.sh
tools/testing/selftests/netfilter/Makefile
tools/testing/selftests/netfilter/nft_concat_range.sh
tools/testing/selftests/netfilter/nft_fib.sh
tools/testing/selftests/netfilter/nft_nat.sh
tools/testing/selftests/netfilter/nft_synproxy.sh [new file with mode: 0755]
tools/testing/selftests/netfilter/nft_zones_many.sh
tools/testing/selftests/openat2/Makefile
tools/testing/selftests/openat2/helpers.h
tools/testing/selftests/openat2/openat2_test.c
tools/testing/selftests/perf_events/sigtrap_threads.c
tools/testing/selftests/pidfd/pidfd.h
tools/testing/selftests/pidfd/pidfd_fdinfo_test.c
tools/testing/selftests/pidfd/pidfd_test.c
tools/testing/selftests/pidfd/pidfd_wait.c
tools/testing/selftests/rtc/settings
tools/testing/selftests/seccomp/Makefile
tools/testing/selftests/vDSO/vdso_test_abi.c
tools/testing/selftests/vm/map_fixed_noreplace.c
tools/testing/selftests/vm/userfaultfd.c
tools/testing/selftests/zram/zram.sh
tools/testing/selftests/zram/zram01.sh
tools/testing/selftests/zram/zram02.sh
tools/testing/selftests/zram/zram_lib.sh
tools/tracing/Makefile
tools/tracing/rtla/Makefile
tools/tracing/rtla/src/osnoise.c
tools/tracing/rtla/src/osnoise_hist.c
tools/tracing/rtla/src/osnoise_top.c
tools/tracing/rtla/src/timerlat_hist.c
tools/tracing/rtla/src/timerlat_top.c
tools/tracing/rtla/src/trace.c
tools/tracing/rtla/src/utils.c
usr/include/Makefile
virt/kvm/eventfd.c
virt/kvm/kvm_main.c

index b157f88..10ee110 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -70,6 +70,7 @@ Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@bootlin.com>
 Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@free-electrons.com>
 Brian Avery <b.avery@hp.com>
 Brian King <brking@us.ibm.com>
+Brian Silverman <bsilver16384@gmail.com> <brian.silverman@bluerivertech.com>
 Changbin Du <changbin.du@intel.com> <changbin.du@gmail.com>
 Changbin Du <changbin.du@intel.com> <changbin.du@intel.com>
 Chao Yu <chao@kernel.org> <chao2.yu@samsung.com>
@@ -79,6 +80,9 @@ Chris Chiu <chris.chiu@canonical.com> <chiu@endlessos.org>
 Christian Borntraeger <borntraeger@linux.ibm.com> <borntraeger@de.ibm.com>
 Christian Borntraeger <borntraeger@linux.ibm.com> <cborntra@de.ibm.com>
 Christian Borntraeger <borntraeger@linux.ibm.com> <borntrae@de.ibm.com>
+Christian Brauner <brauner@kernel.org> <christian@brauner.io>
+Christian Brauner <brauner@kernel.org> <christian.brauner@canonical.com>
+Christian Brauner <brauner@kernel.org> <christian.brauner@ubuntu.com>
 Christophe Ricard <christophe.ricard@gmail.com>
 Christoph Hellwig <hch@lst.de>
 Colin Ian King <colin.king@intel.com> <colin.king@canonical.com>
@@ -329,6 +333,9 @@ Rémi Denis-Courmont <rdenis@simphalempin.com>
 Ricardo Ribalda <ribalda@kernel.org> <ricardo@ribalda.com>
 Ricardo Ribalda <ribalda@kernel.org> Ricardo Ribalda Delgado <ribalda@kernel.org>
 Ricardo Ribalda <ribalda@kernel.org> <ricardo.ribalda@gmail.com>
+Roman Gushchin <roman.gushchin@linux.dev> <guro@fb.com>
+Roman Gushchin <roman.gushchin@linux.dev> <guroan@gmail.com>
+Roman Gushchin <roman.gushchin@linux.dev> <klamm@yandex-team.ru>
 Ross Zwisler <zwisler@kernel.org> <ross.zwisler@linux.intel.com>
 Rudolf Marek <R.Marek@sh.cvut.cz>
 Rui Saraiva <rmps@joel.ist.utl.pt>
index f5724bb..c3fec3c 100644 (file)
@@ -113,3 +113,144 @@ Description:
                    # echo 0 > /sys/devices/platform/firmware\:zynqmp-firmware/health_status
 
 Users:         Xilinx
+
+What:          /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_id
+Date:          Feb 2022
+KernelVersion: 5.18
+Contact:       "Ronak Jain" <ronak.jain@xilinx.com>
+Description:
+               This sysfs interface allows user to configure features at
+               runtime. The user can enable or disable features running at
+               firmware as well as the user can configure the parameters of
+               the features at runtime. The supported features are over
+               temperature and external watchdog. Here, the external watchdog
+               is completely different than the /dev/watchdog as the external
+               watchdog is running on the firmware and it is used to monitor
+               the health of firmware not APU(Linux). Also, the external
+               watchdog is interfaced outside of the zynqmp soc.
+
+               The supported config ids are for the feature configuration is,
+               1. PM_FEATURE_OVERTEMP_STATUS = 1, the user can enable or
+               disable the over temperature feature.
+               2. PM_FEATURE_OVERTEMP_VALUE = 2, the user can configure the
+               over temperature limit in Degree Celsius.
+               3. PM_FEATURE_EXTWDT_STATUS = 3, the user can enable or disable
+               the external watchdog feature.
+               4. PM_FEATURE_EXTWDT_VALUE = 4, the user can configure the
+               external watchdog feature.
+
+               Usage:
+
+               Select over temperature config ID to enable/disable feature
+               # echo 1 > /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_id
+
+               Check over temperature config ID is selected or not
+               # cat /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_id
+               The expected result is 1.
+
+               Select over temperature config ID to configure OT limit
+               # echo 2 > /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_id
+
+               Check over temperature config ID is selected or not
+               # cat /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_id
+               The expected result is 2.
+
+               Select external watchdog config ID to enable/disable feature
+               # echo 3 > /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_id
+
+               Check external watchdog config ID is selected or not
+               # cat /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_id
+               The expected result is 3.
+
+               Select external watchdog config ID to configure time interval
+               # echo 4 > /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_id
+
+               Check external watchdog config ID is selected or not
+               # cat /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_id
+               The expected result is 4.
+
+Users:         Xilinx
+
+What:          /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_value
+Date:          Feb 2022
+KernelVersion: 5.18
+Contact:       "Ronak Jain" <ronak.jain@xilinx.com>
+Description:
+               This sysfs interface allows to configure features at runtime.
+               The user can enable or disable features running at firmware.
+               Also, the user can configure the parameters of the features
+               at runtime. The supported features are over temperature and
+               external watchdog. Here, the external watchdog is completely
+               different than the /dev/watchdog as the external watchdog is
+               running on the firmware and it is used to monitor the health
+               of firmware not APU(Linux). Also, the external watchdog is
+               interfaced outside of the zynqmp soc.
+
+               By default the features are disabled in the firmware. The user
+               can enable features by querying appropriate config id of the
+               features.
+
+               The default limit for the over temperature is 90 Degree Celsius.
+               The default timer interval for the external watchdog is 570ms.
+
+               The supported config ids are for the feature configuration is,
+               1. PM_FEATURE_OVERTEMP_STATUS = 1, the user can enable or
+               disable the over temperature feature.
+               2. PM_FEATURE_OVERTEMP_VALUE = 2, the user can configure the
+               over temperature limit in Degree Celsius.
+               3. PM_FEATURE_EXTWDT_STATUS = 3, the user can enable or disable
+               the external watchdog feature.
+               4. PM_FEATURE_EXTWDT_VALUE = 4, the user can configure the
+               external watchdog feature.
+
+               Usage:
+
+               Enable over temperature feature
+               # echo 1 > /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_id
+               # echo 1 > /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_value
+
+               Check whether the over temperature feature is enabled or not
+               # cat /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_value
+               The expected result is 1.
+
+               Disable over temperature feature
+               # echo 1 > /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_id
+               # echo 0 > /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_value
+
+               Check whether the over temperature feature is disabled or not
+               # cat /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_value
+               The expected result is 0.
+
+               Configure over temperature limit to 50 Degree Celsius
+               # echo 2 > /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_id
+               # echo 50 > /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_value
+
+               Check whether the over temperature limit is configured or not
+               # cat /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_value
+               The expected result is 50.
+
+               Enable external watchdog feature
+               # echo 3 > /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_id
+               # echo 1 > /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_value
+
+               Check whether the external watchdog feature is enabled or not
+               # cat /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_value
+               The expected result is 1.
+
+               Disable external watchdog feature
+               # echo 3 > /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_id
+               # echo 0 > /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_value
+
+               Check whether the external watchdog feature is disabled or not
+               # cat /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_value
+               The expected result is 0.
+
+               Configure external watchdog timer interval to 500ms
+               # echo 4 > /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_id
+               # echo 500 > /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_value
+
+               Check whether the external watchdog timer interval is configured or not
+               # cat /sys/devices/platform/firmware\:zynqmp-firmware/feature_config_value
+               The expected result is 500.
+
+Users:         Xilinx
index 2667cbf..bcf6915 100644 (file)
@@ -12,24 +12,7 @@ What:           /sys/kernel/debug/habanalabs/hl<n>/clk_gate
 Date:           May 2020
 KernelVersion:  5.8
 Contact:        ogabbay@kernel.org
-Description:    Allow the root user to disable/enable in runtime the clock
-                gating mechanism in Gaudi. Due to how Gaudi is built, the
-                clock gating needs to be disabled in order to access the
-                registers of the TPC and MME engines. This is sometimes needed
-                during debug by the user and hence the user needs this option.
-                The user can supply a bitmask value, each bit represents
-                a different engine to disable/enable its clock gating feature.
-                The bitmask is composed of 20 bits:
-
-                =======   ============
-                0  -  7   DMA channels
-                8  - 11   MME engines
-                12 - 19   TPC engines
-                =======   ============
-
-                The bit's location of a specific engine can be determined
-                using (1 << GAUDI_ENGINE_ID_*). GAUDI_ENGINE_ID_* values
-                are defined in uapi habanalabs.h file in enum gaudi_engine_id
+Description:    This setting is now deprecated as clock gating is handled solely by the f/w
 
 What:           /sys/kernel/debug/habanalabs/hl<n>/command_buffers
 Date:           Jan 2019
@@ -239,6 +222,7 @@ KernelVersion:  5.6
 Contact:        ogabbay@kernel.org
 Description:    Sets the stop-on_error option for the device engines. Value of
                 "0" is for disable, otherwise enable.
+                Relevant only for GOYA and GAUDI.
 
 What:           /sys/kernel/debug/habanalabs/hl<n>/timeout_locked
 Date:           Sep 2021
diff --git a/Documentation/ABI/testing/sysfs-bus-peci b/Documentation/ABI/testing/sysfs-bus-peci
new file mode 100644 (file)
index 0000000..87454ec
--- /dev/null
@@ -0,0 +1,16 @@
+What:          /sys/bus/peci/rescan
+Date:          July 2021
+KernelVersion: 5.18
+Contact:       Iwona Winiarska <iwona.winiarska@intel.com>
+Description:
+               Writing a non-zero value to this attribute will
+               initiate scan for PECI devices on all PECI controllers
+               in the system.
+
+What:          /sys/bus/peci/devices/<controller_id>-<device_addr>/remove
+Date:          July 2021
+KernelVersion: 5.18
+Contact:       Iwona Winiarska <iwona.winiarska@intel.com>
+Description:
+               Writing a non-zero value to this attribute will
+               remove the PECI device and any of its children.
index fde21d9..8595013 100644 (file)
@@ -468,6 +468,7 @@ Description:
                        auto:            Charge normally, respect thresholds
                        inhibit-charge:  Do not charge while AC is attached
                        force-discharge: Force discharge while AC is attached
+                       ================ ====================================
 
 What:          /sys/class/power_supply/<supply_name>/technology
 Date:          May 2007
index b363827..910df0e 100644 (file)
@@ -1,4 +1,4 @@
-What:          /sys/bus/platform/drivers/aspeed-uart-routing/*/uart*
+What:          /sys/bus/platform/drivers/aspeed-uart-routing/\*/uart\*
 Date:          September 2021
 Contact:       Oskar Senft <osk@google.com>
                Chia-Wei Wang <chiawei_wang@aspeedtech.com>
@@ -9,7 +9,7 @@ Description:    Selects the RX source of the UARTx device.
                depends on the selected file.
 
                e.g.
-               cat /sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1
+               cat /sys/bus/platform/drivers/aspeed-uart-routing/\*.uart_routing/uart1
                [io1] io2 io3 io4 uart2 uart3 uart4 io6
 
                In this case, UART1 gets its input from IO1 (physical serial port 1).
@@ -17,7 +17,7 @@ Description:  Selects the RX source of the UARTx device.
 Users:         OpenBMC.  Proposed changes should be mailed to
                openbmc@lists.ozlabs.org
 
-What:          /sys/bus/platform/drivers/aspeed-uart-routing/*/io*
+What:          /sys/bus/platform/drivers/aspeed-uart-routing/\*/io\*
 Date:          September 2021
 Contact:       Oskar Senft <osk@google.com>
                Chia-Wei Wang <chiawei_wang@aspeedtech.com>
index 1f127f7..96646fb 100644 (file)
@@ -69,6 +69,12 @@ KernelVersion:  5.1
 Contact:        ogabbay@kernel.org
 Description:    Displays the device's version from the eFuse
 
+What:           /sys/class/habanalabs/hl<n>/fw_os_ver
+Date:           Dec 2021
+KernelVersion:  5.18
+Contact:        ogabbay@kernel.org
+Description:    Version of the firmware OS running on the device's CPU
+
 What:           /sys/class/habanalabs/hl<n>/hard_reset
 Date:           Jan 2019
 KernelVersion:  5.1
@@ -115,7 +121,7 @@ What:           /sys/class/habanalabs/hl<n>/infineon_ver
 Date:           Jan 2019
 KernelVersion:  5.1
 Contact:        ogabbay@kernel.org
-Description:    Version of the Device's power supply F/W code
+Description:    Version of the Device's power supply F/W code. Relevant only to GOYA and GAUDI
 
 What:           /sys/class/habanalabs/hl<n>/max_power
 Date:           Jan 2019
@@ -220,4 +226,10 @@ What:           /sys/class/habanalabs/hl<n>/uboot_ver
 Date:           Jan 2019
 KernelVersion:  5.1
 Contact:        ogabbay@kernel.org
-Description:    Version of the u-boot running on the device's CPU
\ No newline at end of file
+Description:    Version of the u-boot running on the device's CPU
+
+What:           /sys/class/habanalabs/hl<n>/vrm_ver
+Date:           Jan 2022
+KernelVersion:  not yet upstreamed
+Contact:        ogabbay@kernel.org
+Description:    Version of the Device's Voltage Regulator Monitor F/W code. N/A to GOYA and GAUDI
index f2b3439..860fe65 100644 (file)
@@ -92,7 +92,8 @@ Triggers can be set on more than one psi metric and more than one trigger
 for the same psi metric can be specified. However for each trigger a separate
 file descriptor is required to be able to poll it separately from others,
 therefore for each trigger a separate open() syscall should be made even
-when opening the same psi interface file.
+when opening the same psi interface file. Write operations to a file descriptor
+with an already existing psi trigger will fail with EBUSY.
 
 Monitors activate only when system enters stall state for the monitored
 psi metric and deactivates upon exit from the stall state. While system is
index 7db3675..f6861ca 100644 (file)
@@ -10,6 +10,7 @@ gpio
     gpio-aggregator
     sysfs
     gpio-mockup
+    gpio-sim
 
 .. only::  subproject and html
 
index 9485a5a..2f41caa 100644 (file)
@@ -266,10 +266,12 @@ Avanta family
 -------------
 
   Flavors:
+       - 88F6500
        - 88F6510
        - 88F6530P
        - 88F6550
        - 88F6560
+       - 88F6601
 
   Homepage:
        https://web.archive.org/web/20181005145041/http://www.marvell.com/broadband/
index 5342e89..ea281dd 100644 (file)
@@ -52,6 +52,12 @@ stable kernels.
 | Allwinner      | A64/R18         | UNKNOWN1        | SUN50I_ERRATUM_UNKNOWN1     |
 +----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A510     | #2064142        | ARM64_ERRATUM_2064142       |
++----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A510     | #2038923        | ARM64_ERRATUM_2038923       |
++----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A510     | #1902691        | ARM64_ERRATUM_1902691       |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A53      | #826319         | ARM64_ERRATUM_826319        |
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A53      | #827319         | ARM64_ERRATUM_827319        |
@@ -92,12 +98,20 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A77      | #1508412        | ARM64_ERRATUM_1508412       |
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A510     | #2051678        | ARM64_ERRATUM_2051678       |
++----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A510     | #2077057        | ARM64_ERRATUM_2077057       |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A710     | #2119858        | ARM64_ERRATUM_2119858       |
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A710     | #2054223        | ARM64_ERRATUM_2054223       |
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A710     | #2224489        | ARM64_ERRATUM_2224489       |
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-X2       | #2119858        | ARM64_ERRATUM_2119858       |
++----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-X2       | #2224489        | ARM64_ERRATUM_2224489       |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Neoverse-N1     | #1188873,1418040| ARM64_ERRATUM_1418040       |
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Neoverse-N1     | #1349291        | N/A                         |
index 1887d92..17706dc 100644 (file)
@@ -130,3 +130,11 @@ accesses to DMA buffers in both privileged "supervisor" and unprivileged
 subsystem that the buffer is fully accessible at the elevated privilege
 level (and ideally inaccessible or at least read-only at the
 lesser-privileged levels).
+
+DMA_ATTR_OVERWRITE
+------------------
+
+This is a hint to the DMA-mapping subsystem that the device is expected to
+overwrite the entire mapped size, thus the caller does not require any of the
+previous buffer contents to be preserved. This allows bounce-buffering
+implementations to optimise DMA_FROM_DEVICE transfers.
index 3b32336..d84eded 100644 (file)
@@ -75,6 +75,9 @@ And optionally
  .resume - A pointer to a per-policy resume function which is called
  with interrupts disabled and _before_ the governor is started again.
 
+ .ready - A pointer to a per-policy ready function which is called after
+ the policy is fully initialized.
+
  .attr - A pointer to a NULL-terminated list of "struct freq_attr" which
  allow to export values to sysfs.
 
index dcefee7..a833ecf 100644 (file)
@@ -7,6 +7,14 @@ directory. These are intended to be small tests to exercise individual code
 paths in the kernel. Tests are intended to be run after building, installing
 and booting a kernel.
 
+Kselftest from mainline can be run on older stable kernels. Running tests
+from mainline offers the best coverage. Several test rings run mainline
+kselftest suite on stable releases. The reason is that when a new test
+gets added to test existing code to regression test a bug, we should be
+able to run that test on an older kernel. Hence, it is important to keep
+code that can still test an older kernel and make sure it skips the test
+gracefully on newer releases.
+
 You can find additional information on Kselftest framework, how to
 write new tests using the framework on Kselftest wiki:
 
index 76af931..1c83e7d 100644 (file)
@@ -242,7 +242,7 @@ example:
 
        int rectangle_area(struct shape *this)
        {
-               struct rectangle *self = container_of(this, struct shape, parent);
+               struct rectangle *self = container_of(this, struct rectangle, parent);
 
                return self->length * self->width;
        };
index e77635c..fa8b316 100644 (file)
@@ -119,6 +119,9 @@ Boards (incomplete list of examples):
 - OMAP3 BeagleBoard : Low cost community board
   compatible = "ti,omap3-beagle", "ti,omap3430", "ti,omap3"
 
+- OMAP3 BeagleBoard A to B4 : Early BeagleBoard revisions A to B4 with a timer quirk
+  compatible = "ti,omap3-beagle-ab4", "ti,omap3-beagle", "ti,omap3430", "ti,omap3"
+
 - OMAP3 Tobi with Overo : Commercial expansion board with daughter board
   compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap3430", "ti,omap3"
 
diff --git a/Documentation/devicetree/bindings/gpio/delta,tn48m-gpio.yaml b/Documentation/devicetree/bindings/gpio/delta,tn48m-gpio.yaml
new file mode 100644 (file)
index 0000000..e3e668a
--- /dev/null
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpio/delta,tn48m-gpio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Delta Networks TN48M CPLD GPIO controller
+
+maintainers:
+  - Robert Marko <robert.marko@sartura.hr>
+
+description: |
+  This module is part of the Delta TN48M multi-function device. For more
+  details see ../mfd/delta,tn48m-cpld.yaml.
+
+  Delta TN48M has an onboard Lattice CPLD that is used as an GPIO expander.
+  It provides 12 pins in total, they are input-only or ouput-only type.
+
+properties:
+  compatible:
+    enum:
+      - delta,tn48m-gpo
+      - delta,tn48m-gpi
+
+  reg:
+    maxItems: 1
+
+  "#gpio-cells":
+    const: 2
+
+  gpio-controller: true
+
+required:
+  - compatible
+  - reg
+  - "#gpio-cells"
+  - gpio-controller
+
+additionalProperties: false
index e043495..427c587 100644 (file)
@@ -7,7 +7,6 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: SiFive GPIO controller
 
 maintainers:
-  - Yash Shah <yash.shah@sifive.com>
   - Paul Walmsley <paul.walmsley@sifive.com>
 
 properties:
index 79d0358..620f017 100644 (file)
@@ -36,6 +36,7 @@ properties:
           - renesas,intc-ex-r8a77980    # R-Car V3H
           - renesas,intc-ex-r8a77990    # R-Car E3
           - renesas,intc-ex-r8a77995    # R-Car D3
+          - renesas,intc-ex-r8a779a0    # R-Car V3U
       - const: renesas,irqc
 
   '#interrupt-cells':
index 28b6b17..27092c6 100644 (file)
@@ -35,6 +35,10 @@ description:
   contains a specific memory layout, which is documented in chapter 8 of the
   SiFive U5 Coreplex Series Manual <https://static.dev.sifive.com/U54-MC-RVCoreIP.pdf>.
 
+  The thead,c900-plic is different from sifive,plic-1.0.0 in opensbi, the
+  T-HEAD PLIC implementation requires setting a delegation bit to allow access
+  from S-mode. So add thead,c900-plic to distinguish them.
+
 maintainers:
   - Sagar Kadam <sagar.kadam@sifive.com>
   - Paul Walmsley  <paul.walmsley@sifive.com>
@@ -42,12 +46,17 @@ maintainers:
 
 properties:
   compatible:
-    items:
-      - enum:
-          - sifive,fu540-c000-plic
-          - starfive,jh7100-plic
-          - canaan,k210-plic
-      - const: sifive,plic-1.0.0
+    oneOf:
+      - items:
+          - enum:
+              - sifive,fu540-c000-plic
+              - starfive,jh7100-plic
+              - canaan,k210-plic
+          - const: sifive,plic-1.0.0
+      - items:
+          - enum:
+              - allwinner,sun20i-d1-plic
+          - const: thead,c900-plic
 
   reg:
     maxItems: 1
@@ -62,6 +71,7 @@ properties:
 
   interrupts-extended:
     minItems: 1
+    maxItems: 15872
     description:
       Specifies which contexts are connected to the PLIC, with "-1" specifying
       that a context is not present. Each node pointed to should be a
@@ -90,12 +100,11 @@ examples:
       #interrupt-cells = <1>;
       compatible = "sifive,fu540-c000-plic", "sifive,plic-1.0.0";
       interrupt-controller;
-      interrupts-extended = <
-        &cpu0_intc 11
-        &cpu1_intc 11 &cpu1_intc 9
-        &cpu2_intc 11 &cpu2_intc 9
-        &cpu3_intc 11 &cpu3_intc 9
-        &cpu4_intc 11 &cpu4_intc 9>;
+      interrupts-extended = <&cpu0_intc 11>,
+                            <&cpu1_intc 11>, <&cpu1_intc 9>,
+                            <&cpu2_intc 11>, <&cpu2_intc 9>,
+                            <&cpu3_intc 11>, <&cpu3_intc 9>,
+                            <&cpu4_intc 11>, <&cpu4_intc 9>;
       reg = <0xc000000 0x4000000>;
       riscv,ndev = <10>;
     };
diff --git a/Documentation/devicetree/bindings/mfd/delta,tn48m-cpld.yaml b/Documentation/devicetree/bindings/mfd/delta,tn48m-cpld.yaml
new file mode 100644 (file)
index 0000000..f6967c1
--- /dev/null
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/delta,tn48m-cpld.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Delta Networks TN48M CPLD controller
+
+maintainers:
+  - Robert Marko <robert.marko@sartura.hr>
+
+description: |
+  Lattice CPLD onboard the TN48M switches is used for system
+  management.
+
+  It provides information about the hardware model, revision,
+  PSU status etc.
+
+  It is also being used as a GPIO expander and reset controller
+  for the switch MAC-s and other peripherals.
+
+properties:
+  compatible:
+    const: delta,tn48m-cpld
+
+  reg:
+    description:
+      I2C device address.
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+
+patternProperties:
+  "^gpio(@[0-9a-f]+)?$":
+    $ref: ../gpio/delta,tn48m-gpio.yaml
+
+  "^reset-controller?$":
+    $ref: ../reset/delta,tn48m-reset.yaml
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        cpld@41 {
+            compatible = "delta,tn48m-cpld";
+            reg = <0x41>;
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            gpio@31 {
+                compatible = "delta,tn48m-gpo";
+                reg = <0x31>;
+                gpio-controller;
+                #gpio-cells = <2>;
+            };
+
+            gpio@3a {
+                compatible = "delta,tn48m-gpi";
+                reg = <0x3a>;
+                gpio-controller;
+                #gpio-cells = <2>;
+            };
+
+            gpio@40 {
+                compatible = "delta,tn48m-gpi";
+                reg = <0x40>;
+                gpio-controller;
+                #gpio-cells = <2>;
+            };
+
+            reset-controller {
+              compatible = "delta,tn48m-reset";
+              #reset-cells = <1>;
+            };
+        };
+    };
index 272832e..fa86691 100644 (file)
@@ -20,7 +20,7 @@ description: |
 
 maintainers:
   - Kishon Vijay Abraham I <kishon@ti.com>
-  - Roger Quadros <rogerq@ti.com
+  - Roger Quadros <rogerq@kernel.org>
 
 properties:
   compatible:
index 0968b40..e3501bf 100644 (file)
@@ -31,7 +31,7 @@ tcan4x5x: tcan4x5x@0 {
                #address-cells = <1>;
                #size-cells = <1>;
                spi-max-frequency = <10000000>;
-               bosch,mram-cfg = <0x0 0 0 32 0 0 1 1>;
+               bosch,mram-cfg = <0x0 0 0 16 0 0 1 1>;
                interrupt-parent = <&gpio1>;
                interrupts = <14 IRQ_TYPE_LEVEL_LOW>;
                device-state-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
index b86edf6..58ecc62 100644 (file)
@@ -107,6 +107,10 @@ properties:
           - const: imem
           - const: config
 
+  qcom,qmp:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: phandle to the AOSS side-channel message RAM
+
   qcom,smem-states:
     $ref: /schemas/types.yaml#/definitions/phandle-array
     description: State bits used in by the AP to signal the modem.
@@ -222,6 +226,8 @@ examples:
                                      "imem",
                                      "config";
 
+                qcom,qmp = <&aoss_qmp>;
+
                 qcom,smem-states = <&ipa_smp2p_out 0>,
                                    <&ipa_smp2p_out 1>;
                 qcom,smem-state-names = "ipa-clock-enabled-valid",
index 6687ab7..e558587 100644 (file)
@@ -20,6 +20,7 @@ properties:
       - const: allwinner,sun7i-a20-sid
       - const: allwinner,sun8i-a83t-sid
       - const: allwinner,sun8i-h3-sid
+      - const: allwinner,sun20i-d1-sid
       - const: allwinner,sun50i-a64-sid
       - items:
           - const: allwinner,sun50i-a100-sid
diff --git a/Documentation/devicetree/bindings/nvmem/fsl,layerscape-sfp.yaml b/Documentation/devicetree/bindings/nvmem/fsl,layerscape-sfp.yaml
new file mode 100644 (file)
index 0000000..80914b9
--- /dev/null
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/fsl,layerscape-sfp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale Layerscape Security Fuse Processor
+
+maintainers:
+  - Michael Walle <michael@walle.cc>
+
+description: |
+  SFP is the security fuse processor which among other things provide a
+  unique identifier per part.
+
+allOf:
+  - $ref: "nvmem.yaml#"
+
+properties:
+  compatible:
+    enum:
+      - fsl,ls1028a-sfp
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    efuse@1e80000 {
+        compatible = "fsl,ls1028a-sfp";
+        reg = <0x1e80000 0x8000>;
+    };
diff --git a/Documentation/devicetree/bindings/nvmem/sunplus,sp7021-ocotp.yaml b/Documentation/devicetree/bindings/nvmem/sunplus,sp7021-ocotp.yaml
new file mode 100644 (file)
index 0000000..4b28f37
--- /dev/null
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/sunplus,sp7021-ocotp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: On-Chip OTP Memory for Sunplus SP7021
+
+maintainers:
+  - Vincent Shih <vincent.sunplus@gmail.com>
+
+allOf:
+  - $ref: "nvmem.yaml#"
+
+properties:
+  compatible:
+    const: sunplus,sp7021-ocotp
+
+  reg:
+    maxItems: 2
+
+  reg-names:
+    items:
+      - const: hb_gpio
+      - const: otprx
+
+  clocks:
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 1
+
+  thermal-calibration:
+    type: object
+    description: thermal calibration values
+
+  disconnect-voltage:
+    type: object
+    description: disconnect voltages of usb2 port 0 and port 1
+
+  mac-address0:
+    type: object
+    description: MAC address of ethernet port 0
+
+  mac-address1:
+    type: object
+    description: MAC address of ethernet port 1
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - clocks
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/sp-sp7021.h>
+
+    otp: otp@9c00af00 {
+        compatible = "sunplus,sp7021-ocotp";
+        reg = <0x9c00af00 0x34>, <0x9c00af80 0x58>;
+        reg-names = "hb_gpio", "otprx";
+        clocks = <&clks OTPRX>;
+
+        #address-cells = <1>;
+        #size-cells = <1>;
+        therm_calib: thermal-calibration@14 {
+          reg = <0x14 0x3>;
+        };
+        disc_vol: disconnect-voltage@18 {
+          reg = <0x18 0x2>;
+        };
+        mac_addr0: mac-address0@34 {
+          reg = <0x34 0x6>;
+        };
+        mac_addr1: mac-address1@3a {
+          reg = <0x3a 0x6>;
+        };
+    };
+...
diff --git a/Documentation/devicetree/bindings/peci/peci-aspeed.yaml b/Documentation/devicetree/bindings/peci/peci-aspeed.yaml
new file mode 100644 (file)
index 0000000..1e68a80
--- /dev/null
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/peci/peci-aspeed.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Aspeed PECI Bus Device Tree Bindings
+
+maintainers:
+  - Iwona Winiarska <iwona.winiarska@intel.com>
+  - Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+
+allOf:
+  - $ref: peci-controller.yaml#
+
+properties:
+  compatible:
+    enum:
+      - aspeed,ast2400-peci
+      - aspeed,ast2500-peci
+      - aspeed,ast2600-peci
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    description:
+      Clock source for PECI controller. Should reference the external
+      oscillator clock.
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  cmd-timeout-ms:
+    minimum: 1
+    maximum: 1000
+    default: 1000
+
+  clock-frequency:
+    description:
+      The desired operation frequency of PECI controller in Hz.
+    minimum: 2000
+    maximum: 2000000
+    default: 1000000
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - resets
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/ast2600-clock.h>
+    peci-controller@1e78b000 {
+      compatible = "aspeed,ast2600-peci";
+      reg = <0x1e78b000 0x100>;
+      interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+      clocks = <&syscon ASPEED_CLK_GATE_REF0CLK>;
+      resets = <&syscon ASPEED_RESET_PECI>;
+      cmd-timeout-ms = <1000>;
+      clock-frequency = <1000000>;
+    };
+...
diff --git a/Documentation/devicetree/bindings/peci/peci-controller.yaml b/Documentation/devicetree/bindings/peci/peci-controller.yaml
new file mode 100644 (file)
index 0000000..bbc3d3f
--- /dev/null
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/peci/peci-controller.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic Device Tree Bindings for PECI
+
+maintainers:
+  - Iwona Winiarska <iwona.winiarska@intel.com>
+
+description:
+  PECI (Platform Environment Control Interface) is an interface that provides a
+  communication channel from Intel processors and chipset components to external
+  monitoring or control devices.
+
+properties:
+  $nodename:
+    pattern: "^peci-controller(@.*)?$"
+
+  cmd-timeout-ms:
+    description:
+      Command timeout in units of ms.
+
+additionalProperties: true
+
+examples:
+  - |
+    peci-controller@1e78b000 {
+      reg = <0x1e78b000 0x100>;
+      cmd-timeout-ms = <500>;
+    };
+...
index cbbf5e8..f78d324 100644 (file)
@@ -8,7 +8,7 @@ title: OMAP USB2 PHY
 
 maintainers:
   - Kishon Vijay Abraham I <kishon@ti.com>
-  - Roger Quadros <rogerq@ti.com>
+  - Roger Quadros <rogerq@kernel.org>
 
 properties:
   compatible:
index 84e6691..db41cd7 100644 (file)
@@ -8,7 +8,6 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: SiFive PWM controller
 
 maintainers:
-  - Yash Shah <yash.shah@sifive.com>
   - Sagar Kadam <sagar.kadam@sifive.com>
   - Paul Walmsley <paul.walmsley@sifive.com>
 
diff --git a/Documentation/devicetree/bindings/reserved-memory/google,open-dice.yaml b/Documentation/devicetree/bindings/reserved-memory/google,open-dice.yaml
new file mode 100644 (file)
index 0000000..257a0b5
--- /dev/null
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/reserved-memory/google,open-dice.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Open Profile for DICE Device Tree Bindings
+
+description: |
+  This binding represents a reserved memory region containing data
+  generated by the Open Profile for DICE protocol.
+
+  See https://pigweed.googlesource.com/open-dice/
+
+maintainers:
+  - David Brazdil <dbrazdil@google.com>
+
+allOf:
+  - $ref: "reserved-memory.yaml"
+
+properties:
+  compatible:
+    const: google,open-dice
+
+  reg:
+    description: page-aligned region of memory containing DICE data
+
+required:
+  - compatible
+  - reg
+  - no-map
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    reserved-memory {
+        #address-cells = <2>;
+        #size-cells = <1>;
+
+        dice: dice@12340000 {
+            compatible = "google,open-dice";
+            reg = <0x00 0x12340000 0x2000>;
+            no-map;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/reset/delta,tn48m-reset.yaml b/Documentation/devicetree/bindings/reset/delta,tn48m-reset.yaml
new file mode 100644 (file)
index 0000000..0e5ee8d
--- /dev/null
@@ -0,0 +1,35 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/reset/delta,tn48m-reset.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Delta Networks TN48M CPLD reset controller
+
+maintainers:
+  - Robert Marko <robert.marko@sartura.hr>
+
+description: |
+  This module is part of the Delta TN48M multi-function device. For more
+  details see ../mfd/delta,tn48m-cpld.yaml.
+
+  Reset controller modules provides resets for the following:
+  * 88F7040 SoC
+  * 88F6820 SoC
+  * 98DX3265 switch MAC-s
+  * 88E1680 PHY-s
+  * 88E1512 PHY
+  * PoE PSE controller
+
+properties:
+  compatible:
+    const: delta,tn48m-reset
+
+  "#reset-cells":
+    const: 1
+
+required:
+  - compatible
+  - "#reset-cells"
+
+additionalProperties: false
index 2b1f916..e2d330b 100644 (file)
@@ -9,7 +9,6 @@ title: SiFive L2 Cache Controller
 
 maintainers:
   - Sagar Kadam <sagar.kadam@sifive.com>
-  - Yash Shah <yash.shah@sifive.com>
   - Paul Walmsley  <paul.walmsley@sifive.com>
 
 description:
index 77adbeb..c3e9f34 100644 (file)
@@ -8,6 +8,7 @@ title: Audio codec controlled by ChromeOS EC
 
 maintainers:
   - Cheng-Yi Chiang <cychiang@chromium.org>
+  - Tzung-Bi Shih <tzungbi@google.com>
 
 description: |
   Google's ChromeOS EC codec is a digital mic codec provided by the
index b93a2b3..51ddbc5 100644 (file)
@@ -22,7 +22,19 @@ board specific bus parameters.
 - interrupts:
        Usage: required
        Value type: <prop-encoded-array>
-       Definition: should specify the SoundWire Controller IRQ
+       Definition: should specify the SoundWire Controller core and optional
+                   wake IRQ
+
+- interrupt-names:
+       Usage: Optional
+       Value type: boolean
+       Value type: <stringlist>
+       Definition: should be "core" for core and "wakeup" for wake interrupt.
+
+- wakeup-source:
+       Usage: Optional
+       Value type: boolean
+       Definition: should specify if SoundWire Controller is wake up capable.
 
 - clock-names:
        Usage: required
index 5dd2092..3ec2d7b 100644 (file)
@@ -23,8 +23,9 @@ properties:
     minItems: 1
     maxItems: 256
     items:
-      minimum: 0
-      maximum: 256
+      items:
+        - minimum: 0
+          maximum: 256
     description:
       Chip select used by the device.
 
index a634774..eedde38 100644 (file)
@@ -7,7 +7,7 @@ $schema: "http://devicetree.org/meta-schemas/core.yaml#"
 title: Bindings for the TI wrapper module for the Cadence USBSS-DRD controller
 
 maintainers:
-  - Roger Quadros <rogerq@ti.com>
+  - Roger Quadros <rogerq@kernel.org>
 
 properties:
   compatible:
index f6e91a5..4f7a212 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: TI Keystone Soc USB Controller
 
 maintainers:
-  - Roger Quadros <rogerq@ti.com>
+  - Roger Quadros <rogerq@kernel.org>
 
 properties:
   compatible:
index 148e193..5018403 100644 (file)
@@ -368,6 +368,7 @@ MUX
   devm_mux_chip_alloc()
   devm_mux_chip_register()
   devm_mux_control_get()
+  devm_mux_state_get()
 
 NET
   devm_alloc_etherdev()
index 287e868..e336632 100644 (file)
@@ -26,9 +26,7 @@ was a rather big abstraction leak.
 
 This framework aims at solve these problems. It also introduces DT
 representation for consumer devices to go get the data they require (MAC
-Addresses, SoC/Revision ID, part numbers, and so on) from the NVMEMs. This
-framework is based on regmap, so that most of the abstraction available in
-regmap can be reused, across multiple types of buses.
+Addresses, SoC/Revision ID, part numbers, and so on) from the NVMEMs.
 
 NVMEM Providers
 +++++++++++++++
@@ -45,23 +43,21 @@ nvmem_device pointer.
 
 nvmem_unregister(nvmem) is used to unregister a previously registered provider.
 
-For example, a simple qfprom case::
+For example, a simple nvram case::
 
-  static struct nvmem_config econfig = {
-       .name = "qfprom",
-       .owner = THIS_MODULE,
-  };
-
-  static int qfprom_probe(struct platform_device *pdev)
+  static int brcm_nvram_probe(struct platform_device *pdev)
   {
+       struct nvmem_config config = {
+               .name = "brcm-nvram",
+               .reg_read = brcm_nvram_read,
+       };
        ...
-       econfig.dev = &pdev->dev;
-       nvmem = nvmem_register(&econfig);
-       ...
-  }
+       config.dev = &pdev->dev;
+       config.priv = priv;
+       config.size = resource_size(res);
 
-It is mandatory that the NVMEM provider has a regmap associated with its
-struct device. Failure to do would return error code from nvmem_register().
+       devm_nvmem_register(&config);
+  }
 
 Users of board files can define and register nvmem cells using the
 nvmem_cell_table struct::
index 136f8da..4f373a8 100644 (file)
@@ -462,6 +462,10 @@ operation table looks like the following::
                             struct iov_iter *iter,
                             netfs_io_terminated_t term_func,
                             void *term_func_priv);
+
+               int (*query_occupancy)(struct netfs_cache_resources *cres,
+                                      loff_t start, size_t len, size_t granularity,
+                                      loff_t *_data_start, size_t *_data_len);
        };
 
 With a termination handler function pointer::
@@ -536,6 +540,18 @@ The methods defined in the table are:
    indicating whether the termination is definitely happening in the caller's
    context.
 
+ * ``query_occupancy()``
+
+   [Required] Called to find out where the next piece of data is within a
+   particular region of the cache.  The start and length of the region to be
+   queried are passed in, along with the granularity to which the answer needs
+   to be aligned.  The function passes back the start and length of the data,
+   if any, available within that region.  Note that there may be a hole at the
+   front.
+
+   It returns 0 if some data was found, -ENODATA if there was no usable data
+   within the region or -ENOBUFS if there is no caching on this file.
+
 Note that these methods are passed a pointer to the cache resource structure,
 not the read request structure as they could be used in other situations where
 there isn't a read request structure as well, such as writing dirty data to the
index da138dd..a1212b5 100644 (file)
@@ -300,30 +300,6 @@ Contact: Daniel Vetter, Noralf Tronnes
 
 Level: Advanced
 
-Garbage collect fbdev scrolling acceleration
---------------------------------------------
-
-Scroll acceleration has been disabled in fbcon. Now it works as the old
-SCROLL_REDRAW mode. A ton of code was removed in fbcon.c and the hook bmove was
-removed from fbcon_ops.
-Remaining tasks:
-
-- a bunch of the hooks in fbcon_ops could be removed or simplified by calling
-  directly instead of the function table (with a switch on p->rotate)
-
-- fb_copyarea is unused after this, and can be deleted from all drivers
-
-- after that, fb_copyarea can be deleted from fb_ops in include/linux/fb.h as
-  well as cfb_copyarea
-
-Note that not all acceleration code can be deleted, since clearing and cursor
-support is still accelerated, which might be good candidates for further
-deletion projects.
-
-Contact: Daniel Vetter
-
-Level: Intermediate
-
 idr_init_base()
 ---------------
 
index df20022..f387f66 100644 (file)
@@ -161,6 +161,8 @@ Hardware Monitoring Kernel Drivers
    pcf8591
    pim4328
    pm6764tr
+   peci-cputemp
+   peci-dimmtemp
    pmbus
    powr1220
    pxe1610
diff --git a/Documentation/hwmon/peci-cputemp.rst b/Documentation/hwmon/peci-cputemp.rst
new file mode 100644 (file)
index 0000000..fe04222
--- /dev/null
@@ -0,0 +1,90 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+
+Kernel driver peci-cputemp
+==========================
+
+Supported chips:
+       One of Intel server CPUs listed below which is connected to a PECI bus.
+               * Intel Xeon E5/E7 v3 server processors
+                       Intel Xeon E5-14xx v3 family
+                       Intel Xeon E5-24xx v3 family
+                       Intel Xeon E5-16xx v3 family
+                       Intel Xeon E5-26xx v3 family
+                       Intel Xeon E5-46xx v3 family
+                       Intel Xeon E7-48xx v3 family
+                       Intel Xeon E7-88xx v3 family
+               * Intel Xeon E5/E7 v4 server processors
+                       Intel Xeon E5-16xx v4 family
+                       Intel Xeon E5-26xx v4 family
+                       Intel Xeon E5-46xx v4 family
+                       Intel Xeon E7-48xx v4 family
+                       Intel Xeon E7-88xx v4 family
+               * Intel Xeon Scalable server processors
+                       Intel Xeon D family
+                       Intel Xeon Bronze family
+                       Intel Xeon Silver family
+                       Intel Xeon Gold family
+                       Intel Xeon Platinum family
+
+       Datasheet: Available from http://www.intel.com/design/literature.htm
+
+Author: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+
+Description
+-----------
+
+This driver implements a generic PECI hwmon feature which provides Digital
+Thermal Sensor (DTS) thermal readings of the CPU package and CPU cores that are
+accessible via the processor PECI interface.
+
+All temperature values are given in millidegree Celsius and will be measurable
+only when the target CPU is powered on.
+
+Sysfs interface
+-------------------
+
+======================= =======================================================
+temp1_label            "Die"
+temp1_input            Provides current die temperature of the CPU package.
+temp1_max              Provides thermal control temperature of the CPU package
+                       which is also known as Tcontrol.
+temp1_crit             Provides shutdown temperature of the CPU package which
+                       is also known as the maximum processor junction
+                       temperature, Tjmax or Tprochot.
+temp1_crit_hyst                Provides the hysteresis value from Tcontrol to Tjmax of
+                       the CPU package.
+
+temp2_label            "DTS"
+temp2_input            Provides current temperature of the CPU package scaled
+                       to match DTS thermal profile.
+temp2_max              Provides thermal control temperature of the CPU package
+                       which is also known as Tcontrol.
+temp2_crit             Provides shutdown temperature of the CPU package which
+                       is also known as the maximum processor junction
+                       temperature, Tjmax or Tprochot.
+temp2_crit_hyst                Provides the hysteresis value from Tcontrol to Tjmax of
+                       the CPU package.
+
+temp3_label            "Tcontrol"
+temp3_input            Provides current Tcontrol temperature of the CPU
+                       package which is also known as Fan Temperature target.
+                       Indicates the relative value from thermal monitor trip
+                       temperature at which fans should be engaged.
+temp3_crit             Provides Tcontrol critical value of the CPU package
+                       which is same to Tjmax.
+
+temp4_label            "Tthrottle"
+temp4_input            Provides current Tthrottle temperature of the CPU
+                       package. Used for throttling temperature. If this value
+                       is allowed and lower than Tjmax - the throttle will
+                       occur and reported at lower than Tjmax.
+
+temp5_label            "Tjmax"
+temp5_input            Provides the maximum junction temperature, Tjmax of the
+                       CPU package.
+
+temp[6-N]_label                Provides string "Core X", where X is resolved core
+                       number.
+temp[6-N]_input                Provides current temperature of each core.
+
+======================= =======================================================
diff --git a/Documentation/hwmon/peci-dimmtemp.rst b/Documentation/hwmon/peci-dimmtemp.rst
new file mode 100644 (file)
index 0000000..e562aed
--- /dev/null
@@ -0,0 +1,57 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver peci-dimmtemp
+===========================
+
+Supported chips:
+       One of Intel server CPUs listed below which is connected to a PECI bus.
+               * Intel Xeon E5/E7 v3 server processors
+                       Intel Xeon E5-14xx v3 family
+                       Intel Xeon E5-24xx v3 family
+                       Intel Xeon E5-16xx v3 family
+                       Intel Xeon E5-26xx v3 family
+                       Intel Xeon E5-46xx v3 family
+                       Intel Xeon E7-48xx v3 family
+                       Intel Xeon E7-88xx v3 family
+               * Intel Xeon E5/E7 v4 server processors
+                       Intel Xeon E5-16xx v4 family
+                       Intel Xeon E5-26xx v4 family
+                       Intel Xeon E5-46xx v4 family
+                       Intel Xeon E7-48xx v4 family
+                       Intel Xeon E7-88xx v4 family
+               * Intel Xeon Scalable server processors
+                       Intel Xeon D family
+                       Intel Xeon Bronze family
+                       Intel Xeon Silver family
+                       Intel Xeon Gold family
+                       Intel Xeon Platinum family
+
+       Datasheet: Available from http://www.intel.com/design/literature.htm
+
+Author: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+
+Description
+-----------
+
+This driver implements a generic PECI hwmon feature which provides
+Temperature sensor on DIMM readings that are accessible via the processor PECI interface.
+
+All temperature values are given in millidegree Celsius and will be measurable
+only when the target CPU is powered on.
+
+Sysfs interface
+-------------------
+
+======================= =======================================================
+
+temp[N]_label          Provides string "DIMM CI", where C is DIMM channel and
+                       I is DIMM index of the populated DIMM.
+temp[N]_input          Provides current temperature of the populated DIMM.
+temp[N]_max            Provides thermal control temperature of the DIMM.
+temp[N]_crit           Provides shutdown temperature of the DIMM.
+
+======================= =======================================================
+
+Note:
+       DIMM temperature attributes will appear when the client CPU's BIOS
+       completes memory training and testing.
index 2b4de39..1988c19 100644 (file)
@@ -138,6 +138,7 @@ needed).
    scheduler/index
    mhi/index
    tty/index
+   peci/index
 
 Architecture-agnostic documentation
 -----------------------------------
@@ -166,6 +167,7 @@ to ReStructured Text format, or are simply too old.
 .. toctree::
    :maxdepth: 2
 
+   tools/index
    staging/index
    watch_queue
 
index e6cd406..4cbd50e 100644 (file)
@@ -295,7 +295,7 @@ Pete Zaitcev gives the following summary:
 
 -  If you are in a process context (any syscall) and want to lock other
    process out, use a mutex. You can take a mutex and sleep
-   (``copy_from_user*(`` or ``kmalloc(x,GFP_KERNEL)``).
+   (``copy_from_user()`` or ``kmalloc(x,GFP_KERNEL)``).
 
 -  Otherwise (== data can be touched in an interrupt), use
    spin_lock_irqsave() and
diff --git a/Documentation/peci/index.rst b/Documentation/peci/index.rst
new file mode 100644 (file)
index 0000000..989de10
--- /dev/null
@@ -0,0 +1,16 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+
+====================
+Linux PECI Subsystem
+====================
+
+.. toctree::
+
+   peci
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
diff --git a/Documentation/peci/peci.rst b/Documentation/peci/peci.rst
new file mode 100644 (file)
index 0000000..331b1ec
--- /dev/null
@@ -0,0 +1,51 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+
+========
+Overview
+========
+
+The Platform Environment Control Interface (PECI) is a communication
+interface between Intel processor and management controllers
+(e.g. Baseboard Management Controller, BMC).
+PECI provides services that allow the management controller to
+configure, monitor and debug platform by accessing various registers.
+It defines a dedicated command protocol, where the management
+controller is acting as a PECI originator and the processor - as
+a PECI responder.
+PECI can be used in both single processor and multiple-processor based
+systems.
+
+NOTE:
+Intel PECI specification is not released as a dedicated document,
+instead it is a part of External Design Specification (EDS) for given
+Intel CPU. External Design Specifications are usually not publicly
+available.
+
+PECI Wire
+---------
+
+PECI Wire interface uses a single wire for self-clocking and data
+transfer. It does not require any additional control lines - the
+physical layer is a self-clocked one-wire bus signal that begins each
+bit with a driven, rising edge from an idle near zero volts. The
+duration of the signal driven high allows to determine whether the bit
+value is logic '0' or logic '1'. PECI Wire also includes variable data
+rate established with every message.
+
+For PECI Wire, each processor package will utilize unique, fixed
+addresses within a defined range and that address should
+have a fixed relationship with the processor socket ID - if one of the
+processors is removed, it does not affect addresses of remaining
+processors.
+
+PECI subsystem internals
+------------------------
+
+.. kernel-doc:: include/linux/peci.h
+.. kernel-doc:: drivers/peci/internal.h
+.. kernel-doc:: drivers/peci/core.c
+.. kernel-doc:: drivers/peci/request.c
+
+PECI CPU Driver API
+-------------------
+.. kernel-doc:: drivers/peci/cpu.c
diff --git a/Documentation/tools/index.rst b/Documentation/tools/index.rst
new file mode 100644 (file)
index 0000000..0bb1e61
--- /dev/null
@@ -0,0 +1,20 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+============
+Kernel tools
+============
+
+This book covers user-space tools that are shipped with the kernel source;
+more additions are needed here:
+
+.. toctree::
+   :maxdepth: 1
+
+   rtla/index
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
index 0266cd0..df53ff8 100644 (file)
@@ -2,7 +2,7 @@
 
         Set the histogram bucket size (default *1*).
 
-**-e**, **--entries** *N*
+**-E**, **--entries** *N*
 
         Set the number of entries of the histogram (default 256).
 
index 8973c5d..d5d6161 100644 (file)
@@ -1,7 +1,7 @@
 The **rtla osnoise** tool is an interface for the *osnoise* tracer. The
 *osnoise* tracer dispatches a kernel thread per-cpu. These threads read the
 time in a loop while with preemption, softirq and IRQs enabled, thus
-allowing all the sources of operating systme noise during its execution.
+allowing all the sources of operating system noise during its execution.
 The *osnoise*'s tracer threads take note of the delta between each time
 read, along with an interference counter of all sources of interference.
 At the end of each period, the *osnoise* tracer displays a summary of
diff --git a/Documentation/tools/rtla/index.rst b/Documentation/tools/rtla/index.rst
new file mode 100644 (file)
index 0000000..840f0bf
--- /dev/null
@@ -0,0 +1,26 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+================================
+The realtime Linux analysis tool
+================================
+
+RTLA provides a set of tools for the analysis of the kernel's realtime
+behavior on specific hardware.
+
+.. toctree::
+   :maxdepth: 1
+
+   rtla
+   rtla-osnoise
+   rtla-osnoise-hist
+   rtla-osnoise-top
+   rtla-timerlat
+   rtla-timerlat-hist
+   rtla-timerlat-top
+
+.. only::  subproject and html
+
+   Indices
+   =======
+
+   * :ref:`genindex`
index 52298dd..f2e79d2 100644 (file)
@@ -36,7 +36,7 @@ default). The reason for reducing the runtime is to avoid starving the
 **rtla** tool. The tool is also set to run for *one minute*. The output
 histogram is set to group outputs in buckets of *10us* and *25* entries::
 
-  [root@f34 ~/]# rtla osnoise hist -P F:1 -c 0-11 -r 900000 -d 1M -b 10 -e 25
+  [root@f34 ~/]# rtla osnoise hist -P F:1 -c 0-11 -r 900000 -d 1M -b 10 -E 25
   # RTLA osnoise histogram
   # Time unit is microseconds (us)
   # Duration:   0 00:01:00
index 87a3604..2ca9204 100644 (file)
@@ -84,6 +84,8 @@ CPUfreq核心层注册一个cpufreq_driver结构体。
  .resume - 一个指向per-policy恢复函数的指针,该函数在关中断且在调节器再一次启动前被
  调用。
 
+ .ready - 一个指向per-policy准备函数的指针,该函数在策略完全初始化之后被调用。
+
  .attr - 一个指向NULL结尾的"struct freq_attr"列表的指针,该列表允许导出值到
  sysfs。
 
index 687efcf..e6fce2c 100644 (file)
@@ -115,6 +115,7 @@ Code  Seq#    Include File                                           Comments
 'B'   00-1F  linux/cciss_ioctl.h                                     conflict!
 'B'   00-0F  include/linux/pmu.h                                     conflict!
 'B'   C0-FF  advanced bbus                                           <mailto:maassen@uni-freiburg.de>
+'B'   00-0F  xen/xenbus_dev.h                                        conflict!
 'C'   all    linux/soundcard.h                                       conflict!
 'C'   01-2F  linux/capi.h                                            conflict!
 'C'   F0-FF  drivers/net/wan/cosa.h                                  conflict!
@@ -134,6 +135,7 @@ Code  Seq#    Include File                                           Comments
 'F'   80-8F  linux/arcfb.h                                           conflict!
 'F'   DD     video/sstfb.h                                           conflict!
 'G'   00-3F  drivers/misc/sgi-gru/grulib.h                           conflict!
+'G'   00-0F  xen/gntalloc.h, xen/gntdev.h                            conflict!
 'H'   00-7F  linux/hiddev.h                                          conflict!
 'H'   00-0F  linux/hidraw.h                                          conflict!
 'H'   01     linux/mei.h                                             conflict!
@@ -176,6 +178,7 @@ Code  Seq#    Include File                                           Comments
 'P'   60-6F  sound/sscape_ioctl.h                                    conflict!
 'P'   00-0F  drivers/usb/class/usblp.c                               conflict!
 'P'   01-09  drivers/misc/pci_endpoint_test.c                        conflict!
+'P'   00-0F  xen/privcmd.h                                           conflict!
 'Q'   all    linux/soundcard.h
 'R'   00-1F  linux/random.h                                          conflict!
 'R'   01     linux/rfkill.h                                          conflict!
index bb8cfdd..9f31723 100644 (file)
@@ -1394,7 +1394,7 @@ documentation when it pops into existence).
 -------------------
 
 :Capability: KVM_CAP_ENABLE_CAP
-:Architectures: mips, ppc, s390
+:Architectures: mips, ppc, s390, x86
 :Type: vcpu ioctl
 :Parameters: struct kvm_enable_cap (in)
 :Returns: 0 on success; -1 on error
@@ -3268,6 +3268,7 @@ number.
 
 :Capability: KVM_CAP_DEVICE_CTRL, KVM_CAP_VM_ATTRIBUTES for vm device,
              KVM_CAP_VCPU_ATTRIBUTES for vcpu device
+             KVM_CAP_SYS_ATTRIBUTES for system (/dev/kvm) device (no set)
 :Type: device ioctl, vm ioctl, vcpu ioctl
 :Parameters: struct kvm_device_attr
 :Returns: 0 on success, -1 on error
@@ -3302,7 +3303,8 @@ transferred is defined by the particular attribute.
 ------------------------
 
 :Capability: KVM_CAP_DEVICE_CTRL, KVM_CAP_VM_ATTRIBUTES for vm device,
-            KVM_CAP_VCPU_ATTRIBUTES for vcpu device
+             KVM_CAP_VCPU_ATTRIBUTES for vcpu device
+             KVM_CAP_SYS_ATTRIBUTES for system (/dev/kvm) device
 :Type: device ioctl, vm ioctl, vcpu ioctl
 :Parameters: struct kvm_device_attr
 :Returns: 0 on success, -1 on error
@@ -6995,6 +6997,20 @@ indicated by the fd to the VM this is called on.
 This is intended to support intra-host migration of VMs between userspace VMMs,
 upgrading the VMM process without interrupting the guest.
 
+7.30 KVM_CAP_PPC_AIL_MODE_3
+-------------------------------
+
+:Capability: KVM_CAP_PPC_AIL_MODE_3
+:Architectures: ppc
+:Type: vm
+
+This capability indicates that the kernel supports the mode 3 setting for the
+"Address Translation Mode on Interrupt" aka "Alternate Interrupt Location"
+resource that is controlled with the H_SET_MODE hypercall.
+
+This capability allows a guest kernel to use a better-performance mode for
+handling interrupts and system calls.
+
 8. Other capabilities.
 ======================
 
index 81f521f..1a09472 100644 (file)
@@ -9,7 +9,7 @@ Page Table Check
 Introduction
 ============
 
-Page table check allows to hardern the kernel by ensuring that some types of
+Page table check allows to harden the kernel by ensuring that some types of
 the memory corruptions are prevented.
 
 Page table check performs extra verifications at the time when new pages become
index 1de40ce..412d5da 100644 (file)
@@ -190,8 +190,9 @@ M:  Johannes Berg <johannes@sipsolutions.net>
 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/jberg/mac80211.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
+Q:     https://patchwork.kernel.org/project/linux-wireless/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git
 F:     Documentation/driver-api/80211/cfg80211.rst
 F:     Documentation/networking/regulatory.rst
 F:     include/linux/ieee80211.h
@@ -1619,6 +1620,7 @@ M:        Olof Johansson <olof@lixom.net>
 M:     soc@kernel.org
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
+C:     irc://irc.libera.chat/armlinux
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git
 F:     arch/arm/boot/dts/Makefile
 F:     arch/arm64/boot/dts/Makefile
@@ -1626,6 +1628,7 @@ F:        arch/arm64/boot/dts/Makefile
 ARM SUB-ARCHITECTURES
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
+C:     irc://irc.libera.chat/armlinux
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git
 F:     arch/arm/mach-*/
 F:     arch/arm/plat-*/
@@ -1779,6 +1782,7 @@ F:        drivers/irqchip/irq-apple-aic.c
 F:     drivers/mailbox/apple-mailbox.c
 F:     drivers/pinctrl/pinctrl-apple-gpio.c
 F:     drivers/soc/apple/*
+F:     drivers/watchdog/apple_wdt.c
 F:     include/dt-bindings/interrupt-controller/apple-aic.h
 F:     include/dt-bindings/pinctrl/apple.h
 F:     include/linux/apple-mailbox.h
@@ -2569,10 +2573,13 @@ N:      rockchip
 
 ARM/SAMSUNG S3C, S5P AND EXYNOS ARM ARCHITECTURES
 M:     Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+R:     Alim Akhtar <alim.akhtar@samsung.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-samsung-soc@vger.kernel.org
 S:     Maintained
+C:     irc://irc.libera.chat/linux-exynos
 Q:     https://patchwork.kernel.org/project/linux-samsung-soc/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git
 F:     Documentation/arm/samsung/
 F:     Documentation/devicetree/bindings/arm/samsung/
 F:     Documentation/devicetree/bindings/power/pd-samsung.yaml
@@ -2985,6 +2992,14 @@ S:       Maintained
 F:     Documentation/devicetree/bindings/net/asix,ax88796c.yaml
 F:     drivers/net/ethernet/asix/ax88796c_*
 
+ASPEED PECI CONTROLLER
+M:     Iwona Winiarska <iwona.winiarska@intel.com>
+L:     linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
+L:     openbmc@lists.ozlabs.org (moderated for non-subscribers)
+S:     Supported
+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>
 L:     linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
@@ -3132,11 +3147,9 @@ W:       https://wireless.wiki.kernel.org/en/users/Drivers/ath5k
 F:     drivers/net/wireless/ath/ath5k/
 
 ATHEROS ATH6KL WIRELESS DRIVER
-M:     Kalle Valo <kvalo@kernel.org>
 L:     linux-wireless@vger.kernel.org
-S:     Supported
+S:     Orphan
 W:     https://wireless.wiki.kernel.org/en/users/Drivers/ath6kl
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
 F:     drivers/net/wireless/ath/ath6kl/
 
 ATI_REMOTE2 DRIVER
@@ -4156,9 +4169,8 @@ N:        csky
 K:     csky
 
 CA8210 IEEE-802.15.4 RADIO DRIVER
-M:     Harry Morris <h.morris@cascoda.com>
 L:     linux-wpan@vger.kernel.org
-S:     Maintained
+S:     Orphan
 W:     https://github.com/Cascoda/ca8210-linux.git
 F:     Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
 F:     drivers/net/ieee802154/ca8210.c
@@ -4543,6 +4555,7 @@ F:        drivers/platform/chrome/
 
 CHROMEOS EC CODEC DRIVER
 M:     Cheng-Yi Chiang <cychiang@chromium.org>
+M:     Tzung-Bi Shih <tzungbi@google.com>
 R:     Guenter Roeck <groeck@chromium.org>
 S:     Maintained
 F:     Documentation/devicetree/bindings/sound/google,cros-ec-codec.yaml
@@ -4908,7 +4921,8 @@ F:        kernel/cgroup/cpuset.c
 CONTROL GROUP - MEMORY RESOURCE CONTROLLER (MEMCG)
 M:     Johannes Weiner <hannes@cmpxchg.org>
 M:     Michal Hocko <mhocko@kernel.org>
-M:     Vladimir Davydov <vdavydov.dev@gmail.com>
+M:     Roman Gushchin <roman.gushchin@linux.dev>
+M:     Shakeel Butt <shakeelb@google.com>
 L:     cgroups@vger.kernel.org
 L:     linux-mm@kvack.org
 S:     Maintained
@@ -5488,6 +5502,15 @@ S:       Maintained
 F:     Documentation/hwmon/dps920ab.rst
 F:     drivers/hwmon/pmbus/dps920ab.c
 
+DELTA NETWORKS TN48M CPLD DRIVERS
+M:     Robert Marko <robert.marko@sartura.hr>
+S:     Maintained
+F:     Documentation/devicetree/bindings/gpio/delta,tn48m-gpio.yaml
+F:     Documentation/devicetree/bindings/mfd/delta,tn48m-cpld.yaml
+F:     Documentation/devicetree/bindings/reset/delta,tn48m-reset.yaml
+F:     drivers/gpio/gpio-tn48m.c
+F:     include/dt-bindings/reset/delta,tn48m-reset.h
+
 DENALI NAND DRIVER
 L:     linux-mtd@lists.infradead.org
 S:     Orphan
@@ -5772,7 +5795,7 @@ F:        tools/testing/selftests/dma/
 
 DMA-BUF HEAPS FRAMEWORK
 M:     Sumit Semwal <sumit.semwal@linaro.org>
-R:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
+R:     Benjamin Gaignard <benjamin.gaignard@collabora.com>
 R:     Liam Mark <lmark@codeaurora.org>
 R:     Laura Abbott <labbott@redhat.com>
 R:     Brian Starkey <Brian.Starkey@arm.com>
@@ -6502,7 +6525,7 @@ F:        Documentation/devicetree/bindings/display/rockchip/
 F:     drivers/gpu/drm/rockchip/
 
 DRM DRIVERS FOR STI
-M:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
+M:     Alain Volmat <alain.volmat@foss.st.com>
 L:     dri-devel@lists.freedesktop.org
 S:     Maintained
 T:     git git://anongit.freedesktop.org/drm/drm-misc
@@ -6511,8 +6534,8 @@ F:        drivers/gpu/drm/sti
 
 DRM DRIVERS FOR STM
 M:     Yannick Fertre <yannick.fertre@foss.st.com>
+M:     Raphael Gallais-Pou <raphael.gallais-pou@foss.st.com>
 M:     Philippe Cornu <philippe.cornu@foss.st.com>
-M:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
 L:     dri-devel@lists.freedesktop.org
 S:     Maintained
 T:     git git://anongit.freedesktop.org/drm/drm-misc
@@ -7006,12 +7029,6 @@ L:       linux-edac@vger.kernel.org
 S:     Maintained
 F:     drivers/edac/sb_edac.c
 
-EDAC-SIFIVE
-M:     Yash Shah <yash.shah@sifive.com>
-L:     linux-edac@vger.kernel.org
-S:     Supported
-F:     drivers/edac/sifive_edac.c
-
 EDAC-SKYLAKE
 M:     Tony Luck <tony.luck@intel.com>
 L:     linux-edac@vger.kernel.org
@@ -7182,7 +7199,7 @@ F:        drivers/net/can/usb/etas_es58x/
 
 ETHERNET BRIDGE
 M:     Roopa Prabhu <roopa@nvidia.com>
-M:     Nikolay Aleksandrov <nikolay@nvidia.com>
+M:     Nikolay Aleksandrov <razor@blackwall.org>
 L:     bridge@lists.linux-foundation.org (moderated for non-subscribers)
 L:     netdev@vger.kernel.org
 S:     Maintained
@@ -7208,8 +7225,10 @@ F:       drivers/net/mdio/of_mdio.c
 F:     drivers/net/pcs/
 F:     drivers/net/phy/
 F:     include/dt-bindings/net/qca-ar803x.h
+F:     include/linux/linkmode.h
 F:     include/linux/*mdio*.h
 F:     include/linux/mdio/*.h
+F:     include/linux/mii.h
 F:     include/linux/of_net.h
 F:     include/linux/phy.h
 F:     include/linux/phy_fixed.h
@@ -7573,6 +7592,12 @@ S:       Maintained
 W:     http://floatingpoint.sourceforge.net/emulator/index.html
 F:     arch/x86/math-emu/
 
+FRAMEBUFFER CORE
+M:     Daniel Vetter <daniel@ffwll.ch>
+F:     drivers/video/fbdev/core/
+S:     Odd Fixes
+T:     git git://anongit.freedesktop.org/drm/drm-misc
+
 FRAMEBUFFER LAYER
 M:     Helge Deller <deller@gmx.de>
 L:     linux-fbdev@vger.kernel.org
@@ -9250,6 +9275,15 @@ S:       Maintained
 W:     https://github.com/o2genum/ideapad-slidebar
 F:     drivers/input/misc/ideapad_slidebar.c
 
+IDMAPPED MOUNTS
+M:     Christian Brauner <brauner@kernel.org>
+L:     linux-fsdevel@vger.kernel.org
+S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git
+F:     Documentation/filesystems/idmappings.rst
+F:     tools/testing/selftests/mount_setattr/
+F:     include/linux/mnt_idmapping.h
+
 IDT VersaClock 5 CLOCK DRIVER
 M:     Luca Ceresoli <luca@lucaceresoli.net>
 S:     Maintained
@@ -9890,6 +9924,7 @@ F:        drivers/firmware/stratix10-rsu.c
 F:     drivers/firmware/stratix10-svc.c
 F:     include/linux/firmware/intel/stratix10-smc.h
 F:     include/linux/firmware/intel/stratix10-svc-client.h
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git
 
 INTEL TELEMETRY DRIVER
 M:     Rajneesh Bhardwaj <irenic.rajneesh@gmail.com>
@@ -10877,6 +10912,12 @@ T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
 F:     drivers/ata/pata_arasan_cf.c
 F:     include/linux/pata_arasan_cf_data.h
 
+LIBATA PATA DRIVERS
+R:     Sergey Shtylyov <s.shtylyov@omp.ru>
+L:     linux-ide@vger.kernel.org
+F:     drivers/ata/ata_*.c
+F:     drivers/ata/pata_*.c
+
 LIBATA PATA FARADAY FTIDE010 AND GEMINI SATA BRIDGE DRIVERS
 M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-ide@vger.kernel.org
@@ -11366,8 +11407,9 @@ M:      Johannes Berg <johannes@sipsolutions.net>
 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/jberg/mac80211.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
+Q:     https://patchwork.kernel.org/project/linux-wireless/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git
 F:     Documentation/networking/mac80211-injection.rst
 F:     Documentation/networking/mac80211_hwsim/mac80211_hwsim.rst
 F:     drivers/net/wireless/mac80211_hwsim.[ch]
@@ -12396,7 +12438,7 @@ F:      include/uapi/linux/membarrier.h
 F:     kernel/sched/membarrier.c
 
 MEMBLOCK
-M:     Mike Rapoport <rppt@linux.ibm.com>
+M:     Mike Rapoport <rppt@kernel.org>
 L:     linux-mm@kvack.org
 S:     Maintained
 F:     Documentation/core-api/boot-time-mm.rst
@@ -13294,8 +13336,8 @@ W:      http://www.iptables.org/
 W:     http://www.nftables.org/
 Q:     http://patchwork.ozlabs.org/project/netfilter-devel/list/
 C:     irc://irc.libera.chat/netfilter
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next.git
 F:     include/linux/netfilter*
 F:     include/linux/netfilter/
 F:     include/net/netfilter/
@@ -13374,9 +13416,10 @@ NETWORKING DRIVERS (WIRELESS)
 M:     Kalle Valo <kvalo@kernel.org>
 L:     linux-wireless@vger.kernel.org
 S:     Maintained
-Q:     http://patchwork.kernel.org/project/linux-wireless/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next.git
+W:     https://wireless.wiki.kernel.org/
+Q:     https://patchwork.kernel.org/project/linux-wireless/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git
 F:     Documentation/devicetree/bindings/net/wireless/
 F:     drivers/net/wireless/
 
@@ -13449,7 +13492,11 @@ L:     netdev@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
 F:     arch/x86/net/*
+F:     include/linux/ip.h
+F:     include/linux/ipv6*
+F:     include/net/fib*
 F:     include/net/ip*
+F:     include/net/route.h
 F:     net/ipv4/
 F:     net/ipv6/
 
@@ -13510,10 +13557,6 @@ F:     include/net/tls.h
 F:     include/uapi/linux/tls.h
 F:     net/tls/*
 
-NETWORKING [WIRELESS]
-L:     linux-wireless@vger.kernel.org
-Q:     http://patchwork.kernel.org/project/linux-wireless/list/
-
 NETXEN (1/10) GbE SUPPORT
 M:     Manish Chopra <manishc@marvell.com>
 M:     Rahul Verma <rahulv@marvell.com>
@@ -13561,7 +13604,7 @@ F:      tools/testing/selftests/nci/
 
 NFS, SUNRPC, AND LOCKD CLIENTS
 M:     Trond Myklebust <trond.myklebust@hammerspace.com>
-M:     Anna Schumaker <anna.schumaker@netapp.com>
+M:     Anna Schumaker <anna@kernel.org>
 L:     linux-nfs@vger.kernel.org
 S:     Maintained
 W:     http://client.linux-nfs.org
@@ -14379,6 +14422,7 @@ M:      Rob Herring <robh+dt@kernel.org>
 M:     Frank Rowand <frowand.list@gmail.com>
 L:     devicetree@vger.kernel.org
 S:     Maintained
+C:     irc://irc.libera.chat/devicetree
 W:     http://www.devicetree.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git
 F:     Documentation/ABI/testing/sysfs-firmware-ofw
@@ -14390,6 +14434,7 @@ OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
 M:     Rob Herring <robh+dt@kernel.org>
 L:     devicetree@vger.kernel.org
 S:     Maintained
+C:     irc://irc.libera.chat/devicetree
 Q:     http://patchwork.ozlabs.org/project/devicetree-bindings/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git
 F:     Documentation/devicetree/
@@ -15091,6 +15136,24 @@ L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
 F:     drivers/platform/x86/peaq-wmi.c
 
+PECI HARDWARE MONITORING DRIVERS
+M:     Iwona Winiarska <iwona.winiarska@intel.com>
+L:     linux-hwmon@vger.kernel.org
+S:     Supported
+F:     Documentation/hwmon/peci-cputemp.rst
+F:     Documentation/hwmon/peci-dimmtemp.rst
+F:     drivers/hwmon/peci/
+
+PECI SUBSYSTEM
+M:     Iwona Winiarska <iwona.winiarska@intel.com>
+L:     openbmc@lists.ozlabs.org (moderated for non-subscribers)
+S:     Supported
+F:     Documentation/devicetree/bindings/peci/
+F:     Documentation/peci/
+F:     drivers/peci/
+F:     include/linux/peci-cpu.h
+F:     include/linux/peci.h
+
 PENSANDO ETHERNET DRIVERS
 M:     Shannon Nelson <snelson@pensando.io>
 M:     drivers@pensando.io
@@ -15123,7 +15186,7 @@ M:      Ingo Molnar <mingo@redhat.com>
 M:     Arnaldo Carvalho de Melo <acme@kernel.org>
 R:     Mark Rutland <mark.rutland@arm.com>
 R:     Alexander Shishkin <alexander.shishkin@linux.intel.com>
-R:     Jiri Olsa <jolsa@redhat.com>
+R:     Jiri Olsa <jolsa@kernel.org>
 R:     Namhyung Kim <namhyung@kernel.org>
 L:     linux-perf-users@vger.kernel.org
 L:     linux-kernel@vger.kernel.org
@@ -15280,9 +15343,11 @@ PIN CONTROLLER - SAMSUNG
 M:     Tomasz Figa <tomasz.figa@gmail.com>
 M:     Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
 M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
+R:     Alim Akhtar <alim.akhtar@samsung.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-samsung-soc@vger.kernel.org
 S:     Maintained
+C:     irc://irc.libera.chat/linux-exynos
 Q:     https://patchwork.kernel.org/project/linux-samsung-soc/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/samsung.git
 F:     Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
@@ -15539,6 +15604,7 @@ M:      Iurii Zaikin <yzaikin@google.com>
 L:     linux-kernel@vger.kernel.org
 L:     linux-fsdevel@vger.kernel.org
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux.git sysctl-next
 F:     fs/proc/proc_sysctl.c
 F:     include/linux/sysctl.h
 F:     kernel/sysctl-test.c
@@ -15886,6 +15952,7 @@ S:      Supported
 W:     https://wireless.wiki.kernel.org/en/users/Drivers/ath10k
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
 F:     drivers/net/wireless/ath/ath10k/
+F:     Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
 
 QUALCOMM ATHEROS ATH11K WIRELESS DRIVER
 M:     Kalle Valo <kvalo@kernel.org>
@@ -15893,11 +15960,12 @@ L:    ath11k@lists.infradead.org
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
 F:     drivers/net/wireless/ath/ath11k/
+F:     Documentation/devicetree/bindings/net/wireless/qcom,ath11k.txt
 
 QUALCOMM ATHEROS ATH9K WIRELESS DRIVER
-M:     ath9k-devel@qca.qualcomm.com
+M:     Toke Høiland-Jørgensen <toke@toke.dk>
 L:     linux-wireless@vger.kernel.org
-S:     Supported
+S:     Maintained
 W:     https://wireless.wiki.kernel.org/en/users/Drivers/ath9k
 F:     Documentation/devicetree/bindings/net/wireless/qca,ath9k.yaml
 F:     drivers/net/wireless/ath/ath9k/
@@ -15972,14 +16040,6 @@ F:     Documentation/devicetree/bindings/misc/qcom,fastrpc.txt
 F:     drivers/misc/fastrpc.c
 F:     include/uapi/misc/fastrpc.h
 
-QUALCOMM GENERIC INTERFACE I2C DRIVER
-M:     Akash Asthana <akashast@codeaurora.org>
-M:     Mukesh Savaliya <msavaliy@codeaurora.org>
-L:     linux-i2c@vger.kernel.org
-L:     linux-arm-msm@vger.kernel.org
-S:     Supported
-F:     drivers/i2c/busses/i2c-qcom-geni.c
-
 QUALCOMM HEXAGON ARCHITECTURE
 M:     Brian Cain <bcain@codeaurora.org>
 L:     linux-hexagon@vger.kernel.org
@@ -16051,8 +16111,8 @@ F:      Documentation/devicetree/bindings/mtd/qcom,nandc.yaml
 F:     drivers/mtd/nand/raw/qcom_nandc.c
 
 QUALCOMM RMNET DRIVER
-M:     Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
-M:     Sean Tranchetti <stranche@codeaurora.org>
+M:     Subash Abhinov Kasiviswanathan <quic_subashab@quicinc.com>
+M:     Sean Tranchetti <quic_stranche@quicinc.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     Documentation/networking/device_drivers/cellular/qualcomm/rmnet.rst
@@ -16078,11 +16138,10 @@ F:    Documentation/devicetree/bindings/media/*venus*
 F:     drivers/media/platform/qcom/venus/
 
 QUALCOMM WCN36XX WIRELESS DRIVER
-M:     Kalle Valo <kvalo@kernel.org>
+M:     Loic Poulain <loic.poulain@linaro.org>
 L:     wcn36xx@lists.infradead.org
 S:     Supported
 W:     https://wireless.wiki.kernel.org/en/users/Drivers/wcn36xx
-T:     git git://github.com/KrasnikovEugene/wcn36xx.git
 F:     drivers/net/wireless/ath/wcn36xx/
 
 QUANTENNA QTNFMAC WIRELESS DRIVER
@@ -16345,6 +16404,7 @@ F:      drivers/watchdog/realtek_otto_wdt.c
 
 REALTEK RTL83xx SMI DSA ROUTER CHIPS
 M:     Linus Walleij <linus.walleij@linaro.org>
+M:     Alvin Šipraga <alsi@bang-olufsen.dk>
 S:     Maintained
 F:     Documentation/devicetree/bindings/net/dsa/realtek-smi.txt
 F:     drivers/net/dsa/realtek-smi*
@@ -16464,6 +16524,14 @@ F:     Documentation/devicetree/bindings/i2c/renesas,rmobile-iic.yaml
 F:     drivers/i2c/busses/i2c-rcar.c
 F:     drivers/i2c/busses/i2c-sh_mobile.c
 
+RENESAS R-CAR SATA DRIVER
+R:     Sergey Shtylyov <s.shtylyov@omp.ru>
+S:     Supported
+L:     linux-ide@vger.kernel.org
+L:     linux-renesas-soc@vger.kernel.org
+F:     Documentation/devicetree/bindings/ata/renesas,rcar-sata.yaml
+F:     drivers/ata/sata_rcar.c
+
 RENESAS R-CAR THERMAL DRIVERS
 M:     Niklas Söderlund <niklas.soderlund@ragnatech.se>
 L:     linux-renesas-soc@vger.kernel.org
@@ -16532,8 +16600,9 @@ M:      Johannes Berg <johannes@sipsolutions.net>
 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/jberg/mac80211.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
+Q:     https://patchwork.kernel.org/project/linux-wireless/list/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git
 F:     Documentation/ABI/stable/sysfs-class-rfkill
 F:     Documentation/driver-api/rfkill.rst
 F:     include/linux/rfkill.h
@@ -16798,8 +16867,8 @@ F:      drivers/video/fbdev/savage/
 S390
 M:     Heiko Carstens <hca@linux.ibm.com>
 M:     Vasily Gorbik <gor@linux.ibm.com>
-M:     Christian Borntraeger <borntraeger@linux.ibm.com>
-R:     Alexander Gordeev <agordeev@linux.ibm.com>
+M:     Alexander Gordeev <agordeev@linux.ibm.com>
+R:     Christian Borntraeger <borntraeger@linux.ibm.com>
 R:     Sven Schnelle <svens@linux.ibm.com>
 L:     linux-s390@vger.kernel.org
 S:     Supported
@@ -17070,6 +17139,7 @@ SAMSUNG SOC CLOCK DRIVERS
 M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
 M:     Tomasz Figa <tomasz.figa@gmail.com>
 M:     Chanwoo Choi <cw00.choi@samsung.com>
+R:     Alim Akhtar <alim.akhtar@samsung.com>
 L:     linux-samsung-soc@vger.kernel.org
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/snawrocki/clk.git
@@ -17706,6 +17776,21 @@ S:     Maintained
 W:     http://www.winischhofer.at/linuxsisusbvga.shtml
 F:     drivers/usb/misc/sisusbvga/
 
+SL28 CPLD MFD DRIVER
+M:     Michael Walle <michael@walle.cc>
+S:     Maintained
+F:     Documentation/devicetree/bindings/gpio/kontron,sl28cpld-gpio.yaml
+F:     Documentation/devicetree/bindings/hwmon/kontron,sl28cpld-hwmon.yaml
+F:     Documentation/devicetree/bindings/interrupt-controller/kontron,sl28cpld-intc.yaml
+F:     Documentation/devicetree/bindings/mfd/kontron,sl28cpld.yaml
+F:     Documentation/devicetree/bindings/pwm/kontron,sl28cpld-pwm.yaml
+F:     Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml
+F:     drivers/gpio/gpio-sl28cpld.c
+F:     drivers/hwmon/sl28cpld-hwmon.c
+F:     drivers/irqchip/irq-sl28cpld.c
+F:     drivers/pwm/pwm-sl28cpld.c
+F:     drivers/watchdog/sl28cpld_wdt.c
+
 SLAB ALLOCATOR
 M:     Christoph Lameter <cl@linux.com>
 M:     Pekka Enberg <penberg@kernel.org>
@@ -17713,8 +17798,10 @@ M:     David Rientjes <rientjes@google.com>
 M:     Joonsoo Kim <iamjoonsoo.kim@lge.com>
 M:     Andrew Morton <akpm@linux-foundation.org>
 M:     Vlastimil Babka <vbabka@suse.cz>
+R:     Roman Gushchin <roman.gushchin@linux.dev>
 L:     linux-mm@kvack.org
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab.git
 F:     include/linux/sl?b*.h
 F:     mm/sl?b*
 
@@ -18422,7 +18509,7 @@ F:      Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt
 F:     sound/soc/sti/
 
 STI CEC DRIVER
-M:     Benjamin Gaignard <benjamin.gaignard@linaro.org>
+M:     Alain Volmat <alain.volmat@foss.st.com>
 S:     Maintained
 F:     Documentation/devicetree/bindings/media/stih-cec.txt
 F:     drivers/media/cec/platform/sti/
@@ -18491,6 +18578,12 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/rtc/sunplus,sp7021-rtc.yaml
 F:     drivers/rtc/rtc-sunplus.c
 
+SUNPLUS OCOTP DRIVER
+M:     Vincent Shih <vincent.sunplus@gmail.com>
+S:     Maintained
+F:     Documentation/devicetree/bindings/nvmem/sunplus,sp7021-ocotp.yaml
+F:     drivers/nvmem/sunplus-ocotp.c
+
 SUPERH
 M:     Yoshinori Sato <ysato@users.sourceforge.jp>
 M:     Rich Felker <dalias@libc.org>
@@ -19576,6 +19669,14 @@ F:     Documentation/trace/timerlat-tracer.rst
 F:     Documentation/trace/hwlat_detector.rst
 F:     arch/*/kernel/trace.c
 
+Real-time Linux Analysis (RTLA) tools
+M:     Daniel Bristot de Oliveira <bristot@kernel.org>
+M:     Steven Rostedt <rostedt@goodmis.org>
+L:     linux-trace-devel@vger.kernel.org
+S:     Maintained
+F:     Documentation/tools/rtla/
+F:     tools/tracing/rtla/
+
 TRADITIONAL CHINESE DOCUMENTATION
 M:     Hu Haowen <src.res@email.cn>
 L:     linux-doc-tw-discuss@lists.sourceforge.net
index 0fb4f94..daeb5c8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,8 +2,8 @@
 VERSION = 5
 PATCHLEVEL = 17
 SUBLEVEL = 0
-EXTRAVERSION = -rc1
-NAME = Gobble Gobble
+EXTRAVERSION = -rc6
+NAME = Superb Owl
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
index fabe391..4c97cb4 100644 (file)
@@ -83,6 +83,7 @@ config ARM
        select HAVE_EBPF_JIT if !CPU_ENDIAN_BE32
        select HAVE_CONTEXT_TRACKING
        select HAVE_C_RECORDMCOUNT
+       select HAVE_BUILDTIME_MCOUNT_SORT
        select HAVE_DEBUG_KMEMLEAK if !XIP_KERNEL
        select HAVE_DMA_CONTIGUOUS if MMU
        select HAVE_DYNAMIC_FTRACE if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU
index 235ad55..e41eca7 100644 (file)
@@ -806,6 +806,7 @@ dtb-$(CONFIG_ARCH_OMAP3) += \
        logicpd-som-lv-37xx-devkit.dtb \
        omap3430-sdp.dtb \
        omap3-beagle.dtb \
+       omap3-beagle-ab4.dtb \
        omap3-beagle-xm.dtb \
        omap3-beagle-xm-ab.dtb \
        omap3-cm-t3517.dtb \
index 673159d..f957fea 100644 (file)
@@ -55,7 +55,7 @@
                2 1 0 0 /* # 0: INACTIVE, 1: TX, 2: RX */
        >;
        tx-num-evt = <16>;
-       rt-num-evt = <16>;
+       rx-num-evt = <16>;
        status = "okay";
 };
 
index f14dace..fa8b581 100644 (file)
                                };
                        };
 
+                       peci0: peci-controller@1e78b000 {
+                               compatible = "aspeed,ast2400-peci";
+                               reg = <0x1e78b000 0x60>;
+                               interrupts = <15>;
+                               clocks = <&syscon ASPEED_CLK_GATE_REFCLK>;
+                               resets = <&syscon ASPEED_RESET_PECI>;
+                               cmd-timeout-ms = <1000>;
+                               clock-frequency = <1000000>;
+                               status = "disabled";
+                       };
+
                        uart2: serial@1e78d000 {
                                compatible = "ns16550a";
                                reg = <0x1e78d000 0x20>;
index 7495f93..4147b39 100644 (file)
                                };
                        };
 
+                       peci0: peci-controller@1e78b000 {
+                               compatible = "aspeed,ast2500-peci";
+                               reg = <0x1e78b000 0x60>;
+                               interrupts = <15>;
+                               clocks = <&syscon ASPEED_CLK_GATE_REFCLK>;
+                               resets = <&syscon ASPEED_RESET_PECI>;
+                               cmd-timeout-ms = <1000>;
+                               clock-frequency = <1000000>;
+                               status = "disabled";
+                       };
+
                        uart2: serial@1e78d000 {
                                compatible = "ns16550a";
                                reg = <0x1e78d000 0x20>;
index c32e87f..3d5ce9d 100644 (file)
                                status = "disabled";
                        };
 
+                       peci0: peci-controller@1e78b000 {
+                               compatible = "aspeed,ast2600-peci";
+                               reg = <0x1e78b000 0x100>;
+                               interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&syscon ASPEED_CLK_GATE_REF0CLK>;
+                               resets = <&syscon ASPEED_RESET_PECI>;
+                               cmd-timeout-ms = <1000>;
+                               clock-frequency = <1000000>;
+                               status = "disabled";
+                       };
+
                        lpc: lpc@1e789000 {
                                compatible = "aspeed,ast2600-lpc-v2", "simple-mfd", "syscon";
                                reg = <0x1e789000 0x1000>;
index 6b485cb..42bff11 100644 (file)
                target-module@48210000 {
                        compatible = "ti,sysc-omap4-simple", "ti,sysc";
                        power-domains = <&prm_mpu>;
-                       clocks = <&mpu_clkctrl DRA7_MPU_CLKCTRL 0>;
+                       clocks = <&mpu_clkctrl DRA7_MPU_MPU_CLKCTRL 0>;
                        clock-names = "fck";
                        #address-cells = <1>;
                        #size-cells = <1>;
                              <0x58000014 4>;
                        reg-names = "rev", "syss";
                        ti,syss-mask = <1>;
-                       clocks = <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 0>,
-                                <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 9>,
-                                <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 10>,
-                                <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 11>;
+                       clocks = <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 0>,
+                                <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 9>,
+                                <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 10>,
+                                <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 11>;
                        clock-names = "fck", "hdmi_clk", "sys_clk", "tv_clk";
                        #address-cells = <1>;
                        #size-cells = <1>;
                                                         SYSC_OMAP2_SOFTRESET |
                                                         SYSC_OMAP2_AUTOIDLE)>;
                                        ti,syss-mask = <1>;
-                                       clocks = <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 8>;
+                                       clocks = <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 8>;
                                        clock-names = "fck";
                                        #address-cells = <1>;
                                        #size-cells = <1>;
                                                        <SYSC_IDLE_SMART>,
                                                        <SYSC_IDLE_SMART_WKUP>;
                                        ti,sysc-mask = <(SYSC_OMAP4_SOFTRESET)>;
-                                       clocks = <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 9>,
-                                                <&dss_clkctrl DRA7_DSS_CORE_CLKCTRL 8>;
+                                       clocks = <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 9>,
+                                                <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 8>;
                                        clock-names = "fck", "dss_clk";
                                        #address-cells = <1>;
                                        #size-cells = <1>;
                                compatible = "vivante,gc";
                                reg = <0x0 0x700>;
                                interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
-                               clocks = <&dss_clkctrl DRA7_BB2D_CLKCTRL 0>;
+                               clocks = <&dss_clkctrl DRA7_DSS_BB2D_CLKCTRL 0>;
                                clock-names = "core";
                        };
                };
        ti,no-reset-on-init;
        ti,no-idle;
        timer@0 {
-               assigned-clocks = <&wkupaon_clkctrl DRA7_TIMER1_CLKCTRL 24>;
+               assigned-clocks = <&wkupaon_clkctrl DRA7_WKUPAON_TIMER1_CLKCTRL 24>;
                assigned-clock-parents = <&sys_32k_ck>;
        };
 };
index 8cbaf1c..3b609d9 100644 (file)
@@ -79,7 +79,6 @@
                                                MX23_PAD_LCD_RESET__GPIO_1_18
                                                MX23_PAD_PWM3__GPIO_1_29
                                                MX23_PAD_PWM4__GPIO_1_30
-                                               MX23_PAD_SSP1_DETECT__SSP1_DETECT
                                        >;
                                        fsl,drive-strength = <MXS_DRIVE_4mA>;
                                        fsl,voltage = <MXS_VOLTAGE_HIGH>;
index d07d8f8..ccfa8e3 100644 (file)
@@ -5,6 +5,8 @@
  * Author: Fabio Estevam <fabio.estevam@freescale.com>
  */
 
+#include <dt-bindings/gpio/gpio.h>
+
 / {
        aliases {
                backlight = &backlight;
                                MX6QDL_PAD_SD3_DAT1__SD3_DATA1          0x17059
                                MX6QDL_PAD_SD3_DAT2__SD3_DATA2          0x17059
                                MX6QDL_PAD_SD3_DAT3__SD3_DATA3          0x17059
+                               MX6QDL_PAD_SD3_DAT5__GPIO7_IO00         0x1b0b0
                        >;
                };
 
 &usdhc3 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc3>;
-       non-removable;
+       cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
index b7ea37a..bcec98b 100644 (file)
                        interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&pcc2 IMX7ULP_CLK_WDG1>;
                        assigned-clocks = <&pcc2 IMX7ULP_CLK_WDG1>;
-                       assigned-clocks-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>;
+                       assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>;
                        timeout-sec = <40>;
                };
 
index 3be7cba..26eaba3 100644 (file)
@@ -59,7 +59,7 @@
                        };
 
                        uart_A: serial@84c0 {
-                               compatible = "amlogic,meson6-uart", "amlogic,meson-uart";
+                               compatible = "amlogic,meson6-uart";
                                reg = <0x84c0 0x18>;
                                interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>;
                                fifo-size = <128>;
@@ -67,7 +67,7 @@
                        };
 
                        uart_B: serial@84dc {
-                               compatible = "amlogic,meson6-uart", "amlogic,meson-uart";
+                               compatible = "amlogic,meson6-uart";
                                reg = <0x84dc 0x18>;
                                interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>;
                                status = "disabled";
                        };
 
                        uart_C: serial@8700 {
-                               compatible = "amlogic,meson6-uart", "amlogic,meson-uart";
+                               compatible = "amlogic,meson6-uart";
                                reg = <0x8700 0x18>;
                                interrupts = <GIC_SPI 93 IRQ_TYPE_EDGE_RISING>;
                                status = "disabled";
                        };
 
                        uart_AO: serial@4c0 {
-                               compatible = "amlogic,meson6-uart", "amlogic,meson-ao-uart", "amlogic,meson-uart";
+                               compatible = "amlogic,meson6-uart", "amlogic,meson-ao-uart";
                                reg = <0x4c0 0x18>;
                                interrupts = <GIC_SPI 90 IRQ_TYPE_EDGE_RISING>;
                                status = "disabled";
index f80ddc9..9997a5d 100644 (file)
 };
 
 &uart_AO {
-       compatible = "amlogic,meson8-uart", "amlogic,meson-uart";
-       clocks = <&clkc CLKID_CLK81>, <&xtal>, <&clkc CLKID_CLK81>;
-       clock-names = "baud", "xtal", "pclk";
+       compatible = "amlogic,meson8-uart", "amlogic,meson-ao-uart";
+       clocks = <&xtal>, <&clkc CLKID_CLK81>, <&clkc CLKID_CLK81>;
+       clock-names = "xtal", "pclk", "baud";
 };
 
 &uart_A {
-       compatible = "amlogic,meson8-uart", "amlogic,meson-uart";
-       clocks = <&clkc CLKID_CLK81>, <&xtal>, <&clkc CLKID_UART0>;
-       clock-names = "baud", "xtal", "pclk";
+       compatible = "amlogic,meson8-uart";
+       clocks = <&xtal>, <&clkc CLKID_UART0>, <&clkc CLKID_CLK81>;
+       clock-names = "xtal", "pclk", "baud";
 };
 
 &uart_B {
-       compatible = "amlogic,meson8-uart", "amlogic,meson-uart";
-       clocks = <&clkc CLKID_CLK81>, <&xtal>, <&clkc CLKID_UART1>;
-       clock-names = "baud", "xtal", "pclk";
+       compatible = "amlogic,meson8-uart";
+       clocks = <&xtal>, <&clkc CLKID_UART0>, <&clkc CLKID_CLK81>;
+       clock-names = "xtal", "pclk", "baud";
 };
 
 &uart_C {
-       compatible = "amlogic,meson8-uart", "amlogic,meson-uart";
-       clocks = <&clkc CLKID_CLK81>, <&xtal>, <&clkc CLKID_UART2>;
-       clock-names = "baud", "xtal", "pclk";
+       compatible = "amlogic,meson8-uart";
+       clocks = <&xtal>, <&clkc CLKID_UART0>, <&clkc CLKID_CLK81>;
+       clock-names = "xtal", "pclk", "baud";
 };
 
 &usb0 {
index b49b7cb..94f1c03 100644 (file)
 };
 
 &uart_AO {
-       compatible = "amlogic,meson8b-uart", "amlogic,meson-uart";
-       clocks = <&clkc CLKID_CLK81>, <&xtal>, <&clkc CLKID_CLK81>;
-       clock-names = "baud", "xtal", "pclk";
+       compatible = "amlogic,meson8b-uart", "amlogic,meson-ao-uart";
+       clocks = <&xtal>, <&clkc CLKID_CLK81>, <&clkc CLKID_CLK81>;
+       clock-names = "xtal", "pclk", "baud";
 };
 
 &uart_A {
-       compatible = "amlogic,meson8b-uart", "amlogic,meson-uart";
-       clocks = <&clkc CLKID_CLK81>, <&xtal>, <&clkc CLKID_UART0>;
-       clock-names = "baud", "xtal", "pclk";
+       compatible = "amlogic,meson8b-uart";
+       clocks = <&xtal>, <&clkc CLKID_UART0>, <&clkc CLKID_CLK81>;
+       clock-names = "xtal", "pclk", "baud";
 };
 
 &uart_B {
-       compatible = "amlogic,meson8b-uart", "amlogic,meson-uart";
-       clocks = <&clkc CLKID_CLK81>, <&xtal>, <&clkc CLKID_UART1>;
-       clock-names = "baud", "xtal", "pclk";
+       compatible = "amlogic,meson8b-uart";
+       clocks = <&xtal>, <&clkc CLKID_UART0>, <&clkc CLKID_CLK81>;
+       clock-names = "xtal", "pclk", "baud";
 };
 
 &uart_C {
-       compatible = "amlogic,meson8b-uart", "amlogic,meson-uart";
-       clocks = <&clkc CLKID_CLK81>, <&xtal>, <&clkc CLKID_UART2>;
-       clock-names = "baud", "xtal", "pclk";
+       compatible = "amlogic,meson8b-uart";
+       clocks = <&xtal>, <&clkc CLKID_UART0>, <&clkc CLKID_CLK81>;
+       clock-names = "xtal", "pclk", "baud";
 };
 
 &usb0 {
diff --git a/arch/arm/boot/dts/omap3-beagle-ab4.dts b/arch/arm/boot/dts/omap3-beagle-ab4.dts
new file mode 100644 (file)
index 0000000..990ff2d
--- /dev/null
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/dts-v1/;
+
+#include "omap3-beagle.dts"
+
+/ {
+       model = "TI OMAP3 BeagleBoard A to B4";
+       compatible = "ti,omap3-beagle-ab4", "ti,omap3-beagle", "ti,omap3430", "ti,omap3";
+};
+
+/*
+ * Workaround for capacitor C70 issue, see "Boards revision A and < B5"
+ * section at https://elinux.org/BeagleBoard_Community
+ */
+
+/* Unusable as clocksource because of unreliable oscillator */
+&counter32k {
+       status = "disabled";
+};
+
+/* Unusable as clockevent because of unreliable oscillator, allow to idle */
+&timer1_target {
+       /delete-property/ti,no-reset-on-init;
+       /delete-property/ti,no-idle;
+       timer@0 {
+               /delete-property/ti,timer-alwon;
+       };
+};
+
+/* Preferred always-on timer for clocksource */
+&timer12_target {
+       ti,no-reset-on-init;
+       ti,no-idle;
+       timer@0 {
+               /* Always clocked by secure_32k_fck */
+       };
+};
+
+/* Preferred timer for clockevent */
+&timer2_target {
+       ti,no-reset-on-init;
+       ti,no-idle;
+       timer@0 {
+               assigned-clocks = <&gpt2_fck>;
+               assigned-clock-parents = <&sys_ck>;
+       };
+};
index f9f34b8..0548b39 100644 (file)
        phys = <0 &hsusb2_phy>;
 };
 
-/* Unusable as clocksource because of unreliable oscillator */
-&counter32k {
-       status = "disabled";
-};
-
-/* Unusable as clockevent because if unreliable oscillator, allow to idle */
-&timer1_target {
-       /delete-property/ti,no-reset-on-init;
-       /delete-property/ti,no-idle;
-       timer@0 {
-               /delete-property/ti,timer-alwon;
-       };
-};
-
-/* Preferred always-on timer for clocksource */
-&timer12_target {
-       ti,no-reset-on-init;
-       ti,no-idle;
-       timer@0 {
-               /* Always clocked by secure_32k_fck */
-       };
-};
-
-/* Preferred timer for clockevent */
-&timer2_target {
-       ti,no-reset-on-init;
-       ti,no-idle;
-       timer@0 {
-               assigned-clocks = <&gpt2_fck>;
-               assigned-clock-parents = <&sys_ck>;
-       };
-};
-
 &twl_gpio {
        ti,use-leds;
        /* pullups: BIT(1) */
index 367ba48..b587e4e 100644 (file)
                                        #address-cells = <1>;
                                        #size-cells = <0>;
                                        reg = <0x41>;
-                                       irq-over-gpio;
                                        irq-gpios = <&gpiopinctrl 29 0x4>;
                                        id = <0>;
                                        blocks = <0x5>;
index 580ca49..f8c5899 100644 (file)
                        cap-sd-highspeed;
                        cap-mmc-highspeed;
                        /* All direction control is used */
-                       st,sig-dir-cmd;
-                       st,sig-dir-dat0;
-                       st,sig-dir-dat2;
-                       st,sig-dir-dat31;
                        st,sig-pin-fbclk;
                        full-pwr-cycle;
                        vmmc-supply = <&ab8500_ldo_aux3_reg>;
index 17c1c3b..763c73b 100644 (file)
 static int crypto_blake2s_update_arm(struct shash_desc *desc,
                                     const u8 *in, unsigned int inlen)
 {
-       return crypto_blake2s_update(desc, in, inlen, blake2s_compress);
+       return crypto_blake2s_update(desc, in, inlen, false);
 }
 
 static int crypto_blake2s_final_arm(struct shash_desc *desc, u8 *out)
 {
-       return crypto_blake2s_final(desc, out, blake2s_compress);
+       return crypto_blake2s_final(desc, out, false);
 }
 
 #define BLAKE2S_ALG(name, driver_name, digest_size)                    \
index 7d23d4b..6fe6796 100644 (file)
  */
 #define ALT_UP(instr...)                                       \
        .pushsection ".alt.smp.init", "a"                       ;\
+       .align  2                                               ;\
        .long   9998b - .                                       ;\
 9997:  instr                                                   ;\
        .if . - 9997b == 2                                      ;\
        .popsection
 #define ALT_UP_B(label)                                        \
        .pushsection ".alt.smp.init", "a"                       ;\
+       .align  2                                               ;\
        .long   9998b - .                                       ;\
        W(b)    . + (label - 9998b)                                     ;\
        .popsection
index 6af68ed..bdc35c0 100644 (file)
@@ -96,6 +96,7 @@ unsigned long __get_wchan(struct task_struct *p);
 #define __ALT_SMP_ASM(smp, up)                                         \
        "9998:  " smp "\n"                                              \
        "       .pushsection \".alt.smp.init\", \"a\"\n"                \
+       "       .align  2\n"                                            \
        "       .long   9998b - .\n"                                    \
        "       " up "\n"                                               \
        "       .popsection\n"
index 36fbc33..32dbfd8 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/string.h>
 #include <asm/memory.h>
 #include <asm/domain.h>
+#include <asm/unaligned.h>
 #include <asm/unified.h>
 #include <asm/compiler.h>
 
@@ -497,7 +498,10 @@ do {                                                                       \
        }                                                               \
        default: __err = __get_user_bad(); break;                       \
        }                                                               \
-       *(type *)(dst) = __val;                                         \
+       if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))         \
+               put_unaligned(__val, (type *)(dst));                    \
+       else                                                            \
+               *(type *)(dst) = __val; /* aligned by caller */         \
        if (__err)                                                      \
                goto err_label;                                         \
 } while (0)
@@ -507,7 +511,9 @@ do {                                                                        \
        const type *__pk_ptr = (dst);                                   \
        unsigned long __dst = (unsigned long)__pk_ptr;                  \
        int __err = 0;                                                  \
-       type __val = *(type *)src;                                      \
+       type __val = IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) \
+                    ? get_unaligned((type *)(src))                     \
+                    : *(type *)(src);  /* aligned by caller */         \
        switch (sizeof(type)) {                                         \
        case 1: __put_user_asm_byte(__val, __dst, __err, ""); break;    \
        case 2: __put_user_asm_half(__val, __dst, __err, ""); break;    \
index 6daaa64..21413a9 100644 (file)
@@ -263,9 +263,9 @@ static int __init omapdss_init_of(void)
        }
 
        r = of_platform_populate(node, NULL, NULL, &pdev->dev);
+       put_device(&pdev->dev);
        if (r) {
                pr_err("Unable to populate DSS submodule devices\n");
-               put_device(&pdev->dev);
                return r;
        }
 
index ccb0e37..31d1a21 100644 (file)
@@ -752,8 +752,10 @@ static int __init _init_clkctrl_providers(void)
 
        for_each_matching_node(np, ti_clkctrl_match_table) {
                ret = _setup_clkctrl_provider(np);
-               if (ret)
+               if (ret) {
+                       of_node_put(np);
                        break;
+               }
        }
 
        return ret;
index 43ddec6..594edf9 100644 (file)
@@ -2,6 +2,7 @@
 menuconfig ARCH_INTEL_SOCFPGA
        bool "Altera SOCFPGA family"
        depends on ARCH_MULTI_V7
+       select ARCH_HAS_RESET_CONTROLLER
        select ARCH_SUPPORTS_BIG_ENDIAN
        select ARM_AMBA
        select ARM_GIC
@@ -18,6 +19,7 @@ menuconfig ARCH_INTEL_SOCFPGA
        select PL310_ERRATA_727915
        select PL310_ERRATA_753970 if PL310
        select PL310_ERRATA_769419
+       select RESET_CONTROLLER
 
 if ARCH_INTEL_SOCFPGA
 config SOCFPGA_SUSPEND
index 14db56f..6159010 100644 (file)
@@ -1,4 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
+KASAN_SANITIZE_actions-common.o := n
+KASAN_SANITIZE_actions-arm.o := n
+KASAN_SANITIZE_actions-thumb.o := n
 obj-$(CONFIG_KPROBES)          += core.o actions-common.o checkers-common.o
 obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o
 test-kprobes-objs              := test-core.o
index 6978140..09b885c 100644 (file)
@@ -670,15 +670,42 @@ config ARM64_ERRATUM_1508412
 config ARM64_WORKAROUND_TRBE_OVERWRITE_FILL_MODE
        bool
 
+config ARM64_ERRATUM_2051678
+       bool "Cortex-A510: 2051678: disable Hardware Update of the page table dirty bit"
+       default y
+       help
+         This options adds the workaround for ARM Cortex-A510 erratum ARM64_ERRATUM_2051678.
+         Affected Coretex-A510 might not respect the ordering rules for
+         hardware update of the page table's dirty bit. The workaround
+         is to not enable the feature on affected CPUs.
+
+         If unsure, say Y.
+
+config ARM64_ERRATUM_2077057
+       bool "Cortex-A510: 2077057: workaround software-step corrupting SPSR_EL2"
+       help
+         This option adds the workaround for ARM Cortex-A510 erratum 2077057.
+         Affected Cortex-A510 may corrupt SPSR_EL2 when the a step exception is
+         expected, but a Pointer Authentication trap is taken instead. The
+         erratum causes SPSR_EL1 to be copied to SPSR_EL2, which could allow
+         EL1 to cause a return to EL2 with a guest controlled ELR_EL2.
+
+         This can only happen when EL2 is stepping EL1.
+
+         When these conditions occur, the SPSR_EL2 value is unchanged from the
+         previous guest entry, and can be restored from the in-memory copy.
+
+         If unsure, say Y.
+
 config ARM64_ERRATUM_2119858
-       bool "Cortex-A710: 2119858: workaround TRBE overwriting trace data in FILL mode"
+       bool "Cortex-A710/X2: 2119858: workaround TRBE overwriting trace data in FILL mode"
        default y
        depends on CORESIGHT_TRBE
        select ARM64_WORKAROUND_TRBE_OVERWRITE_FILL_MODE
        help
-         This option adds the workaround for ARM Cortex-A710 erratum 2119858.
+         This option adds the workaround for ARM Cortex-A710/X2 erratum 2119858.
 
-         Affected Cortex-A710 cores could overwrite up to 3 cache lines of trace
+         Affected Cortex-A710/X2 cores could overwrite up to 3 cache lines of trace
          data at the base of the buffer (pointed to by TRBASER_EL1) in FILL mode in
          the event of a WRAP event.
 
@@ -761,14 +788,14 @@ config ARM64_ERRATUM_2253138
          If unsure, say Y.
 
 config ARM64_ERRATUM_2224489
-       bool "Cortex-A710: 2224489: workaround TRBE writing to address out-of-range"
+       bool "Cortex-A710/X2: 2224489: workaround TRBE writing to address out-of-range"
        depends on CORESIGHT_TRBE
        default y
        select ARM64_WORKAROUND_TRBE_WRITE_OUT_OF_RANGE
        help
-         This option adds the workaround for ARM Cortex-A710 erratum 2224489.
+         This option adds the workaround for ARM Cortex-A710/X2 erratum 2224489.
 
-         Affected Cortex-A710 cores might write to an out-of-range address, not reserved
+         Affected Cortex-A710/X2 cores might write to an out-of-range address, not reserved
          for TRBE. Under some conditions, the TRBE might generate a write to the next
          virtually addressed page following the last page of the TRBE address space
          (i.e., the TRBLIMITR_EL1.LIMIT), instead of wrapping around to the base.
@@ -778,6 +805,65 @@ config ARM64_ERRATUM_2224489
 
          If unsure, say Y.
 
+config ARM64_ERRATUM_2064142
+       bool "Cortex-A510: 2064142: workaround TRBE register writes while disabled"
+       depends on COMPILE_TEST # Until the CoreSight TRBE driver changes are in
+       default y
+       help
+         This option adds the workaround for ARM Cortex-A510 erratum 2064142.
+
+         Affected Cortex-A510 core might fail to write into system registers after the
+         TRBE has been disabled. Under some conditions after the TRBE has been disabled
+         writes into TRBE registers TRBLIMITR_EL1, TRBPTR_EL1, TRBBASER_EL1, TRBSR_EL1,
+         and TRBTRG_EL1 will be ignored and will not be effected.
+
+         Work around this in the driver by executing TSB CSYNC and DSB after collection
+         is stopped and before performing a system register write to one of the affected
+         registers.
+
+         If unsure, say Y.
+
+config ARM64_ERRATUM_2038923
+       bool "Cortex-A510: 2038923: workaround TRBE corruption with enable"
+       depends on COMPILE_TEST # Until the CoreSight TRBE driver changes are in
+       default y
+       help
+         This option adds the workaround for ARM Cortex-A510 erratum 2038923.
+
+         Affected Cortex-A510 core might cause an inconsistent view on whether trace is
+         prohibited within the CPU. As a result, the trace buffer or trace buffer state
+         might be corrupted. This happens after TRBE buffer has been enabled by setting
+         TRBLIMITR_EL1.E, followed by just a single context synchronization event before
+         execution changes from a context, in which trace is prohibited to one where it
+         isn't, or vice versa. In these mentioned conditions, the view of whether trace
+         is prohibited is inconsistent between parts of the CPU, and the trace buffer or
+         the trace buffer state might be corrupted.
+
+         Work around this in the driver by preventing an inconsistent view of whether the
+         trace is prohibited or not based on TRBLIMITR_EL1.E by immediately following a
+         change to TRBLIMITR_EL1.E with at least one ISB instruction before an ERET, or
+         two ISB instructions if no ERET is to take place.
+
+         If unsure, say Y.
+
+config ARM64_ERRATUM_1902691
+       bool "Cortex-A510: 1902691: workaround TRBE trace corruption"
+       depends on COMPILE_TEST # Until the CoreSight TRBE driver changes are in
+       default y
+       help
+         This option adds the workaround for ARM Cortex-A510 erratum 1902691.
+
+         Affected Cortex-A510 core might cause trace data corruption, when being written
+         into the memory. Effectively TRBE is broken and hence cannot be used to capture
+         trace data.
+
+         Work around this problem in the driver by just preventing TRBE initialization on
+         affected cpus. The firmware must have disabled the access to TRBE for the kernel
+         on such implementations. This will cover the kernel for any firmware that doesn't
+         do this already.
+
+         If unsure, say Y.
+
 config CAVIUM_ERRATUM_22375
        bool "Cavium erratum 22375, 24313"
        default y
index 7d5d588..2169744 100644 (file)
@@ -309,9 +309,6 @@ config ARCH_VISCONTI
        help
          This enables support for Toshiba Visconti SoCs Family.
 
-config ARCH_VULCAN
-       def_bool n
-
 config ARCH_XGENE
        bool "AppliedMicro X-Gene SOC Family"
        help
index 517519e..f84d4b4 100644 (file)
                        no-map;
                };
 
+               /* 32 MiB reserved for ARM Trusted Firmware (BL32) */
+               secmon_reserved_bl32: secmon@5300000 {
+                       reg = <0x0 0x05300000 0x0 0x2000000>;
+                       no-map;
+               };
+
                linux,cma {
                        compatible = "shared-dma-pool";
                        reusable;
index d8838dd..4fb31c2 100644 (file)
                regulator-always-on;
        };
 
-       reserved-memory {
-               /* TEE Reserved Memory */
-               bl32_reserved: bl32@5000000 {
-                       reg = <0x0 0x05300000 0x0 0x2000000>;
-                       no-map;
-               };
-       };
-
        sdio_pwrseq: sdio-pwrseq {
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
index 3e968b2..fd3fa82 100644 (file)
@@ -17,7 +17,7 @@
                rtc1 = &vrtc;
        };
 
-       dioo2133: audio-amplifier-0 {
+       dio2133: audio-amplifier-0 {
                compatible = "simple-audio-amplifier";
                enable-gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_HIGH>;
                VCC-supply = <&vcc_5v>;
                audio-widgets = "Line", "Lineout";
                audio-aux-devs = <&tdmout_b>, <&tdmout_c>, <&tdmin_a>,
                                 <&tdmin_b>, <&tdmin_c>, <&tdmin_lb>,
-                                <&dioo2133>;
+                                <&dio2133>;
                audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1",
                                "TDMOUT_B IN 1", "FRDDR_B OUT 1",
                                "TDMOUT_B IN 2", "FRDDR_C OUT 1",
index 6b457b2..aa14ea0 100644 (file)
                        no-map;
                };
 
+               /* 32 MiB reserved for ARM Trusted Firmware (BL32) */
+               secmon_reserved_bl32: secmon@5300000 {
+                       reg = <0x0 0x05300000 0x0 0x2000000>;
+                       no-map;
+               };
+
                linux,cma {
                        compatible = "shared-dma-pool";
                        reusable;
index 212c6aa..5751c48 100644 (file)
                regulator-min-microvolt = <1800000>;
                regulator-max-microvolt = <3300000>;
 
-               enable-gpio = <&gpio GPIOE_2 GPIO_ACTIVE_HIGH>;
+               enable-gpio = <&gpio_ao GPIOE_2 GPIO_ACTIVE_HIGH>;
                enable-active-high;
                regulator-always-on;
 
index 0bd1e98..ddb1b34 100644 (file)
@@ -48,7 +48,7 @@
                regulator-max-microvolt = <3300000>;
                vin-supply = <&vcc_5v>;
 
-               enable-gpio = <&gpio GPIOE_2 GPIO_ACTIVE_HIGH>;
+               enable-gpio = <&gpio_ao GPIOE_2 GPIO_OPEN_DRAIN>;
                enable-active-high;
                regulator-always-on;
 
index 4274758..a5d79f2 100644 (file)
                regulator-always-on;
        };
 
-       reserved-memory {
-               /* TEE Reserved Memory */
-               bl32_reserved: bl32@5000000 {
-                       reg = <0x0 0x05300000 0x0 0x2000000>;
-                       no-map;
-               };
-       };
-
        sdio_pwrseq: sdio-pwrseq {
                compatible = "mmc-pwrseq-simple";
                reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
index d74e738..c03f4e1 100644 (file)
        };
 };
 
+&ftm_alarm0 {
+       status = "okay";
+};
+
 &gpio1 {
        gpio-line-names =
                "", "", "", "", "", "", "", "",
index f3e3418..2d4a472 100644 (file)
        status = "okay";
 
        ports {
-               port@1 {
-                       reg = <1>;
+               port@0 {
+                       reg = <0>;
 
                        mipi1_sensor_ep: endpoint {
                                remote-endpoint = <&camera1_ep>;
index 2df2510..e92ebb6 100644 (file)
                                assigned-clock-rates = <0>, <0>, <0>, <594000000>;
                                status = "disabled";
 
-                               port@0 {
+                               port {
                                        lcdif_mipi_dsi: endpoint {
                                                remote-endpoint = <&mipi_dsi_lcdif_in>;
                                        };
                                        #address-cells = <1>;
                                        #size-cells = <0>;
 
-                                       port@0 {
-                                               reg = <0>;
+                                       port@1 {
+                                               reg = <1>;
 
                                                csi1_mipi_ep: endpoint {
                                                        remote-endpoint = <&csi1_ep>;
                                        #address-cells = <1>;
                                        #size-cells = <0>;
 
-                                       port@0 {
-                                               reg = <0>;
+                                       port@1 {
+                                               reg = <1>;
 
                                                csi2_mipi_ep: endpoint {
                                                        remote-endpoint = <&csi2_ep>;
index f27e3c8..ce6d5bd 100644 (file)
@@ -91,7 +91,7 @@
 
        sound {
                compatible = "fsl,imx-audio-tlv320aic32x4";
-               model = "tqm-tlv320aic32";
+               model = "imx-audio-tlv320aic32x4";
                ssi-controller = <&sai3>;
                audio-codec = <&tlv320aic3x04>;
        };
index a5a24f9..b210cc0 100644 (file)
        model = "Texas Instruments J721S2 EVM";
 
        chosen {
-               stdout-path = "serial10:115200n8";
-               bootargs = "console=ttyS10,115200n8 earlycon=ns16550a,mmio32,2880000";
+               stdout-path = "serial2:115200n8";
+               bootargs = "console=ttyS2,115200n8 earlycon=ns16550a,mmio32,2880000";
+       };
+
+       aliases {
+               serial1 = &mcu_uart0;
+               serial2 = &main_uart8;
+               mmc0 = &main_sdhci0;
+               mmc1 = &main_sdhci1;
+               can0 = &main_mcan16;
+               can1 = &mcu_mcan0;
+               can2 = &mcu_mcan1;
        };
 
        evm_12v0: fixedregulator-evm12v0 {
index 80d3cae..fe5234c 100644 (file)
        #address-cells = <2>;
        #size-cells = <2>;
 
-       aliases {
-               serial0 = &wkup_uart0;
-               serial1 = &mcu_uart0;
-               serial2 = &main_uart0;
-               serial3 = &main_uart1;
-               serial4 = &main_uart2;
-               serial5 = &main_uart3;
-               serial6 = &main_uart4;
-               serial7 = &main_uart5;
-               serial8 = &main_uart6;
-               serial9 = &main_uart7;
-               serial10 = &main_uart8;
-               serial11 = &main_uart9;
-               mmc0 = &main_sdhci0;
-               mmc1 = &main_sdhci1;
-               can0 = &main_mcan16;
-               can1 = &mcu_mcan0;
-               can2 = &mcu_mcan1;
-               can3 = &main_mcan3;
-               can4 = &main_mcan5;
-       };
-
        chosen { };
 
        cpus {
index 19b8441..999b914 100644 (file)
@@ -73,7 +73,9 @@
 #define ARM_CPU_PART_CORTEX_A76                0xD0B
 #define ARM_CPU_PART_NEOVERSE_N1       0xD0C
 #define ARM_CPU_PART_CORTEX_A77                0xD0D
+#define ARM_CPU_PART_CORTEX_A510       0xD46
 #define ARM_CPU_PART_CORTEX_A710       0xD47
+#define ARM_CPU_PART_CORTEX_X2         0xD48
 #define ARM_CPU_PART_NEOVERSE_N2       0xD49
 
 #define APM_CPU_PART_POTENZA           0x000
 #define MIDR_CORTEX_A76        MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76)
 #define MIDR_NEOVERSE_N1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N1)
 #define MIDR_CORTEX_A77        MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A77)
+#define MIDR_CORTEX_A510 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A510)
 #define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710)
+#define MIDR_CORTEX_X2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X2)
 #define MIDR_NEOVERSE_N2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N2)
 #define MIDR_THUNDERX  MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
 #define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
index 3198acb..7f3c87f 100644 (file)
        msr_s   SYS_ICC_SRE_EL2, x0
        isb                                     // Make sure SRE is now set
        mrs_s   x0, SYS_ICC_SRE_EL2             // Read SRE back,
-       tbz     x0, #0, 1f                      // and check that it sticks
+       tbz     x0, #0, .Lskip_gicv3_\@         // and check that it sticks
        msr_s   SYS_ICH_HCR_EL2, xzr            // Reset ICC_HCR_EL2 to defaults
 .Lskip_gicv3_\@:
 .endm
index 9e1c1ae..b217941 100644 (file)
@@ -347,6 +347,7 @@ static const struct midr_range trbe_overwrite_fill_mode_cpus[] = {
 #endif
 #ifdef CONFIG_ARM64_ERRATUM_2119858
        MIDR_ALL_VERSIONS(MIDR_CORTEX_A710),
+       MIDR_RANGE(MIDR_CORTEX_X2, 0, 0, 2, 0),
 #endif
        {},
 };
@@ -371,6 +372,7 @@ static struct midr_range trbe_write_out_of_range_cpus[] = {
 #endif
 #ifdef CONFIG_ARM64_ERRATUM_2224489
        MIDR_ALL_VERSIONS(MIDR_CORTEX_A710),
+       MIDR_RANGE(MIDR_CORTEX_X2, 0, 0, 2, 0),
 #endif
        {},
 };
@@ -597,6 +599,41 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
                .type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE,
                CAP_MIDR_RANGE_LIST(trbe_write_out_of_range_cpus),
        },
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_2077057
+       {
+               .desc = "ARM erratum 2077057",
+               .capability = ARM64_WORKAROUND_2077057,
+               .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
+               ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 2),
+       },
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_2064142
+       {
+               .desc = "ARM erratum 2064142",
+               .capability = ARM64_WORKAROUND_2064142,
+
+               /* Cortex-A510 r0p0 - r0p2 */
+               ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 2)
+       },
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_2038923
+       {
+               .desc = "ARM erratum 2038923",
+               .capability = ARM64_WORKAROUND_2038923,
+
+               /* Cortex-A510 r0p0 - r0p2 */
+               ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 2)
+       },
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_1902691
+       {
+               .desc = "ARM erratum 1902691",
+               .capability = ARM64_WORKAROUND_1902691,
+
+               /* Cortex-A510 r0p0 - r0p1 */
+               ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 1)
+       },
 #endif
        {
        }
index a46ab3b..e5f23da 100644 (file)
@@ -1645,6 +1645,9 @@ static bool cpu_has_broken_dbm(void)
                MIDR_ALL_VERSIONS(MIDR_CORTEX_A55),
                /* Kryo4xx Silver (rdpe => r1p0) */
                MIDR_REV(MIDR_QCOM_KRYO_4XX_SILVER, 0xd, 0xe),
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_2051678
+               MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 2),
 #endif
                {},
        };
index 0fb58fe..e4103e0 100644 (file)
@@ -33,8 +33,8 @@
  */
 
 
-static void start_backtrace(struct stackframe *frame, unsigned long fp,
-                           unsigned long pc)
+static notrace void start_backtrace(struct stackframe *frame, unsigned long fp,
+                                   unsigned long pc)
 {
        frame->fp = fp;
        frame->pc = pc;
@@ -55,6 +55,7 @@ static void start_backtrace(struct stackframe *frame, unsigned long fp,
        frame->prev_fp = 0;
        frame->prev_type = STACK_TYPE_UNKNOWN;
 }
+NOKPROBE_SYMBOL(start_backtrace);
 
 /*
  * Unwind from one frame record (A) to the next frame record (B).
index 6081349..172452f 100644 (file)
@@ -29,8 +29,11 @@ ldflags-y := -shared -soname=linux-vdso.so.1 --hash-style=sysv       \
 ccflags-y := -fno-common -fno-builtin -fno-stack-protector -ffixed-x18
 ccflags-y += -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO
 
+# -Wmissing-prototypes and -Wmissing-declarations are removed from
+# the CFLAGS of vgettimeofday.c to make possible to build the
+# kernel with CONFIG_WERROR enabled.
 CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_FTRACE) -Os $(CC_FLAGS_SCS) $(GCC_PLUGINS_CFLAGS) \
-                               $(CC_FLAGS_LTO)
+                               $(CC_FLAGS_LTO) -Wmissing-prototypes -Wmissing-declarations
 KASAN_SANITIZE                 := n
 KCSAN_SANITIZE                 := n
 UBSAN_SANITIZE                 := n
index a4a0063..ecc5958 100644 (file)
@@ -797,6 +797,24 @@ static bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu, int *ret)
                        xfer_to_guest_mode_work_pending();
 }
 
+/*
+ * Actually run the vCPU, entering an RCU extended quiescent state (EQS) while
+ * the vCPU is running.
+ *
+ * This must be noinstr as instrumentation may make use of RCU, and this is not
+ * safe during the EQS.
+ */
+static int noinstr kvm_arm_vcpu_enter_exit(struct kvm_vcpu *vcpu)
+{
+       int ret;
+
+       guest_state_enter_irqoff();
+       ret = kvm_call_hyp_ret(__kvm_vcpu_run, vcpu);
+       guest_state_exit_irqoff();
+
+       return ret;
+}
+
 /**
  * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code
  * @vcpu:      The VCPU pointer
@@ -881,9 +899,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
                 * Enter the guest
                 */
                trace_kvm_entry(*vcpu_pc(vcpu));
-               guest_enter_irqoff();
+               guest_timing_enter_irqoff();
 
-               ret = kvm_call_hyp_ret(__kvm_vcpu_run, vcpu);
+               ret = kvm_arm_vcpu_enter_exit(vcpu);
 
                vcpu->mode = OUTSIDE_GUEST_MODE;
                vcpu->stat.exits++;
@@ -918,26 +936,23 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
                kvm_arch_vcpu_ctxsync_fp(vcpu);
 
                /*
-                * We may have taken a host interrupt in HYP mode (ie
-                * while executing the guest). This interrupt is still
-                * pending, as we haven't serviced it yet!
+                * We must ensure that any pending interrupts are taken before
+                * we exit guest timing so that timer ticks are accounted as
+                * guest time. Transiently unmask interrupts so that any
+                * pending interrupts are taken.
                 *
-                * We're now back in SVC mode, with interrupts
-                * disabled.  Enabling the interrupts now will have
-                * the effect of taking the interrupt again, in SVC
-                * mode this time.
+                * Per ARM DDI 0487G.b section D1.13.4, an ISB (or other
+                * context synchronization event) is necessary to ensure that
+                * pending interrupts are taken.
                 */
                local_irq_enable();
+               isb();
+               local_irq_disable();
+
+               guest_timing_exit_irqoff();
+
+               local_irq_enable();
 
-               /*
-                * We do local_irq_enable() before calling guest_exit() so
-                * that if a timer interrupt hits while running the guest we
-                * account that tick as being spent in the guest.  We enable
-                * preemption after calling guest_exit() so that if we get
-                * preempted we make sure ticks after that is not counted as
-                * guest time.
-                */
-               guest_exit();
                trace_kvm_exit(ret, kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu));
 
                /* Exit types that need handling before we can be preempted */
index fd2dd26..e3140ab 100644 (file)
@@ -228,6 +228,14 @@ int handle_exit(struct kvm_vcpu *vcpu, int exception_index)
 {
        struct kvm_run *run = vcpu->run;
 
+       if (ARM_SERROR_PENDING(exception_index)) {
+               /*
+                * The SError is handled by handle_exit_early(). If the guest
+                * survives it will re-execute the original instruction.
+                */
+               return 1;
+       }
+
        exception_index = ARM_EXCEPTION_CODE(exception_index);
 
        switch (exception_index) {
index 0418399..c5d0097 100644 (file)
@@ -38,7 +38,10 @@ static inline void __vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg)
 
 static void __vcpu_write_spsr(struct kvm_vcpu *vcpu, u64 val)
 {
-       write_sysreg_el1(val, SYS_SPSR);
+       if (has_vhe())
+               write_sysreg_el1(val, SYS_SPSR);
+       else
+               __vcpu_sys_reg(vcpu, SPSR_EL1) = val;
 }
 
 static void __vcpu_write_spsr_abt(struct kvm_vcpu *vcpu, u64 val)
index 58e14f8..701cfb9 100644 (file)
@@ -402,6 +402,24 @@ static inline bool kvm_hyp_handle_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
        return false;
 }
 
+static inline void synchronize_vcpu_pstate(struct kvm_vcpu *vcpu, u64 *exit_code)
+{
+       /*
+        * Check for the conditions of Cortex-A510's #2077057. When these occur
+        * SPSR_EL2 can't be trusted, but isn't needed either as it is
+        * unchanged from the value in vcpu_gp_regs(vcpu)->pstate.
+        * Are we single-stepping the guest, and took a PAC exception from the
+        * active-not-pending state?
+        */
+       if (cpus_have_final_cap(ARM64_WORKAROUND_2077057)               &&
+           vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP                 &&
+           *vcpu_cpsr(vcpu) & DBG_SPSR_SS                              &&
+           ESR_ELx_EC(read_sysreg_el2(SYS_ESR)) == ESR_ELx_EC_PAC)
+               write_sysreg_el2(*vcpu_cpsr(vcpu), SYS_SPSR);
+
+       vcpu->arch.ctxt.regs.pstate = read_sysreg_el2(SYS_SPSR);
+}
+
 /*
  * Return true when we were able to fixup the guest exit and should return to
  * the guest, false when we should restore the host state and return to the
@@ -413,7 +431,7 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
         * Save PSTATE early so that we can evaluate the vcpu mode
         * early on.
         */
-       vcpu->arch.ctxt.regs.pstate = read_sysreg_el2(SYS_SPSR);
+       synchronize_vcpu_pstate(vcpu, exit_code);
 
        /*
         * Check whether we want to repaint the state one way or
@@ -424,7 +442,8 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
        if (ARM_EXCEPTION_CODE(*exit_code) != ARM_EXCEPTION_IRQ)
                vcpu->arch.fault.esr_el2 = read_sysreg_el2(SYS_ESR);
 
-       if (ARM_SERROR_PENDING(*exit_code)) {
+       if (ARM_SERROR_PENDING(*exit_code) &&
+           ARM_EXCEPTION_CODE(*exit_code) != ARM_EXCEPTION_IRQ) {
                u8 esr_ec = kvm_vcpu_trap_get_class(vcpu);
 
                /*
index 844a6f0..2cb3867 100644 (file)
@@ -983,13 +983,9 @@ static int stage2_unmap_walker(u64 addr, u64 end, u32 level, kvm_pte_t *ptep,
         */
        stage2_put_pte(ptep, mmu, addr, level, mm_ops);
 
-       if (need_flush) {
-               kvm_pte_t *pte_follow = kvm_pte_follow(pte, mm_ops);
-
-               dcache_clean_inval_poc((unsigned long)pte_follow,
-                                   (unsigned long)pte_follow +
-                                           kvm_granule_size(level));
-       }
+       if (need_flush && mm_ops->dcache_clean_inval_poc)
+               mm_ops->dcache_clean_inval_poc(kvm_pte_follow(pte, mm_ops),
+                                              kvm_granule_size(level));
 
        if (childp)
                mm_ops->put_page(childp);
@@ -1151,15 +1147,13 @@ static int stage2_flush_walker(u64 addr, u64 end, u32 level, kvm_pte_t *ptep,
        struct kvm_pgtable *pgt = arg;
        struct kvm_pgtable_mm_ops *mm_ops = pgt->mm_ops;
        kvm_pte_t pte = *ptep;
-       kvm_pte_t *pte_follow;
 
        if (!kvm_pte_valid(pte) || !stage2_pte_cacheable(pgt, pte))
                return 0;
 
-       pte_follow = kvm_pte_follow(pte, mm_ops);
-       dcache_clean_inval_poc((unsigned long)pte_follow,
-                           (unsigned long)pte_follow +
-                                   kvm_granule_size(level));
+       if (mm_ops->dcache_clean_inval_poc)
+               mm_ops->dcache_clean_inval_poc(kvm_pte_follow(pte, mm_ops),
+                                              kvm_granule_size(level));
        return 0;
 }
 
index 20db2f2..4fb419f 100644 (file)
@@ -983,6 +983,9 @@ static void __vgic_v3_read_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
        val = ((vtr >> 29) & 7) << ICC_CTLR_EL1_PRI_BITS_SHIFT;
        /* IDbits */
        val |= ((vtr >> 23) & 7) << ICC_CTLR_EL1_ID_BITS_SHIFT;
+       /* SEIS */
+       if (kvm_vgic_global_state.ich_vtr_el2 & ICH_VTR_SEIS_MASK)
+               val |= BIT(ICC_CTLR_EL1_SEIS_SHIFT);
        /* A3V */
        val |= ((vtr >> 21) & 1) << ICC_CTLR_EL1_A3V_SHIFT;
        /* EOImode */
index 7068da0..49837d3 100644 (file)
@@ -248,6 +248,8 @@ unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
                                                    IRQCHIP_STATE_PENDING,
                                                    &val);
                        WARN_RATELIMIT(err, "IRQ %d", irq->host_irq);
+               } else if (vgic_irq_is_mapped_level(irq)) {
+                       val = vgic_get_phys_line_level(irq);
                } else {
                        val = irq_is_pending(irq);
                }
index a33d436..b549af8 100644 (file)
@@ -609,6 +609,18 @@ static int __init early_gicv4_enable(char *buf)
 }
 early_param("kvm-arm.vgic_v4_enable", early_gicv4_enable);
 
+static const struct midr_range broken_seis[] = {
+       MIDR_ALL_VERSIONS(MIDR_APPLE_M1_ICESTORM),
+       MIDR_ALL_VERSIONS(MIDR_APPLE_M1_FIRESTORM),
+       {},
+};
+
+static bool vgic_v3_broken_seis(void)
+{
+       return ((kvm_vgic_global_state.ich_vtr_el2 & ICH_VTR_SEIS_MASK) &&
+               is_midr_in_range_list(read_cpuid_id(), broken_seis));
+}
+
 /**
  * vgic_v3_probe - probe for a VGICv3 compatible interrupt controller
  * @info:      pointer to the GIC description
@@ -676,9 +688,10 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
                group1_trap = true;
        }
 
-       if (kvm_vgic_global_state.ich_vtr_el2 & ICH_VTR_SEIS_MASK) {
-               kvm_info("GICv3 with locally generated SEI\n");
+       if (vgic_v3_broken_seis()) {
+               kvm_info("GICv3 with broken locally generated SEI\n");
 
+               kvm_vgic_global_state.ich_vtr_el2 &= ~ICH_VTR_SEIS_MASK;
                group0_trap = true;
                group1_trap = true;
                if (ich_vtr_el2 & ICH_VTR_TDS_MASK)
index c0181e6..4894553 100644 (file)
@@ -40,8 +40,8 @@ static bool
 ex_handler_load_unaligned_zeropad(const struct exception_table_entry *ex,
                                  struct pt_regs *regs)
 {
-       int reg_data = FIELD_GET(EX_DATA_REG_DATA, ex->type);
-       int reg_addr = FIELD_GET(EX_DATA_REG_ADDR, ex->type);
+       int reg_data = FIELD_GET(EX_DATA_REG_DATA, ex->data);
+       int reg_addr = FIELD_GET(EX_DATA_REG_ADDR, ex->data);
        unsigned long data, addr, offset;
 
        addr = pt_regs_read_reg(regs, reg_addr);
index 870c395..9c65b1e 100644 (file)
@@ -55,6 +55,10 @@ WORKAROUND_1418040
 WORKAROUND_1463225
 WORKAROUND_1508412
 WORKAROUND_1542419
+WORKAROUND_1902691
+WORKAROUND_2038923
+WORKAROUND_2064142
+WORKAROUND_2077057
 WORKAROUND_TRBE_OVERWRITE_FILL_MODE
 WORKAROUND_TSB_FLUSH_FAILURE
 WORKAROUND_TRBE_WRITE_OUT_OF_RANGE
index 7039528..a7e0157 100644 (file)
@@ -318,7 +318,7 @@ config ARCH_PROC_KCORE_TEXT
        depends on PROC_KCORE
 
 config IA64_MCA_RECOVERY
-       tristate "MCA recovery from errors other than TLB."
+       bool "MCA recovery from errors other than TLB."
 
 config IA64_PALINFO
        tristate "/proc/pal support"
index acb55a4..2bcdd7d 100644 (file)
@@ -76,5 +76,5 @@ static void pci_fixup_video(struct pci_dev *pdev)
                }
        }
 }
-DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
-                               PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video);
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID,
+                              PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video);
index 3e336b3..ab6e3dc 100644 (file)
@@ -83,6 +83,8 @@
                label = "HDMI OUT";
                type = "a";
 
+               ddc-en-gpios = <&gpa 25 GPIO_ACTIVE_HIGH>;
+
                port {
                        hdmi_con: endpoint {
                                remote-endpoint = <&dw_hdmi_out>;
                gpio = <&gpf 14 GPIO_ACTIVE_LOW>;
                enable-active-high;
        };
-
-       hdmi_power: fixedregulator@3 {
-               compatible = "regulator-fixed";
-
-               regulator-name = "hdmi_power";
-               regulator-min-microvolt = <5000000>;
-               regulator-max-microvolt = <5000000>;
-
-               gpio = <&gpa 25 0>;
-               enable-active-high;
-       };
 };
 
 &ext {
        pinctrl-names = "default";
        pinctrl-0 = <&pins_hdmi_ddc>;
 
-       hdmi-5v-supply = <&hdmi_power>;
-
        ports {
                #address-cells = <1>;
                #size-cells = <0>;
index 0a515cd..25860fb 100644 (file)
@@ -74,7 +74,7 @@
 #define EXC(inst_reg,addr,handler)             \
 9:     inst_reg, addr;                         \
        .section __ex_table,"a";                \
-       PTR     9b, handler;                    \
+       PTR_WD  9b, handler;                    \
        .previous
 
 /*
index 6ffdd4b..336ac9b 100644 (file)
@@ -285,7 +285,7 @@ symbol              =       value
 
 #define PTR_SCALESHIFT 2
 
-#define PTR            .word
+#define PTR_WD         .word
 #define PTRSIZE                4
 #define PTRLOG         2
 #endif
@@ -310,7 +310,7 @@ symbol              =       value
 
 #define PTR_SCALESHIFT 3
 
-#define PTR            .dword
+#define PTR_WD         .dword
 #define PTRSIZE                8
 #define PTRLOG         3
 #endif
index b463f2a..db497a8 100644 (file)
@@ -32,7 +32,7 @@ do {                                                  \
                ".previous\n"                           \
                                                        \
                ".section\t__ex_table,\"a\"\n\t"        \
-               STR(PTR) "\t1b, 3b\n\t"                 \
+               STR(PTR_WD) "\t1b, 3b\n\t"              \
                ".previous\n"                           \
                                                        \
                : [tmp_dst] "=&r" (dst), [tmp_err] "=r" (error)\
@@ -54,7 +54,7 @@ do {                                          \
                ".previous\n"                   \
                                                \
                ".section\t__ex_table,\"a\"\n\t"\
-               STR(PTR) "\t1b, 3b\n\t"         \
+               STR(PTR_WD) "\t1b, 3b\n\t"      \
                ".previous\n"                   \
                                                \
                : [tmp_err] "=r" (error)        \
index af37885..431a1c9 100644 (file)
@@ -119,7 +119,7 @@ static inline void flush_scache_line(unsigned long addr)
        "       j       2b                      \n"             \
        "       .previous                       \n"             \
        "       .section __ex_table,\"a\"       \n"             \
-       "       "STR(PTR)" 1b, 3b               \n"             \
+       "       "STR(PTR_WD)" 1b, 3b            \n"             \
        "       .previous"                                      \
        : "+r" (__err)                                          \
        : "i" (op), "r" (addr), "i" (-EFAULT));                 \
@@ -142,7 +142,7 @@ static inline void flush_scache_line(unsigned long addr)
        "       j       2b                      \n"             \
        "       .previous                       \n"             \
        "       .section __ex_table,\"a\"       \n"             \
-       "       "STR(PTR)" 1b, 3b               \n"             \
+       "       "STR(PTR_WD)" 1b, 3b            \n"             \
        "       .previous"                                      \
        : "+r" (__err)                                          \
        : "i" (op), "r" (addr), "i" (-EFAULT));                 \
index 2022b18..9af0f4d 100644 (file)
@@ -20,8 +20,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -41,8 +41,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -74,10 +74,10 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -102,8 +102,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -125,8 +125,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -145,8 +145,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -178,10 +178,10 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -223,14 +223,14 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
-               STR(PTR)"\t5b, 11b\n\t"             \
-               STR(PTR)"\t6b, 11b\n\t"             \
-               STR(PTR)"\t7b, 11b\n\t"             \
-               STR(PTR)"\t8b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
+               STR(PTR_WD)"\t5b, 11b\n\t"          \
+               STR(PTR_WD)"\t6b, 11b\n\t"          \
+               STR(PTR_WD)"\t7b, 11b\n\t"          \
+               STR(PTR_WD)"\t8b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -255,8 +255,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"              \
-               STR(PTR)"\t2b, 4b\n\t"              \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=r" (res)                        \
                : "r" (value), "r" (addr), "i" (-EFAULT));\
@@ -276,8 +276,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=r" (res)                                \
                : "r" (value), "r" (addr), "i" (-EFAULT));  \
@@ -296,8 +296,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=r" (res)                                \
                : "r" (value), "r" (addr), "i" (-EFAULT));  \
@@ -325,10 +325,10 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (res)                               \
                : "r" (value), "r" (addr), "i" (-EFAULT)    \
@@ -365,14 +365,14 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
-               STR(PTR)"\t5b, 11b\n\t"             \
-               STR(PTR)"\t6b, 11b\n\t"             \
-               STR(PTR)"\t7b, 11b\n\t"             \
-               STR(PTR)"\t8b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
+               STR(PTR_WD)"\t5b, 11b\n\t"          \
+               STR(PTR_WD)"\t6b, 11b\n\t"          \
+               STR(PTR_WD)"\t7b, 11b\n\t"          \
+               STR(PTR_WD)"\t8b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (res)                               \
                : "r" (value), "r" (addr), "i" (-EFAULT)    \
@@ -398,8 +398,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -419,8 +419,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -452,10 +452,10 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -481,8 +481,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -504,8 +504,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -524,8 +524,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -557,10 +557,10 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -602,14 +602,14 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
-               STR(PTR)"\t5b, 11b\n\t"             \
-               STR(PTR)"\t6b, 11b\n\t"             \
-               STR(PTR)"\t7b, 11b\n\t"             \
-               STR(PTR)"\t8b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
+               STR(PTR_WD)"\t5b, 11b\n\t"          \
+               STR(PTR_WD)"\t6b, 11b\n\t"          \
+               STR(PTR_WD)"\t7b, 11b\n\t"          \
+               STR(PTR_WD)"\t8b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (value), "=r" (res)         \
                : "r" (addr), "i" (-EFAULT));       \
@@ -632,8 +632,8 @@ do {                                                 \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=r" (res)                        \
                : "r" (value), "r" (addr), "i" (-EFAULT));\
@@ -653,8 +653,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=r" (res)                                \
                : "r" (value), "r" (addr), "i" (-EFAULT));  \
@@ -673,8 +673,8 @@ do {                                                \
                "j\t3b\n\t"                         \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 4b\n\t"               \
-               STR(PTR)"\t2b, 4b\n\t"               \
+               STR(PTR_WD)"\t1b, 4b\n\t"           \
+               STR(PTR_WD)"\t2b, 4b\n\t"           \
                ".previous"                         \
                : "=r" (res)                                \
                : "r" (value), "r" (addr), "i" (-EFAULT));  \
@@ -703,10 +703,10 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (res)                               \
                : "r" (value), "r" (addr), "i" (-EFAULT)    \
@@ -743,14 +743,14 @@ do {                                                \
                "j\t10b\n\t"                        \
                ".previous\n\t"                     \
                ".section\t__ex_table,\"a\"\n\t"    \
-               STR(PTR)"\t1b, 11b\n\t"             \
-               STR(PTR)"\t2b, 11b\n\t"             \
-               STR(PTR)"\t3b, 11b\n\t"             \
-               STR(PTR)"\t4b, 11b\n\t"             \
-               STR(PTR)"\t5b, 11b\n\t"             \
-               STR(PTR)"\t6b, 11b\n\t"             \
-               STR(PTR)"\t7b, 11b\n\t"             \
-               STR(PTR)"\t8b, 11b\n\t"             \
+               STR(PTR_WD)"\t1b, 11b\n\t"          \
+               STR(PTR_WD)"\t2b, 11b\n\t"          \
+               STR(PTR_WD)"\t3b, 11b\n\t"          \
+               STR(PTR_WD)"\t4b, 11b\n\t"          \
+               STR(PTR_WD)"\t5b, 11b\n\t"          \
+               STR(PTR_WD)"\t6b, 11b\n\t"          \
+               STR(PTR_WD)"\t7b, 11b\n\t"          \
+               STR(PTR_WD)"\t8b, 11b\n\t"          \
                ".previous"                         \
                : "=&r" (res)                               \
                : "r" (value), "r" (addr), "i" (-EFAULT)    \
index a39ec75..750fe56 100644 (file)
@@ -1258,10 +1258,10 @@ fpu_emul:
                        "       j       10b\n"
                        "       .previous\n"
                        "       .section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,8b\n"
-                       STR(PTR) " 2b,8b\n"
-                       STR(PTR) " 3b,8b\n"
-                       STR(PTR) " 4b,8b\n"
+                       STR(PTR_WD) " 1b,8b\n"
+                       STR(PTR_WD) " 2b,8b\n"
+                       STR(PTR_WD) " 3b,8b\n"
+                       STR(PTR_WD) " 4b,8b\n"
                        "       .previous\n"
                        "       .set    pop\n"
                        : "+&r"(rt), "=&r"(rs),
@@ -1333,10 +1333,10 @@ fpu_emul:
                        "       j       10b\n"
                        "       .previous\n"
                        "       .section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,8b\n"
-                       STR(PTR) " 2b,8b\n"
-                       STR(PTR) " 3b,8b\n"
-                       STR(PTR) " 4b,8b\n"
+                       STR(PTR_WD) " 1b,8b\n"
+                       STR(PTR_WD) " 2b,8b\n"
+                       STR(PTR_WD) " 3b,8b\n"
+                       STR(PTR_WD) " 4b,8b\n"
                        "       .previous\n"
                        "       .set    pop\n"
                        : "+&r"(rt), "=&r"(rs),
@@ -1404,10 +1404,10 @@ fpu_emul:
                        "       j       9b\n"
                        "       .previous\n"
                        "       .section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,8b\n"
-                       STR(PTR) " 2b,8b\n"
-                       STR(PTR) " 3b,8b\n"
-                       STR(PTR) " 4b,8b\n"
+                       STR(PTR_WD) " 1b,8b\n"
+                       STR(PTR_WD) " 2b,8b\n"
+                       STR(PTR_WD) " 3b,8b\n"
+                       STR(PTR_WD) " 4b,8b\n"
                        "       .previous\n"
                        "       .set    pop\n"
                        : "+&r"(rt), "=&r"(rs),
@@ -1474,10 +1474,10 @@ fpu_emul:
                        "       j       9b\n"
                        "       .previous\n"
                        "       .section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,8b\n"
-                       STR(PTR) " 2b,8b\n"
-                       STR(PTR) " 3b,8b\n"
-                       STR(PTR) " 4b,8b\n"
+                       STR(PTR_WD) " 1b,8b\n"
+                       STR(PTR_WD) " 2b,8b\n"
+                       STR(PTR_WD) " 3b,8b\n"
+                       STR(PTR_WD) " 4b,8b\n"
                        "       .previous\n"
                        "       .set    pop\n"
                        : "+&r"(rt), "=&r"(rs),
@@ -1589,14 +1589,14 @@ fpu_emul:
                        "       j       9b\n"
                        "       .previous\n"
                        "       .section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,8b\n"
-                       STR(PTR) " 2b,8b\n"
-                       STR(PTR) " 3b,8b\n"
-                       STR(PTR) " 4b,8b\n"
-                       STR(PTR) " 5b,8b\n"
-                       STR(PTR) " 6b,8b\n"
-                       STR(PTR) " 7b,8b\n"
-                       STR(PTR) " 0b,8b\n"
+                       STR(PTR_WD) " 1b,8b\n"
+                       STR(PTR_WD) " 2b,8b\n"
+                       STR(PTR_WD) " 3b,8b\n"
+                       STR(PTR_WD) " 4b,8b\n"
+                       STR(PTR_WD) " 5b,8b\n"
+                       STR(PTR_WD) " 6b,8b\n"
+                       STR(PTR_WD) " 7b,8b\n"
+                       STR(PTR_WD) " 0b,8b\n"
                        "       .previous\n"
                        "       .set    pop\n"
                        : "+&r"(rt), "=&r"(rs),
@@ -1708,14 +1708,14 @@ fpu_emul:
                        "       j      9b\n"
                        "       .previous\n"
                        "       .section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,8b\n"
-                       STR(PTR) " 2b,8b\n"
-                       STR(PTR) " 3b,8b\n"
-                       STR(PTR) " 4b,8b\n"
-                       STR(PTR) " 5b,8b\n"
-                       STR(PTR) " 6b,8b\n"
-                       STR(PTR) " 7b,8b\n"
-                       STR(PTR) " 0b,8b\n"
+                       STR(PTR_WD) " 1b,8b\n"
+                       STR(PTR_WD) " 2b,8b\n"
+                       STR(PTR_WD) " 3b,8b\n"
+                       STR(PTR_WD) " 4b,8b\n"
+                       STR(PTR_WD) " 5b,8b\n"
+                       STR(PTR_WD) " 6b,8b\n"
+                       STR(PTR_WD) " 7b,8b\n"
+                       STR(PTR_WD) " 0b,8b\n"
                        "       .previous\n"
                        "       .set    pop\n"
                        : "+&r"(rt), "=&r"(rs),
@@ -1827,14 +1827,14 @@ fpu_emul:
                        "       j       9b\n"
                        "       .previous\n"
                        "       .section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,8b\n"
-                       STR(PTR) " 2b,8b\n"
-                       STR(PTR) " 3b,8b\n"
-                       STR(PTR) " 4b,8b\n"
-                       STR(PTR) " 5b,8b\n"
-                       STR(PTR) " 6b,8b\n"
-                       STR(PTR) " 7b,8b\n"
-                       STR(PTR) " 0b,8b\n"
+                       STR(PTR_WD) " 1b,8b\n"
+                       STR(PTR_WD) " 2b,8b\n"
+                       STR(PTR_WD) " 3b,8b\n"
+                       STR(PTR_WD) " 4b,8b\n"
+                       STR(PTR_WD) " 5b,8b\n"
+                       STR(PTR_WD) " 6b,8b\n"
+                       STR(PTR_WD) " 7b,8b\n"
+                       STR(PTR_WD) " 0b,8b\n"
                        "       .previous\n"
                        "       .set    pop\n"
                        : "+&r"(rt), "=&r"(rs),
@@ -1945,14 +1945,14 @@ fpu_emul:
                        "       j       9b\n"
                        "       .previous\n"
                        "       .section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,8b\n"
-                       STR(PTR) " 2b,8b\n"
-                       STR(PTR) " 3b,8b\n"
-                       STR(PTR) " 4b,8b\n"
-                       STR(PTR) " 5b,8b\n"
-                       STR(PTR) " 6b,8b\n"
-                       STR(PTR) " 7b,8b\n"
-                       STR(PTR) " 0b,8b\n"
+                       STR(PTR_WD) " 1b,8b\n"
+                       STR(PTR_WD) " 2b,8b\n"
+                       STR(PTR_WD) " 3b,8b\n"
+                       STR(PTR_WD) " 4b,8b\n"
+                       STR(PTR_WD) " 5b,8b\n"
+                       STR(PTR_WD) " 6b,8b\n"
+                       STR(PTR_WD) " 7b,8b\n"
+                       STR(PTR_WD) " 0b,8b\n"
                        "       .previous\n"
                        "       .set    pop\n"
                        : "+&r"(rt), "=&r"(rs),
@@ -2007,7 +2007,7 @@ fpu_emul:
                        "j      2b\n"
                        ".previous\n"
                        ".section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,3b\n"
+                       STR(PTR_WD) " 1b,3b\n"
                        ".previous\n"
                        : "=&r"(res), "+&r"(err)
                        : "r"(vaddr), "i"(SIGSEGV)
@@ -2065,7 +2065,7 @@ fpu_emul:
                        "j      2b\n"
                        ".previous\n"
                        ".section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,3b\n"
+                       STR(PTR_WD) " 1b,3b\n"
                        ".previous\n"
                        : "+&r"(res), "+&r"(err)
                        : "r"(vaddr), "i"(SIGSEGV));
@@ -2126,7 +2126,7 @@ fpu_emul:
                        "j      2b\n"
                        ".previous\n"
                        ".section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,3b\n"
+                       STR(PTR_WD) " 1b,3b\n"
                        ".previous\n"
                        : "=&r"(res), "+&r"(err)
                        : "r"(vaddr), "i"(SIGSEGV)
@@ -2189,7 +2189,7 @@ fpu_emul:
                        "j      2b\n"
                        ".previous\n"
                        ".section        __ex_table,\"a\"\n"
-                       STR(PTR) " 1b,3b\n"
+                       STR(PTR_WD) " 1b,3b\n"
                        ".previous\n"
                        : "+&r"(res), "+&r"(err)
                        : "r"(vaddr), "i"(SIGSEGV));
index cbf6db9..2748c55 100644 (file)
 #define EX(a,b)                                                        \
 9:     a,##b;                                                  \
        .section __ex_table,"a";                                \
-       PTR     9b,fault;                                       \
+       PTR_WD  9b,fault;                                       \
        .previous
 
 #define EX2(a,b)                                               \
 9:     a,##b;                                                  \
        .section __ex_table,"a";                                \
-       PTR     9b,fault;                                       \
-       PTR     9b+4,fault;                                     \
+       PTR_WD  9b,fault;                                       \
+       PTR_WD  9b+4,fault;                                     \
        .previous
 
        .set    mips1
index b91e911..2e687c6 100644 (file)
@@ -31,7 +31,7 @@
 .ex\@: \insn   \reg, \src
        .set    pop
        .section __ex_table,"a"
-       PTR     .ex\@, fault
+       PTR_WD  .ex\@, fault
        .previous
        .endm
 
index f3c908a..cfde14b 100644 (file)
@@ -147,10 +147,10 @@ LEAF(kexec_smp_wait)
 
 kexec_args:
        EXPORT(kexec_args)
-arg0:  PTR             0x0
-arg1:  PTR             0x0
-arg2:  PTR             0x0
-arg3:  PTR             0x0
+arg0:  PTR_WD          0x0
+arg1:  PTR_WD          0x0
+arg2:  PTR_WD          0x0
+arg3:  PTR_WD          0x0
        .size   kexec_args,PTRSIZE*4
 
 #ifdef CONFIG_SMP
@@ -161,10 +161,10 @@ arg3:     PTR             0x0
  */
 secondary_kexec_args:
        EXPORT(secondary_kexec_args)
-s_arg0: PTR            0x0
-s_arg1: PTR            0x0
-s_arg2: PTR            0x0
-s_arg3: PTR            0x0
+s_arg0: PTR_WD         0x0
+s_arg1: PTR_WD         0x0
+s_arg2: PTR_WD         0x0
+s_arg3: PTR_WD         0x0
        .size   secondary_kexec_args,PTRSIZE*4
 kexec_flag:
        LONG            0x1
@@ -173,17 +173,17 @@ kexec_flag:
 
 kexec_start_address:
        EXPORT(kexec_start_address)
-       PTR             0x0
+       PTR_WD          0x0
        .size           kexec_start_address, PTRSIZE
 
 kexec_indirection_page:
        EXPORT(kexec_indirection_page)
-       PTR             0
+       PTR_WD          0
        .size           kexec_indirection_page, PTRSIZE
 
 relocate_new_kernel_end:
 
 relocate_new_kernel_size:
        EXPORT(relocate_new_kernel_size)
-       PTR             relocate_new_kernel_end - relocate_new_kernel
+       PTR_WD          relocate_new_kernel_end - relocate_new_kernel
        .size           relocate_new_kernel_size, PTRSIZE
index b1b2e10..9bfce5f 100644 (file)
@@ -72,10 +72,10 @@ loads_done:
        .set    pop
 
        .section __ex_table,"a"
-       PTR     load_a4, bad_stack_a4
-       PTR     load_a5, bad_stack_a5
-       PTR     load_a6, bad_stack_a6
-       PTR     load_a7, bad_stack_a7
+       PTR_WD  load_a4, bad_stack_a4
+       PTR_WD  load_a5, bad_stack_a5
+       PTR_WD  load_a6, bad_stack_a6
+       PTR_WD  load_a7, bad_stack_a7
        .previous
 
        lw      t0, TI_FLAGS($28)       # syscall tracing enabled?
@@ -216,7 +216,7 @@ einval: li  v0, -ENOSYS
 #endif /* CONFIG_MIPS_MT_FPAFF */
 
 #define __SYSCALL_WITH_COMPAT(nr, native, compat)      __SYSCALL(nr, native)
-#define __SYSCALL(nr, entry)   PTR entry
+#define __SYSCALL(nr, entry)   PTR_WD entry
        .align  2
        .type   sys_call_table, @object
 EXPORT(sys_call_table)
index f650c55..97456b2 100644 (file)
@@ -101,7 +101,7 @@ not_n32_scall:
 
        END(handle_sysn32)
 
-#define __SYSCALL(nr, entry)   PTR entry
+#define __SYSCALL(nr, entry)   PTR_WD entry
        .type   sysn32_call_table, @object
 EXPORT(sysn32_call_table)
 #include <asm/syscall_table_n32.h>
index 5d7bfc6..5f6ed4b 100644 (file)
@@ -109,7 +109,7 @@ illegal_syscall:
        j       n64_syscall_exit
        END(handle_sys64)
 
-#define __SYSCALL(nr, entry)   PTR entry
+#define __SYSCALL(nr, entry)   PTR_WD entry
        .align  3
        .type   sys_call_table, @object
 EXPORT(sys_call_table)
index cedc8bd..d3c2616 100644 (file)
@@ -73,10 +73,10 @@ load_a7: lw a7, 28(t0)              # argument #8 from usp
 loads_done:
 
        .section __ex_table,"a"
-       PTR     load_a4, bad_stack_a4
-       PTR     load_a5, bad_stack_a5
-       PTR     load_a6, bad_stack_a6
-       PTR     load_a7, bad_stack_a7
+       PTR_WD  load_a4, bad_stack_a4
+       PTR_WD  load_a5, bad_stack_a5
+       PTR_WD  load_a6, bad_stack_a6
+       PTR_WD  load_a7, bad_stack_a7
        .previous
 
        li      t1, _TIF_WORK_SYSCALL_ENTRY
@@ -214,7 +214,7 @@ einval: li  v0, -ENOSYS
        END(sys32_syscall)
 
 #define __SYSCALL_WITH_COMPAT(nr, native, compat)      __SYSCALL(nr, compat)
-#define __SYSCALL(nr, entry)   PTR entry
+#define __SYSCALL(nr, entry)   PTR_WD entry
        .align  3
        .type   sys32_call_table,@object
 EXPORT(sys32_call_table)
index 5512cd5..ae93a60 100644 (file)
@@ -122,8 +122,8 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new)
                "       j       3b                                      \n"
                "       .previous                                       \n"
                "       .section __ex_table,\"a\"                       \n"
-               "       "STR(PTR)"      1b, 4b                          \n"
-               "       "STR(PTR)"      2b, 4b                          \n"
+               "       "STR(PTR_WD)"   1b, 4b                          \n"
+               "       "STR(PTR_WD)"   2b, 4b                          \n"
                "       .previous                                       \n"
                "       .set    pop                                     \n"
                : [old] "=&r" (old),
@@ -152,8 +152,8 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new)
                "       j       3b                                      \n"
                "       .previous                                       \n"
                "       .section __ex_table,\"a\"                       \n"
-               "       "STR(PTR)"      1b, 5b                          \n"
-               "       "STR(PTR)"      2b, 5b                          \n"
+               "       "STR(PTR_WD)"   1b, 5b                          \n"
+               "       "STR(PTR_WD)"   2b, 5b                          \n"
                "       .previous                                       \n"
                "       .set    pop                                     \n"
                : [old] "=&r" (old),
index e59cb62..a25e0b7 100644 (file)
@@ -414,6 +414,24 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
        return -ENOIOCTLCMD;
 }
 
+/*
+ * Actually run the vCPU, entering an RCU extended quiescent state (EQS) while
+ * the vCPU is running.
+ *
+ * This must be noinstr as instrumentation may make use of RCU, and this is not
+ * safe during the EQS.
+ */
+static int noinstr kvm_mips_vcpu_enter_exit(struct kvm_vcpu *vcpu)
+{
+       int ret;
+
+       guest_state_enter_irqoff();
+       ret = kvm_mips_callbacks->vcpu_run(vcpu);
+       guest_state_exit_irqoff();
+
+       return ret;
+}
+
 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 {
        int r = -EINTR;
@@ -434,7 +452,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
        lose_fpu(1);
 
        local_irq_disable();
-       guest_enter_irqoff();
+       guest_timing_enter_irqoff();
        trace_kvm_enter(vcpu);
 
        /*
@@ -445,10 +463,23 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
         */
        smp_store_mb(vcpu->mode, IN_GUEST_MODE);
 
-       r = kvm_mips_callbacks->vcpu_run(vcpu);
+       r = kvm_mips_vcpu_enter_exit(vcpu);
+
+       /*
+        * We must ensure that any pending interrupts are taken before
+        * we exit guest timing so that timer ticks are accounted as
+        * guest time. Transiently unmask interrupts so that any
+        * pending interrupts are taken.
+        *
+        * TODO: is there a barrier which ensures that pending interrupts are
+        * recognised? Currently this just hopes that the CPU takes any pending
+        * interrupts between the enable and disable.
+        */
+       local_irq_enable();
+       local_irq_disable();
 
        trace_kvm_out(vcpu);
-       guest_exit_irqoff();
+       guest_timing_exit_irqoff();
        local_irq_enable();
 
 out:
@@ -1168,7 +1199,7 @@ static void kvm_mips_set_c0_status(void)
 /*
  * Return value is in the form (errcode<<2 | RESUME_FLAG_HOST | RESUME_FLAG_NV)
  */
-int kvm_mips_handle_exit(struct kvm_vcpu *vcpu)
+static int __kvm_mips_handle_exit(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *run = vcpu->run;
        u32 cause = vcpu->arch.host_cp0_cause;
@@ -1357,6 +1388,17 @@ int kvm_mips_handle_exit(struct kvm_vcpu *vcpu)
        return ret;
 }
 
+int noinstr kvm_mips_handle_exit(struct kvm_vcpu *vcpu)
+{
+       int ret;
+
+       guest_state_exit_irqoff();
+       ret = __kvm_mips_handle_exit(vcpu);
+       guest_state_enter_irqoff();
+
+       return ret;
+}
+
 /* Enable FPU for guest and restore context */
 void kvm_own_fpu(struct kvm_vcpu *vcpu)
 {
index 4adca5a..c706f58 100644 (file)
@@ -458,8 +458,8 @@ void kvm_vz_acquire_htimer(struct kvm_vcpu *vcpu)
 /**
  * _kvm_vz_save_htimer() - Switch to software emulation of guest timer.
  * @vcpu:      Virtual CPU.
- * @compare:   Pointer to write compare value to.
- * @cause:     Pointer to write cause value to.
+ * @out_compare: Pointer to write compare value to.
+ * @out_cause: Pointer to write cause value to.
  *
  * Save VZ guest timer state and switch to software emulation of guest CP0
  * timer. The hard timer must already be in use, so preemption should be
@@ -1541,11 +1541,14 @@ static int kvm_trap_vz_handle_guest_exit(struct kvm_vcpu *vcpu)
 }
 
 /**
- * kvm_trap_vz_handle_cop_unusuable() - Guest used unusable coprocessor.
+ * kvm_trap_vz_handle_cop_unusable() - Guest used unusable coprocessor.
  * @vcpu:      Virtual CPU context.
  *
  * Handle when the guest attempts to use a coprocessor which hasn't been allowed
  * by the root context.
+ *
+ * Return: value indicating whether to resume the host or the guest
+ *        (RESUME_HOST or RESUME_GUEST)
  */
 static int kvm_trap_vz_handle_cop_unusable(struct kvm_vcpu *vcpu)
 {
@@ -1592,6 +1595,9 @@ static int kvm_trap_vz_handle_cop_unusable(struct kvm_vcpu *vcpu)
  *
  * Handle when the guest attempts to use MSA when it is disabled in the root
  * context.
+ *
+ * Return: value indicating whether to resume the host or the guest
+ *        (RESUME_HOST or RESUME_GUEST)
  */
 static int kvm_trap_vz_handle_msa_disabled(struct kvm_vcpu *vcpu)
 {
index a46db08..7767137 100644 (file)
@@ -347,7 +347,7 @@ EXPORT_SYMBOL(csum_partial)
        .if \mode == LEGACY_MODE;               \
 9:             insn reg, addr;                 \
                .section __ex_table,"a";        \
-               PTR     9b, .L_exc;             \
+               PTR_WD  9b, .L_exc;             \
                .previous;                      \
        /* This is enabled in EVA mode */       \
        .else;                                  \
@@ -356,7 +356,7 @@ EXPORT_SYMBOL(csum_partial)
                    ((\to == USEROP) && (type == ST_INSN));     \
 9:                     __BUILD_EVA_INSN(insn##e, reg, addr);   \
                        .section __ex_table,"a";                \
-                       PTR     9b, .L_exc;                     \
+                       PTR_WD  9b, .L_exc;                     \
                        .previous;                              \
                .else;                                          \
                        /* EVA without exception */             \
index 277c322..18a43f2 100644 (file)
        .if \mode == LEGACY_MODE;                               \
 9:             insn reg, addr;                                 \
                .section __ex_table,"a";                        \
-               PTR     9b, handler;                            \
+               PTR_WD  9b, handler;                            \
                .previous;                                      \
        /* This is assembled in EVA mode */                     \
        .else;                                                  \
                    ((\to == USEROP) && (type == ST_INSN));     \
 9:                     __BUILD_EVA_INSN(insn##e, reg, addr);   \
                        .section __ex_table,"a";                \
-                       PTR     9b, handler;                    \
+                       PTR_WD  9b, handler;                    \
                        .previous;                              \
                .else;                                          \
                        /*                                      \
index b0baa3c..0b342ba 100644 (file)
@@ -52,7 +52,7 @@
 9:             ___BUILD_EVA_INSN(insn, reg, addr);     \
        .endif;                                         \
        .section __ex_table,"a";                        \
-       PTR     9b, handler;                            \
+       PTR_WD  9b, handler;                            \
        .previous
 
        .macro  f_fill64 dst, offset, val, fixup, mode
index 556acf6..13aaa99 100644 (file)
@@ -15,7 +15,7 @@
 #define EX(insn,reg,addr,handler)                      \
 9:     insn    reg, addr;                              \
        .section __ex_table,"a";                        \
-       PTR     9b, handler;                            \
+       PTR_WD  9b, handler;                            \
        .previous
 
 /*
@@ -59,7 +59,7 @@ LEAF(__strncpy_from_user_asm)
        jr              ra
 
        .section        __ex_table,"a"
-       PTR             1b, .Lfault
+       PTR_WD          1b, .Lfault
        .previous
 
        EXPORT_SYMBOL(__strncpy_from_user_asm)
index 92b63f2..6de31b6 100644 (file)
@@ -14,7 +14,7 @@
 #define EX(insn,reg,addr,handler)                      \
 9:     insn    reg, addr;                              \
        .section __ex_table,"a";                        \
-       PTR     9b, handler;                            \
+       PTR_WD  9b, handler;                            \
        .previous
 
 /*
index 9a29e94..3115d4d 100644 (file)
@@ -3,7 +3,7 @@
 #include <linux/pci.h>
 #include <loongson.h>
 
-static void pci_fixup_radeon(struct pci_dev *pdev)
+static void pci_fixup_video(struct pci_dev *pdev)
 {
        struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
 
@@ -22,8 +22,7 @@ static void pci_fixup_radeon(struct pci_dev *pdev)
        res->flags = IORESOURCE_MEM | IORESOURCE_ROM_SHADOW |
                     IORESOURCE_PCI_FIXED;
 
-       dev_info(&pdev->dev, "BAR %d: assigned %pR for Radeon ROM\n",
-                PCI_ROM_RESOURCE, res);
+       dev_info(&pdev->dev, "Video device with shadowed ROM at %pR\n", res);
 }
-DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_ATI, 0x9615,
-                               PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_radeon);
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_ATI, 0x9615,
+                              PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video);
index 0ec9cfc..56ffd26 100644 (file)
 #include <asm/barrier.h>
 #include <linux/atomic.h>
 
+/* compiler build environment sanity checks: */
+#if !defined(CONFIG_64BIT) && defined(__LP64__)
+#error "Please use 'ARCH=parisc' to build the 32-bit kernel."
+#endif
+#if defined(CONFIG_64BIT) && !defined(__LP64__)
+#error "Please use 'ARCH=parisc64' to build the 64-bit kernel."
+#endif
+
 /* See http://marc.theaimsgroup.com/?t=108826637900003 for discussion
  * on use of volatile and __*_bit() (set/clear/change):
  *     *_bit() want use of volatile.
index ebf8a84..123d5f1 100644 (file)
@@ -89,8 +89,8 @@ struct exception_table_entry {
        __asm__("1: " ldx " 0(" sr "%2),%0\n"           \
                "9:\n"                                  \
                ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
-               : "=r"(__gu_val), "=r"(__gu_err)        \
-               : "r"(ptr), "1"(__gu_err));             \
+               : "=r"(__gu_val), "+r"(__gu_err)        \
+               : "r"(ptr));                            \
                                                        \
        (val) = (__force __typeof__(*(ptr))) __gu_val;  \
 }
@@ -123,8 +123,8 @@ struct exception_table_entry {
                "9:\n"                                  \
                ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
                ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \
-               : "=&r"(__gu_tmp.l), "=r"(__gu_err)     \
-               : "r"(ptr), "1"(__gu_err));             \
+               : "=&r"(__gu_tmp.l), "+r"(__gu_err)     \
+               : "r"(ptr));                            \
                                                        \
        (val) = __gu_tmp.t;                             \
 }
@@ -135,13 +135,12 @@ struct exception_table_entry {
 #define __put_user_internal(sr, x, ptr)                                \
 ({                                                             \
        ASM_EXCEPTIONTABLE_VAR(__pu_err);                       \
-        __typeof__(*(ptr)) __x = (__typeof__(*(ptr)))(x);      \
                                                                \
        switch (sizeof(*(ptr))) {                               \
-       case 1: __put_user_asm(sr, "stb", __x, ptr); break;     \
-       case 2: __put_user_asm(sr, "sth", __x, ptr); break;     \
-       case 4: __put_user_asm(sr, "stw", __x, ptr); break;     \
-       case 8: STD_USER(sr, __x, ptr); break;                  \
+       case 1: __put_user_asm(sr, "stb", x, ptr); break;       \
+       case 2: __put_user_asm(sr, "sth", x, ptr); break;       \
+       case 4: __put_user_asm(sr, "stw", x, ptr); break;       \
+       case 8: STD_USER(sr, x, ptr); break;                    \
        default: BUILD_BUG();                                   \
        }                                                       \
                                                                \
@@ -150,7 +149,9 @@ struct exception_table_entry {
 
 #define __put_user(x, ptr)                                     \
 ({                                                             \
-       __put_user_internal("%%sr3,", x, ptr);                  \
+       __typeof__(&*(ptr)) __ptr = ptr;                        \
+       __typeof__(*(__ptr)) __x = (__typeof__(*(__ptr)))(x);   \
+       __put_user_internal("%%sr3,", __x, __ptr);              \
 })
 
 #define __put_kernel_nofault(dst, src, type, err_label)                \
@@ -180,8 +181,8 @@ struct exception_table_entry {
                "1: " stx " %2,0(" sr "%1)\n"                   \
                "9:\n"                                          \
                ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b)         \
-               : "=r"(__pu_err)                                \
-               : "r"(ptr), "r"(x), "0"(__pu_err))
+               : "+r"(__pu_err)                                \
+               : "r"(ptr), "r"(x))
 
 
 #if !defined(CONFIG_64BIT)
@@ -193,8 +194,8 @@ struct exception_table_entry {
                "9:\n"                                          \
                ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b)         \
                ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b)         \
-               : "=r"(__pu_err)                                \
-               : "r"(ptr), "r"(__val), "0"(__pu_err));         \
+               : "+r"(__pu_err)                                \
+               : "r"(ptr), "r"(__val));                        \
 } while (0)
 
 #endif /* !defined(CONFIG_64BIT) */
index 237d20d..286cec4 100644 (file)
@@ -340,7 +340,7 @@ static int emulate_stw(struct pt_regs *regs, int frreg, int flop)
        : "r" (val), "r" (regs->ior), "r" (regs->isr)
        : "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER );
 
-       return 0;
+       return ret;
 }
 static int emulate_std(struct pt_regs *regs, int frreg, int flop)
 {
@@ -397,7 +397,7 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
        __asm__ __volatile__ (
 "      mtsp    %4, %%sr1\n"
 "      zdep    %2, 29, 2, %%r19\n"
-"      dep     %%r0, 31, 2, %2\n"
+"      dep     %%r0, 31, 2, %3\n"
 "      mtsar   %%r19\n"
 "      zvdepi  -2, 32, %%r19\n"
 "1:    ldw     0(%%sr1,%3),%%r20\n"
@@ -409,7 +409,7 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
 "      andcm   %%r21, %%r19, %%r21\n"
 "      or      %1, %%r20, %1\n"
 "      or      %2, %%r21, %2\n"
-"3:    stw     %1,0(%%sr1,%1)\n"
+"3:    stw     %1,0(%%sr1,%3)\n"
 "4:    stw     %%r1,4(%%sr1,%3)\n"
 "5:    stw     %2,8(%%sr1,%3)\n"
 "      copy    %%r0, %0\n"
@@ -596,7 +596,6 @@ void handle_unaligned(struct pt_regs *regs)
                ret = ERR_NOTHANDLED;   /* "undefined", but lets kill them. */
                break;
        }
-#ifdef CONFIG_PA20
        switch (regs->iir & OPCODE2_MASK)
        {
        case OPCODE_FLDD_L:
@@ -607,22 +606,23 @@ void handle_unaligned(struct pt_regs *regs)
                flop=1;
                ret = emulate_std(regs, R2(regs->iir),1);
                break;
+#ifdef CONFIG_PA20
        case OPCODE_LDD_L:
                ret = emulate_ldd(regs, R2(regs->iir),0);
                break;
        case OPCODE_STD_L:
                ret = emulate_std(regs, R2(regs->iir),0);
                break;
-       }
 #endif
+       }
        switch (regs->iir & OPCODE3_MASK)
        {
        case OPCODE_FLDW_L:
                flop=1;
-               ret = emulate_ldw(regs, R2(regs->iir),0);
+               ret = emulate_ldw(regs, R2(regs->iir), 1);
                break;
        case OPCODE_LDW_M:
-               ret = emulate_ldw(regs, R2(regs->iir),1);
+               ret = emulate_ldw(regs, R2(regs->iir), 0);
                break;
 
        case OPCODE_FSTW_L:
index 367f639..8603850 100644 (file)
@@ -346,6 +346,16 @@ u64 ioread64be(const void __iomem *addr)
        return *((u64 *)addr);
 }
 
+u64 ioread64_lo_hi(const void __iomem *addr)
+{
+       u32 low, high;
+
+       low = ioread32(addr);
+       high = ioread32(addr + sizeof(u32));
+
+       return low + ((u64)high << 32);
+}
+
 u64 ioread64_hi_lo(const void __iomem *addr)
 {
        u32 low, high;
@@ -419,6 +429,12 @@ void iowrite64be(u64 datum, void __iomem *addr)
        }
 }
 
+void iowrite64_lo_hi(u64 val, void __iomem *addr)
+{
+       iowrite32(val, addr);
+       iowrite32(val >> 32, addr + sizeof(u32));
+}
+
 void iowrite64_hi_lo(u64 val, void __iomem *addr)
 {
        iowrite32(val >> 32, addr + sizeof(u32));
@@ -530,6 +546,7 @@ EXPORT_SYMBOL(ioread32);
 EXPORT_SYMBOL(ioread32be);
 EXPORT_SYMBOL(ioread64);
 EXPORT_SYMBOL(ioread64be);
+EXPORT_SYMBOL(ioread64_lo_hi);
 EXPORT_SYMBOL(ioread64_hi_lo);
 EXPORT_SYMBOL(iowrite8);
 EXPORT_SYMBOL(iowrite16);
@@ -538,6 +555,7 @@ EXPORT_SYMBOL(iowrite32);
 EXPORT_SYMBOL(iowrite32be);
 EXPORT_SYMBOL(iowrite64);
 EXPORT_SYMBOL(iowrite64be);
+EXPORT_SYMBOL(iowrite64_lo_hi);
 EXPORT_SYMBOL(iowrite64_hi_lo);
 EXPORT_SYMBOL(ioread8_rep);
 EXPORT_SYMBOL(ioread16_rep);
index 1ae31db..1dc2e88 100644 (file)
@@ -337,9 +337,9 @@ static void __init setup_bootmem(void)
 
 static bool kernel_set_to_readonly;
 
-static void __init map_pages(unsigned long start_vaddr,
-                            unsigned long start_paddr, unsigned long size,
-                            pgprot_t pgprot, int force)
+static void __ref map_pages(unsigned long start_vaddr,
+                           unsigned long start_paddr, unsigned long size,
+                           pgprot_t pgprot, int force)
 {
        pmd_t *pmd;
        pte_t *pg_table;
@@ -449,7 +449,7 @@ void __init set_kernel_text_rw(int enable_read_write)
        flush_tlb_all();
 }
 
-void __ref free_initmem(void)
+void free_initmem(void)
 {
        unsigned long init_begin = (unsigned long)__init_begin;
        unsigned long init_end = (unsigned long)__init_end;
@@ -463,7 +463,6 @@ void __ref free_initmem(void)
        /* The init text pages are marked R-X.  We have to
         * flush the icache and mark them RW-
         *
-        * This is tricky, because map_pages is in the init section.
         * Do a dummy remap of the data section first (the data
         * section is already PAGE_KERNEL) to pull in the TLB entries
         * for map_kernel */
index 7be2786..78c6a5f 100644 (file)
@@ -223,6 +223,8 @@ static __always_inline void update_user_segments(u32 val)
        update_user_segment(15, val);
 }
 
+int __init find_free_bat(void);
+unsigned int bat_block_size(unsigned long base, unsigned long top);
 #endif /* !__ASSEMBLY__ */
 
 /* We happily ignore the smaller BATs on 601, we don't actually use
index 609c80f..f8b94f7 100644 (file)
@@ -178,6 +178,7 @@ static inline bool pte_user(pte_t pte)
 #ifndef __ASSEMBLY__
 
 int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot);
+void unmap_kernel_page(unsigned long va);
 
 #endif /* !__ASSEMBLY__ */
 
index 33e073d..875730d 100644 (file)
@@ -1082,6 +1082,8 @@ static inline int map_kernel_page(unsigned long ea, unsigned long pa, pgprot_t p
        return hash__map_kernel_page(ea, pa, prot);
 }
 
+void unmap_kernel_page(unsigned long va);
+
 static inline int __meminit vmemmap_create_mapping(unsigned long start,
                                                   unsigned long page_size,
                                                   unsigned long phys)
index 947b5b9..a832aea 100644 (file)
@@ -111,8 +111,10 @@ static inline void __set_fixmap(enum fixed_addresses idx,
                BUILD_BUG_ON(idx >= __end_of_fixed_addresses);
        else if (WARN_ON(idx >= __end_of_fixed_addresses))
                return;
-
-       map_kernel_page(__fix_to_virt(idx), phys, flags);
+       if (pgprot_val(flags))
+               map_kernel_page(__fix_to_virt(idx), phys, flags);
+       else
+               unmap_kernel_page(__fix_to_virt(idx));
 }
 
 #define __early_set_fixmap     __set_fixmap
index a58fb4a..674e5aa 100644 (file)
@@ -473,7 +473,7 @@ static inline bool arch_irq_disabled_regs(struct pt_regs *regs)
        return !(regs->msr & MSR_EE);
 }
 
-static inline bool should_hard_irq_enable(void)
+static __always_inline bool should_hard_irq_enable(void)
 {
        return false;
 }
index fe07558..827038a 100644 (file)
@@ -39,7 +39,6 @@ struct kvm_nested_guest {
        pgd_t *shadow_pgtable;          /* our page table for this guest */
        u64 l1_gr_to_hr;                /* L1's addr of part'n-scoped table */
        u64 process_table;              /* process table entry for this guest */
-       u64 hfscr;                      /* HFSCR that the L1 requested for this nested guest */
        long refcnt;                    /* number of pointers to this struct */
        struct mutex tlb_lock;          /* serialize page faults and tlbies */
        struct kvm_nested_guest *next;
index a770443..d9bf60b 100644 (file)
@@ -818,6 +818,7 @@ struct kvm_vcpu_arch {
 
        /* For support of nested guests */
        struct kvm_nested_guest *nested;
+       u64 nested_hfscr;       /* HFSCR that the L1 requested for the nested guest */
        u32 nested_vcpu_id;
        gpa_t nested_io_gpr;
 #endif
index b67742e..d959c2a 100644 (file)
@@ -64,6 +64,7 @@ extern int icache_44x_need_flush;
 #ifndef __ASSEMBLY__
 
 int map_kernel_page(unsigned long va, phys_addr_t pa, pgprot_t prot);
+void unmap_kernel_page(unsigned long va);
 
 #endif /* !__ASSEMBLY__ */
 
index a3313e8..2816d15 100644 (file)
@@ -308,6 +308,7 @@ static inline void __ptep_set_access_flags(struct vm_area_struct *vma,
 #define __swp_entry_to_pte(x)          __pte((x).val)
 
 int map_kernel_page(unsigned long ea, unsigned long pa, pgprot_t prot);
+void unmap_kernel_page(unsigned long va);
 extern int __meminit vmemmap_create_mapping(unsigned long start,
                                            unsigned long page_size,
                                            unsigned long phys);
index efad070..9675303 100644 (file)
 #define PPC_RAW_LDX(r, base, b)                (0x7c00002a | ___PPC_RT(r) | ___PPC_RA(base) | ___PPC_RB(b))
 #define PPC_RAW_LHZ(r, base, i)                (0xa0000000 | ___PPC_RT(r) | ___PPC_RA(base) | IMM_L(i))
 #define PPC_RAW_LHBRX(r, base, b)      (0x7c00062c | ___PPC_RT(r) | ___PPC_RA(base) | ___PPC_RB(b))
+#define PPC_RAW_LWBRX(r, base, b)      (0x7c00042c | ___PPC_RT(r) | ___PPC_RA(base) | ___PPC_RB(b))
 #define PPC_RAW_LDBRX(r, base, b)      (0x7c000428 | ___PPC_RT(r) | ___PPC_RA(base) | ___PPC_RB(b))
 #define PPC_RAW_STWCX(s, a, b)         (0x7c00012d | ___PPC_RS(s) | ___PPC_RA(a) | ___PPC_RB(b))
 #define PPC_RAW_CMPWI(a, i)            (0x2c000000 | ___PPC_RA(a) | IMM_L(i))
index 52d05b4..25fc8ad 100644 (file)
@@ -90,7 +90,7 @@ static inline void syscall_get_arguments(struct task_struct *task,
        unsigned long val, mask = -1UL;
        unsigned int n = 6;
 
-       if (is_32bit_task())
+       if (is_tsk_32bit_task(task))
                mask = 0xffffffff;
 
        while (n--) {
@@ -105,7 +105,7 @@ static inline void syscall_get_arguments(struct task_struct *task,
 
 static inline int syscall_get_arch(struct task_struct *task)
 {
-       if (is_32bit_task())
+       if (is_tsk_32bit_task(task))
                return AUDIT_ARCH_PPC;
        else if (IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN))
                return AUDIT_ARCH_PPC64LE;
index 5725029..d6e649b 100644 (file)
@@ -168,8 +168,10 @@ static inline bool test_thread_local_flags(unsigned int flags)
 
 #ifdef CONFIG_COMPAT
 #define is_32bit_task()        (test_thread_flag(TIF_32BIT))
+#define is_tsk_32bit_task(tsk) (test_tsk_thread_flag(tsk, TIF_32BIT))
 #else
 #define is_32bit_task()        (IS_ENABLED(CONFIG_PPC32))
+#define is_tsk_32bit_task(tsk) (IS_ENABLED(CONFIG_PPC32))
 #endif
 
 #if defined(CONFIG_PPC64)
index fa84744..b876ef8 100644 (file)
@@ -421,14 +421,14 @@ InstructionTLBMiss:
  */
        /* Get PTE (linux-style) and check access */
        mfspr   r3,SPRN_IMISS
-#ifdef CONFIG_MODULES
+#if defined(CONFIG_MODULES) || defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KFENCE)
        lis     r1, TASK_SIZE@h         /* check if kernel address */
        cmplw   0,r1,r3
 #endif
        mfspr   r2, SPRN_SDR1
        li      r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC | _PAGE_USER
        rlwinm  r2, r2, 28, 0xfffff000
-#ifdef CONFIG_MODULES
+#if defined(CONFIG_MODULES) || defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KFENCE)
        bgt-    112f
        lis     r2, (swapper_pg_dir - PAGE_OFFSET)@ha   /* if kernel address, use */
        li      r1,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC
index 92088f8..7bab2d7 100644 (file)
@@ -30,6 +30,7 @@ COMPAT_SYS_CALL_TABLE:
        .ifc \srr,srr
        mfspr   r11,SPRN_SRR0
        ld      r12,_NIP(r1)
+       clrrdi  r11,r11,2
        clrrdi  r12,r12,2
 100:   tdne    r11,r12
        EMIT_WARN_ENTRY 100b,__FILE__,__LINE__,(BUGFLAG_WARNING | BUGFLAG_ONCE)
@@ -40,6 +41,7 @@ COMPAT_SYS_CALL_TABLE:
        .else
        mfspr   r11,SPRN_HSRR0
        ld      r12,_NIP(r1)
+       clrrdi  r11,r11,2
        clrrdi  r12,r12,2
 100:   tdne    r11,r12
        EMIT_WARN_ENTRY 100b,__FILE__,__LINE__,(BUGFLAG_WARNING | BUGFLAG_ONCE)
index 62361cc..cd0b8b7 100644 (file)
@@ -649,8 +649,9 @@ DEFINE_INTERRUPT_HANDLER_ASYNC(timer_interrupt)
                __this_cpu_inc(irq_stat.timer_irqs_event);
        } else {
                now = *next_tb - now;
-               if (now <= decrementer_max)
-                       set_dec_or_work(now);
+               if (now > decrementer_max)
+                       now = decrementer_max;
+               set_dec_or_work(now);
                __this_cpu_inc(irq_stat.timer_irqs_others);
        }
 
index d1817cd..84c89f0 100644 (file)
@@ -1816,7 +1816,6 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu,
 
 static int kvmppc_handle_nested_exit(struct kvm_vcpu *vcpu)
 {
-       struct kvm_nested_guest *nested = vcpu->arch.nested;
        int r;
        int srcu_idx;
 
@@ -1922,7 +1921,7 @@ static int kvmppc_handle_nested_exit(struct kvm_vcpu *vcpu)
                 * it into a HEAI.
                 */
                if (!(vcpu->arch.hfscr_permitted & (1UL << cause)) ||
-                                       (nested->hfscr & (1UL << cause))) {
+                               (vcpu->arch.nested_hfscr & (1UL << cause))) {
                        vcpu->arch.trap = BOOK3S_INTERRUPT_H_EMUL_ASSIST;
 
                        /*
index 8f8daae..9d373f8 100644 (file)
@@ -363,7 +363,7 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu)
        /* set L1 state to L2 state */
        vcpu->arch.nested = l2;
        vcpu->arch.nested_vcpu_id = l2_hv.vcpu_token;
-       l2->hfscr = l2_hv.hfscr;
+       vcpu->arch.nested_hfscr = l2_hv.hfscr;
        vcpu->arch.regs = l2_regs;
 
        /* Guest must always run with ME enabled, HV disabled. */
index a94b0cd..bd3734d 100644 (file)
@@ -3264,12 +3264,14 @@ void emulate_update_regs(struct pt_regs *regs, struct instruction_op *op)
                case BARRIER_EIEIO:
                        eieio();
                        break;
+#ifdef CONFIG_PPC64
                case BARRIER_LWSYNC:
                        asm volatile("lwsync" : : : "memory");
                        break;
                case BARRIER_PTESYNC:
                        asm volatile("ptesync" : : : "memory");
                        break;
+#endif
                }
                break;
 
index 94045b2..203735c 100644 (file)
@@ -76,7 +76,7 @@ unsigned long p_block_mapped(phys_addr_t pa)
        return 0;
 }
 
-static int __init find_free_bat(void)
+int __init find_free_bat(void)
 {
        int b;
        int n = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
@@ -100,7 +100,7 @@ static int __init find_free_bat(void)
  * - block size has to be a power of two. This is calculated by finding the
  *   highest bit set to 1.
  */
-static unsigned int block_size(unsigned long base, unsigned long top)
+unsigned int bat_block_size(unsigned long base, unsigned long top)
 {
        unsigned int max_size = SZ_256M;
        unsigned int base_shift = (ffs(base) - 1) & 31;
@@ -145,7 +145,7 @@ static unsigned long __init __mmu_mapin_ram(unsigned long base, unsigned long to
        int idx;
 
        while ((idx = find_free_bat()) != -1 && base != top) {
-               unsigned int size = block_size(base, top);
+               unsigned int size = bat_block_size(base, top);
 
                if (size < 128 << 10)
                        break;
@@ -201,12 +201,12 @@ void mmu_mark_initmem_nx(void)
        unsigned long size;
 
        for (i = 0; i < nb - 1 && base < top;) {
-               size = block_size(base, top);
+               size = bat_block_size(base, top);
                setibat(i++, PAGE_OFFSET + base, base, size, PAGE_KERNEL_TEXT);
                base += size;
        }
        if (base < top) {
-               size = block_size(base, top);
+               size = bat_block_size(base, top);
                if ((top - base) > size) {
                        size <<= 1;
                        if (strict_kernel_rwx_enabled() && base + size > border)
index 35b287b..450a67e 100644 (file)
@@ -10,48 +10,51 @@ int __init kasan_init_region(void *start, size_t size)
 {
        unsigned long k_start = (unsigned long)kasan_mem_to_shadow(start);
        unsigned long k_end = (unsigned long)kasan_mem_to_shadow(start + size);
-       unsigned long k_cur = k_start;
-       int k_size = k_end - k_start;
-       int k_size_base = 1 << (ffs(k_size) - 1);
+       unsigned long k_nobat = k_start;
+       unsigned long k_cur;
+       phys_addr_t phys;
        int ret;
-       void *block;
 
-       block = memblock_alloc(k_size, k_size_base);
-
-       if (block && k_size_base >= SZ_128K && k_start == ALIGN(k_start, k_size_base)) {
-               int shift = ffs(k_size - k_size_base);
-               int k_size_more = shift ? 1 << (shift - 1) : 0;
-
-               setbat(-1, k_start, __pa(block), k_size_base, PAGE_KERNEL);
-               if (k_size_more >= SZ_128K)
-                       setbat(-1, k_start + k_size_base, __pa(block) + k_size_base,
-                              k_size_more, PAGE_KERNEL);
-               if (v_block_mapped(k_start))
-                       k_cur = k_start + k_size_base;
-               if (v_block_mapped(k_start + k_size_base))
-                       k_cur = k_start + k_size_base + k_size_more;
-
-               update_bats();
+       while (k_nobat < k_end) {
+               unsigned int k_size = bat_block_size(k_nobat, k_end);
+               int idx = find_free_bat();
+
+               if (idx == -1)
+                       break;
+               if (k_size < SZ_128K)
+                       break;
+               phys = memblock_phys_alloc_range(k_size, k_size, 0,
+                                                MEMBLOCK_ALLOC_ANYWHERE);
+               if (!phys)
+                       break;
+
+               setbat(idx, k_nobat, phys, k_size, PAGE_KERNEL);
+               k_nobat += k_size;
        }
+       if (k_nobat != k_start)
+               update_bats();
 
-       if (!block)
-               block = memblock_alloc(k_size, PAGE_SIZE);
-       if (!block)
-               return -ENOMEM;
+       if (k_nobat < k_end) {
+               phys = memblock_phys_alloc_range(k_end - k_nobat, PAGE_SIZE, 0,
+                                                MEMBLOCK_ALLOC_ANYWHERE);
+               if (!phys)
+                       return -ENOMEM;
+       }
 
        ret = kasan_init_shadow_page_tables(k_start, k_end);
        if (ret)
                return ret;
 
-       kasan_update_early_region(k_start, k_cur, __pte(0));
+       kasan_update_early_region(k_start, k_nobat, __pte(0));
 
-       for (; k_cur < k_end; k_cur += PAGE_SIZE) {
+       for (k_cur = k_nobat; k_cur < k_end; k_cur += PAGE_SIZE) {
                pmd_t *pmd = pmd_off_k(k_cur);
-               void *va = block + k_cur - k_start;
-               pte_t pte = pfn_pte(PHYS_PFN(__pa(va)), PAGE_KERNEL);
+               pte_t pte = pfn_pte(PHYS_PFN(phys + k_cur - k_nobat), PAGE_KERNEL);
 
                __set_pte_at(&init_mm, k_cur, pte_offset_kernel(pmd, k_cur), pte, 0);
        }
        flush_tlb_kernel_range(k_start, k_end);
+       memset(kasan_mem_to_shadow(start), 0, k_end - k_start);
+
        return 0;
 }
index abb3198..6ec5a7d 100644 (file)
@@ -206,6 +206,15 @@ void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
        __set_pte_at(mm, addr, ptep, pte, 0);
 }
 
+void unmap_kernel_page(unsigned long va)
+{
+       pmd_t *pmdp = pmd_off_k(va);
+       pte_t *ptep = pte_offset_kernel(pmdp, va);
+
+       pte_clear(&init_mm, va, ptep);
+       flush_tlb_kernel_range(va, va + PAGE_SIZE);
+}
+
 /*
  * This is called when relaxing access to a PTE. It's also called in the page
  * fault path when we don't hit any of the major fault cases, ie, a minor
index d6ffdd0..56dd1f4 100644 (file)
@@ -23,15 +23,15 @@ static void bpf_jit_fill_ill_insns(void *area, unsigned int size)
        memset32(area, BREAKPOINT_INSTRUCTION, size / 4);
 }
 
-/* Fix the branch target addresses for subprog calls */
-static int bpf_jit_fixup_subprog_calls(struct bpf_prog *fp, u32 *image,
-                                      struct codegen_context *ctx, u32 *addrs)
+/* Fix updated addresses (for subprog calls, ldimm64, et al) during extra pass */
+static int bpf_jit_fixup_addresses(struct bpf_prog *fp, u32 *image,
+                                  struct codegen_context *ctx, u32 *addrs)
 {
        const struct bpf_insn *insn = fp->insnsi;
        bool func_addr_fixed;
        u64 func_addr;
        u32 tmp_idx;
-       int i, ret;
+       int i, j, ret;
 
        for (i = 0; i < fp->len; i++) {
                /*
@@ -66,6 +66,23 @@ static int bpf_jit_fixup_subprog_calls(struct bpf_prog *fp, u32 *image,
                         * of the JITed sequence remains unchanged.
                         */
                        ctx->idx = tmp_idx;
+               } else if (insn[i].code == (BPF_LD | BPF_IMM | BPF_DW)) {
+                       tmp_idx = ctx->idx;
+                       ctx->idx = addrs[i] / 4;
+#ifdef CONFIG_PPC32
+                       PPC_LI32(ctx->b2p[insn[i].dst_reg] - 1, (u32)insn[i + 1].imm);
+                       PPC_LI32(ctx->b2p[insn[i].dst_reg], (u32)insn[i].imm);
+                       for (j = ctx->idx - addrs[i] / 4; j < 4; j++)
+                               EMIT(PPC_RAW_NOP());
+#else
+                       func_addr = ((u64)(u32)insn[i].imm) | (((u64)(u32)insn[i + 1].imm) << 32);
+                       PPC_LI64(b2p[insn[i].dst_reg], func_addr);
+                       /* overwrite rest with nops */
+                       for (j = ctx->idx - addrs[i] / 4; j < 5; j++)
+                               EMIT(PPC_RAW_NOP());
+#endif
+                       ctx->idx = tmp_idx;
+                       i++;
                }
        }
 
@@ -200,13 +217,13 @@ skip_init_ctx:
                /*
                 * Do not touch the prologue and epilogue as they will remain
                 * unchanged. Only fix the branch target address for subprog
-                * calls in the body.
+                * calls in the body, and ldimm64 instructions.
                 *
                 * This does not change the offsets and lengths of the subprog
                 * call instruction sequences and hence, the size of the JITed
                 * image as well.
                 */
-               bpf_jit_fixup_subprog_calls(fp, code_base, &cgctx, addrs);
+               bpf_jit_fixup_addresses(fp, code_base, &cgctx, addrs);
 
                /* There is no need to perform the usual passes. */
                goto skip_codegen_passes;
index faaebd4..cf8dd8a 100644 (file)
@@ -191,6 +191,9 @@ void bpf_jit_emit_func_call_rel(u32 *image, struct codegen_context *ctx, u64 fun
 
        if (image && rel < 0x2000000 && rel >= -0x2000000) {
                PPC_BL_ABS(func);
+               EMIT(PPC_RAW_NOP());
+               EMIT(PPC_RAW_NOP());
+               EMIT(PPC_RAW_NOP());
        } else {
                /* Load function address into r0 */
                EMIT(PPC_RAW_LIS(_R0, IMM_H(func)));
@@ -290,6 +293,8 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
                bool func_addr_fixed;
                u64 func_addr;
                u32 true_cond;
+               u32 tmp_idx;
+               int j;
 
                /*
                 * addrs[] maps a BPF bytecode address into a real offset from
@@ -905,8 +910,12 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
                 * 16 byte instruction that uses two 'struct bpf_insn'
                 */
                case BPF_LD | BPF_IMM | BPF_DW: /* dst = (u64) imm */
+                       tmp_idx = ctx->idx;
                        PPC_LI32(dst_reg_h, (u32)insn[i + 1].imm);
                        PPC_LI32(dst_reg, (u32)insn[i].imm);
+                       /* padding to allow full 4 instructions for later patching */
+                       for (j = ctx->idx - tmp_idx; j < 4; j++)
+                               EMIT(PPC_RAW_NOP());
                        /* Adjust for two bpf instructions */
                        addrs[++i] = ctx->idx * 4;
                        break;
index 9eae8d8..e1e8c93 100644 (file)
@@ -319,6 +319,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *
                u64 imm64;
                u32 true_cond;
                u32 tmp_idx;
+               int j;
 
                /*
                 * addrs[] maps a BPF bytecode address into a real offset from
@@ -633,17 +634,21 @@ bpf_alu32_trunc:
                                EMIT(PPC_RAW_MR(dst_reg, b2p[TMP_REG_1]));
                                break;
                        case 64:
-                               /*
-                                * Way easier and faster(?) to store the value
-                                * into stack and then use ldbrx
-                                *
-                                * ctx->seen will be reliable in pass2, but
-                                * the instructions generated will remain the
-                                * same across all passes
-                                */
+                               /* Store the value to stack and then use byte-reverse loads */
                                PPC_BPF_STL(dst_reg, 1, bpf_jit_stack_local(ctx));
                                EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1], 1, bpf_jit_stack_local(ctx)));
-                               EMIT(PPC_RAW_LDBRX(dst_reg, 0, b2p[TMP_REG_1]));
+                               if (cpu_has_feature(CPU_FTR_ARCH_206)) {
+                                       EMIT(PPC_RAW_LDBRX(dst_reg, 0, b2p[TMP_REG_1]));
+                               } else {
+                                       EMIT(PPC_RAW_LWBRX(dst_reg, 0, b2p[TMP_REG_1]));
+                                       if (IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN))
+                                               EMIT(PPC_RAW_SLDI(dst_reg, dst_reg, 32));
+                                       EMIT(PPC_RAW_LI(b2p[TMP_REG_2], 4));
+                                       EMIT(PPC_RAW_LWBRX(b2p[TMP_REG_2], b2p[TMP_REG_2], b2p[TMP_REG_1]));
+                                       if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+                                               EMIT(PPC_RAW_SLDI(b2p[TMP_REG_2], b2p[TMP_REG_2], 32));
+                                       EMIT(PPC_RAW_OR(dst_reg, dst_reg, b2p[TMP_REG_2]));
+                               }
                                break;
                        }
                        break;
@@ -848,9 +853,13 @@ emit_clear:
                case BPF_LD | BPF_IMM | BPF_DW: /* dst = (u64) imm */
                        imm64 = ((u64)(u32) insn[i].imm) |
                                    (((u64)(u32) insn[i+1].imm) << 32);
+                       tmp_idx = ctx->idx;
+                       PPC_LI64(dst_reg, imm64);
+                       /* padding to allow full 5 instructions for later patching */
+                       for (j = ctx->idx - tmp_idx; j < 5; j++)
+                               EMIT(PPC_RAW_NOP());
                        /* Adjust for two bpf instructions */
                        addrs[++i] = ctx->idx * 4;
-                       PPC_LI64(dst_reg, imm64);
                        break;
 
                /*
index a684901..b5b42cf 100644 (file)
@@ -776,6 +776,34 @@ static void pmao_restore_workaround(bool ebb)
        mtspr(SPRN_PMC6, pmcs[5]);
 }
 
+/*
+ * If the perf subsystem wants performance monitor interrupts as soon as
+ * possible (e.g., to sample the instruction address and stack chain),
+ * this should return true. The IRQ masking code can then enable MSR[EE]
+ * in some places (e.g., interrupt handlers) that allows PMI interrupts
+ * through to improve accuracy of profiles, at the cost of some performance.
+ *
+ * The PMU counters can be enabled by other means (e.g., sysfs raw SPR
+ * access), but in that case there is no need for prompt PMI handling.
+ *
+ * This currently returns true if any perf counter is being used. It
+ * could possibly return false if only events are being counted rather than
+ * samples being taken, but for now this is good enough.
+ */
+bool power_pmu_wants_prompt_pmi(void)
+{
+       struct cpu_hw_events *cpuhw;
+
+       /*
+        * This could simply test local_paca->pmcregs_in_use if that were not
+        * under ifdef KVM.
+        */
+       if (!ppmu)
+               return false;
+
+       cpuhw = this_cpu_ptr(&cpu_hw_events);
+       return cpuhw->n_events;
+}
 #endif /* CONFIG_PPC64 */
 
 static void perf_event_interrupt(struct pt_regs *regs);
@@ -1327,9 +1355,20 @@ static void power_pmu_disable(struct pmu *pmu)
                 * Otherwise provide a warning if there is PMI pending, but
                 * no counter is found overflown.
                 */
-               if (any_pmc_overflown(cpuhw))
-                       clear_pmi_irq_pending();
-               else
+               if (any_pmc_overflown(cpuhw)) {
+                       /*
+                        * Since power_pmu_disable runs under local_irq_save, it
+                        * could happen that code hits a PMC overflow without PMI
+                        * pending in paca. Hence only clear PMI pending if it was
+                        * set.
+                        *
+                        * If a PMI is pending, then MSR[EE] must be disabled (because
+                        * the masked PMI handler disabling EE). So it is safe to
+                        * call clear_pmi_irq_pending().
+                        */
+                       if (pmi_irq_pending())
+                               clear_pmi_irq_pending();
+               } else
                        WARN_ON(pmi_irq_pending());
 
                val = mmcra = cpuhw->mmcr.mmcra;
@@ -2438,36 +2477,6 @@ static void perf_event_interrupt(struct pt_regs *regs)
        perf_sample_event_took(sched_clock() - start_clock);
 }
 
-/*
- * If the perf subsystem wants performance monitor interrupts as soon as
- * possible (e.g., to sample the instruction address and stack chain),
- * this should return true. The IRQ masking code can then enable MSR[EE]
- * in some places (e.g., interrupt handlers) that allows PMI interrupts
- * though to improve accuracy of profiles, at the cost of some performance.
- *
- * The PMU counters can be enabled by other means (e.g., sysfs raw SPR
- * access), but in that case there is no need for prompt PMI handling.
- *
- * This currently returns true if any perf counter is being used. It
- * could possibly return false if only events are being counted rather than
- * samples being taken, but for now this is good enough.
- */
-bool power_pmu_wants_prompt_pmi(void)
-{
-       struct cpu_hw_events *cpuhw;
-
-       /*
-        * This could simply test local_paca->pmcregs_in_use if that were not
-        * under ifdef KVM.
-        */
-
-       if (!ppmu)
-               return false;
-
-       cpuhw = this_cpu_ptr(&cpu_hw_events);
-       return cpuhw->n_events;
-}
-
 static int power_pmu_prepare_cpu(unsigned int cpu)
 {
        struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
index 8a107ed..7d81102 100644 (file)
@@ -50,6 +50,12 @@ riscv-march-$(CONFIG_ARCH_RV32I)     := rv32ima
 riscv-march-$(CONFIG_ARCH_RV64I)       := rv64ima
 riscv-march-$(CONFIG_FPU)              := $(riscv-march-y)fd
 riscv-march-$(CONFIG_RISCV_ISA_C)      := $(riscv-march-y)c
+
+# Newer binutils versions default to ISA spec version 20191213 which moves some
+# instructions from the I extension to the Zicsr and Zifencei extensions.
+toolchain-need-zicsr-zifencei := $(call cc-option-yn, -march=$(riscv-march-y)_zicsr_zifencei)
+riscv-march-$(toolchain-need-zicsr-zifencei) := $(riscv-march-y)_zicsr_zifencei
+
 KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y))
 KBUILD_AFLAGS += -march=$(riscv-march-y)
 
index 2a82a3b..af64b95 100644 (file)
@@ -23,7 +23,7 @@ CONFIG_SLOB=y
 CONFIG_SOC_CANAAN=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=2
-CONFIG_CMDLINE="earlycon console=ttySIF0 rootdelay=2 root=/dev/mmcblk0p1 ro"
+CONFIG_CMDLINE="earlycon console=ttySIF0 root=/dev/mmcblk0p1 rootwait ro"
 CONFIG_CMDLINE_FORCE=y
 # CONFIG_SECCOMP is not set
 # CONFIG_STACKPROTECTOR is not set
index 612556f..ffc87e7 100644 (file)
@@ -51,6 +51,8 @@ obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o
 obj-$(CONFIG_FUNCTION_TRACER)  += mcount.o ftrace.o
 obj-$(CONFIG_DYNAMIC_FTRACE)   += mcount-dyn.o
 
+obj-$(CONFIG_TRACE_IRQFLAGS)   += trace_irq.o
+
 obj-$(CONFIG_RISCV_BASE_PMU)   += perf_event.o
 obj-$(CONFIG_PERF_EVENTS)      += perf_callchain.o
 obj-$(CONFIG_HAVE_PERF_REGS)   += perf_regs.o
index be7f05b..f7a832e 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/sched/hotplug.h>
 #include <asm/irq.h>
 #include <asm/cpu_ops.h>
+#include <asm/numa.h>
 #include <asm/sbi.h>
 
 bool cpu_has_hotplug(unsigned int cpu)
@@ -40,6 +41,7 @@ int __cpu_disable(void)
                return ret;
 
        remove_cpu_topology(cpu);
+       numa_remove_cpu(cpu);
        set_cpu_online(cpu, false);
        irq_migrate_all_off_this_cpu();
 
index ed29e9c..d6a46ed 100644 (file)
@@ -108,7 +108,7 @@ _save_context:
 .option pop
 
 #ifdef CONFIG_TRACE_IRQFLAGS
-       call trace_hardirqs_off
+       call __trace_hardirqs_off
 #endif
 
 #ifdef CONFIG_CONTEXT_TRACKING
@@ -143,7 +143,7 @@ skip_context_tracking:
        li t0, EXC_BREAKPOINT
        beq s4, t0, 1f
 #ifdef CONFIG_TRACE_IRQFLAGS
-       call trace_hardirqs_on
+       call __trace_hardirqs_on
 #endif
        csrs CSR_STATUS, SR_IE
 
@@ -234,7 +234,7 @@ ret_from_exception:
        REG_L s0, PT_STATUS(sp)
        csrc CSR_STATUS, SR_IE
 #ifdef CONFIG_TRACE_IRQFLAGS
-       call trace_hardirqs_off
+       call __trace_hardirqs_off
 #endif
 #ifdef CONFIG_RISCV_M_MODE
        /* the MPP value is too large to be used as an immediate arg for addi */
@@ -270,10 +270,10 @@ restore_all:
        REG_L s1, PT_STATUS(sp)
        andi t0, s1, SR_PIE
        beqz t0, 1f
-       call trace_hardirqs_on
+       call __trace_hardirqs_on
        j 2f
 1:
-       call trace_hardirqs_off
+       call __trace_hardirqs_off
 2:
 #endif
        REG_L a0, PT_STATUS(sp)
index 2363b43..ec07f99 100644 (file)
        add \reg, \reg, t0
 .endm
 .macro XIP_FIXUP_FLASH_OFFSET reg
-       la t1, __data_loc
-       li t0, XIP_OFFSET_MASK
-       and t1, t1, t0
-       li t1, XIP_OFFSET
-       sub t0, t0, t1
-       sub \reg, \reg, t0
+       la t0, __data_loc
+       REG_L t1, _xip_phys_offset
+       sub \reg, \reg, t1
+       add \reg, \reg, t0
 .endm
 _xip_fixup: .dword CONFIG_PHYS_RAM_BASE - CONFIG_XIP_PHYS_ADDR - XIP_OFFSET
+_xip_phys_offset: .dword CONFIG_XIP_PHYS_ADDR + XIP_OFFSET
 #else
 .macro XIP_FIXUP_OFFSET reg
 .endm
index f72527f..775d332 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (c) 2020 Western Digital Corporation or its affiliates.
  */
 
+#include <linux/bits.h>
 #include <linux/init.h>
 #include <linux/pm.h>
 #include <linux/reboot.h>
@@ -85,7 +86,7 @@ static unsigned long __sbi_v01_cpumask_to_hartmask(const struct cpumask *cpu_mas
                        pr_warn("Unable to send any request to hartid > BITS_PER_LONG for SBI v0.1\n");
                        break;
                }
-               hmask |= 1 << hartid;
+               hmask |= BIT(hartid);
        }
 
        return hmask;
@@ -160,7 +161,7 @@ static int __sbi_send_ipi_v01(const struct cpumask *cpu_mask)
 {
        unsigned long hart_mask;
 
-       if (!cpu_mask)
+       if (!cpu_mask || cpumask_empty(cpu_mask))
                cpu_mask = cpu_online_mask;
        hart_mask = __sbi_v01_cpumask_to_hartmask(cpu_mask);
 
@@ -176,7 +177,7 @@ static int __sbi_rfence_v01(int fid, const struct cpumask *cpu_mask,
        int result = 0;
        unsigned long hart_mask;
 
-       if (!cpu_mask)
+       if (!cpu_mask || cpumask_empty(cpu_mask))
                cpu_mask = cpu_online_mask;
        hart_mask = __sbi_v01_cpumask_to_hartmask(cpu_mask);
 
@@ -249,26 +250,37 @@ static void __sbi_set_timer_v02(uint64_t stime_value)
 
 static int __sbi_send_ipi_v02(const struct cpumask *cpu_mask)
 {
-       unsigned long hartid, cpuid, hmask = 0, hbase = 0;
+       unsigned long hartid, cpuid, hmask = 0, hbase = 0, htop = 0;
        struct sbiret ret = {0};
        int result;
 
-       if (!cpu_mask)
+       if (!cpu_mask || cpumask_empty(cpu_mask))
                cpu_mask = cpu_online_mask;
 
        for_each_cpu(cpuid, cpu_mask) {
                hartid = cpuid_to_hartid_map(cpuid);
-               if (hmask && ((hbase + BITS_PER_LONG) <= hartid)) {
-                       ret = sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI,
-                                       hmask, hbase, 0, 0, 0, 0);
-                       if (ret.error)
-                               goto ecall_failed;
-                       hmask = 0;
-                       hbase = 0;
+               if (hmask) {
+                       if (hartid + BITS_PER_LONG <= htop ||
+                           hbase + BITS_PER_LONG <= hartid) {
+                               ret = sbi_ecall(SBI_EXT_IPI,
+                                               SBI_EXT_IPI_SEND_IPI, hmask,
+                                               hbase, 0, 0, 0, 0);
+                               if (ret.error)
+                                       goto ecall_failed;
+                               hmask = 0;
+                       } else if (hartid < hbase) {
+                               /* shift the mask to fit lower hartid */
+                               hmask <<= hbase - hartid;
+                               hbase = hartid;
+                       }
                }
-               if (!hmask)
+               if (!hmask) {
                        hbase = hartid;
-               hmask |= 1UL << (hartid - hbase);
+                       htop = hartid;
+               } else if (hartid > htop) {
+                       htop = hartid;
+               }
+               hmask |= BIT(hartid - hbase);
        }
 
        if (hmask) {
@@ -344,25 +356,35 @@ static int __sbi_rfence_v02(int fid, const struct cpumask *cpu_mask,
                            unsigned long start, unsigned long size,
                            unsigned long arg4, unsigned long arg5)
 {
-       unsigned long hartid, cpuid, hmask = 0, hbase = 0;
+       unsigned long hartid, cpuid, hmask = 0, hbase = 0, htop = 0;
        int result;
 
-       if (!cpu_mask)
+       if (!cpu_mask || cpumask_empty(cpu_mask))
                cpu_mask = cpu_online_mask;
 
        for_each_cpu(cpuid, cpu_mask) {
                hartid = cpuid_to_hartid_map(cpuid);
-               if (hmask && ((hbase + BITS_PER_LONG) <= hartid)) {
-                       result = __sbi_rfence_v02_call(fid, hmask, hbase,
-                                                      start, size, arg4, arg5);
-                       if (result)
-                               return result;
-                       hmask = 0;
-                       hbase = 0;
+               if (hmask) {
+                       if (hartid + BITS_PER_LONG <= htop ||
+                           hbase + BITS_PER_LONG <= hartid) {
+                               result = __sbi_rfence_v02_call(fid, hmask,
+                                               hbase, start, size, arg4, arg5);
+                               if (result)
+                                       return result;
+                               hmask = 0;
+                       } else if (hartid < hbase) {
+                               /* shift the mask to fit lower hartid */
+                               hmask <<= hbase - hartid;
+                               hbase = hartid;
+                       }
                }
-               if (!hmask)
+               if (!hmask) {
                        hbase = hartid;
-               hmask |= 1UL << (hartid - hbase);
+                       htop = hartid;
+               } else if (hartid > htop) {
+                       htop = hartid;
+               }
+               hmask |= BIT(hartid - hbase);
        }
 
        if (hmask) {
index 201ee20..14d2b53 100644 (file)
@@ -22,15 +22,16 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
                             bool (*fn)(void *, unsigned long), void *arg)
 {
        unsigned long fp, sp, pc;
+       int level = 0;
 
        if (regs) {
                fp = frame_pointer(regs);
                sp = user_stack_pointer(regs);
                pc = instruction_pointer(regs);
        } else if (task == NULL || task == current) {
-               fp = (unsigned long)__builtin_frame_address(1);
-               sp = (unsigned long)__builtin_frame_address(0);
-               pc = (unsigned long)__builtin_return_address(0);
+               fp = (unsigned long)__builtin_frame_address(0);
+               sp = sp_in_global;
+               pc = (unsigned long)walk_stackframe;
        } else {
                /* task blocked in __switch_to */
                fp = task->thread.s[0];
@@ -42,7 +43,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
                unsigned long low, high;
                struct stackframe *frame;
 
-               if (unlikely(!__kernel_text_address(pc) || !fn(arg, pc)))
+               if (unlikely(!__kernel_text_address(pc) || (level++ >= 1 && !fn(arg, pc))))
                        break;
 
                /* Validate frame pointer */
diff --git a/arch/riscv/kernel/trace_irq.c b/arch/riscv/kernel/trace_irq.c
new file mode 100644 (file)
index 0000000..095ac97
--- /dev/null
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Changbin Du <changbin.du@gmail.com>
+ */
+
+#include <linux/irqflags.h>
+#include <linux/kprobes.h>
+#include "trace_irq.h"
+
+/*
+ * trace_hardirqs_on/off require the caller to setup frame pointer properly.
+ * Otherwise, CALLER_ADDR1 might trigger an pagging exception in kernel.
+ * Here we add one extra level so they can be safely called by low
+ * level entry code which $fp is used for other purpose.
+ */
+
+void __trace_hardirqs_on(void)
+{
+       trace_hardirqs_on();
+}
+NOKPROBE_SYMBOL(__trace_hardirqs_on);
+
+void __trace_hardirqs_off(void)
+{
+       trace_hardirqs_off();
+}
+NOKPROBE_SYMBOL(__trace_hardirqs_off);
diff --git a/arch/riscv/kernel/trace_irq.h b/arch/riscv/kernel/trace_irq.h
new file mode 100644 (file)
index 0000000..99fe673
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022 Changbin Du <changbin.du@gmail.com>
+ */
+#ifndef __TRACE_IRQ_H
+#define __TRACE_IRQ_H
+
+void __trace_hardirqs_on(void);
+void __trace_hardirqs_off(void);
+
+#endif /* __TRACE_IRQ_H */
index 0c5239e..6241660 100644 (file)
@@ -90,6 +90,7 @@ int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
 int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpu_context *cntx;
+       struct kvm_vcpu_csr *reset_csr = &vcpu->arch.guest_reset_csr;
 
        /* Mark this VCPU never ran */
        vcpu->arch.ran_atleast_once = false;
@@ -106,6 +107,9 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
        cntx->hstatus |= HSTATUS_SPVP;
        cntx->hstatus |= HSTATUS_SPV;
 
+       /* By default, make CY, TM, and IR counters accessible in VU mode */
+       reset_csr->scounteren = 0x7;
+
        /* Setup VCPU timer */
        kvm_riscv_vcpu_timer_init(vcpu);
 
@@ -699,6 +703,20 @@ static void kvm_riscv_update_hvip(struct kvm_vcpu *vcpu)
        csr_write(CSR_HVIP, csr->hvip);
 }
 
+/*
+ * Actually run the vCPU, entering an RCU extended quiescent state (EQS) while
+ * the vCPU is running.
+ *
+ * This must be noinstr as instrumentation may make use of RCU, and this is not
+ * safe during the EQS.
+ */
+static void noinstr kvm_riscv_vcpu_enter_exit(struct kvm_vcpu *vcpu)
+{
+       guest_state_enter_irqoff();
+       __kvm_riscv_switch_to(&vcpu->arch);
+       guest_state_exit_irqoff();
+}
+
 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 {
        int ret;
@@ -790,9 +808,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
                        continue;
                }
 
-               guest_enter_irqoff();
+               guest_timing_enter_irqoff();
 
-               __kvm_riscv_switch_to(&vcpu->arch);
+               kvm_riscv_vcpu_enter_exit(vcpu);
 
                vcpu->mode = OUTSIDE_GUEST_MODE;
                vcpu->stat.exits++;
@@ -812,25 +830,21 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
                kvm_riscv_vcpu_sync_interrupts(vcpu);
 
                /*
-                * We may have taken a host interrupt in VS/VU-mode (i.e.
-                * while executing the guest). This interrupt is still
-                * pending, as we haven't serviced it yet!
+                * We must ensure that any pending interrupts are taken before
+                * we exit guest timing so that timer ticks are accounted as
+                * guest time. Transiently unmask interrupts so that any
+                * pending interrupts are taken.
                 *
-                * We're now back in HS-mode with interrupts disabled
-                * so enabling the interrupts now will have the effect
-                * of taking the interrupt again, in HS-mode this time.
+                * There's no barrier which ensures that pending interrupts are
+                * recognised, so we just hope that the CPU takes any pending
+                * interrupts between the enable and disable.
                 */
                local_irq_enable();
+               local_irq_disable();
 
-               /*
-                * We do local_irq_enable() before calling guest_exit() so
-                * that if a timer interrupt hits while running the guest
-                * we account that tick as being spent in the guest. We
-                * enable preemption after calling guest_exit() so that if
-                * we get preempted we make sure ticks after that is not
-                * counted as guest time.
-                */
-               guest_exit();
+               guest_timing_exit_irqoff();
+
+               local_irq_enable();
 
                preempt_enable();
 
index 4ecf377..48f4310 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/kvm_host.h>
+#include <linux/version.h>
 #include <asm/csr.h>
 #include <asm/sbi.h>
 #include <asm/kvm_vcpu_timer.h>
@@ -32,7 +33,7 @@ static int kvm_sbi_ext_base_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
                *out_val = KVM_SBI_IMPID;
                break;
        case SBI_EXT_BASE_GET_IMP_VERSION:
-               *out_val = 0;
+               *out_val = LINUX_VERSION_CODE;
                break;
        case SBI_EXT_BASE_PROBE_EXT:
                if ((cp->a0 >= SBI_EXT_EXPERIMENTAL_START &&
index 05978f7..35484d8 100644 (file)
@@ -33,7 +33,7 @@ static inline void regs_set_gpr(struct pt_regs *regs, unsigned int offset,
        if (unlikely(offset > MAX_REG_OFFSET))
                return;
 
-       if (!offset)
+       if (offset)
                *(unsigned long *)((unsigned long)regs + offset) = val;
 }
 
@@ -43,8 +43,8 @@ static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex,
        int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
        int reg_zero = FIELD_GET(EX_DATA_REG_ZERO, ex->data);
 
-       regs_set_gpr(regs, reg_err, -EFAULT);
-       regs_set_gpr(regs, reg_zero, 0);
+       regs_set_gpr(regs, reg_err * sizeof(unsigned long), -EFAULT);
+       regs_set_gpr(regs, reg_zero * sizeof(unsigned long), 0);
 
        regs->epc = get_ex_fixup(ex);
        return true;
index cf4d018..c272941 100644 (file)
@@ -232,6 +232,7 @@ static pmd_t __maybe_unused early_dtb_pmd[PTRS_PER_PMD] __initdata __aligned(PAG
 
 #ifdef CONFIG_XIP_KERNEL
 #define pt_ops                 (*(struct pt_alloc_ops *)XIP_FIXUP(&pt_ops))
+#define riscv_pfn_base         (*(unsigned long  *)XIP_FIXUP(&riscv_pfn_base))
 #define trampoline_pg_dir      ((pgd_t *)XIP_FIXUP(trampoline_pg_dir))
 #define fixmap_pte             ((pte_t *)XIP_FIXUP(fixmap_pte))
 #define early_pg_dir           ((pgd_t *)XIP_FIXUP(early_pg_dir))
@@ -522,6 +523,7 @@ static uintptr_t __init best_map_size(phys_addr_t base, phys_addr_t size)
 }
 
 #ifdef CONFIG_XIP_KERNEL
+#define phys_ram_base  (*(phys_addr_t *)XIP_FIXUP(&phys_ram_base))
 extern char _xiprom[], _exiprom[], __data_loc;
 
 /* called from head.S with MMU off */
index 9750f92..be9f39f 100644 (file)
@@ -945,6 +945,9 @@ config S390_GUEST
 
 endmenu
 
+config S390_MODULES_SANITY_TEST_HELPERS
+       def_bool n
+
 menu "Selftests"
 
 config S390_UNWIND_SELFTEST
@@ -971,4 +974,16 @@ config S390_KPROBES_SANITY_TEST
 
          Say N if you are unsure.
 
+config S390_MODULES_SANITY_TEST
+       def_tristate n
+       depends on KUNIT
+       default KUNIT_ALL_TESTS
+       prompt "Enable s390 specific modules tests"
+       select S390_MODULES_SANITY_TEST_HELPERS
+       help
+         This option enables an s390 specific modules test. This option is
+         not useful for distributions or general kernels, but only for
+         kernel developers working on architecture code.
+
+         Say N if you are unsure.
 endmenu
index 7fe8975..498bed9 100644 (file)
@@ -63,6 +63,7 @@ CONFIG_APPLDATA_BASE=y
 CONFIG_KVM=m
 CONFIG_S390_UNWIND_SELFTEST=m
 CONFIG_S390_KPROBES_SANITY_TEST=m
+CONFIG_S390_MODULES_SANITY_TEST=m
 CONFIG_KPROBES=y
 CONFIG_JUMP_LABEL=y
 CONFIG_STATIC_KEYS_SELFTEST=y
@@ -96,7 +97,6 @@ CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTREMOVE=y
 CONFIG_KSM=y
 CONFIG_TRANSPARENT_HUGEPAGE=y
-CONFIG_FRONTSWAP=y
 CONFIG_CMA_DEBUG=y
 CONFIG_CMA_DEBUGFS=y
 CONFIG_CMA_SYSFS=y
@@ -109,6 +109,7 @@ CONFIG_DEFERRED_STRUCT_PAGE_INIT=y
 CONFIG_IDLE_PAGE_TRACKING=y
 CONFIG_PERCPU_STATS=y
 CONFIG_GUP_TEST=y
+CONFIG_ANON_VMA_NAME=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -116,7 +117,6 @@ CONFIG_UNIX=y
 CONFIG_UNIX_DIAG=m
 CONFIG_XFRM_USER=m
 CONFIG_NET_KEY=m
-CONFIG_NET_SWITCHDEV=y
 CONFIG_SMC=m
 CONFIG_SMC_DIAG=m
 CONFIG_INET=y
@@ -185,7 +185,6 @@ CONFIG_NF_CT_NETLINK_TIMEOUT=m
 CONFIG_NF_TABLES=m
 CONFIG_NF_TABLES_INET=y
 CONFIG_NFT_CT=m
-CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
@@ -391,6 +390,7 @@ CONFIG_OPENVSWITCH=m
 CONFIG_VSOCKETS=m
 CONFIG_VIRTIO_VSOCKETS=m
 CONFIG_NETLINK_DIAG=m
+CONFIG_NET_SWITCHDEV=y
 CONFIG_CGROUP_NET_PRIO=y
 CONFIG_NET_PKTGEN=m
 CONFIG_PCI=y
@@ -400,6 +400,7 @@ CONFIG_PCI_IOV=y
 CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_S390=y
 CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_SAFE=y
 CONFIG_CONNECTOR=y
 CONFIG_ZRAM=y
 CONFIG_BLK_DEV_LOOP=m
@@ -501,6 +502,7 @@ CONFIG_NLMON=m
 # CONFIG_NET_VENDOR_DEC is not set
 # CONFIG_NET_VENDOR_DLINK is not set
 # CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_ENGLEDER is not set
 # CONFIG_NET_VENDOR_EZCHIP is not set
 # CONFIG_NET_VENDOR_GOOGLE is not set
 # CONFIG_NET_VENDOR_HUAWEI is not set
@@ -511,7 +513,6 @@ CONFIG_NLMON=m
 CONFIG_MLX4_EN=m
 CONFIG_MLX5_CORE=m
 CONFIG_MLX5_CORE_EN=y
-CONFIG_MLX5_ESWITCH=y
 # CONFIG_NET_VENDOR_MICREL is not set
 # CONFIG_NET_VENDOR_MICROCHIP is not set
 # CONFIG_NET_VENDOR_MICROSEMI is not set
@@ -542,6 +543,7 @@ CONFIG_MLX5_ESWITCH=y
 # CONFIG_NET_VENDOR_SYNOPSYS is not set
 # CONFIG_NET_VENDOR_TEHUTI is not set
 # CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_VERTEXCOM is not set
 # CONFIG_NET_VENDOR_VIA is not set
 # CONFIG_NET_VENDOR_WIZNET is not set
 # CONFIG_NET_VENDOR_XILINX is not set
@@ -592,6 +594,7 @@ CONFIG_VIRTIO_BALLOON=m
 CONFIG_VIRTIO_INPUT=y
 CONFIG_VHOST_NET=m
 CONFIG_VHOST_VSOCK=m
+# CONFIG_SURFACE_PLATFORMS is not set
 CONFIG_S390_CCW_IOMMU=y
 CONFIG_S390_AP_IOMMU=y
 CONFIG_EXT4_FS=y
@@ -756,9 +759,6 @@ CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
 CONFIG_CRYPTO_STATS=y
-CONFIG_CRYPTO_LIB_BLAKE2S=m
-CONFIG_CRYPTO_LIB_CURVE25519=m
-CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 CONFIG_ZCRYPT=m
 CONFIG_PKEY=m
 CONFIG_CRYPTO_PAES_S390=m
@@ -774,6 +774,8 @@ CONFIG_CRYPTO_GHASH_S390=m
 CONFIG_CRYPTO_CRC32_S390=y
 CONFIG_CRYPTO_DEV_VIRTIO=m
 CONFIG_CORDIC=m
+CONFIG_CRYPTO_LIB_CURVE25519=m
+CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 CONFIG_CRC32_SELFTEST=y
 CONFIG_CRC4=m
 CONFIG_CRC7=m
@@ -807,7 +809,6 @@ CONFIG_SLUB_DEBUG_ON=y
 CONFIG_SLUB_STATS=y
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_VM=y
-CONFIG_DEBUG_VM_VMACACHE=y
 CONFIG_DEBUG_VM_PGFLAGS=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m
@@ -819,12 +820,11 @@ CONFIG_PANIC_ON_OOPS=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_WQ_WATCHDOG=y
 CONFIG_TEST_LOCKUP=m
-CONFIG_DEBUG_TIMEKEEPING=y
 CONFIG_PROVE_LOCKING=y
 CONFIG_LOCK_STAT=y
-CONFIG_DEBUG_LOCKDEP=y
 CONFIG_DEBUG_ATOMIC_SLEEP=y
 CONFIG_DEBUG_LOCKING_API_SELFTESTS=y
+CONFIG_DEBUG_IRQFLAGS=y
 CONFIG_DEBUG_SG=y
 CONFIG_DEBUG_NOTIFIERS=y
 CONFIG_BUG_ON_DATA_CORRUPTION=y
index 466780c..61e36b9 100644 (file)
@@ -61,6 +61,7 @@ CONFIG_APPLDATA_BASE=y
 CONFIG_KVM=m
 CONFIG_S390_UNWIND_SELFTEST=m
 CONFIG_S390_KPROBES_SANITY_TEST=m
+CONFIG_S390_MODULES_SANITY_TEST=m
 CONFIG_KPROBES=y
 CONFIG_JUMP_LABEL=y
 # CONFIG_GCC_PLUGINS is not set
@@ -91,7 +92,6 @@ CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTREMOVE=y
 CONFIG_KSM=y
 CONFIG_TRANSPARENT_HUGEPAGE=y
-CONFIG_FRONTSWAP=y
 CONFIG_CMA_SYSFS=y
 CONFIG_CMA_AREAS=7
 CONFIG_MEM_SOFT_DIRTY=y
@@ -101,6 +101,7 @@ CONFIG_ZSMALLOC_STAT=y
 CONFIG_DEFERRED_STRUCT_PAGE_INIT=y
 CONFIG_IDLE_PAGE_TRACKING=y
 CONFIG_PERCPU_STATS=y
+CONFIG_ANON_VMA_NAME=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=m
@@ -108,7 +109,6 @@ CONFIG_UNIX=y
 CONFIG_UNIX_DIAG=m
 CONFIG_XFRM_USER=m
 CONFIG_NET_KEY=m
-CONFIG_NET_SWITCHDEV=y
 CONFIG_SMC=m
 CONFIG_SMC_DIAG=m
 CONFIG_INET=y
@@ -177,7 +177,6 @@ CONFIG_NF_CT_NETLINK_TIMEOUT=m
 CONFIG_NF_TABLES=m
 CONFIG_NF_TABLES_INET=y
 CONFIG_NFT_CT=m
-CONFIG_NFT_COUNTER=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
@@ -382,6 +381,7 @@ CONFIG_OPENVSWITCH=m
 CONFIG_VSOCKETS=m
 CONFIG_VIRTIO_VSOCKETS=m
 CONFIG_NETLINK_DIAG=m
+CONFIG_NET_SWITCHDEV=y
 CONFIG_CGROUP_NET_PRIO=y
 CONFIG_NET_PKTGEN=m
 CONFIG_PCI=y
@@ -391,6 +391,7 @@ CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_S390=y
 CONFIG_UEVENT_HELPER=y
 CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_SAFE=y
 CONFIG_CONNECTOR=y
 CONFIG_ZRAM=y
 CONFIG_BLK_DEV_LOOP=m
@@ -492,6 +493,7 @@ CONFIG_NLMON=m
 # CONFIG_NET_VENDOR_DEC is not set
 # CONFIG_NET_VENDOR_DLINK is not set
 # CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_ENGLEDER is not set
 # CONFIG_NET_VENDOR_EZCHIP is not set
 # CONFIG_NET_VENDOR_GOOGLE is not set
 # CONFIG_NET_VENDOR_HUAWEI is not set
@@ -502,7 +504,6 @@ CONFIG_NLMON=m
 CONFIG_MLX4_EN=m
 CONFIG_MLX5_CORE=m
 CONFIG_MLX5_CORE_EN=y
-CONFIG_MLX5_ESWITCH=y
 # CONFIG_NET_VENDOR_MICREL is not set
 # CONFIG_NET_VENDOR_MICROCHIP is not set
 # CONFIG_NET_VENDOR_MICROSEMI is not set
@@ -533,6 +534,7 @@ CONFIG_MLX5_ESWITCH=y
 # CONFIG_NET_VENDOR_SYNOPSYS is not set
 # CONFIG_NET_VENDOR_TEHUTI is not set
 # CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_VERTEXCOM is not set
 # CONFIG_NET_VENDOR_VIA is not set
 # CONFIG_NET_VENDOR_WIZNET is not set
 # CONFIG_NET_VENDOR_XILINX is not set
@@ -582,6 +584,7 @@ CONFIG_VIRTIO_BALLOON=m
 CONFIG_VIRTIO_INPUT=y
 CONFIG_VHOST_NET=m
 CONFIG_VHOST_VSOCK=m
+# CONFIG_SURFACE_PLATFORMS is not set
 CONFIG_S390_CCW_IOMMU=y
 CONFIG_S390_AP_IOMMU=y
 CONFIG_EXT4_FS=y
@@ -743,9 +746,6 @@ CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
 CONFIG_CRYPTO_STATS=y
-CONFIG_CRYPTO_LIB_BLAKE2S=m
-CONFIG_CRYPTO_LIB_CURVE25519=m
-CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 CONFIG_ZCRYPT=m
 CONFIG_PKEY=m
 CONFIG_CRYPTO_PAES_S390=m
@@ -762,6 +762,8 @@ CONFIG_CRYPTO_CRC32_S390=y
 CONFIG_CRYPTO_DEV_VIRTIO=m
 CONFIG_CORDIC=m
 CONFIG_PRIME_NUMBERS=m
+CONFIG_CRYPTO_LIB_CURVE25519=m
+CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 CONFIG_CRC4=m
 CONFIG_CRC7=m
 CONFIG_CRC8=m
index eed3b9a..c55c668 100644 (file)
@@ -1,6 +1,7 @@
 # CONFIG_SWAP is not set
 CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BPF_SYSCALL=y
 # CONFIG_CPU_ISOLATION is not set
 # CONFIG_UTS_NS is not set
 # CONFIG_TIME_NS is not set
@@ -34,6 +35,7 @@ CONFIG_NET=y
 # CONFIG_PCPU_DEV_REFCNT is not set
 # CONFIG_ETHTOOL_NETLINK is not set
 CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_SAFE=y
 CONFIG_BLK_DEV_RAM=y
 # CONFIG_DCSSBLK is not set
 # CONFIG_DASD is not set
@@ -58,6 +60,7 @@ CONFIG_ZFCP=y
 # CONFIG_HID is not set
 # CONFIG_VIRTIO_MENU is not set
 # CONFIG_VHOST_MENU is not set
+# CONFIG_SURFACE_PLATFORMS is not set
 # CONFIG_IOMMU_SUPPORT is not set
 # CONFIG_DNOTIFY is not set
 # CONFIG_INOTIFY_USER is not set
index 33f973f..e8f15db 100644 (file)
@@ -20,6 +20,7 @@
 
 static char local_guest[] = "        ";
 static char all_guests[] = "*       ";
+static char *all_groups = all_guests;
 static char *guest_query;
 
 struct diag2fc_data {
@@ -62,10 +63,11 @@ static int diag2fc(int size, char* query, void *addr)
 
        memcpy(parm_list.userid, query, NAME_LEN);
        ASCEBC(parm_list.userid, NAME_LEN);
-       parm_list.addr = (unsigned long) addr ;
+       memcpy(parm_list.aci_grp, all_groups, NAME_LEN);
+       ASCEBC(parm_list.aci_grp, NAME_LEN);
+       parm_list.addr = (unsigned long)addr;
        parm_list.size = size;
        parm_list.fmt = 0x02;
-       memset(parm_list.aci_grp, 0x40, NAME_LEN);
        rc = -1;
 
        diag_stat_inc(DIAG_STAT_X2FC);
index 147cb35..d74e26b 100644 (file)
@@ -47,8 +47,6 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n);
 int __put_user_bad(void) __attribute__((noreturn));
 int __get_user_bad(void) __attribute__((noreturn));
 
-#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
-
 union oac {
        unsigned int val;
        struct {
@@ -71,6 +69,8 @@ union oac {
        };
 };
 
+#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
+
 #define __put_get_user_asm(to, from, size, oac_spec)                   \
 ({                                                                     \
        int __rc;                                                       \
index d52d853..b032e55 100644 (file)
@@ -33,7 +33,7 @@
 #define DEBUGP(fmt , ...)
 #endif
 
-#define PLT_ENTRY_SIZE 20
+#define PLT_ENTRY_SIZE 22
 
 void *module_alloc(unsigned long size)
 {
@@ -341,27 +341,26 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
        case R_390_PLTOFF32:    /* 32 bit offset from GOT to PLT. */
        case R_390_PLTOFF64:    /* 16 bit offset from GOT to PLT. */
                if (info->plt_initialized == 0) {
-                       unsigned int insn[5];
-                       unsigned int *ip = me->core_layout.base +
-                                          me->arch.plt_offset +
-                                          info->plt_offset;
-
-                       insn[0] = 0x0d10e310;   /* basr 1,0  */
-                       insn[1] = 0x100a0004;   /* lg   1,10(1) */
+                       unsigned char insn[PLT_ENTRY_SIZE];
+                       char *plt_base;
+                       char *ip;
+
+                       plt_base = me->core_layout.base + me->arch.plt_offset;
+                       ip = plt_base + info->plt_offset;
+                       *(int *)insn = 0x0d10e310;      /* basr 1,0  */
+                       *(int *)&insn[4] = 0x100c0004;  /* lg   1,12(1) */
                        if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) {
-                               unsigned int *ij;
-                               ij = me->core_layout.base +
-                                       me->arch.plt_offset +
-                                       me->arch.plt_size - PLT_ENTRY_SIZE;
-                               insn[2] = 0xa7f40000 +  /* j __jump_r1 */
-                                       (unsigned int)(u16)
-                                       (((unsigned long) ij - 8 -
-                                         (unsigned long) ip) / 2);
+                               char *jump_r1;
+
+                               jump_r1 = plt_base + me->arch.plt_size -
+                                       PLT_ENTRY_SIZE;
+                               /* brcl 0xf,__jump_r1 */
+                               *(short *)&insn[8] = 0xc0f4;
+                               *(int *)&insn[10] = (jump_r1 - (ip + 8)) / 2;
                        } else {
-                               insn[2] = 0x07f10000;   /* br %r1 */
+                               *(int *)&insn[8] = 0x07f10000;  /* br %r1 */
                        }
-                       insn[3] = (unsigned int) (val >> 32);
-                       insn[4] = (unsigned int) val;
+                       *(long *)&insn[14] = val;
 
                        write(ip, insn, sizeof(insn));
                        info->plt_initialized = 1;
index 0c9e894..651a519 100644 (file)
@@ -264,7 +264,14 @@ static int notrace s390_validate_registers(union mci mci, int umode)
                /* Validate vector registers */
                union ctlreg0 cr0;
 
-               if (!mci.vr) {
+               /*
+                * The vector validity must only be checked if not running a
+                * KVM guest. For KVM guests the machine check is forwarded by
+                * KVM and it is the responsibility of the guest to take
+                * appropriate actions. The host vector or FPU values have been
+                * saved by KVM and will be restored by KVM.
+                */
+               if (!mci.vr && !test_cpu_flag(CIF_MCCK_GUEST)) {
                        /*
                         * Vector registers can't be restored. If the kernel
                         * currently uses vector registers the system is
@@ -307,11 +314,21 @@ static int notrace s390_validate_registers(union mci mci, int umode)
        if (cr2.gse) {
                if (!mci.gs) {
                        /*
-                        * Guarded storage register can't be restored and
-                        * the current processes uses guarded storage.
-                        * It has to be terminated.
+                        * 2 cases:
+                        * - machine check in kernel or userspace
+                        * - machine check while running SIE (KVM guest)
+                        * For kernel or userspace the userspace values of
+                        * guarded storage control can not be recreated, the
+                        * process must be terminated.
+                        * For SIE the guest values of guarded storage can not
+                        * be recreated. This is either due to a bug or due to
+                        * GS being disabled in the guest. The guest will be
+                        * notified by KVM code and the guests machine check
+                        * handling must take care of this.  The host values
+                        * are saved by KVM and are not affected.
                         */
-                       kill_task = 1;
+                       if (!test_cpu_flag(CIF_MCCK_GUEST))
+                               kill_task = 1;
                } else {
                        load_gs_cb((struct gs_cb *)mcesa->guarded_storage_save_area);
                }
index 577f1ea..2296b1f 100644 (file)
@@ -4667,6 +4667,8 @@ static long kvm_s390_guest_sida_op(struct kvm_vcpu *vcpu,
                return -EINVAL;
        if (mop->size + mop->sida_offset > sida_size(vcpu->arch.sie_block))
                return -E2BIG;
+       if (!kvm_s390_pv_cpu_is_protected(vcpu))
+               return -EINVAL;
 
        switch (mop->op) {
        case KVM_S390_MEMOP_SIDA_READ:
index 707cd46..69feb8e 100644 (file)
@@ -17,4 +17,7 @@ KASAN_SANITIZE_uaccess.o := n
 obj-$(CONFIG_S390_UNWIND_SELFTEST) += test_unwind.o
 CFLAGS_test_unwind.o += -fno-optimize-sibling-calls
 
+obj-$(CONFIG_S390_MODULES_SANITY_TEST) += test_modules.o
+obj-$(CONFIG_S390_MODULES_SANITY_TEST_HELPERS) += test_modules_helpers.o
+
 lib-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
diff --git a/arch/s390/lib/test_modules.c b/arch/s390/lib/test_modules.c
new file mode 100644 (file)
index 0000000..9894009
--- /dev/null
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <kunit/test.h>
+#include <linux/module.h>
+
+#include "test_modules.h"
+
+/*
+ * Test that modules with many relocations are loaded properly.
+ */
+static void test_modules_many_vmlinux_relocs(struct kunit *test)
+{
+       int result = 0;
+
+#define CALL_RETURN(i) result += test_modules_return_ ## i()
+       REPEAT_10000(CALL_RETURN);
+       KUNIT_ASSERT_EQ(test, result, 49995000);
+}
+
+static struct kunit_case modules_testcases[] = {
+       KUNIT_CASE(test_modules_many_vmlinux_relocs),
+       {}
+};
+
+static struct kunit_suite modules_test_suite = {
+       .name = "modules_test_s390",
+       .test_cases = modules_testcases,
+};
+
+kunit_test_suites(&modules_test_suite);
+
+MODULE_LICENSE("GPL");
diff --git a/arch/s390/lib/test_modules.h b/arch/s390/lib/test_modules.h
new file mode 100644 (file)
index 0000000..6371fcf
--- /dev/null
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#ifndef TEST_MODULES_H
+#define TEST_MODULES_H
+
+#define __REPEAT_10000_3(f, x) \
+       f(x ## 0); \
+       f(x ## 1); \
+       f(x ## 2); \
+       f(x ## 3); \
+       f(x ## 4); \
+       f(x ## 5); \
+       f(x ## 6); \
+       f(x ## 7); \
+       f(x ## 8); \
+       f(x ## 9)
+#define __REPEAT_10000_2(f, x) \
+       __REPEAT_10000_3(f, x ## 0); \
+       __REPEAT_10000_3(f, x ## 1); \
+       __REPEAT_10000_3(f, x ## 2); \
+       __REPEAT_10000_3(f, x ## 3); \
+       __REPEAT_10000_3(f, x ## 4); \
+       __REPEAT_10000_3(f, x ## 5); \
+       __REPEAT_10000_3(f, x ## 6); \
+       __REPEAT_10000_3(f, x ## 7); \
+       __REPEAT_10000_3(f, x ## 8); \
+       __REPEAT_10000_3(f, x ## 9)
+#define __REPEAT_10000_1(f, x) \
+       __REPEAT_10000_2(f, x ## 0); \
+       __REPEAT_10000_2(f, x ## 1); \
+       __REPEAT_10000_2(f, x ## 2); \
+       __REPEAT_10000_2(f, x ## 3); \
+       __REPEAT_10000_2(f, x ## 4); \
+       __REPEAT_10000_2(f, x ## 5); \
+       __REPEAT_10000_2(f, x ## 6); \
+       __REPEAT_10000_2(f, x ## 7); \
+       __REPEAT_10000_2(f, x ## 8); \
+       __REPEAT_10000_2(f, x ## 9)
+#define REPEAT_10000(f) \
+       __REPEAT_10000_1(f, 0); \
+       __REPEAT_10000_1(f, 1); \
+       __REPEAT_10000_1(f, 2); \
+       __REPEAT_10000_1(f, 3); \
+       __REPEAT_10000_1(f, 4); \
+       __REPEAT_10000_1(f, 5); \
+       __REPEAT_10000_1(f, 6); \
+       __REPEAT_10000_1(f, 7); \
+       __REPEAT_10000_1(f, 8); \
+       __REPEAT_10000_1(f, 9)
+
+#define DECLARE_RETURN(i) int test_modules_return_ ## i(void)
+REPEAT_10000(DECLARE_RETURN);
+
+#endif
diff --git a/arch/s390/lib/test_modules_helpers.c b/arch/s390/lib/test_modules_helpers.c
new file mode 100644 (file)
index 0000000..1670349
--- /dev/null
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/export.h>
+
+#include "test_modules.h"
+
+#define DEFINE_RETURN(i) \
+       int test_modules_return_ ## i(void) \
+       { \
+               return 1 ## i - 10000; \
+       } \
+       EXPORT_SYMBOL_GPL(test_modules_return_ ## i)
+REPEAT_10000(DEFINE_RETURN);
index ebe8fc7..9f5bd41 100644 (file)
@@ -186,6 +186,7 @@ config X86
        select HAVE_CONTEXT_TRACKING_OFFSTACK   if HAVE_CONTEXT_TRACKING
        select HAVE_C_RECORDMCOUNT
        select HAVE_OBJTOOL_MCOUNT              if STACK_VALIDATION
+       select HAVE_BUILDTIME_MCOUNT_SORT
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DMA_CONTIGUOUS
        select HAVE_DYNAMIC_FTRACE
index f9e2fec..59ae28a 100644 (file)
 static int crypto_blake2s_update_x86(struct shash_desc *desc,
                                     const u8 *in, unsigned int inlen)
 {
-       return crypto_blake2s_update(desc, in, inlen, blake2s_compress);
+       return crypto_blake2s_update(desc, in, inlen, false);
 }
 
 static int crypto_blake2s_final_x86(struct shash_desc *desc, u8 *out)
 {
-       return crypto_blake2s_final(desc, out, blake2s_compress);
+       return crypto_blake2s_final(desc, out, false);
 }
 
 #define BLAKE2S_ALG(name, driver_name, digest_size)                    \
index fd9f908..a3c7ca8 100644 (file)
@@ -4703,6 +4703,19 @@ static __initconst const struct x86_pmu intel_pmu = {
        .lbr_read               = intel_pmu_lbr_read_64,
        .lbr_save               = intel_pmu_lbr_save,
        .lbr_restore            = intel_pmu_lbr_restore,
+
+       /*
+        * SMM has access to all 4 rings and while traditionally SMM code only
+        * ran in CPL0, 2021-era firmware is starting to make use of CPL3 in SMM.
+        *
+        * Since the EVENTSEL.{USR,OS} CPL filtering makes no distinction
+        * between SMM or not, this results in what should be pure userspace
+        * counters including SMM data.
+        *
+        * This is a clear privilege issue, therefore globally disable
+        * counting SMM by default.
+        */
+       .attr_freeze_on_smi     = 1,
 };
 
 static __init void intel_clovertown_quirk(void)
@@ -6236,6 +6249,19 @@ __init int intel_pmu_init(void)
                        pmu->num_counters = x86_pmu.num_counters;
                        pmu->num_counters_fixed = x86_pmu.num_counters_fixed;
                }
+
+               /*
+                * Quirk: For some Alder Lake machine, when all E-cores are disabled in
+                * a BIOS, the leaf 0xA will enumerate all counters of P-cores. However,
+                * the X86_FEATURE_HYBRID_CPU is still set. The above codes will
+                * mistakenly add extra counters for P-cores. Correct the number of
+                * counters here.
+                */
+               if ((pmu->num_counters > 8) || (pmu->num_counters_fixed > 4)) {
+                       pmu->num_counters = x86_pmu.num_counters;
+                       pmu->num_counters_fixed = x86_pmu.num_counters_fixed;
+               }
+
                pmu->max_pebs_events = min_t(unsigned, MAX_PEBS_EVENTS, pmu->num_counters);
                pmu->unconstrained = (struct event_constraint)
                                        __EVENT_CONSTRAINT(0, (1ULL << pmu->num_counters) - 1,
@@ -6340,6 +6366,8 @@ __init int intel_pmu_init(void)
        }
 
        if (x86_pmu.lbr_nr) {
+               intel_pmu_lbr_init();
+
                pr_cont("%d-deep LBR, ", x86_pmu.lbr_nr);
 
                /* only support branch_stack snapshot for perfmon >= v2 */
index 8043213..669c2be 100644 (file)
@@ -8,14 +8,6 @@
 
 #include "../perf_event.h"
 
-static const enum {
-       LBR_EIP_FLAGS           = 1,
-       LBR_TSX                 = 2,
-} lbr_desc[LBR_FORMAT_MAX_KNOWN + 1] = {
-       [LBR_FORMAT_EIP_FLAGS]  = LBR_EIP_FLAGS,
-       [LBR_FORMAT_EIP_FLAGS2] = LBR_EIP_FLAGS | LBR_TSX,
-};
-
 /*
  * Intel LBR_SELECT bits
  * Intel Vol3a, April 2011, Section 16.7 Table 16-10
@@ -243,7 +235,7 @@ void intel_pmu_lbr_reset_64(void)
        for (i = 0; i < x86_pmu.lbr_nr; i++) {
                wrmsrl(x86_pmu.lbr_from + i, 0);
                wrmsrl(x86_pmu.lbr_to   + i, 0);
-               if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
+               if (x86_pmu.lbr_has_info)
                        wrmsrl(x86_pmu.lbr_info + i, 0);
        }
 }
@@ -305,11 +297,10 @@ enum {
  */
 static inline bool lbr_from_signext_quirk_needed(void)
 {
-       int lbr_format = x86_pmu.intel_cap.lbr_format;
        bool tsx_support = boot_cpu_has(X86_FEATURE_HLE) ||
                           boot_cpu_has(X86_FEATURE_RTM);
 
-       return !tsx_support && (lbr_desc[lbr_format] & LBR_TSX);
+       return !tsx_support && x86_pmu.lbr_has_tsx;
 }
 
 static DEFINE_STATIC_KEY_FALSE(lbr_from_quirk_key);
@@ -427,12 +418,12 @@ rdlbr_all(struct lbr_entry *lbr, unsigned int idx, bool need_info)
 
 void intel_pmu_lbr_restore(void *ctx)
 {
-       bool need_info = x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO;
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
        struct x86_perf_task_context *task_ctx = ctx;
-       int i;
-       unsigned lbr_idx, mask;
+       bool need_info = x86_pmu.lbr_has_info;
        u64 tos = task_ctx->tos;
+       unsigned lbr_idx, mask;
+       int i;
 
        mask = x86_pmu.lbr_nr - 1;
        for (i = 0; i < task_ctx->valid_lbrs; i++) {
@@ -444,7 +435,7 @@ void intel_pmu_lbr_restore(void *ctx)
                lbr_idx = (tos - i) & mask;
                wrlbr_from(lbr_idx, 0);
                wrlbr_to(lbr_idx, 0);
-               if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
+               if (need_info)
                        wrlbr_info(lbr_idx, 0);
        }
 
@@ -519,9 +510,9 @@ static void __intel_pmu_lbr_restore(void *ctx)
 
 void intel_pmu_lbr_save(void *ctx)
 {
-       bool need_info = x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO;
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
        struct x86_perf_task_context *task_ctx = ctx;
+       bool need_info = x86_pmu.lbr_has_info;
        unsigned lbr_idx, mask;
        u64 tos;
        int i;
@@ -816,7 +807,6 @@ void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
 {
        bool need_info = false, call_stack = false;
        unsigned long mask = x86_pmu.lbr_nr - 1;
-       int lbr_format = x86_pmu.intel_cap.lbr_format;
        u64 tos = intel_pmu_lbr_tos();
        int i;
        int out = 0;
@@ -831,9 +821,7 @@ void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
        for (i = 0; i < num; i++) {
                unsigned long lbr_idx = (tos - i) & mask;
                u64 from, to, mis = 0, pred = 0, in_tx = 0, abort = 0;
-               int skip = 0;
                u16 cycles = 0;
-               int lbr_flags = lbr_desc[lbr_format];
 
                from = rdlbr_from(lbr_idx, NULL);
                to   = rdlbr_to(lbr_idx, NULL);
@@ -845,37 +833,39 @@ void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
                if (call_stack && !from)
                        break;
 
-               if (lbr_format == LBR_FORMAT_INFO && need_info) {
-                       u64 info;
-
-                       info = rdlbr_info(lbr_idx, NULL);
-                       mis = !!(info & LBR_INFO_MISPRED);
-                       pred = !mis;
-                       in_tx = !!(info & LBR_INFO_IN_TX);
-                       abort = !!(info & LBR_INFO_ABORT);
-                       cycles = (info & LBR_INFO_CYCLES);
-               }
-
-               if (lbr_format == LBR_FORMAT_TIME) {
-                       mis = !!(from & LBR_FROM_FLAG_MISPRED);
-                       pred = !mis;
-                       skip = 1;
-                       cycles = ((to >> 48) & LBR_INFO_CYCLES);
-
-                       to = (u64)((((s64)to) << 16) >> 16);
-               }
-
-               if (lbr_flags & LBR_EIP_FLAGS) {
-                       mis = !!(from & LBR_FROM_FLAG_MISPRED);
-                       pred = !mis;
-                       skip = 1;
-               }
-               if (lbr_flags & LBR_TSX) {
-                       in_tx = !!(from & LBR_FROM_FLAG_IN_TX);
-                       abort = !!(from & LBR_FROM_FLAG_ABORT);
-                       skip = 3;
+               if (x86_pmu.lbr_has_info) {
+                       if (need_info) {
+                               u64 info;
+
+                               info = rdlbr_info(lbr_idx, NULL);
+                               mis = !!(info & LBR_INFO_MISPRED);
+                               pred = !mis;
+                               cycles = (info & LBR_INFO_CYCLES);
+                               if (x86_pmu.lbr_has_tsx) {
+                                       in_tx = !!(info & LBR_INFO_IN_TX);
+                                       abort = !!(info & LBR_INFO_ABORT);
+                               }
+                       }
+               } else {
+                       int skip = 0;
+
+                       if (x86_pmu.lbr_from_flags) {
+                               mis = !!(from & LBR_FROM_FLAG_MISPRED);
+                               pred = !mis;
+                               skip = 1;
+                       }
+                       if (x86_pmu.lbr_has_tsx) {
+                               in_tx = !!(from & LBR_FROM_FLAG_IN_TX);
+                               abort = !!(from & LBR_FROM_FLAG_ABORT);
+                               skip = 3;
+                       }
+                       from = (u64)((((s64)from) << skip) >> skip);
+
+                       if (x86_pmu.lbr_to_cycles) {
+                               cycles = ((to >> 48) & LBR_INFO_CYCLES);
+                               to = (u64)((((s64)to) << 16) >> 16);
+                       }
                }
-               from = (u64)((((s64)from) << skip) >> skip);
 
                /*
                 * Some CPUs report duplicated abort records,
@@ -903,37 +893,40 @@ void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
        cpuc->lbr_stack.hw_idx = tos;
 }
 
+static DEFINE_STATIC_KEY_FALSE(x86_lbr_mispred);
+static DEFINE_STATIC_KEY_FALSE(x86_lbr_cycles);
+static DEFINE_STATIC_KEY_FALSE(x86_lbr_type);
+
 static __always_inline int get_lbr_br_type(u64 info)
 {
-       if (!static_cpu_has(X86_FEATURE_ARCH_LBR) || !x86_pmu.lbr_br_type)
-               return 0;
+       int type = 0;
 
-       return (info & LBR_INFO_BR_TYPE) >> LBR_INFO_BR_TYPE_OFFSET;
+       if (static_branch_likely(&x86_lbr_type))
+               type = (info & LBR_INFO_BR_TYPE) >> LBR_INFO_BR_TYPE_OFFSET;
+
+       return type;
 }
 
 static __always_inline bool get_lbr_mispred(u64 info)
 {
-       if (static_cpu_has(X86_FEATURE_ARCH_LBR) && !x86_pmu.lbr_mispred)
-               return 0;
+       bool mispred = 0;
 
-       return !!(info & LBR_INFO_MISPRED);
-}
+       if (static_branch_likely(&x86_lbr_mispred))
+               mispred = !!(info & LBR_INFO_MISPRED);
 
-static __always_inline bool get_lbr_predicted(u64 info)
-{
-       if (static_cpu_has(X86_FEATURE_ARCH_LBR) && !x86_pmu.lbr_mispred)
-               return 0;
-
-       return !(info & LBR_INFO_MISPRED);
+       return mispred;
 }
 
 static __always_inline u16 get_lbr_cycles(u64 info)
 {
+       u16 cycles = info & LBR_INFO_CYCLES;
+
        if (static_cpu_has(X86_FEATURE_ARCH_LBR) &&
-           !(x86_pmu.lbr_timed_lbr && info & LBR_INFO_CYC_CNT_VALID))
-               return 0;
+           (!static_branch_likely(&x86_lbr_cycles) ||
+            !(info & LBR_INFO_CYC_CNT_VALID)))
+               cycles = 0;
 
-       return info & LBR_INFO_CYCLES;
+       return cycles;
 }
 
 static void intel_pmu_store_lbr(struct cpu_hw_events *cpuc,
@@ -961,7 +954,7 @@ static void intel_pmu_store_lbr(struct cpu_hw_events *cpuc,
                e->from         = from;
                e->to           = to;
                e->mispred      = get_lbr_mispred(info);
-               e->predicted    = get_lbr_predicted(info);
+               e->predicted    = !e->mispred;
                e->in_tx        = !!(info & LBR_INFO_IN_TX);
                e->abort        = !!(info & LBR_INFO_ABORT);
                e->cycles       = get_lbr_cycles(info);
@@ -1120,7 +1113,7 @@ static int intel_pmu_setup_hw_lbr_filter(struct perf_event *event)
 
        if ((br_type & PERF_SAMPLE_BRANCH_NO_CYCLES) &&
            (br_type & PERF_SAMPLE_BRANCH_NO_FLAGS) &&
-           (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO))
+           x86_pmu.lbr_has_info)
                reg->config |= LBR_NO_INFO;
 
        return 0;
@@ -1706,6 +1699,38 @@ void intel_pmu_lbr_init_knl(void)
                x86_pmu.intel_cap.lbr_format = LBR_FORMAT_EIP_FLAGS;
 }
 
+void intel_pmu_lbr_init(void)
+{
+       switch (x86_pmu.intel_cap.lbr_format) {
+       case LBR_FORMAT_EIP_FLAGS2:
+               x86_pmu.lbr_has_tsx = 1;
+               fallthrough;
+       case LBR_FORMAT_EIP_FLAGS:
+               x86_pmu.lbr_from_flags = 1;
+               break;
+
+       case LBR_FORMAT_INFO:
+               x86_pmu.lbr_has_tsx = 1;
+               fallthrough;
+       case LBR_FORMAT_INFO2:
+               x86_pmu.lbr_has_info = 1;
+               break;
+
+       case LBR_FORMAT_TIME:
+               x86_pmu.lbr_from_flags = 1;
+               x86_pmu.lbr_to_cycles = 1;
+               break;
+       }
+
+       if (x86_pmu.lbr_has_info) {
+               /*
+                * Only used in combination with baseline pebs.
+                */
+               static_branch_enable(&x86_lbr_mispred);
+               static_branch_enable(&x86_lbr_cycles);
+       }
+}
+
 /*
  * LBR state size is variable based on the max number of registers.
  * This calculates the expected state size, which should match
@@ -1726,6 +1751,9 @@ static bool is_arch_lbr_xsave_available(void)
         * Check the LBR state with the corresponding software structure.
         * Disable LBR XSAVES support if the size doesn't match.
         */
+       if (xfeature_size(XFEATURE_LBR) == 0)
+               return false;
+
        if (WARN_ON(xfeature_size(XFEATURE_LBR) != get_lbr_state_size()))
                return false;
 
@@ -1765,6 +1793,12 @@ void __init intel_pmu_arch_lbr_init(void)
        x86_pmu.lbr_br_type = ecx.split.lbr_br_type;
        x86_pmu.lbr_nr = lbr_nr;
 
+       if (x86_pmu.lbr_mispred)
+               static_branch_enable(&x86_lbr_mispred);
+       if (x86_pmu.lbr_timed_lbr)
+               static_branch_enable(&x86_lbr_cycles);
+       if (x86_pmu.lbr_br_type)
+               static_branch_enable(&x86_lbr_type);
 
        arch_lbr_xsave = is_arch_lbr_xsave_available();
        if (arch_lbr_xsave) {
index 7f406c1..2d33bba 100644 (file)
@@ -897,8 +897,9 @@ static void pt_handle_status(struct pt *pt)
                 * means we are already losing data; need to let the decoder
                 * know.
                 */
-               if (!intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries) ||
-                   buf->output_off == pt_buffer_region_size(buf)) {
+               if (!buf->single &&
+                   (!intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries) ||
+                    buf->output_off == pt_buffer_region_size(buf))) {
                        perf_aux_output_flag(&pt->handle,
                                             PERF_AUX_FLAG_TRUNCATED);
                        advance++;
index f1ba6ab..e497da9 100644 (file)
@@ -1762,7 +1762,7 @@ static const struct intel_uncore_init_fun rkl_uncore_init __initconst = {
 
 static const struct intel_uncore_init_fun adl_uncore_init __initconst = {
        .cpu_init = adl_uncore_cpu_init,
-       .mmio_init = tgl_uncore_mmio_init,
+       .mmio_init = adl_uncore_mmio_init,
 };
 
 static const struct intel_uncore_init_fun icx_uncore_init __initconst = {
index b968798..2adeaf4 100644 (file)
@@ -584,10 +584,11 @@ void snb_uncore_cpu_init(void);
 void nhm_uncore_cpu_init(void);
 void skl_uncore_cpu_init(void);
 void icl_uncore_cpu_init(void);
-void adl_uncore_cpu_init(void);
 void tgl_uncore_cpu_init(void);
+void adl_uncore_cpu_init(void);
 void tgl_uncore_mmio_init(void);
 void tgl_l_uncore_mmio_init(void);
+void adl_uncore_mmio_init(void);
 int snb_pci2phy_map_init(int devid);
 
 /* uncore_snbep.c */
index 3049c64..6ddadb4 100644 (file)
@@ -494,8 +494,8 @@ void intel_generic_uncore_mmio_enable_box(struct intel_uncore_box *box)
        writel(0, box->io_addr);
 }
 
-static void intel_generic_uncore_mmio_enable_event(struct intel_uncore_box *box,
-                                            struct perf_event *event)
+void intel_generic_uncore_mmio_enable_event(struct intel_uncore_box *box,
+                                           struct perf_event *event)
 {
        struct hw_perf_event *hwc = &event->hw;
 
index 6d73561..cfaf558 100644 (file)
@@ -139,6 +139,8 @@ void intel_generic_uncore_mmio_disable_box(struct intel_uncore_box *box);
 void intel_generic_uncore_mmio_enable_box(struct intel_uncore_box *box);
 void intel_generic_uncore_mmio_disable_event(struct intel_uncore_box *box,
                                             struct perf_event *event);
+void intel_generic_uncore_mmio_enable_event(struct intel_uncore_box *box,
+                                           struct perf_event *event);
 
 void intel_generic_uncore_pci_init_box(struct intel_uncore_box *box);
 void intel_generic_uncore_pci_disable_box(struct intel_uncore_box *box);
index 0f63706..f698a55 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Nehalem/SandBridge/Haswell/Broadwell/Skylake uncore support */
 #include "uncore.h"
+#include "uncore_discovery.h"
 
 /* Uncore IMC PCI IDs */
 #define PCI_DEVICE_ID_INTEL_SNB_IMC            0x0100
 #define PCI_DEVICE_ID_INTEL_RKL_2_IMC          0x4c53
 #define PCI_DEVICE_ID_INTEL_ADL_1_IMC          0x4660
 #define PCI_DEVICE_ID_INTEL_ADL_2_IMC          0x4641
+#define PCI_DEVICE_ID_INTEL_ADL_3_IMC          0x4601
+#define PCI_DEVICE_ID_INTEL_ADL_4_IMC          0x4602
+#define PCI_DEVICE_ID_INTEL_ADL_5_IMC          0x4609
+#define PCI_DEVICE_ID_INTEL_ADL_6_IMC          0x460a
+#define PCI_DEVICE_ID_INTEL_ADL_7_IMC          0x4621
+#define PCI_DEVICE_ID_INTEL_ADL_8_IMC          0x4623
+#define PCI_DEVICE_ID_INTEL_ADL_9_IMC          0x4629
+#define PCI_DEVICE_ID_INTEL_ADL_10_IMC         0x4637
+#define PCI_DEVICE_ID_INTEL_ADL_11_IMC         0x463b
+#define PCI_DEVICE_ID_INTEL_ADL_12_IMC         0x4648
+#define PCI_DEVICE_ID_INTEL_ADL_13_IMC         0x4649
+#define PCI_DEVICE_ID_INTEL_ADL_14_IMC         0x4650
+#define PCI_DEVICE_ID_INTEL_ADL_15_IMC         0x4668
+#define PCI_DEVICE_ID_INTEL_ADL_16_IMC         0x4670
 
 /* SNB event control */
 #define SNB_UNC_CTL_EV_SEL_MASK                        0x000000ff
 
 DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
 DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(chmask, chmask, "config:8-11");
 DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
 DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23");
 DEFINE_UNCORE_FORMAT_ATTR(cmask5, cmask, "config:24-28");
@@ -1334,6 +1350,62 @@ static const struct pci_device_id tgl_uncore_pci_ids[] = {
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_2_IMC),
                .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
        },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_3_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_4_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_5_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_6_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_7_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_8_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_9_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_10_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_11_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_12_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_13_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_14_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_15_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ADL_16_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
        { /* end: all zeroes */ }
 };
 
@@ -1390,7 +1462,8 @@ static struct pci_dev *tgl_uncore_get_mc_dev(void)
 #define TGL_UNCORE_MMIO_IMC_MEM_OFFSET         0x10000
 #define TGL_UNCORE_PCI_IMC_MAP_SIZE            0xe000
 
-static void tgl_uncore_imc_freerunning_init_box(struct intel_uncore_box *box)
+static void __uncore_imc_init_box(struct intel_uncore_box *box,
+                                 unsigned int base_offset)
 {
        struct pci_dev *pdev = tgl_uncore_get_mc_dev();
        struct intel_uncore_pmu *pmu = box->pmu;
@@ -1417,11 +1490,17 @@ static void tgl_uncore_imc_freerunning_init_box(struct intel_uncore_box *box)
        addr |= ((resource_size_t)mch_bar << 32);
 #endif
 
+       addr += base_offset;
        box->io_addr = ioremap(addr, type->mmio_map_size);
        if (!box->io_addr)
                pr_warn("perf uncore: Failed to ioremap for %s.\n", type->name);
 }
 
+static void tgl_uncore_imc_freerunning_init_box(struct intel_uncore_box *box)
+{
+       __uncore_imc_init_box(box, 0);
+}
+
 static struct intel_uncore_ops tgl_uncore_imc_freerunning_ops = {
        .init_box       = tgl_uncore_imc_freerunning_init_box,
        .exit_box       = uncore_mmio_exit_box,
@@ -1469,3 +1548,136 @@ void tgl_uncore_mmio_init(void)
 }
 
 /* end of Tiger Lake MMIO uncore support */
+
+/* Alder Lake MMIO uncore support */
+#define ADL_UNCORE_IMC_BASE                    0xd900
+#define ADL_UNCORE_IMC_MAP_SIZE                        0x200
+#define ADL_UNCORE_IMC_CTR                     0xe8
+#define ADL_UNCORE_IMC_CTRL                    0xd0
+#define ADL_UNCORE_IMC_GLOBAL_CTL              0xc0
+#define ADL_UNCORE_IMC_BOX_CTL                 0xc4
+#define ADL_UNCORE_IMC_FREERUNNING_BASE                0xd800
+#define ADL_UNCORE_IMC_FREERUNNING_MAP_SIZE    0x100
+
+#define ADL_UNCORE_IMC_CTL_FRZ                 (1 << 0)
+#define ADL_UNCORE_IMC_CTL_RST_CTRL            (1 << 1)
+#define ADL_UNCORE_IMC_CTL_RST_CTRS            (1 << 2)
+#define ADL_UNCORE_IMC_CTL_INT                 (ADL_UNCORE_IMC_CTL_RST_CTRL | \
+                                               ADL_UNCORE_IMC_CTL_RST_CTRS)
+
+static void adl_uncore_imc_init_box(struct intel_uncore_box *box)
+{
+       __uncore_imc_init_box(box, ADL_UNCORE_IMC_BASE);
+
+       /* The global control in MC1 can control both MCs. */
+       if (box->io_addr && (box->pmu->pmu_idx == 1))
+               writel(ADL_UNCORE_IMC_CTL_INT, box->io_addr + ADL_UNCORE_IMC_GLOBAL_CTL);
+}
+
+static void adl_uncore_mmio_disable_box(struct intel_uncore_box *box)
+{
+       if (!box->io_addr)
+               return;
+
+       writel(ADL_UNCORE_IMC_CTL_FRZ, box->io_addr + uncore_mmio_box_ctl(box));
+}
+
+static void adl_uncore_mmio_enable_box(struct intel_uncore_box *box)
+{
+       if (!box->io_addr)
+               return;
+
+       writel(0, box->io_addr + uncore_mmio_box_ctl(box));
+}
+
+static struct intel_uncore_ops adl_uncore_mmio_ops = {
+       .init_box       = adl_uncore_imc_init_box,
+       .exit_box       = uncore_mmio_exit_box,
+       .disable_box    = adl_uncore_mmio_disable_box,
+       .enable_box     = adl_uncore_mmio_enable_box,
+       .disable_event  = intel_generic_uncore_mmio_disable_event,
+       .enable_event   = intel_generic_uncore_mmio_enable_event,
+       .read_counter   = uncore_mmio_read_counter,
+};
+
+#define ADL_UNC_CTL_CHMASK_MASK                        0x00000f00
+#define ADL_UNC_IMC_EVENT_MASK                 (SNB_UNC_CTL_EV_SEL_MASK | \
+                                                ADL_UNC_CTL_CHMASK_MASK | \
+                                                SNB_UNC_CTL_EDGE_DET)
+
+static struct attribute *adl_uncore_imc_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_chmask.attr,
+       &format_attr_edge.attr,
+       NULL,
+};
+
+static const struct attribute_group adl_uncore_imc_format_group = {
+       .name           = "format",
+       .attrs          = adl_uncore_imc_formats_attr,
+};
+
+static struct intel_uncore_type adl_uncore_imc = {
+       .name           = "imc",
+       .num_counters   = 5,
+       .num_boxes      = 2,
+       .perf_ctr_bits  = 64,
+       .perf_ctr       = ADL_UNCORE_IMC_CTR,
+       .event_ctl      = ADL_UNCORE_IMC_CTRL,
+       .event_mask     = ADL_UNC_IMC_EVENT_MASK,
+       .box_ctl        = ADL_UNCORE_IMC_BOX_CTL,
+       .mmio_offset    = 0,
+       .mmio_map_size  = ADL_UNCORE_IMC_MAP_SIZE,
+       .ops            = &adl_uncore_mmio_ops,
+       .format_group   = &adl_uncore_imc_format_group,
+};
+
+enum perf_adl_uncore_imc_freerunning_types {
+       ADL_MMIO_UNCORE_IMC_DATA_TOTAL,
+       ADL_MMIO_UNCORE_IMC_DATA_READ,
+       ADL_MMIO_UNCORE_IMC_DATA_WRITE,
+       ADL_MMIO_UNCORE_IMC_FREERUNNING_TYPE_MAX
+};
+
+static struct freerunning_counters adl_uncore_imc_freerunning[] = {
+       [ADL_MMIO_UNCORE_IMC_DATA_TOTAL]        = { 0x40, 0x0, 0x0, 1, 64 },
+       [ADL_MMIO_UNCORE_IMC_DATA_READ]         = { 0x58, 0x0, 0x0, 1, 64 },
+       [ADL_MMIO_UNCORE_IMC_DATA_WRITE]        = { 0xA0, 0x0, 0x0, 1, 64 },
+};
+
+static void adl_uncore_imc_freerunning_init_box(struct intel_uncore_box *box)
+{
+       __uncore_imc_init_box(box, ADL_UNCORE_IMC_FREERUNNING_BASE);
+}
+
+static struct intel_uncore_ops adl_uncore_imc_freerunning_ops = {
+       .init_box       = adl_uncore_imc_freerunning_init_box,
+       .exit_box       = uncore_mmio_exit_box,
+       .read_counter   = uncore_mmio_read_counter,
+       .hw_config      = uncore_freerunning_hw_config,
+};
+
+static struct intel_uncore_type adl_uncore_imc_free_running = {
+       .name                   = "imc_free_running",
+       .num_counters           = 3,
+       .num_boxes              = 2,
+       .num_freerunning_types  = ADL_MMIO_UNCORE_IMC_FREERUNNING_TYPE_MAX,
+       .mmio_map_size          = ADL_UNCORE_IMC_FREERUNNING_MAP_SIZE,
+       .freerunning            = adl_uncore_imc_freerunning,
+       .ops                    = &adl_uncore_imc_freerunning_ops,
+       .event_descs            = tgl_uncore_imc_events,
+       .format_group           = &tgl_uncore_imc_format_group,
+};
+
+static struct intel_uncore_type *adl_mmio_uncores[] = {
+       &adl_uncore_imc,
+       &adl_uncore_imc_free_running,
+       NULL
+};
+
+void adl_uncore_mmio_init(void)
+{
+       uncore_mmio_uncores = adl_mmio_uncores;
+}
+
+/* end of Alder Lake MMIO uncore support */
index 3660f69..ed86944 100644 (file)
@@ -5482,7 +5482,7 @@ static struct intel_uncore_type icx_uncore_imc = {
        .fixed_ctr_bits = 48,
        .fixed_ctr      = SNR_IMC_MMIO_PMON_FIXED_CTR,
        .fixed_ctl      = SNR_IMC_MMIO_PMON_FIXED_CTL,
-       .event_descs    = hswep_uncore_imc_events,
+       .event_descs    = snr_uncore_imc_events,
        .perf_ctr       = SNR_IMC_MMIO_PMON_CTR0,
        .event_ctl      = SNR_IMC_MMIO_PMON_CTL0,
        .event_mask     = SNBEP_PMON_RAW_EVENT_MASK,
index 9d376e5..150261d 100644 (file)
@@ -215,7 +215,8 @@ enum {
        LBR_FORMAT_EIP_FLAGS2   = 0x04,
        LBR_FORMAT_INFO         = 0x05,
        LBR_FORMAT_TIME         = 0x06,
-       LBR_FORMAT_MAX_KNOWN    = LBR_FORMAT_TIME,
+       LBR_FORMAT_INFO2        = 0x07,
+       LBR_FORMAT_MAX_KNOWN    = LBR_FORMAT_INFO2,
 };
 
 enum {
@@ -840,6 +841,11 @@ struct x86_pmu {
        bool            lbr_double_abort;          /* duplicated lbr aborts */
        bool            lbr_pt_coexist;            /* (LBR|BTS) may coexist with PT */
 
+       unsigned int    lbr_has_info:1;
+       unsigned int    lbr_has_tsx:1;
+       unsigned int    lbr_from_flags:1;
+       unsigned int    lbr_to_cycles:1;
+
        /*
         * Intel Architectural LBR CPUID Enumeration
         */
@@ -1392,6 +1398,8 @@ void intel_pmu_lbr_init_skl(void);
 
 void intel_pmu_lbr_init_knl(void);
 
+void intel_pmu_lbr_init(void);
+
 void intel_pmu_arch_lbr_init(void);
 
 void intel_pmu_pebs_data_source_nhm(void);
index 85feafa..77e3a47 100644 (file)
@@ -536,11 +536,14 @@ static struct perf_msr intel_rapl_spr_msrs[] = {
  * - perf_msr_probe(PERF_RAPL_MAX)
  * - want to use same event codes across both architectures
  */
-static struct perf_msr amd_rapl_msrs[PERF_RAPL_MAX] = {
-       [PERF_RAPL_PKG]  = { MSR_AMD_PKG_ENERGY_STATUS,  &rapl_events_pkg_group,   test_msr },
+static struct perf_msr amd_rapl_msrs[] = {
+       [PERF_RAPL_PP0]  = { 0, &rapl_events_cores_group, 0, false, 0 },
+       [PERF_RAPL_PKG]  = { MSR_AMD_PKG_ENERGY_STATUS,  &rapl_events_pkg_group,   test_msr, false, RAPL_MSR_MASK },
+       [PERF_RAPL_RAM]  = { 0, &rapl_events_ram_group,   0, false, 0 },
+       [PERF_RAPL_PP1]  = { 0, &rapl_events_gpu_group,   0, false, 0 },
+       [PERF_RAPL_PSYS] = { 0, &rapl_events_psys_group,  0, false, 0 },
 };
 
-
 static int rapl_cpu_offline(unsigned int cpu)
 {
        struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
index 84b8753..bab883c 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 
-#define _BUG_FLAGS(ins, flags)                                         \
+#define _BUG_FLAGS(ins, flags, extra)                                  \
 do {                                                                   \
        asm_inline volatile("1:\t" ins "\n"                             \
                     ".pushsection __bug_table,\"aw\"\n"                \
@@ -31,7 +31,8 @@ do {                                                                  \
                     "\t.word %c1"        "\t# bug_entry::line\n"       \
                     "\t.word %c2"        "\t# bug_entry::flags\n"      \
                     "\t.org 2b+%c3\n"                                  \
-                    ".popsection"                                      \
+                    ".popsection\n"                                    \
+                    extra                                              \
                     : : "i" (__FILE__), "i" (__LINE__),                \
                         "i" (flags),                                   \
                         "i" (sizeof(struct bug_entry)));               \
@@ -39,14 +40,15 @@ do {                                                                        \
 
 #else /* !CONFIG_DEBUG_BUGVERBOSE */
 
-#define _BUG_FLAGS(ins, flags)                                         \
+#define _BUG_FLAGS(ins, flags, extra)                                  \
 do {                                                                   \
        asm_inline volatile("1:\t" ins "\n"                             \
                     ".pushsection __bug_table,\"aw\"\n"                \
                     "2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n"   \
                     "\t.word %c0"        "\t# bug_entry::flags\n"      \
                     "\t.org 2b+%c1\n"                                  \
-                    ".popsection"                                      \
+                    ".popsection\n"                                    \
+                    extra                                              \
                     : : "i" (flags),                                   \
                         "i" (sizeof(struct bug_entry)));               \
 } while (0)
@@ -55,7 +57,7 @@ do {                                                                  \
 
 #else
 
-#define _BUG_FLAGS(ins, flags)  asm volatile(ins)
+#define _BUG_FLAGS(ins, flags, extra)  asm volatile(ins)
 
 #endif /* CONFIG_GENERIC_BUG */
 
@@ -63,8 +65,8 @@ do {                                                                  \
 #define BUG()                                                  \
 do {                                                           \
        instrumentation_begin();                                \
-       _BUG_FLAGS(ASM_UD2, 0);                                 \
-       unreachable();                                          \
+       _BUG_FLAGS(ASM_UD2, 0, "");                             \
+       __builtin_unreachable();                                \
 } while (0)
 
 /*
@@ -75,9 +77,9 @@ do {                                                          \
  */
 #define __WARN_FLAGS(flags)                                    \
 do {                                                           \
+       __auto_type f = BUGFLAG_WARNING|(flags);                \
        instrumentation_begin();                                \
-       _BUG_FLAGS(ASM_UD2, BUGFLAG_WARNING|(flags));           \
-       annotate_reachable();                                   \
+       _BUG_FLAGS(ASM_UD2, f, ASM_REACHABLE);                  \
        instrumentation_end();                                  \
 } while (0)
 
index 631d504..d39e0de 100644 (file)
@@ -82,7 +82,7 @@ KVM_X86_OP_NULL(guest_apic_has_interrupt)
 KVM_X86_OP(load_eoi_exitmap)
 KVM_X86_OP(set_virtual_apic_mode)
 KVM_X86_OP_NULL(set_apic_access_page_addr)
-KVM_X86_OP(deliver_posted_interrupt)
+KVM_X86_OP(deliver_interrupt)
 KVM_X86_OP_NULL(sync_pir_to_irr)
 KVM_X86_OP(set_tss_addr)
 KVM_X86_OP(set_identity_map_addr)
index 1384517..ec9830d 100644 (file)
@@ -703,7 +703,6 @@ struct kvm_vcpu_arch {
        struct fpu_guest guest_fpu;
 
        u64 xcr0;
-       u64 guest_supported_xcr0;
 
        struct kvm_pio_request pio;
        void *pio_data;
@@ -1410,7 +1409,8 @@ struct kvm_x86_ops {
        void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
        void (*set_virtual_apic_mode)(struct kvm_vcpu *vcpu);
        void (*set_apic_access_page_addr)(struct kvm_vcpu *vcpu);
-       int (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, int vector);
+       void (*deliver_interrupt)(struct kvm_lapic *apic, int delivery_mode,
+                                 int trig_mode, int vector);
        int (*sync_pir_to_irr)(struct kvm_vcpu *vcpu);
        int (*set_tss_addr)(struct kvm *kvm, unsigned int addr);
        int (*set_identity_map_addr)(struct kvm *kvm, u64 ident_addr);
@@ -1483,7 +1483,8 @@ struct kvm_x86_ops {
 
        int (*get_msr_feature)(struct kvm_msr_entry *entry);
 
-       bool (*can_emulate_instruction)(struct kvm_vcpu *vcpu, void *insn, int insn_len);
+       bool (*can_emulate_instruction)(struct kvm_vcpu *vcpu, int emul_type,
+                                       void *insn, int insn_len);
 
        bool (*apic_init_signal_blocked)(struct kvm_vcpu *vcpu);
        int (*enable_direct_tlbflush)(struct kvm_vcpu *vcpu);
@@ -1496,6 +1497,7 @@ struct kvm_x86_ops {
 };
 
 struct kvm_x86_nested_ops {
+       void (*leave_nested)(struct kvm_vcpu *vcpu);
        int (*check_events)(struct kvm_vcpu *vcpu);
        bool (*hv_timer_pending)(struct kvm_vcpu *vcpu);
        void (*triple_fault)(struct kvm_vcpu *vcpu);
@@ -1861,7 +1863,6 @@ int kvm_cpu_has_extint(struct kvm_vcpu *v);
 int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu);
 int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
 void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event);
-void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu);
 
 int kvm_pv_send_ipi(struct kvm *kvm, unsigned long ipi_bitmap_low,
                    unsigned long ipi_bitmap_high, u32 min,
index 3faf0f9..a4a39c3 100644 (file)
 #define MSR_AMD64_ICIBSEXTDCTL         0xc001103c
 #define MSR_AMD64_IBSOPDATA4           0xc001103d
 #define MSR_AMD64_IBS_REG_COUNT_MAX    8 /* includes MSR_AMD64_IBSBRTARGET */
+#define MSR_AMD64_SVM_AVIC_DOORBELL    0xc001011b
 #define MSR_AMD64_VM_PAGE_FLUSH                0xc001011e
 #define MSR_AMD64_SEV_ES_GHCB          0xc0010130
 #define MSR_AMD64_SEV                  0xc0010131
index b00dbc5..bb2fb78 100644 (file)
@@ -220,6 +220,42 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
 #define SVM_NESTED_CTL_SEV_ENABLE      BIT(1)
 #define SVM_NESTED_CTL_SEV_ES_ENABLE   BIT(2)
 
+
+/* AVIC */
+#define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK   (0xFF)
+#define AVIC_LOGICAL_ID_ENTRY_VALID_BIT                        31
+#define AVIC_LOGICAL_ID_ENTRY_VALID_MASK               (1 << 31)
+
+#define AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK   (0xFFULL)
+#define AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK       (0xFFFFFFFFFFULL << 12)
+#define AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK         (1ULL << 62)
+#define AVIC_PHYSICAL_ID_ENTRY_VALID_MASK              (1ULL << 63)
+#define AVIC_PHYSICAL_ID_TABLE_SIZE_MASK               (0xFF)
+
+#define AVIC_DOORBELL_PHYSICAL_ID_MASK                 (0xFF)
+
+#define AVIC_UNACCEL_ACCESS_WRITE_MASK         1
+#define AVIC_UNACCEL_ACCESS_OFFSET_MASK                0xFF0
+#define AVIC_UNACCEL_ACCESS_VECTOR_MASK                0xFFFFFFFF
+
+enum avic_ipi_failure_cause {
+       AVIC_IPI_FAILURE_INVALID_INT_TYPE,
+       AVIC_IPI_FAILURE_TARGET_NOT_RUNNING,
+       AVIC_IPI_FAILURE_INVALID_TARGET,
+       AVIC_IPI_FAILURE_INVALID_BACKING_PAGE,
+};
+
+
+/*
+ * 0xff is broadcast, so the max index allowed for physical APIC ID
+ * table is 0xfe.  APIC IDs above 0xff are reserved.
+ */
+#define AVIC_MAX_PHYSICAL_ID_COUNT     0xff
+
+#define AVIC_HPA_MASK  ~((0xFFFULL << 52) | 0xFFF)
+#define VMCB_AVIC_APIC_BAR_MASK                0xFFFFFFFFFF000ULL
+
+
 struct vmcb_seg {
        u16 selector;
        u16 attrib;
index a963010..78e667a 100644 (file)
 /* Memory mapped from other domains has valid IOMMU entries */
 #define XEN_HVM_CPUID_IOMMU_MAPPINGS   (1u << 2)
 #define XEN_HVM_CPUID_VCPU_ID_PRESENT  (1u << 3) /* vcpu id is present in EBX */
+#define XEN_HVM_CPUID_DOMID_PRESENT    (1u << 4) /* domid is present in ECX */
+/*
+ * Bits 55:49 from the IO-APIC RTE and bits 11:5 from the MSI address can be
+ * used to store high bits for the Destination ID. This expands the Destination
+ * ID field from 8 to 15 bits, allowing to target APIC IDs up 32768.
+ */
+#define XEN_HVM_CPUID_EXT_DEST_ID      (1u << 5)
 
 /*
  * Leaf 6 (0x40000x05)
index 1bf2ad3..16f548a 100644 (file)
@@ -43,20 +43,6 @@ static inline uint32_t xen_cpuid_base(void)
        return hypervisor_cpuid_base("XenVMMXenVMM", 2);
 }
 
-#ifdef CONFIG_XEN
-extern bool __init xen_hvm_need_lapic(void);
-
-static inline bool __init xen_x2apic_para_available(void)
-{
-       return xen_hvm_need_lapic();
-}
-#else
-static inline bool __init xen_x2apic_para_available(void)
-{
-       return (xen_cpuid_base() != 0);
-}
-#endif
-
 struct pci_dev;
 
 #ifdef CONFIG_XEN_PV_DOM0
index 2da3316..bf6e960 100644 (file)
@@ -452,6 +452,9 @@ struct kvm_sync_regs {
 
 #define KVM_STATE_VMX_PREEMPTION_TIMER_DEADLINE        0x00000001
 
+/* attributes for system fd (group 0) */
+#define KVM_X86_XCOMP_GUEST_SUPP       0
+
 struct kvm_vmx_nested_state_data {
        __u8 vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
        __u8 shadow_vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
index a1e2f41..9f4b508 100644 (file)
@@ -423,7 +423,7 @@ static void threshold_restart_bank(void *_tr)
        u32 hi, lo;
 
        /* sysfs write might race against an offline operation */
-       if (this_cpu_read(threshold_banks))
+       if (!this_cpu_read(threshold_banks) && !tr->set_lvt_off)
                return;
 
        rdmsr(tr->b->address, lo, hi);
index bb9a46a..baafbb3 100644 (file)
@@ -486,6 +486,7 @@ static void intel_ppin_init(struct cpuinfo_x86 *c)
        case INTEL_FAM6_BROADWELL_X:
        case INTEL_FAM6_SKYLAKE_X:
        case INTEL_FAM6_ICELAKE_X:
+       case INTEL_FAM6_ICELAKE_D:
        case INTEL_FAM6_SAPPHIRERAPIDS_X:
        case INTEL_FAM6_XEON_PHI_KNL:
        case INTEL_FAM6_XEON_PHI_KNM:
index 001808e..48afe96 100644 (file)
@@ -410,6 +410,8 @@ void sgx_encl_release(struct kref *ref)
                }
 
                kfree(entry);
+               /* Invoke scheduler to prevent soft lockups. */
+               cond_resched();
        }
 
        xa_destroy(&encl->page_array);
index 4b41efc..8e4bc64 100644 (file)
@@ -344,10 +344,8 @@ static void sgx_reclaim_pages(void)
 {
        struct sgx_epc_page *chunk[SGX_NR_TO_SCAN];
        struct sgx_backing backing[SGX_NR_TO_SCAN];
-       struct sgx_epc_section *section;
        struct sgx_encl_page *encl_page;
        struct sgx_epc_page *epc_page;
-       struct sgx_numa_node *node;
        pgoff_t page_index;
        int cnt = 0;
        int ret;
@@ -418,13 +416,7 @@ skip:
                kref_put(&encl_page->encl->refcount, sgx_encl_release);
                epc_page->flags &= ~SGX_EPC_PAGE_RECLAIMER_TRACKED;
 
-               section = &sgx_epc_sections[epc_page->section];
-               node = section->node;
-
-               spin_lock(&node->lock);
-               list_add_tail(&epc_page->list, &node->free_page_list);
-               spin_unlock(&node->lock);
-               atomic_long_inc(&sgx_nr_free_pages);
+               sgx_free_epc_page(epc_page);
        }
 }
 
index 437d7c9..75ffaef 100644 (file)
@@ -91,11 +91,9 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
                const void *kbuf, const void __user *ubuf)
 {
        struct fpu *fpu = &target->thread.fpu;
-       struct user32_fxsr_struct newstate;
+       struct fxregs_state newstate;
        int ret;
 
-       BUILD_BUG_ON(sizeof(newstate) != sizeof(struct fxregs_state));
-
        if (!cpu_feature_enabled(X86_FEATURE_FXSR))
                return -ENODEV;
 
@@ -116,9 +114,10 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
        /* Copy the state  */
        memcpy(&fpu->fpstate->regs.fxsave, &newstate, sizeof(newstate));
 
-       /* Clear xmm8..15 */
+       /* Clear xmm8..15 for 32-bit callers */
        BUILD_BUG_ON(sizeof(fpu->__fpstate.regs.fxsave.xmm_space) != 16 * 16);
-       memset(&fpu->fpstate->regs.fxsave.xmm_space[8], 0, 8 * 16);
+       if (in_ia32_syscall())
+               memset(&fpu->fpstate->regs.fxsave.xmm_space[8*4], 0, 8 * 16);
 
        /* Mark FP and SSE as in use when XSAVE is enabled */
        if (use_xsave())
index 02b3dda..7c7824a 100644 (file)
@@ -1558,7 +1558,10 @@ static int fpstate_realloc(u64 xfeatures, unsigned int ksize,
                fpregs_restore_userregs();
 
        newfps->xfeatures = curfps->xfeatures | xfeatures;
-       newfps->user_xfeatures = curfps->user_xfeatures | xfeatures;
+
+       if (!guest_fpu)
+               newfps->user_xfeatures = curfps->user_xfeatures | xfeatures;
+
        newfps->xfd = curfps->xfd & ~xfeatures;
 
        /* Do the final updates within the locked region */
index a438217..f734e3b 100644 (file)
@@ -462,19 +462,22 @@ static bool pv_tlb_flush_supported(void)
 {
        return (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH) &&
                !kvm_para_has_hint(KVM_HINTS_REALTIME) &&
-               kvm_para_has_feature(KVM_FEATURE_STEAL_TIME));
+               kvm_para_has_feature(KVM_FEATURE_STEAL_TIME) &&
+               (num_possible_cpus() != 1));
 }
 
 static bool pv_ipi_supported(void)
 {
-       return kvm_para_has_feature(KVM_FEATURE_PV_SEND_IPI);
+       return (kvm_para_has_feature(KVM_FEATURE_PV_SEND_IPI) &&
+              (num_possible_cpus() != 1));
 }
 
 static bool pv_sched_yield_supported(void)
 {
        return (kvm_para_has_feature(KVM_FEATURE_PV_SCHED_YIELD) &&
                !kvm_para_has_hint(KVM_HINTS_REALTIME) &&
-           kvm_para_has_feature(KVM_FEATURE_STEAL_TIME));
+           kvm_para_has_feature(KVM_FEATURE_STEAL_TIME) &&
+           (num_possible_cpus() != 1));
 }
 
 #define KVM_IPI_CLUSTER_SIZE   (2 * BITS_PER_LONG)
index 6d2244c..8d2f2f9 100644 (file)
@@ -1224,7 +1224,7 @@ static struct user_regset x86_64_regsets[] __ro_after_init = {
        },
        [REGSET_FP] = {
                .core_note_type = NT_PRFPREG,
-               .n = sizeof(struct user_i387_struct) / sizeof(long),
+               .n = sizeof(struct fxregs_state) / sizeof(long),
                .size = sizeof(long), .align = sizeof(long),
                .active = regset_xregset_fpregs_active, .regset_get = xfpregs_get, .set = xfpregs_set
        },
@@ -1271,7 +1271,7 @@ static struct user_regset x86_32_regsets[] __ro_after_init = {
        },
        [REGSET_XFP] = {
                .core_note_type = NT_PRXFPREG,
-               .n = sizeof(struct user32_fxsr_struct) / sizeof(u32),
+               .n = sizeof(struct fxregs_state) / sizeof(u32),
                .size = sizeof(u32), .align = sizeof(u32),
                .active = regset_xregset_fpregs_active, .regset_get = xfpregs_get, .set = xfpregs_set
        },
index 9ae64f9..9b9fb78 100644 (file)
@@ -1,5 +1,4 @@
 // SPDX-License-Identifier: GPL-2.0
-#include <linux/dmi.h>
 #include <linux/ioport.h>
 #include <asm/e820/api.h>
 
@@ -24,31 +23,11 @@ static void resource_clip(struct resource *res, resource_size_t start,
                res->start = end + 1;
 }
 
-/*
- * Some BIOS-es contain a bug where they add addresses which map to
- * system RAM in the PCI host bridge window returned by the ACPI _CRS
- * method, see commit 4dc2287c1805 ("x86: avoid E820 regions when
- * allocating address space"). To avoid this Linux by default excludes
- * E820 reservations when allocating addresses since 2010.
- * In 2019 some systems have shown-up with E820 reservations which cover
- * the entire _CRS returned PCI host bridge window, causing all attempts
- * to assign memory to PCI BARs to fail if Linux uses E820 reservations.
- *
- * Ideally Linux would fully stop using E820 reservations, but then
- * the old systems this was added for will regress.
- * Instead keep the old behavior for old systems, while ignoring the
- * E820 reservations for any systems from now on.
- */
 static void remove_e820_regions(struct resource *avail)
 {
-       int i, year = dmi_get_bios_year();
+       int i;
        struct e820_entry *entry;
 
-       if (year >= 2018)
-               return;
-
-       pr_info_once("PCI: Removing E820 reservations from host bridge windows\n");
-
        for (i = 0; i < e820_table->nr_entries; i++) {
                entry = &e820_table->entries[i];
 
index 3902c28..b8f8d26 100644 (file)
@@ -133,6 +133,7 @@ static int kvm_cpuid_check_equal(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2
                orig = &vcpu->arch.cpuid_entries[i];
                if (e2[i].function != orig->function ||
                    e2[i].index != orig->index ||
+                   e2[i].flags != orig->flags ||
                    e2[i].eax != orig->eax || e2[i].ebx != orig->ebx ||
                    e2[i].ecx != orig->ecx || e2[i].edx != orig->edx)
                        return -EINVAL;
@@ -196,10 +197,26 @@ void kvm_update_pv_runtime(struct kvm_vcpu *vcpu)
                vcpu->arch.pv_cpuid.features = best->eax;
 }
 
+/*
+ * Calculate guest's supported XCR0 taking into account guest CPUID data and
+ * supported_xcr0 (comprised of host configuration and KVM_SUPPORTED_XCR0).
+ */
+static u64 cpuid_get_supported_xcr0(struct kvm_cpuid_entry2 *entries, int nent)
+{
+       struct kvm_cpuid_entry2 *best;
+
+       best = cpuid_entry2_find(entries, nent, 0xd, 0);
+       if (!best)
+               return 0;
+
+       return (best->eax | ((u64)best->edx << 32)) & supported_xcr0;
+}
+
 static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *entries,
                                       int nent)
 {
        struct kvm_cpuid_entry2 *best;
+       u64 guest_supported_xcr0 = cpuid_get_supported_xcr0(entries, nent);
 
        best = cpuid_entry2_find(entries, nent, 1, 0);
        if (best) {
@@ -238,6 +255,21 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e
                                           vcpu->arch.ia32_misc_enable_msr &
                                           MSR_IA32_MISC_ENABLE_MWAIT);
        }
+
+       /*
+        * Bits 127:0 of the allowed SECS.ATTRIBUTES (CPUID.0x12.0x1) enumerate
+        * the supported XSAVE Feature Request Mask (XFRM), i.e. the enclave's
+        * requested XCR0 value.  The enclave's XFRM must be a subset of XCRO
+        * at the time of EENTER, thus adjust the allowed XFRM by the guest's
+        * supported XCR0.  Similar to XCR0 handling, FP and SSE are forced to
+        * '1' even on CPUs that don't support XSAVE.
+        */
+       best = cpuid_entry2_find(entries, nent, 0x12, 0x1);
+       if (best) {
+               best->ecx &= guest_supported_xcr0 & 0xffffffff;
+               best->edx &= guest_supported_xcr0 >> 32;
+               best->ecx |= XFEATURE_MASK_FPSSE;
+       }
 }
 
 void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu)
@@ -250,6 +282,7 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
        struct kvm_cpuid_entry2 *best;
+       u64 guest_supported_xcr0;
 
        best = kvm_find_cpuid_entry(vcpu, 1, 0);
        if (best && apic) {
@@ -261,27 +294,10 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
                kvm_apic_set_version(vcpu);
        }
 
-       best = kvm_find_cpuid_entry(vcpu, 0xD, 0);
-       if (!best)
-               vcpu->arch.guest_supported_xcr0 = 0;
-       else
-               vcpu->arch.guest_supported_xcr0 =
-                       (best->eax | ((u64)best->edx << 32)) & supported_xcr0;
+       guest_supported_xcr0 =
+               cpuid_get_supported_xcr0(vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent);
 
-       /*
-        * Bits 127:0 of the allowed SECS.ATTRIBUTES (CPUID.0x12.0x1) enumerate
-        * the supported XSAVE Feature Request Mask (XFRM), i.e. the enclave's
-        * requested XCR0 value.  The enclave's XFRM must be a subset of XCRO
-        * at the time of EENTER, thus adjust the allowed XFRM by the guest's
-        * supported XCR0.  Similar to XCR0 handling, FP and SSE are forced to
-        * '1' even on CPUs that don't support XSAVE.
-        */
-       best = kvm_find_cpuid_entry(vcpu, 0x12, 0x1);
-       if (best) {
-               best->ecx &= vcpu->arch.guest_supported_xcr0 & 0xffffffff;
-               best->edx &= vcpu->arch.guest_supported_xcr0 >> 32;
-               best->ecx |= XFEATURE_MASK_FPSSE;
-       }
+       vcpu->arch.guest_fpu.fpstate->user_xfeatures = guest_supported_xcr0;
 
        kvm_update_pv_runtime(vcpu);
 
@@ -346,8 +362,14 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
         * KVM_SET_CPUID{,2} again. To support this legacy behavior, check
         * whether the supplied CPUID data is equal to what's already set.
         */
-       if (vcpu->arch.last_vmentry_cpu != -1)
-               return kvm_cpuid_check_equal(vcpu, e2, nent);
+       if (vcpu->arch.last_vmentry_cpu != -1) {
+               r = kvm_cpuid_check_equal(vcpu, e2, nent);
+               if (r)
+                       return r;
+
+               kvfree(e2);
+               return 0;
+       }
 
        r = kvm_check_cpuid(vcpu, e2, nent);
        if (r)
@@ -535,12 +557,13 @@ void kvm_set_cpu_caps(void)
        );
 
        kvm_cpu_cap_mask(CPUID_7_0_EBX,
-               F(FSGSBASE) | F(SGX) | F(BMI1) | F(HLE) | F(AVX2) | F(SMEP) |
-               F(BMI2) | F(ERMS) | F(INVPCID) | F(RTM) | 0 /*MPX*/ | F(RDSEED) |
-               F(ADX) | F(SMAP) | F(AVX512IFMA) | F(AVX512F) | F(AVX512PF) |
-               F(AVX512ER) | F(AVX512CD) | F(CLFLUSHOPT) | F(CLWB) | F(AVX512DQ) |
-               F(SHA_NI) | F(AVX512BW) | F(AVX512VL) | 0 /*INTEL_PT*/
-       );
+               F(FSGSBASE) | F(SGX) | F(BMI1) | F(HLE) | F(AVX2) |
+               F(FDP_EXCPTN_ONLY) | F(SMEP) | F(BMI2) | F(ERMS) | F(INVPCID) |
+               F(RTM) | F(ZERO_FCS_FDS) | 0 /*MPX*/ | F(AVX512F) |
+               F(AVX512DQ) | F(RDSEED) | F(ADX) | F(SMAP) | F(AVX512IFMA) |
+               F(CLFLUSHOPT) | F(CLWB) | 0 /*INTEL_PT*/ | F(AVX512PF) |
+               F(AVX512ER) | F(AVX512CD) | F(SHA_NI) | F(AVX512BW) |
+               F(AVX512VL));
 
        kvm_cpu_cap_mask(CPUID_7_ECX,
                F(AVX512VBMI) | F(LA57) | F(PKU) | 0 /*OSPKE*/ | F(RDPID) |
@@ -887,13 +910,14 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
                }
                break;
        case 0xd: {
-               u64 guest_perm = xstate_get_guest_group_perm();
+               u64 permitted_xcr0 = supported_xcr0 & xstate_get_guest_group_perm();
+               u64 permitted_xss = supported_xss;
 
-               entry->eax &= supported_xcr0 & guest_perm;
-               entry->ebx = xstate_required_size(supported_xcr0, false);
+               entry->eax &= permitted_xcr0;
+               entry->ebx = xstate_required_size(permitted_xcr0, false);
                entry->ecx = entry->ebx;
-               entry->edx &= (supported_xcr0 & guest_perm) >> 32;
-               if (!supported_xcr0)
+               entry->edx &= permitted_xcr0 >> 32;
+               if (!permitted_xcr0)
                        break;
 
                entry = do_host_cpuid(array, function, 1);
@@ -902,20 +926,20 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
 
                cpuid_entry_override(entry, CPUID_D_1_EAX);
                if (entry->eax & (F(XSAVES)|F(XSAVEC)))
-                       entry->ebx = xstate_required_size(supported_xcr0 | supported_xss,
+                       entry->ebx = xstate_required_size(permitted_xcr0 | permitted_xss,
                                                          true);
                else {
-                       WARN_ON_ONCE(supported_xss != 0);
+                       WARN_ON_ONCE(permitted_xss != 0);
                        entry->ebx = 0;
                }
-               entry->ecx &= supported_xss;
-               entry->edx &= supported_xss >> 32;
+               entry->ecx &= permitted_xss;
+               entry->edx &= permitted_xss >> 32;
 
                for (i = 2; i < 64; ++i) {
                        bool s_state;
-                       if (supported_xcr0 & BIT_ULL(i))
+                       if (permitted_xcr0 & BIT_ULL(i))
                                s_state = false;
-                       else if (supported_xss & BIT_ULL(i))
+                       else if (permitted_xss & BIT_ULL(i))
                                s_state = true;
                        else
                                continue;
@@ -929,7 +953,7 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
                         * invalid sub-leafs.  Only valid sub-leafs should
                         * reach this point, and they should have a non-zero
                         * save state size.  Furthermore, check whether the
-                        * processor agrees with supported_xcr0/supported_xss
+                        * processor agrees with permitted_xcr0/permitted_xss
                         * on whether this is an XCR0- or IA32_XSS-managed area.
                         */
                        if (WARN_ON_ONCE(!entry->eax || (entry->ecx & 0x1) != s_state)) {
index baca9fa..9322e63 100644 (file)
@@ -1096,14 +1096,8 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                                                       apic->regs + APIC_TMR);
                }
 
-               if (static_call(kvm_x86_deliver_posted_interrupt)(vcpu, vector)) {
-                       kvm_lapic_set_irr(vector, apic);
-                       kvm_make_request(KVM_REQ_EVENT, vcpu);
-                       kvm_vcpu_kick(vcpu);
-               } else {
-                       trace_kvm_apicv_accept_irq(vcpu->vcpu_id, delivery_mode,
-                                                  trig_mode, vector);
-               }
+               static_call(kvm_x86_deliver_interrupt)(apic, delivery_mode,
+                                                      trig_mode, vector);
                break;
 
        case APIC_DM_REMRD:
@@ -2312,7 +2306,12 @@ void kvm_apic_update_apicv(struct kvm_vcpu *vcpu)
                apic->irr_pending = true;
                apic->isr_count = 1;
        } else {
-               apic->irr_pending = (apic_search_irr(apic) != -1);
+               /*
+                * Don't clear irr_pending, searching the IRR can race with
+                * updates from the CPU as APICv is still active from hardware's
+                * perspective.  The flag will be cleared as appropriate when
+                * KVM injects the interrupt.
+                */
                apic->isr_count = count_vectors(apic->regs + APIC_ISR);
        }
 }
@@ -2629,7 +2628,7 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s)
        kvm_apic_set_version(vcpu);
 
        apic_update_ppr(apic);
-       hrtimer_cancel(&apic->lapic_timer.timer);
+       cancel_apic_timer(apic);
        apic->lapic_timer.expired_tscdeadline = 0;
        apic_update_lvtt(apic);
        apic_manage_nmi_watchdog(apic, kvm_lapic_get_reg(apic, APIC_LVT0));
index 593093b..8e24f73 100644 (file)
@@ -3889,12 +3889,23 @@ static void shadow_page_table_clear_flood(struct kvm_vcpu *vcpu, gva_t addr)
        walk_shadow_page_lockless_end(vcpu);
 }
 
+static u32 alloc_apf_token(struct kvm_vcpu *vcpu)
+{
+       /* make sure the token value is not 0 */
+       u32 id = vcpu->arch.apf.id;
+
+       if (id << 12 == 0)
+               vcpu->arch.apf.id = 1;
+
+       return (vcpu->arch.apf.id++ << 12) | vcpu->vcpu_id;
+}
+
 static bool kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
                                    gfn_t gfn)
 {
        struct kvm_arch_async_pf arch;
 
-       arch.token = (vcpu->arch.apf.id++ << 12) | vcpu->vcpu_id;
+       arch.token = alloc_apf_token(vcpu);
        arch.gfn = gfn;
        arch.direct_map = vcpu->arch.mmu->direct_map;
        arch.cr3 = vcpu->arch.mmu->get_guest_pgd(vcpu);
index f614f95..b1a0299 100644 (file)
@@ -95,7 +95,7 @@ static void kvm_perf_overflow(struct perf_event *perf_event,
 }
 
 static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type,
-                                 unsigned config, bool exclude_user,
+                                 u64 config, bool exclude_user,
                                  bool exclude_kernel, bool intr,
                                  bool in_tx, bool in_tx_cp)
 {
@@ -181,7 +181,8 @@ static int cmp_u64(const void *a, const void *b)
 
 void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
 {
-       unsigned config, type = PERF_TYPE_RAW;
+       u64 config;
+       u32 type = PERF_TYPE_RAW;
        struct kvm *kvm = pmc->vcpu->kvm;
        struct kvm_pmu_event_filter *filter;
        bool allow_event = true;
@@ -220,7 +221,7 @@ void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel)
        }
 
        if (type == PERF_TYPE_RAW)
-               config = eventsel & X86_RAW_EVENT_MASK;
+               config = eventsel & AMD64_RAW_EVENT_MASK;
 
        if (pmc->current_config == eventsel && pmc_resume_counter(pmc))
                return;
index 90364d0..fb3e207 100644 (file)
 #include "irq.h"
 #include "svm.h"
 
-#define SVM_AVIC_DOORBELL      0xc001011b
-
-#define AVIC_HPA_MASK  ~((0xFFFULL << 52) | 0xFFF)
-
-/*
- * 0xff is broadcast, so the max index allowed for physical APIC ID
- * table is 0xfe.  APIC IDs above 0xff are reserved.
- */
-#define AVIC_MAX_PHYSICAL_ID_COUNT     255
-
-#define AVIC_UNACCEL_ACCESS_WRITE_MASK         1
-#define AVIC_UNACCEL_ACCESS_OFFSET_MASK                0xFF0
-#define AVIC_UNACCEL_ACCESS_VECTOR_MASK                0xFFFFFFFF
-
 /* AVIC GATAG is encoded using VM and VCPU IDs */
 #define AVIC_VCPU_ID_BITS              8
 #define AVIC_VCPU_ID_MASK              ((1 << AVIC_VCPU_ID_BITS) - 1)
@@ -73,12 +59,6 @@ struct amd_svm_iommu_ir {
        void *data;             /* Storing pointer to struct amd_ir_data */
 };
 
-enum avic_ipi_failure_cause {
-       AVIC_IPI_FAILURE_INVALID_INT_TYPE,
-       AVIC_IPI_FAILURE_TARGET_NOT_RUNNING,
-       AVIC_IPI_FAILURE_INVALID_TARGET,
-       AVIC_IPI_FAILURE_INVALID_BACKING_PAGE,
-};
 
 /* Note:
  * This function is called from IOMMU driver to notify
@@ -289,6 +269,22 @@ static int avic_init_backing_page(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+void avic_ring_doorbell(struct kvm_vcpu *vcpu)
+{
+       /*
+        * Note, the vCPU could get migrated to a different pCPU at any point,
+        * which could result in signalling the wrong/previous pCPU.  But if
+        * that happens the vCPU is guaranteed to do a VMRUN (after being
+        * migrated) and thus will process pending interrupts, i.e. a doorbell
+        * is not needed (and the spurious one is harmless).
+        */
+       int cpu = READ_ONCE(vcpu->cpu);
+
+       if (cpu != get_cpu())
+               wrmsrl(MSR_AMD64_SVM_AVIC_DOORBELL, kvm_cpu_get_apicid(cpu));
+       put_cpu();
+}
+
 static void avic_kick_target_vcpus(struct kvm *kvm, struct kvm_lapic *source,
                                   u32 icrl, u32 icrh)
 {
@@ -304,8 +300,13 @@ static void avic_kick_target_vcpus(struct kvm *kvm, struct kvm_lapic *source,
        kvm_for_each_vcpu(i, vcpu, kvm) {
                if (kvm_apic_match_dest(vcpu, source, icrl & APIC_SHORT_MASK,
                                        GET_APIC_DEST_FIELD(icrh),
-                                       icrl & APIC_DEST_MASK))
-                       kvm_vcpu_wake_up(vcpu);
+                                       icrl & APIC_DEST_MASK)) {
+                       vcpu->arch.apic->irr_pending = true;
+                       svm_complete_interrupt_delivery(vcpu,
+                                                       icrl & APIC_MODE_MASK,
+                                                       icrl & APIC_INT_LEVELTRIG,
+                                                       icrl & APIC_VECTOR_MASK);
+               }
        }
 }
 
@@ -345,8 +346,6 @@ int avic_incomplete_ipi_interception(struct kvm_vcpu *vcpu)
                avic_kick_target_vcpus(vcpu->kvm, apic, icrl, icrh);
                break;
        case AVIC_IPI_FAILURE_INVALID_TARGET:
-               WARN_ONCE(1, "Invalid IPI target: index=%u, vcpu=%d, icr=%#0x:%#0x\n",
-                         index, vcpu->vcpu_id, icrh, icrl);
                break;
        case AVIC_IPI_FAILURE_INVALID_BACKING_PAGE:
                WARN_ONCE(1, "Invalid backing page\n");
@@ -669,52 +668,6 @@ void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
        return;
 }
 
-int svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec)
-{
-       if (!vcpu->arch.apicv_active)
-               return -1;
-
-       kvm_lapic_set_irr(vec, vcpu->arch.apic);
-
-       /*
-        * Pairs with the smp_mb_*() after setting vcpu->guest_mode in
-        * vcpu_enter_guest() to ensure the write to the vIRR is ordered before
-        * the read of guest_mode, which guarantees that either VMRUN will see
-        * and process the new vIRR entry, or that the below code will signal
-        * the doorbell if the vCPU is already running in the guest.
-        */
-       smp_mb__after_atomic();
-
-       /*
-        * Signal the doorbell to tell hardware to inject the IRQ if the vCPU
-        * is in the guest.  If the vCPU is not in the guest, hardware will
-        * automatically process AVIC interrupts at VMRUN.
-        */
-       if (vcpu->mode == IN_GUEST_MODE) {
-               int cpu = READ_ONCE(vcpu->cpu);
-
-               /*
-                * Note, the vCPU could get migrated to a different pCPU at any
-                * point, which could result in signalling the wrong/previous
-                * pCPU.  But if that happens the vCPU is guaranteed to do a
-                * VMRUN (after being migrated) and thus will process pending
-                * interrupts, i.e. a doorbell is not needed (and the spurious
-                * one is harmless).
-                */
-               if (cpu != get_cpu())
-                       wrmsrl(SVM_AVIC_DOORBELL, kvm_cpu_get_apicid(cpu));
-               put_cpu();
-       } else {
-               /*
-                * Wake the vCPU if it was blocking.  KVM will then detect the
-                * pending IRQ when checking if the vCPU has a wake event.
-                */
-               kvm_vcpu_wake_up(vcpu);
-       }
-
-       return 0;
-}
-
 bool svm_dy_apicv_has_pending_interrupt(struct kvm_vcpu *vcpu)
 {
        return false;
index cf20685..39d280e 100644 (file)
@@ -983,9 +983,9 @@ void svm_free_nested(struct vcpu_svm *svm)
 /*
  * Forcibly leave nested mode in order to be able to reset the VCPU later on.
  */
-void svm_leave_nested(struct vcpu_svm *svm)
+void svm_leave_nested(struct kvm_vcpu *vcpu)
 {
-       struct kvm_vcpu *vcpu = &svm->vcpu;
+       struct vcpu_svm *svm = to_svm(vcpu);
 
        if (is_guest_mode(vcpu)) {
                svm->nested.nested_run_pending = 0;
@@ -1411,7 +1411,7 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
                return -EINVAL;
 
        if (!(kvm_state->flags & KVM_STATE_NESTED_GUEST_MODE)) {
-               svm_leave_nested(svm);
+               svm_leave_nested(vcpu);
                svm_set_gif(svm, !!(kvm_state->flags & KVM_STATE_NESTED_GIF_SET));
                return 0;
        }
@@ -1457,18 +1457,6 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
            !__nested_vmcb_check_save(vcpu, &save_cached))
                goto out_free;
 
-       /*
-        * While the nested guest CR3 is already checked and set by
-        * KVM_SET_SREGS, it was set when nested state was yet loaded,
-        * thus MMU might not be initialized correctly.
-        * Set it again to fix this.
-        */
-
-       ret = nested_svm_load_cr3(&svm->vcpu, vcpu->arch.cr3,
-                                 nested_npt_enabled(svm), false);
-       if (WARN_ON_ONCE(ret))
-               goto out_free;
-
 
        /*
         * All checks done, we can enter guest mode. Userspace provides
@@ -1478,7 +1466,7 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
         */
 
        if (is_guest_mode(vcpu))
-               svm_leave_nested(svm);
+               svm_leave_nested(vcpu);
        else
                svm->nested.vmcb02.ptr->save = svm->vmcb01.ptr->save;
 
@@ -1494,6 +1482,20 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
 
        svm_switch_vmcb(svm, &svm->nested.vmcb02);
        nested_vmcb02_prepare_control(svm);
+
+       /*
+        * While the nested guest CR3 is already checked and set by
+        * KVM_SET_SREGS, it was set when nested state was yet loaded,
+        * thus MMU might not be initialized correctly.
+        * Set it again to fix this.
+        */
+
+       ret = nested_svm_load_cr3(&svm->vcpu, vcpu->arch.cr3,
+                                 nested_npt_enabled(svm), false);
+       if (WARN_ON_ONCE(ret))
+               goto out_free;
+
+
        kvm_make_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu);
        ret = 0;
 out_free:
@@ -1532,6 +1534,7 @@ static bool svm_get_nested_state_pages(struct kvm_vcpu *vcpu)
 }
 
 struct kvm_x86_nested_ops svm_nested_ops = {
+       .leave_nested = svm_leave_nested,
        .check_events = svm_check_nested_events,
        .triple_fault = nested_svm_triple_fault,
        .get_nested_state_pages = svm_get_nested_state_pages,
index 6a22798..17b5345 100644 (file)
@@ -2100,8 +2100,13 @@ void __init sev_hardware_setup(void)
        if (!sev_enabled || !npt_enabled)
                goto out;
 
-       /* Does the CPU support SEV? */
-       if (!boot_cpu_has(X86_FEATURE_SEV))
+       /*
+        * SEV must obviously be supported in hardware.  Sanity check that the
+        * CPU supports decode assists, which is mandatory for SEV guests to
+        * support instruction emulation.
+        */
+       if (!boot_cpu_has(X86_FEATURE_SEV) ||
+           WARN_ON_ONCE(!boot_cpu_has(X86_FEATURE_DECODEASSISTS)))
                goto out;
 
        /* Retrieve SEV CPUID information */
index 2c99b18..fd3a00c 100644 (file)
@@ -290,7 +290,7 @@ int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
 
        if ((old_efer & EFER_SVME) != (efer & EFER_SVME)) {
                if (!(efer & EFER_SVME)) {
-                       svm_leave_nested(svm);
+                       svm_leave_nested(vcpu);
                        svm_set_gif(svm, true);
                        /* #GP intercept is still needed for vmware backdoor */
                        if (!enable_vmware_backdoor)
@@ -312,7 +312,11 @@ int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
                                return ret;
                        }
 
-                       if (svm_gp_erratum_intercept)
+                       /*
+                        * Never intercept #GP for SEV guests, KVM can't
+                        * decrypt guest memory to workaround the erratum.
+                        */
+                       if (svm_gp_erratum_intercept && !sev_guest(vcpu->kvm))
                                set_exception_intercept(svm, GP_VECTOR);
                }
        }
@@ -1010,9 +1014,10 @@ static void init_vmcb(struct kvm_vcpu *vcpu)
         * Guest access to VMware backdoor ports could legitimately
         * trigger #GP because of TSS I/O permission bitmap.
         * We intercept those #GP and allow access to them anyway
-        * as VMware does.
+        * as VMware does.  Don't intercept #GP for SEV guests as KVM can't
+        * decrypt guest memory to decode the faulting instruction.
         */
-       if (enable_vmware_backdoor)
+       if (enable_vmware_backdoor && !sev_guest(vcpu->kvm))
                set_exception_intercept(svm, GP_VECTOR);
 
        svm_set_intercept(svm, INTERCEPT_INTR);
@@ -1580,6 +1585,7 @@ void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
        u64 hcr0 = cr0;
+       bool old_paging = is_paging(vcpu);
 
 #ifdef CONFIG_X86_64
        if (vcpu->arch.efer & EFER_LME && !vcpu->arch.guest_state_protected) {
@@ -1596,8 +1602,11 @@ void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 #endif
        vcpu->arch.cr0 = cr0;
 
-       if (!npt_enabled)
+       if (!npt_enabled) {
                hcr0 |= X86_CR0_PG | X86_CR0_WP;
+               if (old_paging != is_paging(vcpu))
+                       svm_set_cr4(vcpu, kvm_read_cr4(vcpu));
+       }
 
        /*
         * re-enable caching here because the QEMU bios
@@ -1641,8 +1650,12 @@ void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
                svm_flush_tlb(vcpu);
 
        vcpu->arch.cr4 = cr4;
-       if (!npt_enabled)
+       if (!npt_enabled) {
                cr4 |= X86_CR4_PAE;
+
+               if (!is_paging(vcpu))
+                       cr4 &= ~(X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_PKE);
+       }
        cr4 |= host_cr4_mce;
        to_svm(vcpu)->vmcb->save.cr4 = cr4;
        vmcb_mark_dirty(to_svm(vcpu)->vmcb, VMCB_CR);
@@ -2091,10 +2104,6 @@ static int gp_interception(struct kvm_vcpu *vcpu)
        if (error_code)
                goto reinject;
 
-       /* All SVM instructions expect page aligned RAX */
-       if (svm->vmcb->save.rax & ~PAGE_MASK)
-               goto reinject;
-
        /* Decode the instruction for usage later */
        if (x86_decode_emulated_instruction(vcpu, 0, NULL, 0) != EMULATION_OK)
                goto reinject;
@@ -2112,8 +2121,13 @@ static int gp_interception(struct kvm_vcpu *vcpu)
                if (!is_guest_mode(vcpu))
                        return kvm_emulate_instruction(vcpu,
                                EMULTYPE_VMWARE_GP | EMULTYPE_NO_DECODE);
-       } else
+       } else {
+               /* All SVM instructions expect page aligned RAX */
+               if (svm->vmcb->save.rax & ~PAGE_MASK)
+                       goto reinject;
+
                return emulate_svm_instr(vcpu, opcode);
+       }
 
 reinject:
        kvm_queue_exception_e(vcpu, GP_VECTOR, error_code);
@@ -2679,8 +2693,23 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
        u64 data = msr->data;
        switch (ecx) {
        case MSR_AMD64_TSC_RATIO:
-               if (!msr->host_initiated && !svm->tsc_scaling_enabled)
-                       return 1;
+
+               if (!svm->tsc_scaling_enabled) {
+
+                       if (!msr->host_initiated)
+                               return 1;
+                       /*
+                        * In case TSC scaling is not enabled, always
+                        * leave this MSR at the default value.
+                        *
+                        * Due to bug in qemu 6.2.0, it would try to set
+                        * this msr to 0 if tsc scaling is not enabled.
+                        * Ignore this value as well.
+                        */
+                       if (data != 0 && data != svm->tsc_ratio_msr)
+                               return 1;
+                       break;
+               }
 
                if (data & TSC_RATIO_RSVD)
                        return 1;
@@ -3285,6 +3314,55 @@ static void svm_set_irq(struct kvm_vcpu *vcpu)
                SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR;
 }
 
+void svm_complete_interrupt_delivery(struct kvm_vcpu *vcpu, int delivery_mode,
+                                    int trig_mode, int vector)
+{
+       /*
+        * vcpu->arch.apicv_active must be read after vcpu->mode.
+        * Pairs with smp_store_release in vcpu_enter_guest.
+        */
+       bool in_guest_mode = (smp_load_acquire(&vcpu->mode) == IN_GUEST_MODE);
+
+       if (!READ_ONCE(vcpu->arch.apicv_active)) {
+               /* Process the interrupt via inject_pending_event */
+               kvm_make_request(KVM_REQ_EVENT, vcpu);
+               kvm_vcpu_kick(vcpu);
+               return;
+       }
+
+       trace_kvm_apicv_accept_irq(vcpu->vcpu_id, delivery_mode, trig_mode, vector);
+       if (in_guest_mode) {
+               /*
+                * Signal the doorbell to tell hardware to inject the IRQ.  If
+                * the vCPU exits the guest before the doorbell chimes, hardware
+                * will automatically process AVIC interrupts at the next VMRUN.
+                */
+               avic_ring_doorbell(vcpu);
+       } else {
+               /*
+                * Wake the vCPU if it was blocking.  KVM will then detect the
+                * pending IRQ when checking if the vCPU has a wake event.
+                */
+               kvm_vcpu_wake_up(vcpu);
+       }
+}
+
+static void svm_deliver_interrupt(struct kvm_lapic *apic,  int delivery_mode,
+                                 int trig_mode, int vector)
+{
+       kvm_lapic_set_irr(vector, apic);
+
+       /*
+        * Pairs with the smp_mb_*() after setting vcpu->guest_mode in
+        * vcpu_enter_guest() to ensure the write to the vIRR is ordered before
+        * the read of guest_mode.  This guarantees that either VMRUN will see
+        * and process the new vIRR entry, or that svm_complete_interrupt_delivery
+        * will signal the doorbell if the CPU has already entered the guest.
+        */
+       smp_mb__after_atomic();
+       svm_complete_interrupt_delivery(apic->vcpu, delivery_mode, trig_mode, vector);
+}
+
 static void svm_update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -3332,11 +3410,13 @@ static int svm_nmi_allowed(struct kvm_vcpu *vcpu, bool for_injection)
        if (svm->nested.nested_run_pending)
                return -EBUSY;
 
+       if (svm_nmi_blocked(vcpu))
+               return 0;
+
        /* An NMI must not be injected into L2 if it's supposed to VM-Exit.  */
        if (for_injection && is_guest_mode(vcpu) && nested_exit_on_nmi(svm))
                return -EBUSY;
-
-       return !svm_nmi_blocked(vcpu);
+       return 1;
 }
 
 static bool svm_get_nmi_mask(struct kvm_vcpu *vcpu)
@@ -3388,9 +3468,13 @@ bool svm_interrupt_blocked(struct kvm_vcpu *vcpu)
 static int svm_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
+
        if (svm->nested.nested_run_pending)
                return -EBUSY;
 
+       if (svm_interrupt_blocked(vcpu))
+               return 0;
+
        /*
         * An IRQ must not be injected into L2 if it's supposed to VM-Exit,
         * e.g. if the IRQ arrived asynchronously after checking nested events.
@@ -3398,7 +3482,7 @@ static int svm_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection)
        if (for_injection && is_guest_mode(vcpu) && nested_exit_on_intr(svm))
                return -EBUSY;
 
-       return !svm_interrupt_blocked(vcpu);
+       return 1;
 }
 
 static void svm_enable_irq_window(struct kvm_vcpu *vcpu)
@@ -3609,7 +3693,7 @@ static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu)
        struct vcpu_svm *svm = to_svm(vcpu);
        unsigned long vmcb_pa = svm->current_vmcb->pa;
 
-       kvm_guest_enter_irqoff();
+       guest_state_enter_irqoff();
 
        if (sev_es_guest(vcpu->kvm)) {
                __svm_sev_es_vcpu_run(vmcb_pa);
@@ -3629,7 +3713,7 @@ static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu)
                vmload(__sme_page_pa(sd->save_area));
        }
 
-       kvm_guest_exit_irqoff();
+       guest_state_exit_irqoff();
 }
 
 static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu)
@@ -4129,11 +4213,14 @@ static int svm_smi_allowed(struct kvm_vcpu *vcpu, bool for_injection)
        if (svm->nested.nested_run_pending)
                return -EBUSY;
 
+       if (svm_smi_blocked(vcpu))
+               return 0;
+
        /* An SMI must not be injected into L2 if it's supposed to VM-Exit.  */
        if (for_injection && is_guest_mode(vcpu) && nested_exit_on_smi(svm))
                return -EBUSY;
 
-       return !svm_smi_blocked(vcpu);
+       return 1;
 }
 
 static int svm_enter_smm(struct kvm_vcpu *vcpu, char *smstate)
@@ -4227,11 +4314,18 @@ static int svm_leave_smm(struct kvm_vcpu *vcpu, const char *smstate)
         * Enter the nested guest now
         */
 
+       vmcb_mark_all_dirty(svm->vmcb01.ptr);
+
        vmcb12 = map.hva;
        nested_copy_vmcb_control_to_cache(svm, &vmcb12->control);
        nested_copy_vmcb_save_to_cache(svm, &vmcb12->save);
        ret = enter_svm_guest_mode(vcpu, vmcb12_gpa, vmcb12, false);
 
+       if (ret)
+               goto unmap_save;
+
+       svm->nested.nested_run_pending = 1;
+
 unmap_save:
        kvm_vcpu_unmap(vcpu, &map_save, true);
 unmap_map:
@@ -4252,79 +4346,140 @@ static void svm_enable_smi_window(struct kvm_vcpu *vcpu)
        }
 }
 
-static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, void *insn, int insn_len)
+static bool svm_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type,
+                                       void *insn, int insn_len)
 {
        bool smep, smap, is_user;
        unsigned long cr4;
+       u64 error_code;
+
+       /* Emulation is always possible when KVM has access to all guest state. */
+       if (!sev_guest(vcpu->kvm))
+               return true;
+
+       /* #UD and #GP should never be intercepted for SEV guests. */
+       WARN_ON_ONCE(emul_type & (EMULTYPE_TRAP_UD |
+                                 EMULTYPE_TRAP_UD_FORCED |
+                                 EMULTYPE_VMWARE_GP));
 
        /*
-        * When the guest is an SEV-ES guest, emulation is not possible.
+        * Emulation is impossible for SEV-ES guests as KVM doesn't have access
+        * to guest register state.
         */
        if (sev_es_guest(vcpu->kvm))
                return false;
 
+       /*
+        * Emulation is possible if the instruction is already decoded, e.g.
+        * when completing I/O after returning from userspace.
+        */
+       if (emul_type & EMULTYPE_NO_DECODE)
+               return true;
+
+       /*
+        * Emulation is possible for SEV guests if and only if a prefilled
+        * buffer containing the bytes of the intercepted instruction is
+        * available. SEV guest memory is encrypted with a guest specific key
+        * and cannot be decrypted by KVM, i.e. KVM would read cyphertext and
+        * decode garbage.
+        *
+        * Inject #UD if KVM reached this point without an instruction buffer.
+        * In practice, this path should never be hit by a well-behaved guest,
+        * e.g. KVM doesn't intercept #UD or #GP for SEV guests, but this path
+        * is still theoretically reachable, e.g. via unaccelerated fault-like
+        * AVIC access, and needs to be handled by KVM to avoid putting the
+        * guest into an infinite loop.   Injecting #UD is somewhat arbitrary,
+        * but its the least awful option given lack of insight into the guest.
+        */
+       if (unlikely(!insn)) {
+               kvm_queue_exception(vcpu, UD_VECTOR);
+               return false;
+       }
+
+       /*
+        * Emulate for SEV guests if the insn buffer is not empty.  The buffer
+        * will be empty if the DecodeAssist microcode cannot fetch bytes for
+        * the faulting instruction because the code fetch itself faulted, e.g.
+        * the guest attempted to fetch from emulated MMIO or a guest page
+        * table used to translate CS:RIP resides in emulated MMIO.
+        */
+       if (likely(insn_len))
+               return true;
+
        /*
         * Detect and workaround Errata 1096 Fam_17h_00_0Fh.
         *
         * Errata:
-        * When CPU raise #NPF on guest data access and vCPU CR4.SMAP=1, it is
-        * possible that CPU microcode implementing DecodeAssist will fail
-        * to read bytes of instruction which caused #NPF. In this case,
-        * GuestIntrBytes field of the VMCB on a VMEXIT will incorrectly
-        * return 0 instead of the correct guest instruction bytes.
-        *
-        * This happens because CPU microcode reading instruction bytes
-        * uses a special opcode which attempts to read data using CPL=0
-        * privileges. The microcode reads CS:RIP and if it hits a SMAP
-        * fault, it gives up and returns no instruction bytes.
+        * When CPU raises #NPF on guest data access and vCPU CR4.SMAP=1, it is
+        * possible that CPU microcode implementing DecodeAssist will fail to
+        * read guest memory at CS:RIP and vmcb.GuestIntrBytes will incorrectly
+        * be '0'.  This happens because microcode reads CS:RIP using a _data_
+        * loap uop with CPL=0 privileges.  If the load hits a SMAP #PF, ucode
+        * gives up and does not fill the instruction bytes buffer.
         *
-        * Detection:
-        * We reach here in case CPU supports DecodeAssist, raised #NPF and
-        * returned 0 in GuestIntrBytes field of the VMCB.
-        * First, errata can only be triggered in case vCPU CR4.SMAP=1.
-        * Second, if vCPU CR4.SMEP=1, errata could only be triggered
-        * in case vCPU CPL==3 (Because otherwise guest would have triggered
-        * a SMEP fault instead of #NPF).
-        * Otherwise, vCPU CR4.SMEP=0, errata could be triggered by any vCPU CPL.
-        * As most guests enable SMAP if they have also enabled SMEP, use above
-        * logic in order to attempt minimize false-positive of detecting errata
-        * while still preserving all cases semantic correctness.
+        * As above, KVM reaches this point iff the VM is an SEV guest, the CPU
+        * supports DecodeAssist, a #NPF was raised, KVM's page fault handler
+        * triggered emulation (e.g. for MMIO), and the CPU returned 0 in the
+        * GuestIntrBytes field of the VMCB.
         *
-        * Workaround:
-        * To determine what instruction the guest was executing, the hypervisor
-        * will have to decode the instruction at the instruction pointer.
+        * This does _not_ mean that the erratum has been encountered, as the
+        * DecodeAssist will also fail if the load for CS:RIP hits a legitimate
+        * #PF, e.g. if the guest attempt to execute from emulated MMIO and
+        * encountered a reserved/not-present #PF.
         *
-        * In non SEV guest, hypervisor will be able to read the guest
-        * memory to decode the instruction pointer when insn_len is zero
-        * so we return true to indicate that decoding is possible.
+        * To hit the erratum, the following conditions must be true:
+        *    1. CR4.SMAP=1 (obviously).
+        *    2. CR4.SMEP=0 || CPL=3.  If SMEP=1 and CPL<3, the erratum cannot
+        *       have been hit as the guest would have encountered a SMEP
+        *       violation #PF, not a #NPF.
+        *    3. The #NPF is not due to a code fetch, in which case failure to
+        *       retrieve the instruction bytes is legitimate (see abvoe).
         *
-        * But in the SEV guest, the guest memory is encrypted with the
-        * guest specific key and hypervisor will not be able to decode the
-        * instruction pointer so we will not able to workaround it. Lets
-        * print the error and request to kill the guest.
-        */
-       if (likely(!insn || insn_len))
-               return true;
-
-       /*
-        * If RIP is invalid, go ahead with emulation which will cause an
-        * internal error exit.
+        * In addition, don't apply the erratum workaround if the #NPF occurred
+        * while translating guest page tables (see below).
         */
-       if (!kvm_vcpu_gfn_to_memslot(vcpu, kvm_rip_read(vcpu) >> PAGE_SHIFT))
-               return true;
+       error_code = to_svm(vcpu)->vmcb->control.exit_info_1;
+       if (error_code & (PFERR_GUEST_PAGE_MASK | PFERR_FETCH_MASK))
+               goto resume_guest;
 
        cr4 = kvm_read_cr4(vcpu);
        smep = cr4 & X86_CR4_SMEP;
        smap = cr4 & X86_CR4_SMAP;
        is_user = svm_get_cpl(vcpu) == 3;
        if (smap && (!smep || is_user)) {
-               if (!sev_guest(vcpu->kvm))
-                       return true;
-
                pr_err_ratelimited("KVM: SEV Guest triggered AMD Erratum 1096\n");
-               kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
+
+               /*
+                * If the fault occurred in userspace, arbitrarily inject #GP
+                * to avoid killing the guest and to hopefully avoid confusing
+                * the guest kernel too much, e.g. injecting #PF would not be
+                * coherent with respect to the guest's page tables.  Request
+                * triple fault if the fault occurred in the kernel as there's
+                * no fault that KVM can inject without confusing the guest.
+                * In practice, the triple fault is moot as no sane SEV kernel
+                * will execute from user memory while also running with SMAP=1.
+                */
+               if (is_user)
+                       kvm_inject_gp(vcpu, 0);
+               else
+                       kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
        }
 
+resume_guest:
+       /*
+        * If the erratum was not hit, simply resume the guest and let it fault
+        * again.  While awful, e.g. the vCPU may get stuck in an infinite loop
+        * if the fault is at CPL=0, it's the lesser of all evils.  Exiting to
+        * userspace will kill the guest, and letting the emulator read garbage
+        * will yield random behavior and potentially corrupt the guest.
+        *
+        * Simply resuming the guest is technically not a violation of the SEV
+        * architecture.  AMD's APM states that all code fetches and page table
+        * accesses for SEV guest are encrypted, regardless of the C-Bit.  The
+        * APM also states that encrypted accesses to MMIO are "ignored", but
+        * doesn't explicitly define "ignored", i.e. doing nothing and letting
+        * the guest spin is technically "ignoring" the access.
+        */
        return false;
 }
 
@@ -4478,7 +4633,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
        .pmu_ops = &amd_pmu_ops,
        .nested_ops = &svm_nested_ops,
 
-       .deliver_posted_interrupt = svm_deliver_avic_intr,
+       .deliver_interrupt = svm_deliver_interrupt,
        .dy_apicv_has_pending_interrupt = svm_dy_apicv_has_pending_interrupt,
        .update_pi_irte = svm_update_pi_irte,
        .setup_mce = svm_setup_mce,
@@ -4555,6 +4710,7 @@ static __init void svm_set_cpu_caps(void)
        /* CPUID 0x80000001 and 0x8000000A (SVM features) */
        if (nested) {
                kvm_cpu_cap_set(X86_FEATURE_SVM);
+               kvm_cpu_cap_set(X86_FEATURE_VMCBCLEAN);
 
                if (nrips)
                        kvm_cpu_cap_set(X86_FEATURE_NRIPS);
index 47ef8f4..fa98d68 100644 (file)
@@ -304,11 +304,6 @@ static inline void vmcb_mark_all_clean(struct vmcb *vmcb)
                               & ~VMCB_ALWAYS_DIRTY_MASK;
 }
 
-static inline bool vmcb_is_clean(struct vmcb *vmcb, int bit)
-{
-       return (vmcb->control.clean & (1 << bit));
-}
-
 static inline void vmcb_mark_dirty(struct vmcb *vmcb, int bit)
 {
        vmcb->control.clean &= ~(1 << bit);
@@ -494,6 +489,8 @@ void svm_set_gif(struct vcpu_svm *svm, bool value);
 int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 exit_code);
 void set_msr_interception(struct kvm_vcpu *vcpu, u32 *msrpm, u32 msr,
                          int read, int write);
+void svm_complete_interrupt_delivery(struct kvm_vcpu *vcpu, int delivery_mode,
+                                    int trig_mode, int vec);
 
 /* nested.c */
 
@@ -525,7 +522,7 @@ static inline bool nested_exit_on_nmi(struct vcpu_svm *svm)
 
 int enter_svm_guest_mode(struct kvm_vcpu *vcpu,
                         u64 vmcb_gpa, struct vmcb *vmcb12, bool from_vmrun);
-void svm_leave_nested(struct vcpu_svm *svm);
+void svm_leave_nested(struct kvm_vcpu *vcpu);
 void svm_free_nested(struct vcpu_svm *svm);
 int svm_allocate_nested(struct vcpu_svm *svm);
 int nested_svm_vmrun(struct kvm_vcpu *vcpu);
@@ -561,17 +558,6 @@ extern struct kvm_x86_nested_ops svm_nested_ops;
 
 /* avic.c */
 
-#define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK   (0xFF)
-#define AVIC_LOGICAL_ID_ENTRY_VALID_BIT                        31
-#define AVIC_LOGICAL_ID_ENTRY_VALID_MASK               (1 << 31)
-
-#define AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK   (0xFFULL)
-#define AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK       (0xFFFFFFFFFFULL << 12)
-#define AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK         (1ULL << 62)
-#define AVIC_PHYSICAL_ID_ENTRY_VALID_MASK              (1ULL << 63)
-
-#define VMCB_AVIC_APIC_BAR_MASK                0xFFFFFFFFFF000ULL
-
 int avic_ga_log_notifier(u32 ga_tag);
 void avic_vm_destroy(struct kvm *kvm);
 int avic_vm_init(struct kvm *kvm);
@@ -588,12 +574,12 @@ bool svm_check_apicv_inhibit_reasons(ulong bit);
 void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
 void svm_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr);
 void svm_hwapic_isr_update(struct kvm_vcpu *vcpu, int max_isr);
-int svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec);
 bool svm_dy_apicv_has_pending_interrupt(struct kvm_vcpu *vcpu);
 int svm_update_pi_irte(struct kvm *kvm, unsigned int host_irq,
                       uint32_t guest_irq, bool set);
 void avic_vcpu_blocking(struct kvm_vcpu *vcpu);
 void avic_vcpu_unblocking(struct kvm_vcpu *vcpu);
+void avic_ring_doorbell(struct kvm_vcpu *vcpu);
 
 /* sev.c */
 
index c53b8bf..489ca56 100644 (file)
@@ -46,6 +46,9 @@ static inline void svm_hv_init_vmcb(struct vmcb *vmcb)
        if (npt_enabled &&
            ms_hyperv.nested_features & HV_X64_NESTED_ENLIGHTENED_TLB)
                hve->hv_enlightenments_control.enlightened_npt_tlb = 1;
+
+       if (ms_hyperv.nested_features & HV_X64_NESTED_MSR_BITMAP)
+               hve->hv_enlightenments_control.msr_bitmap = 1;
 }
 
 static inline void svm_hv_hardware_setup(void)
@@ -83,14 +86,7 @@ static inline void svm_hv_vmcb_dirty_nested_enlightenments(
        struct hv_enlightenments *hve =
                (struct hv_enlightenments *)vmcb->control.reserved_sw;
 
-       /*
-        * vmcb can be NULL if called during early vcpu init.
-        * And its okay not to mark vmcb dirty during vcpu init
-        * as we mark it dirty unconditionally towards end of vcpu
-        * init phase.
-        */
-       if (vmcb_is_clean(vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS) &&
-           hve->hv_enlightenments_control.msr_bitmap)
+       if (hve->hv_enlightenments_control.msr_bitmap)
                vmcb_mark_dirty(vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS);
 }
 
index 959b59d..3f430e2 100644 (file)
@@ -54,7 +54,6 @@ struct nested_vmx_msrs {
 
 struct vmcs_config {
        int size;
-       int order;
        u32 basic_cap;
        u32 revision_id;
        u32 pin_based_exec_ctrl;
index ba6f99f..87e3dc1 100644 (file)
@@ -12,8 +12,6 @@
 
 DEFINE_STATIC_KEY_FALSE(enable_evmcs);
 
-#if IS_ENABLED(CONFIG_HYPERV)
-
 #define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x)
 #define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \
                {EVMCS1_OFFSET(name), clean_field}
@@ -296,6 +294,7 @@ const struct evmcs_field vmcs_field_to_evmcs_1[] = {
 };
 const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1);
 
+#if IS_ENABLED(CONFIG_HYPERV)
 __init void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf)
 {
        vmcs_conf->pin_based_exec_ctrl &= ~EVMCS1_UNSUPPORTED_PINCTRL;
@@ -362,6 +361,7 @@ void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata)
        case MSR_IA32_VMX_PROCBASED_CTLS2:
                ctl_high &= ~EVMCS1_UNSUPPORTED_2NDEXEC;
                break;
+       case MSR_IA32_VMX_TRUE_PINBASED_CTLS:
        case MSR_IA32_VMX_PINBASED_CTLS:
                ctl_high &= ~EVMCS1_UNSUPPORTED_PINCTRL;
                break;
index 16731d2..8d70f9a 100644 (file)
@@ -59,12 +59,12 @@ DECLARE_STATIC_KEY_FALSE(enable_evmcs);
         SECONDARY_EXEC_SHADOW_VMCS |                                   \
         SECONDARY_EXEC_TSC_SCALING |                                   \
         SECONDARY_EXEC_PAUSE_LOOP_EXITING)
-#define EVMCS1_UNSUPPORTED_VMEXIT_CTRL (VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL)
+#define EVMCS1_UNSUPPORTED_VMEXIT_CTRL                                 \
+       (VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL |                           \
+        VM_EXIT_SAVE_VMX_PREEMPTION_TIMER)
 #define EVMCS1_UNSUPPORTED_VMENTRY_CTRL (VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL)
 #define EVMCS1_UNSUPPORTED_VMFUNC (VMX_VMFUNC_EPTP_SWITCHING)
 
-#if IS_ENABLED(CONFIG_HYPERV)
-
 struct evmcs_field {
        u16 offset;
        u16 clean_field;
@@ -73,26 +73,56 @@ struct evmcs_field {
 extern const struct evmcs_field vmcs_field_to_evmcs_1[];
 extern const unsigned int nr_evmcs_1_fields;
 
-static __always_inline int get_evmcs_offset(unsigned long field,
-                                           u16 *clean_field)
+static __always_inline int evmcs_field_offset(unsigned long field,
+                                             u16 *clean_field)
 {
        unsigned int index = ROL16(field, 6);
        const struct evmcs_field *evmcs_field;
 
-       if (unlikely(index >= nr_evmcs_1_fields)) {
-               WARN_ONCE(1, "KVM: accessing unsupported EVMCS field %lx\n",
-                         field);
+       if (unlikely(index >= nr_evmcs_1_fields))
                return -ENOENT;
-       }
 
        evmcs_field = &vmcs_field_to_evmcs_1[index];
 
+       /*
+        * Use offset=0 to detect holes in eVMCS. This offset belongs to
+        * 'revision_id' but this field has no encoding and is supposed to
+        * be accessed directly.
+        */
+       if (unlikely(!evmcs_field->offset))
+               return -ENOENT;
+
        if (clean_field)
                *clean_field = evmcs_field->clean_field;
 
        return evmcs_field->offset;
 }
 
+static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs,
+                                unsigned long field, u16 offset)
+{
+       /*
+        * vmcs12_read_any() doesn't care whether the supplied structure
+        * is 'struct vmcs12' or 'struct hv_enlightened_vmcs' as it takes
+        * the exact offset of the required field, use it for convenience
+        * here.
+        */
+       return vmcs12_read_any((void *)evmcs, field, offset);
+}
+
+#if IS_ENABLED(CONFIG_HYPERV)
+
+static __always_inline int get_evmcs_offset(unsigned long field,
+                                           u16 *clean_field)
+{
+       int offset = evmcs_field_offset(field, clean_field);
+
+       WARN_ONCE(offset < 0, "KVM: accessing unsupported EVMCS field %lx\n",
+                 field);
+
+       return offset;
+}
+
 static __always_inline void evmcs_write64(unsigned long field, u64 value)
 {
        u16 clean_field;
index f235f77..ba34e94 100644 (file)
@@ -7,6 +7,7 @@
 #include <asm/mmu_context.h>
 
 #include "cpuid.h"
+#include "evmcs.h"
 #include "hyperv.h"
 #include "mmu.h"
 #include "nested.h"
@@ -4851,18 +4852,20 @@ static struct vmcs *alloc_shadow_vmcs(struct kvm_vcpu *vcpu)
        struct loaded_vmcs *loaded_vmcs = vmx->loaded_vmcs;
 
        /*
-        * We should allocate a shadow vmcs for vmcs01 only when L1
-        * executes VMXON and free it when L1 executes VMXOFF.
-        * As it is invalid to execute VMXON twice, we shouldn't reach
-        * here when vmcs01 already have an allocated shadow vmcs.
+        * KVM allocates a shadow VMCS only when L1 executes VMXON and frees it
+        * when L1 executes VMXOFF or the vCPU is forced out of nested
+        * operation.  VMXON faults if the CPU is already post-VMXON, so it
+        * should be impossible to already have an allocated shadow VMCS.  KVM
+        * doesn't support virtualization of VMCS shadowing, so vmcs01 should
+        * always be the loaded VMCS.
         */
-       WARN_ON(loaded_vmcs == &vmx->vmcs01 && loaded_vmcs->shadow_vmcs);
+       if (WARN_ON(loaded_vmcs != &vmx->vmcs01 || loaded_vmcs->shadow_vmcs))
+               return loaded_vmcs->shadow_vmcs;
+
+       loaded_vmcs->shadow_vmcs = alloc_vmcs(true);
+       if (loaded_vmcs->shadow_vmcs)
+               vmcs_clear(loaded_vmcs->shadow_vmcs);
 
-       if (!loaded_vmcs->shadow_vmcs) {
-               loaded_vmcs->shadow_vmcs = alloc_vmcs(true);
-               if (loaded_vmcs->shadow_vmcs)
-                       vmcs_clear(loaded_vmcs->shadow_vmcs);
-       }
        return loaded_vmcs->shadow_vmcs;
 }
 
@@ -5099,27 +5102,49 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
        if (!nested_vmx_check_permission(vcpu))
                return 1;
 
-       /*
-        * In VMX non-root operation, when the VMCS-link pointer is INVALID_GPA,
-        * any VMREAD sets the ALU flags for VMfailInvalid.
-        */
-       if (vmx->nested.current_vmptr == INVALID_GPA ||
-           (is_guest_mode(vcpu) &&
-            get_vmcs12(vcpu)->vmcs_link_pointer == INVALID_GPA))
-               return nested_vmx_failInvalid(vcpu);
-
        /* Decode instruction info and find the field to read */
        field = kvm_register_read(vcpu, (((instr_info) >> 28) & 0xf));
 
-       offset = vmcs_field_to_offset(field);
-       if (offset < 0)
-               return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
+       if (!evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
+               /*
+                * In VMX non-root operation, when the VMCS-link pointer is INVALID_GPA,
+                * any VMREAD sets the ALU flags for VMfailInvalid.
+                */
+               if (vmx->nested.current_vmptr == INVALID_GPA ||
+                   (is_guest_mode(vcpu) &&
+                    get_vmcs12(vcpu)->vmcs_link_pointer == INVALID_GPA))
+                       return nested_vmx_failInvalid(vcpu);
 
-       if (!is_guest_mode(vcpu) && is_vmcs12_ext_field(field))
-               copy_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
+               offset = get_vmcs12_field_offset(field);
+               if (offset < 0)
+                       return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
+
+               if (!is_guest_mode(vcpu) && is_vmcs12_ext_field(field))
+                       copy_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
 
-       /* Read the field, zero-extended to a u64 value */
-       value = vmcs12_read_any(vmcs12, field, offset);
+               /* Read the field, zero-extended to a u64 value */
+               value = vmcs12_read_any(vmcs12, field, offset);
+       } else {
+               /*
+                * Hyper-V TLFS (as of 6.0b) explicitly states, that while an
+                * enlightened VMCS is active VMREAD/VMWRITE instructions are
+                * unsupported. Unfortunately, certain versions of Windows 11
+                * don't comply with this requirement which is not enforced in
+                * genuine Hyper-V. Allow VMREAD from an enlightened VMCS as a
+                * workaround, as misbehaving guests will panic on VM-Fail.
+                * Note, enlightened VMCS is incompatible with shadow VMCS so
+                * all VMREADs from L2 should go to L1.
+                */
+               if (WARN_ON_ONCE(is_guest_mode(vcpu)))
+                       return nested_vmx_failInvalid(vcpu);
+
+               offset = evmcs_field_offset(field, NULL);
+               if (offset < 0)
+                       return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
+
+               /* Read the field, zero-extended to a u64 value */
+               value = evmcs_read_any(vmx->nested.hv_evmcs, field, offset);
+       }
 
        /*
         * Now copy part of this value to register or memory, as requested.
@@ -5214,7 +5239,7 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu)
 
        field = kvm_register_read(vcpu, (((instr_info) >> 28) & 0xf));
 
-       offset = vmcs_field_to_offset(field);
+       offset = get_vmcs12_field_offset(field);
        if (offset < 0)
                return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
 
@@ -6462,7 +6487,7 @@ static u64 nested_vmx_calc_vmcs_enum_msr(void)
        max_idx = 0;
        for (i = 0; i < nr_vmcs12_fields; i++) {
                /* The vmcs12 table is very, very sparsely populated. */
-               if (!vmcs_field_to_offset_table[i])
+               if (!vmcs12_field_offsets[i])
                        continue;
 
                idx = vmcs_field_index(VMCS12_IDX_TO_ENC(i));
@@ -6771,6 +6796,7 @@ __init int nested_vmx_hardware_setup(int (*exit_handlers[])(struct kvm_vcpu *))
 }
 
 struct kvm_x86_nested_ops vmx_nested_ops = {
+       .leave_nested = vmx_leave_nested,
        .check_events = vmx_check_nested_events,
        .hv_timer_pending = nested_vmx_preemption_timer_pending,
        .triple_fault = nested_vmx_triple_fault,
index cab6ba7..2251b60 100644 (file)
@@ -8,7 +8,7 @@
        FIELD(number, name),                                            \
        [ROL16(number##_HIGH, 6)] = VMCS12_OFFSET(name) + sizeof(u32)
 
-const unsigned short vmcs_field_to_offset_table[] = {
+const unsigned short vmcs12_field_offsets[] = {
        FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id),
        FIELD(POSTED_INTR_NV, posted_intr_nv),
        FIELD(GUEST_ES_SELECTOR, guest_es_selector),
@@ -151,4 +151,4 @@ const unsigned short vmcs_field_to_offset_table[] = {
        FIELD(HOST_RSP, host_rsp),
        FIELD(HOST_RIP, host_rip),
 };
-const unsigned int nr_vmcs12_fields = ARRAY_SIZE(vmcs_field_to_offset_table);
+const unsigned int nr_vmcs12_fields = ARRAY_SIZE(vmcs12_field_offsets);
index 2a45f02..746129d 100644 (file)
@@ -361,10 +361,10 @@ static inline void vmx_check_vmcs12_offsets(void)
        CHECK_OFFSET(guest_pml_index, 996);
 }
 
-extern const unsigned short vmcs_field_to_offset_table[];
+extern const unsigned short vmcs12_field_offsets[];
 extern const unsigned int nr_vmcs12_fields;
 
-static inline short vmcs_field_to_offset(unsigned long field)
+static inline short get_vmcs12_field_offset(unsigned long field)
 {
        unsigned short offset;
        unsigned int index;
@@ -377,7 +377,7 @@ static inline short vmcs_field_to_offset(unsigned long field)
                return -ENOENT;
 
        index = array_index_nospec(index, nr_vmcs12_fields);
-       offset = vmcs_field_to_offset_table[index];
+       offset = vmcs12_field_offsets[index];
        if (offset == 0)
                return -ENOENT;
        return offset;
index 4ac6760..efda5e4 100644 (file)
@@ -1487,11 +1487,12 @@ static int vmx_rtit_ctl_check(struct kvm_vcpu *vcpu, u64 data)
        return 0;
 }
 
-static bool vmx_can_emulate_instruction(struct kvm_vcpu *vcpu, void *insn, int insn_len)
+static bool vmx_can_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type,
+                                       void *insn, int insn_len)
 {
        /*
         * Emulation of instructions in SGX enclaves is impossible as RIP does
-        * not point  tthe failing instruction, and even if it did, the code
+        * not point at the failing instruction, and even if it did, the code
         * stream is inaccessible.  Inject #UD instead of exiting to userspace
         * so that guest userspace can't DoS the guest simply by triggering
         * emulation (enclaves are CPL3 only).
@@ -2603,7 +2604,6 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf,
                return -EIO;
 
        vmcs_conf->size = vmx_msr_high & 0x1fff;
-       vmcs_conf->order = get_order(vmcs_conf->size);
        vmcs_conf->basic_cap = vmx_msr_high & ~0x1fff;
 
        vmcs_conf->revision_id = vmx_msr_low;
@@ -2628,7 +2628,7 @@ struct vmcs *alloc_vmcs_cpu(bool shadow, int cpu, gfp_t flags)
        struct page *pages;
        struct vmcs *vmcs;
 
-       pages = __alloc_pages_node(node, flags, vmcs_config.order);
+       pages = __alloc_pages_node(node, flags, 0);
        if (!pages)
                return NULL;
        vmcs = page_address(pages);
@@ -2647,7 +2647,7 @@ struct vmcs *alloc_vmcs_cpu(bool shadow, int cpu, gfp_t flags)
 
 void free_vmcs(struct vmcs *vmcs)
 {
-       free_pages((unsigned long)vmcs, vmcs_config.order);
+       free_page((unsigned long)vmcs);
 }
 
 /*
@@ -4041,6 +4041,21 @@ static int vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector)
        return 0;
 }
 
+static void vmx_deliver_interrupt(struct kvm_lapic *apic, int delivery_mode,
+                                 int trig_mode, int vector)
+{
+       struct kvm_vcpu *vcpu = apic->vcpu;
+
+       if (vmx_deliver_posted_interrupt(vcpu, vector)) {
+               kvm_lapic_set_irr(vector, apic);
+               kvm_make_request(KVM_REQ_EVENT, vcpu);
+               kvm_vcpu_kick(vcpu);
+       } else {
+               trace_kvm_apicv_accept_irq(vcpu->vcpu_id, delivery_mode,
+                                          trig_mode, vector);
+       }
+}
+
 /*
  * Set up the vmcs's constant host-state fields, i.e., host-state fields that
  * will not change in the lifetime of the guest.
@@ -4094,10 +4109,14 @@ void vmx_set_constant_host_state(struct vcpu_vmx *vmx)
        vmcs_write32(HOST_IA32_SYSENTER_CS, low32);
 
        /*
-        * If 32-bit syscall is enabled, vmx_vcpu_load_vcms rewrites
-        * HOST_IA32_SYSENTER_ESP.
+        * SYSENTER is used for 32-bit system calls on either 32-bit or
+        * 64-bit kernels.  It is always zero If neither is allowed, otherwise
+        * vmx_vcpu_load_vmcs loads it with the per-CPU entry stack (and may
+        * have already done so!).
         */
-       vmcs_writel(HOST_IA32_SYSENTER_ESP, 0);
+       if (!IS_ENABLED(CONFIG_IA32_EMULATION) && !IS_ENABLED(CONFIG_X86_32))
+               vmcs_writel(HOST_IA32_SYSENTER_ESP, 0);
+
        rdmsrl(MSR_IA32_SYSENTER_EIP, tmpl);
        vmcs_writel(HOST_IA32_SYSENTER_EIP, tmpl);   /* 22.2.3 */
 
@@ -4901,8 +4920,33 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu)
                dr6 = vmx_get_exit_qual(vcpu);
                if (!(vcpu->guest_debug &
                      (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))) {
+                       /*
+                        * If the #DB was due to ICEBP, a.k.a. INT1, skip the
+                        * instruction.  ICEBP generates a trap-like #DB, but
+                        * despite its interception control being tied to #DB,
+                        * is an instruction intercept, i.e. the VM-Exit occurs
+                        * on the ICEBP itself.  Note, skipping ICEBP also
+                        * clears STI and MOVSS blocking.
+                        *
+                        * For all other #DBs, set vmcs.PENDING_DBG_EXCEPTIONS.BS
+                        * if single-step is enabled in RFLAGS and STI or MOVSS
+                        * blocking is active, as the CPU doesn't set the bit
+                        * on VM-Exit due to #DB interception.  VM-Entry has a
+                        * consistency check that a single-step #DB is pending
+                        * in this scenario as the previous instruction cannot
+                        * have toggled RFLAGS.TF 0=>1 (because STI and POP/MOV
+                        * don't modify RFLAGS), therefore the one instruction
+                        * delay when activating single-step breakpoints must
+                        * have already expired.  Note, the CPU sets/clears BS
+                        * as appropriate for all other VM-Exits types.
+                        */
                        if (is_icebp(intr_info))
                                WARN_ON(!skip_emulated_instruction(vcpu));
+                       else if ((vmx_get_rflags(vcpu) & X86_EFLAGS_TF) &&
+                                (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) &
+                                 (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)))
+                               vmcs_writel(GUEST_PENDING_DBG_EXCEPTIONS,
+                                           vmcs_readl(GUEST_PENDING_DBG_EXCEPTIONS) | DR6_BS);
 
                        kvm_queue_exception_p(vcpu, DB_VECTOR, dr6);
                        return 1;
@@ -5397,7 +5441,7 @@ static int handle_ept_misconfig(struct kvm_vcpu *vcpu)
 {
        gpa_t gpa;
 
-       if (!vmx_can_emulate_instruction(vcpu, NULL, 0))
+       if (!vmx_can_emulate_instruction(vcpu, EMULTYPE_PF, NULL, 0))
                return 1;
 
        /*
@@ -6725,7 +6769,7 @@ static fastpath_t vmx_exit_handlers_fastpath(struct kvm_vcpu *vcpu)
 static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
                                        struct vcpu_vmx *vmx)
 {
-       kvm_guest_enter_irqoff();
+       guest_state_enter_irqoff();
 
        /* L1D Flush includes CPU buffer clear to mitigate MDS */
        if (static_branch_unlikely(&vmx_l1d_should_flush))
@@ -6741,7 +6785,7 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
 
        vcpu->arch.cr2 = native_read_cr2();
 
-       kvm_guest_exit_irqoff();
+       guest_state_exit_irqoff();
 }
 
 static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu)
@@ -7615,6 +7659,7 @@ static int vmx_leave_smm(struct kvm_vcpu *vcpu, const char *smstate)
                if (ret)
                        return ret;
 
+               vmx->nested.nested_run_pending = 1;
                vmx->nested.smm.guest_mode = false;
        }
        return 0;
@@ -7739,7 +7784,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
        .hwapic_isr_update = vmx_hwapic_isr_update,
        .guest_apic_has_interrupt = vmx_guest_apic_has_interrupt,
        .sync_pir_to_irr = vmx_sync_pir_to_irr,
-       .deliver_posted_interrupt = vmx_deliver_posted_interrupt,
+       .deliver_interrupt = vmx_deliver_interrupt,
        .dy_apicv_has_pending_interrupt = pi_has_pending_interrupt,
 
        .set_tss_addr = vmx_set_tss_addr,
index 9e43d75..82a9dcd 100644 (file)
@@ -90,6 +90,8 @@
 u64 __read_mostly kvm_mce_cap_supported = MCG_CTL_P | MCG_SER_P;
 EXPORT_SYMBOL_GPL(kvm_mce_cap_supported);
 
+#define  ERR_PTR_USR(e)  ((void __user *)ERR_PTR(e))
+
 #define emul_to_vcpu(ctxt) \
        ((struct kvm_vcpu *)(ctxt)->vcpu)
 
@@ -982,6 +984,18 @@ void kvm_load_host_xsave_state(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_load_host_xsave_state);
 
+static inline u64 kvm_guest_supported_xcr0(struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.guest_fpu.fpstate->user_xfeatures;
+}
+
+#ifdef CONFIG_X86_64
+static inline u64 kvm_guest_supported_xfd(struct kvm_vcpu *vcpu)
+{
+       return kvm_guest_supported_xcr0(vcpu) & XFEATURE_MASK_USER_DYNAMIC;
+}
+#endif
+
 static int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
 {
        u64 xcr0 = xcr;
@@ -1001,7 +1015,7 @@ static int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
         * saving.  However, xcr0 bit 0 is always set, even if the
         * emulated CPU does not support XSAVE (see kvm_vcpu_reset()).
         */
-       valid_bits = vcpu->arch.guest_supported_xcr0 | XFEATURE_MASK_FP;
+       valid_bits = kvm_guest_supported_xcr0(vcpu) | XFEATURE_MASK_FP;
        if (xcr0 & ~valid_bits)
                return 1;
 
@@ -2349,10 +2363,12 @@ static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)
        return tsc;
 }
 
+#ifdef CONFIG_X86_64
 static inline int gtod_is_based_on_tsc(int mode)
 {
        return mode == VDSO_CLOCKMODE_TSC || mode == VDSO_CLOCKMODE_HVCLOCK;
 }
+#endif
 
 static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu)
 {
@@ -3535,6 +3551,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                if (data & ~supported_xss)
                        return 1;
                vcpu->arch.ia32_xss = data;
+               kvm_update_cpuid_runtime(vcpu);
                break;
        case MSR_SMI_COUNT:
                if (!msr_info->host_initiated)
@@ -3703,8 +3720,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                    !guest_cpuid_has(vcpu, X86_FEATURE_XFD))
                        return 1;
 
-               if (data & ~(XFEATURE_MASK_USER_DYNAMIC &
-                            vcpu->arch.guest_supported_xcr0))
+               if (data & ~kvm_guest_supported_xfd(vcpu))
                        return 1;
 
                fpu_update_guest_xfd(&vcpu->arch.guest_fpu, data);
@@ -3714,8 +3730,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                    !guest_cpuid_has(vcpu, X86_FEATURE_XFD))
                        return 1;
 
-               if (data & ~(XFEATURE_MASK_USER_DYNAMIC &
-                            vcpu->arch.guest_supported_xcr0))
+               if (data & ~kvm_guest_supported_xfd(vcpu))
                        return 1;
 
                vcpu->arch.guest_fpu.xfd_err = data;
@@ -4229,6 +4244,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_SREGS2:
        case KVM_CAP_EXIT_ON_EMULATION_FAILURE:
        case KVM_CAP_VCPU_ATTRIBUTES:
+       case KVM_CAP_SYS_ATTRIBUTES:
+       case KVM_CAP_ENABLE_CAP:
                r = 1;
                break;
        case KVM_CAP_EXIT_HYPERCALL:
@@ -4331,7 +4348,49 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
                break;
        }
        return r;
+}
+
+static inline void __user *kvm_get_attr_addr(struct kvm_device_attr *attr)
+{
+       void __user *uaddr = (void __user*)(unsigned long)attr->addr;
 
+       if ((u64)(unsigned long)uaddr != attr->addr)
+               return ERR_PTR_USR(-EFAULT);
+       return uaddr;
+}
+
+static int kvm_x86_dev_get_attr(struct kvm_device_attr *attr)
+{
+       u64 __user *uaddr = kvm_get_attr_addr(attr);
+
+       if (attr->group)
+               return -ENXIO;
+
+       if (IS_ERR(uaddr))
+               return PTR_ERR(uaddr);
+
+       switch (attr->attr) {
+       case KVM_X86_XCOMP_GUEST_SUPP:
+               if (put_user(supported_xcr0, uaddr))
+                       return -EFAULT;
+               return 0;
+       default:
+               return -ENXIO;
+               break;
+       }
+}
+
+static int kvm_x86_dev_has_attr(struct kvm_device_attr *attr)
+{
+       if (attr->group)
+               return -ENXIO;
+
+       switch (attr->attr) {
+       case KVM_X86_XCOMP_GUEST_SUPP:
+               return 0;
+       default:
+               return -ENXIO;
+       }
 }
 
 long kvm_arch_dev_ioctl(struct file *filp,
@@ -4422,6 +4481,22 @@ long kvm_arch_dev_ioctl(struct file *filp,
        case KVM_GET_SUPPORTED_HV_CPUID:
                r = kvm_ioctl_get_supported_hv_cpuid(NULL, argp);
                break;
+       case KVM_GET_DEVICE_ATTR: {
+               struct kvm_device_attr attr;
+               r = -EFAULT;
+               if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
+                       break;
+               r = kvm_x86_dev_get_attr(&attr);
+               break;
+       }
+       case KVM_HAS_DEVICE_ATTR: {
+               struct kvm_device_attr attr;
+               r = -EFAULT;
+               if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
+                       break;
+               r = kvm_x86_dev_has_attr(&attr);
+               break;
+       }
        default:
                r = -EINVAL;
                break;
@@ -4860,8 +4935,10 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
                vcpu->arch.apic->sipi_vector = events->sipi_vector;
 
        if (events->flags & KVM_VCPUEVENT_VALID_SMM) {
-               if (!!(vcpu->arch.hflags & HF_SMM_MASK) != events->smi.smm)
+               if (!!(vcpu->arch.hflags & HF_SMM_MASK) != events->smi.smm) {
+                       kvm_x86_ops.nested_ops->leave_nested(vcpu);
                        kvm_smm_changed(vcpu, events->smi.smm);
+               }
 
                vcpu->arch.smi_pending = events->smi.pending;
 
@@ -5022,11 +5099,11 @@ static int kvm_arch_tsc_has_attr(struct kvm_vcpu *vcpu,
 static int kvm_arch_tsc_get_attr(struct kvm_vcpu *vcpu,
                                 struct kvm_device_attr *attr)
 {
-       u64 __user *uaddr = (u64 __user *)(unsigned long)attr->addr;
+       u64 __user *uaddr = kvm_get_attr_addr(attr);
        int r;
 
-       if ((u64)(unsigned long)uaddr != attr->addr)
-               return -EFAULT;
+       if (IS_ERR(uaddr))
+               return PTR_ERR(uaddr);
 
        switch (attr->attr) {
        case KVM_VCPU_TSC_OFFSET:
@@ -5045,12 +5122,12 @@ static int kvm_arch_tsc_get_attr(struct kvm_vcpu *vcpu,
 static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcpu,
                                 struct kvm_device_attr *attr)
 {
-       u64 __user *uaddr = (u64 __user *)(unsigned long)attr->addr;
+       u64 __user *uaddr = kvm_get_attr_addr(attr);
        struct kvm *kvm = vcpu->kvm;
        int r;
 
-       if ((u64)(unsigned long)uaddr != attr->addr)
-               return -EFAULT;
+       if (IS_ERR(uaddr))
+               return PTR_ERR(uaddr);
 
        switch (attr->attr) {
        case KVM_VCPU_TSC_OFFSET: {
@@ -6810,6 +6887,13 @@ int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val,
 }
 EXPORT_SYMBOL_GPL(kvm_write_guest_virt_system);
 
+static int kvm_can_emulate_insn(struct kvm_vcpu *vcpu, int emul_type,
+                               void *insn, int insn_len)
+{
+       return static_call(kvm_x86_can_emulate_instruction)(vcpu, emul_type,
+                                                           insn, insn_len);
+}
+
 int handle_ud(struct kvm_vcpu *vcpu)
 {
        static const char kvm_emulate_prefix[] = { __KVM_EMULATE_PREFIX };
@@ -6817,7 +6901,7 @@ int handle_ud(struct kvm_vcpu *vcpu)
        char sig[5]; /* ud2; .ascii "kvm" */
        struct x86_exception e;
 
-       if (unlikely(!static_call(kvm_x86_can_emulate_instruction)(vcpu, NULL, 0)))
+       if (unlikely(!kvm_can_emulate_insn(vcpu, emul_type, NULL, 0)))
                return 1;
 
        if (force_emulation_prefix &&
@@ -8193,7 +8277,7 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
        bool writeback = true;
        bool write_fault_to_spt;
 
-       if (unlikely(!static_call(kvm_x86_can_emulate_instruction)(vcpu, insn, insn_len)))
+       if (unlikely(!kvm_can_emulate_insn(vcpu, emulation_type, insn, insn_len)))
                return 1;
 
        vcpu->arch.l1tf_flush_l1d = true;
@@ -8871,6 +8955,13 @@ static int kvm_pv_clock_pairing(struct kvm_vcpu *vcpu, gpa_t paddr,
        if (clock_type != KVM_CLOCK_PAIRING_WALLCLOCK)
                return -KVM_EOPNOTSUPP;
 
+       /*
+        * When tsc is in permanent catchup mode guests won't be able to use
+        * pvclock_read_retry loop to get consistent view of pvclock
+        */
+       if (vcpu->arch.tsc_always_catchup)
+               return -KVM_EOPNOTSUPP;
+
        if (!kvm_get_walltime_and_clockread(&ts, &cycle))
                return -KVM_EOPNOTSUPP;
 
@@ -9706,7 +9797,7 @@ void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
                kvm_make_all_cpus_request(kvm, KVM_REQ_APIC_PAGE_RELOAD);
 }
 
-void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu)
+static void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu)
 {
        if (!lapic_in_kernel(vcpu))
                return;
@@ -9912,7 +10003,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
         * result in virtual interrupt delivery.
         */
        local_irq_disable();
-       vcpu->mode = IN_GUEST_MODE;
+
+       /* Store vcpu->apicv_active before vcpu->mode.  */
+       smp_store_release(&vcpu->mode, IN_GUEST_MODE);
 
        srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
 
@@ -9972,6 +10065,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                set_debugreg(0, 7);
        }
 
+       guest_timing_enter_irqoff();
+
        for (;;) {
                /*
                 * Assert that vCPU vs. VM APICv state is consistent.  An APICv
@@ -10056,7 +10151,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
         * of accounting via context tracking, but the loss of accuracy is
         * acceptable for all known use cases.
         */
-       vtime_account_guest_exit();
+       guest_timing_exit_irqoff();
 
        if (lapic_in_kernel(vcpu)) {
                s64 delta = vcpu->arch.apic->lapic_timer.advance_expire_delta;
@@ -11209,7 +11304,8 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
 
                vcpu->arch.msr_misc_features_enables = 0;
 
-               vcpu->arch.xcr0 = XFEATURE_MASK_FP;
+               __kvm_set_xcr(vcpu, 0, XFEATURE_MASK_FP);
+               __kvm_set_msr(vcpu, MSR_IA32_XSS, 0, true);
        }
 
        /* All GPRs except RDX (handled below) are zeroed on RESET/INIT. */
@@ -11226,8 +11322,6 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
        cpuid_0x1 = kvm_find_cpuid_entry(vcpu, 1, 0);
        kvm_rdx_write(vcpu, cpuid_0x1 ? cpuid_0x1->eax : 0x600);
 
-       vcpu->arch.ia32_xss = 0;
-
        static_call(kvm_x86_vcpu_reset)(vcpu, init_event);
 
        kvm_set_rflags(vcpu, X86_EFLAGS_FIXED);
@@ -11571,8 +11665,6 @@ void kvm_arch_sync_events(struct kvm *kvm)
        kvm_free_pit(kvm);
 }
 
-#define  ERR_PTR_USR(e)  ((void __user *)ERR_PTR(e))
-
 /**
  * __x86_set_memory_region: Setup KVM internal memory slot
  *
index 635b75f..767ec7f 100644 (file)
 
 void kvm_spurious_fault(void);
 
-static __always_inline void kvm_guest_enter_irqoff(void)
-{
-       /*
-        * VMENTER enables interrupts (host state), but the kernel state is
-        * interrupts disabled when this is invoked. Also tell RCU about
-        * it. This is the same logic as for exit_to_user_mode().
-        *
-        * This ensures that e.g. latency analysis on the host observes
-        * guest mode as interrupt enabled.
-        *
-        * guest_enter_irqoff() informs context tracking about the
-        * transition to guest mode and if enabled adjusts RCU state
-        * accordingly.
-        */
-       instrumentation_begin();
-       trace_hardirqs_on_prepare();
-       lockdep_hardirqs_on_prepare(CALLER_ADDR0);
-       instrumentation_end();
-
-       guest_enter_irqoff();
-       lockdep_hardirqs_on(CALLER_ADDR0);
-}
-
-static __always_inline void kvm_guest_exit_irqoff(void)
-{
-       /*
-        * VMEXIT disables interrupts (host state), but tracing and lockdep
-        * have them in state 'on' as recorded before entering guest mode.
-        * Same as enter_from_user_mode().
-        *
-        * context_tracking_guest_exit() restores host context and reinstates
-        * RCU if enabled and required.
-        *
-        * This needs to be done immediately after VM-Exit, before any code
-        * that might contain tracepoints or call out to the greater world,
-        * e.g. before x86_spec_ctrl_restore_host().
-        */
-       lockdep_hardirqs_off(CALLER_ADDR0);
-       context_tracking_guest_exit();
-
-       instrumentation_begin();
-       trace_hardirqs_off_finish();
-       instrumentation_end();
-}
-
 #define KVM_NESTED_VMENTER_CONSISTENCY_CHECK(consistency_check)                \
 ({                                                                     \
        bool failed = (consistency_check);                              \
index 0e3f7d6..74be1fd 100644 (file)
@@ -133,32 +133,57 @@ static void kvm_xen_update_runstate(struct kvm_vcpu *v, int state)
 void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, int state)
 {
        struct kvm_vcpu_xen *vx = &v->arch.xen;
+       struct gfn_to_hva_cache *ghc = &vx->runstate_cache;
+       struct kvm_memslots *slots = kvm_memslots(v->kvm);
+       bool atomic = (state == RUNSTATE_runnable);
        uint64_t state_entry_time;
-       unsigned int offset;
+       int __user *user_state;
+       uint64_t __user *user_times;
 
        kvm_xen_update_runstate(v, state);
 
        if (!vx->runstate_set)
                return;
 
-       BUILD_BUG_ON(sizeof(struct compat_vcpu_runstate_info) != 0x2c);
+       if (unlikely(slots->generation != ghc->generation || kvm_is_error_hva(ghc->hva)) &&
+           kvm_gfn_to_hva_cache_init(v->kvm, ghc, ghc->gpa, ghc->len))
+               return;
+
+       /* We made sure it fits in a single page */
+       BUG_ON(!ghc->memslot);
+
+       if (atomic)
+               pagefault_disable();
 
-       offset = offsetof(struct compat_vcpu_runstate_info, state_entry_time);
-#ifdef CONFIG_X86_64
        /*
-        * The only difference is alignment of uint64_t in 32-bit.
-        * So the first field 'state' is accessed directly using
-        * offsetof() (where its offset happens to be zero), while the
-        * remaining fields which are all uint64_t, start at 'offset'
-        * which we tweak here by adding 4.
+        * The only difference between 32-bit and 64-bit versions of the
+        * runstate struct us the alignment of uint64_t in 32-bit, which
+        * means that the 64-bit version has an additional 4 bytes of
+        * padding after the first field 'state'.
+        *
+        * So we use 'int __user *user_state' to point to the state field,
+        * and 'uint64_t __user *user_times' for runstate_entry_time. So
+        * the actual array of time[] in each state starts at user_times[1].
         */
+       BUILD_BUG_ON(offsetof(struct vcpu_runstate_info, state) != 0);
+       BUILD_BUG_ON(offsetof(struct compat_vcpu_runstate_info, state) != 0);
+       user_state = (int __user *)ghc->hva;
+
+       BUILD_BUG_ON(sizeof(struct compat_vcpu_runstate_info) != 0x2c);
+
+       user_times = (uint64_t __user *)(ghc->hva +
+                                        offsetof(struct compat_vcpu_runstate_info,
+                                                 state_entry_time));
+#ifdef CONFIG_X86_64
        BUILD_BUG_ON(offsetof(struct vcpu_runstate_info, state_entry_time) !=
                     offsetof(struct compat_vcpu_runstate_info, state_entry_time) + 4);
        BUILD_BUG_ON(offsetof(struct vcpu_runstate_info, time) !=
                     offsetof(struct compat_vcpu_runstate_info, time) + 4);
 
        if (v->kvm->arch.xen.long_mode)
-               offset = offsetof(struct vcpu_runstate_info, state_entry_time);
+               user_times = (uint64_t __user *)(ghc->hva +
+                                                offsetof(struct vcpu_runstate_info,
+                                                         state_entry_time));
 #endif
        /*
         * First write the updated state_entry_time at the appropriate
@@ -172,10 +197,8 @@ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, int state)
        BUILD_BUG_ON(sizeof_field(struct compat_vcpu_runstate_info, state_entry_time) !=
                     sizeof(state_entry_time));
 
-       if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache,
-                                         &state_entry_time, offset,
-                                         sizeof(state_entry_time)))
-               return;
+       if (__put_user(state_entry_time, user_times))
+               goto out;
        smp_wmb();
 
        /*
@@ -189,11 +212,8 @@ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, int state)
        BUILD_BUG_ON(sizeof_field(struct compat_vcpu_runstate_info, state) !=
                     sizeof(vx->current_runstate));
 
-       if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache,
-                                         &vx->current_runstate,
-                                         offsetof(struct vcpu_runstate_info, state),
-                                         sizeof(vx->current_runstate)))
-               return;
+       if (__put_user(vx->current_runstate, user_state))
+               goto out;
 
        /*
         * Write the actual runstate times immediately after the
@@ -208,24 +228,23 @@ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, int state)
        BUILD_BUG_ON(sizeof_field(struct vcpu_runstate_info, time) !=
                     sizeof(vx->runstate_times));
 
-       if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache,
-                                         &vx->runstate_times[0],
-                                         offset + sizeof(u64),
-                                         sizeof(vx->runstate_times)))
-               return;
-
+       if (__copy_to_user(user_times + 1, vx->runstate_times, sizeof(vx->runstate_times)))
+               goto out;
        smp_wmb();
 
        /*
         * Finally, clear the XEN_RUNSTATE_UPDATE bit in the guest's
         * runstate_entry_time field.
         */
-
        state_entry_time &= ~XEN_RUNSTATE_UPDATE;
-       if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache,
-                                         &state_entry_time, offset,
-                                         sizeof(state_entry_time)))
-               return;
+       __put_user(state_entry_time, user_times);
+       smp_wmb();
+
+ out:
+       mark_page_dirty_in_slot(v->kvm, ghc->memslot, ghc->gpa >> PAGE_SHIFT);
+
+       if (atomic)
+               pagefault_enable();
 }
 
 int __kvm_xen_has_interrupt(struct kvm_vcpu *v)
@@ -316,10 +335,7 @@ int __kvm_xen_has_interrupt(struct kvm_vcpu *v)
                                     "\tnotq %0\n"
                                     "\t" LOCK_PREFIX "andq %0, %2\n"
                                     "2:\n"
-                                    "\t.section .fixup,\"ax\"\n"
-                                    "3:\tjmp\t2b\n"
-                                    "\t.previous\n"
-                                    _ASM_EXTABLE_UA(1b, 3b)
+                                    _ASM_EXTABLE_UA(1b, 2b)
                                     : "=r" (evtchn_pending_sel),
                                       "+m" (vi->evtchn_pending_sel),
                                       "+m" (v->arch.xen.evtchn_pending_sel)
@@ -335,10 +351,7 @@ int __kvm_xen_has_interrupt(struct kvm_vcpu *v)
                                     "\tnotl %0\n"
                                     "\t" LOCK_PREFIX "andl %0, %2\n"
                                     "2:\n"
-                                    "\t.section .fixup,\"ax\"\n"
-                                    "3:\tjmp\t2b\n"
-                                    "\t.previous\n"
-                                    _ASM_EXTABLE_UA(1b, 3b)
+                                    _ASM_EXTABLE_UA(1b, 2b)
                                     : "=r" (evtchn_pending_sel32),
                                       "+m" (vi->evtchn_pending_sel),
                                       "+m" (v->arch.xen.evtchn_pending_sel)
@@ -449,6 +462,12 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
                        break;
                }
 
+               /* It must fit within a single page */
+               if ((data->u.gpa & ~PAGE_MASK) + sizeof(struct vcpu_info) > PAGE_SIZE) {
+                       r = -EINVAL;
+                       break;
+               }
+
                r = kvm_gfn_to_hva_cache_init(vcpu->kvm,
                                              &vcpu->arch.xen.vcpu_info_cache,
                                              data->u.gpa,
@@ -466,6 +485,12 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
                        break;
                }
 
+               /* It must fit within a single page */
+               if ((data->u.gpa & ~PAGE_MASK) + sizeof(struct pvclock_vcpu_time_info) > PAGE_SIZE) {
+                       r = -EINVAL;
+                       break;
+               }
+
                r = kvm_gfn_to_hva_cache_init(vcpu->kvm,
                                              &vcpu->arch.xen.vcpu_time_info_cache,
                                              data->u.gpa,
@@ -487,6 +512,12 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
                        break;
                }
 
+               /* It must fit within a single page */
+               if ((data->u.gpa & ~PAGE_MASK) + sizeof(struct vcpu_runstate_info) > PAGE_SIZE) {
+                       r = -EINVAL;
+                       break;
+               }
+
                r = kvm_gfn_to_hva_cache_init(vcpu->kvm,
                                              &vcpu->arch.xen.runstate_cache,
                                              data->u.gpa,
index 2edd866..615a76d 100644 (file)
@@ -353,8 +353,8 @@ static void pci_fixup_video(struct pci_dev *pdev)
                }
        }
 }
-DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
-                               PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video);
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID,
+                              PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video);
 
 
 static const struct dmi_system_id msi_k8t_dmi_table[] = {
index 4230094..517a9d8 100644 (file)
@@ -9,6 +9,7 @@
 #include <xen/events.h>
 #include <xen/interface/memory.h>
 
+#include <asm/apic.h>
 #include <asm/cpu.h>
 #include <asm/smp.h>
 #include <asm/io_apic.h>
@@ -184,8 +185,7 @@ static int xen_cpu_dead_hvm(unsigned int cpu)
 
        if (xen_have_vector_callback && xen_feature(XENFEAT_hvm_safe_pvclock))
                xen_teardown_timer(cpu);
-
-       return 0;
+       return 0;
 }
 
 static bool no_vector_callback __initdata;
@@ -242,15 +242,14 @@ static __init int xen_parse_no_vector_callback(char *arg)
 }
 early_param("xen_no_vector_callback", xen_parse_no_vector_callback);
 
-bool __init xen_hvm_need_lapic(void)
+static __init bool xen_x2apic_available(void)
 {
-       if (xen_pv_domain())
-               return false;
-       if (!xen_hvm_domain())
-               return false;
-       if (xen_feature(XENFEAT_hvm_pirqs) && xen_have_vector_callback)
-               return false;
-       return true;
+       return x2apic_supported();
+}
+
+static bool __init msi_ext_dest_id(void)
+{
+       return cpuid_eax(xen_cpuid_base() + 4) & XEN_HVM_CPUID_EXT_DEST_ID;
 }
 
 static __init void xen_hvm_guest_late_init(void)
@@ -312,9 +311,10 @@ struct hypervisor_x86 x86_hyper_xen_hvm __initdata = {
        .detect                 = xen_platform_hvm,
        .type                   = X86_HYPER_XEN_HVM,
        .init.init_platform     = xen_hvm_guest_init,
-       .init.x2apic_available  = xen_x2apic_para_available,
+       .init.x2apic_available  = xen_x2apic_available,
        .init.init_mem_mapping  = xen_hvm_init_mem_mapping,
        .init.guest_late_init   = xen_hvm_guest_late_init,
+       .init.msi_ext_dest_id   = msi_ext_dest_id,
        .runtime.pin_vcpu       = xen_pin_vcpu,
        .ignore_nopv            = true,
 };
index 5004feb..d47c3d1 100644 (file)
@@ -1341,10 +1341,6 @@ asmlinkage __visible void __init xen_start_kernel(void)
 
                xen_acpi_sleep_register();
 
-               /* Avoid searching for BIOS MP tables */
-               x86_init.mpparse.find_smp_config = x86_init_noop;
-               x86_init.mpparse.get_smp_config = x86_init_uint_noop;
-
                xen_boot_params_init_edd();
 
 #ifdef CONFIG_ACPI
index 6a8f3b5..4a60192 100644 (file)
@@ -148,28 +148,12 @@ int xen_smp_intr_init_pv(unsigned int cpu)
        return rc;
 }
 
-static void __init xen_fill_possible_map(void)
-{
-       int i, rc;
-
-       if (xen_initial_domain())
-               return;
-
-       for (i = 0; i < nr_cpu_ids; i++) {
-               rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
-               if (rc >= 0) {
-                       num_processors++;
-                       set_cpu_possible(i, true);
-               }
-       }
-}
-
-static void __init xen_filter_cpu_maps(void)
+static void __init _get_smp_config(unsigned int early)
 {
        int i, rc;
        unsigned int subtract = 0;
 
-       if (!xen_initial_domain())
+       if (early)
                return;
 
        num_processors = 0;
@@ -210,7 +194,6 @@ static void __init xen_pv_smp_prepare_boot_cpu(void)
                 * sure the old memory can be recycled. */
                make_lowmem_page_readwrite(xen_initial_gdt);
 
-       xen_filter_cpu_maps();
        xen_setup_vcpu_info_placement();
 
        /*
@@ -476,5 +459,8 @@ static const struct smp_ops xen_smp_ops __initconst = {
 void __init xen_smp_init(void)
 {
        smp_ops = xen_smp_ops;
-       xen_fill_possible_map();
+
+       /* Avoid searching for BIOS MP tables */
+       x86_init.mpparse.find_smp_config = x86_init_noop;
+       x86_init.mpparse.get_smp_config = _get_smp_config;
 }
index 31b1e34..14ea32e 100644 (file)
@@ -57,6 +57,14 @@ void __init xen_init_vga(const struct dom0_vga_console_info *info, size_t size)
                screen_info->rsvd_size = info->u.vesa_lfb.rsvd_size;
                screen_info->rsvd_pos = info->u.vesa_lfb.rsvd_pos;
 
+               if (size >= offsetof(struct dom0_vga_console_info,
+                                    u.vesa_lfb.ext_lfb_base)
+                   + sizeof(info->u.vesa_lfb.ext_lfb_base)
+                   && info->u.vesa_lfb.ext_lfb_base) {
+                       screen_info->ext_lfb_base = info->u.vesa_lfb.ext_lfb_base;
+                       screen_info->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
+               }
+
                if (info->video_type == XEN_VGATYPE_EFI_LFB) {
                        screen_info->orig_video_isVGA = VIDEO_TYPE_EFI;
                        break;
@@ -66,14 +74,6 @@ void __init xen_init_vga(const struct dom0_vga_console_info *info, size_t size)
                                     u.vesa_lfb.mode_attrs)
                    + sizeof(info->u.vesa_lfb.mode_attrs))
                        screen_info->vesa_attributes = info->u.vesa_lfb.mode_attrs;
-
-               if (size >= offsetof(struct dom0_vga_console_info,
-                                    u.vesa_lfb.ext_lfb_base)
-                   + sizeof(info->u.vesa_lfb.ext_lfb_base)
-                   && info->u.vesa_lfb.ext_lfb_base) {
-                       screen_info->ext_lfb_base = info->u.vesa_lfb.ext_lfb_base;
-                       screen_info->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
-               }
                break;
        }
 }
index 0c612a9..36a66e9 100644 (file)
@@ -7018,6 +7018,8 @@ static void bfq_exit_queue(struct elevator_queue *e)
        spin_unlock_irq(&bfqd->lock);
 #endif
 
+       wbt_enable_default(bfqd->queue);
+
        kfree(bfqd);
 }
 
index d251147..0827b19 100644 (file)
@@ -373,7 +373,7 @@ void bio_integrity_advance(struct bio *bio, unsigned int bytes_done)
        struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
        unsigned bytes = bio_integrity_bytes(bi, bytes_done >> 9);
 
-       bip->bip_iter.bi_sector += bytes_done >> 9;
+       bip->bip_iter.bi_sector += bio_integrity_intervals(bi, bytes_done >> 9);
        bvec_iter_advance(bip->bip_vec, &bip->bip_iter, bytes);
 }
 
index 97f8bc8..1039515 100644 (file)
@@ -284,13 +284,6 @@ void blk_queue_start_drain(struct request_queue *q)
        wake_up_all(&q->mq_freeze_wq);
 }
 
-void blk_set_queue_dying(struct request_queue *q)
-{
-       blk_queue_flag_set(QUEUE_FLAG_DYING, q);
-       blk_queue_start_drain(q);
-}
-EXPORT_SYMBOL_GPL(blk_set_queue_dying);
-
 /**
  * blk_cleanup_queue - shutdown a request queue
  * @q: request queue to shutdown
@@ -308,7 +301,8 @@ void blk_cleanup_queue(struct request_queue *q)
        WARN_ON_ONCE(blk_queue_registered(q));
 
        /* mark @q DYING, no new request or merges will be allowed afterwards */
-       blk_set_queue_dying(q);
+       blk_queue_flag_set(QUEUE_FLAG_DYING, q);
+       blk_queue_start_drain(q);
 
        blk_queue_flag_set(QUEUE_FLAG_NOMERGES, q);
        blk_queue_flag_set(QUEUE_FLAG_NOXMERGES, q);
@@ -1061,20 +1055,32 @@ again:
 }
 
 static unsigned long __part_start_io_acct(struct block_device *part,
-                                         unsigned int sectors, unsigned int op)
+                                         unsigned int sectors, unsigned int op,
+                                         unsigned long start_time)
 {
        const int sgrp = op_stat_group(op);
-       unsigned long now = READ_ONCE(jiffies);
 
        part_stat_lock();
-       update_io_ticks(part, now, false);
+       update_io_ticks(part, start_time, false);
        part_stat_inc(part, ios[sgrp]);
        part_stat_add(part, sectors[sgrp], sectors);
        part_stat_local_inc(part, in_flight[op_is_write(op)]);
        part_stat_unlock();
 
-       return now;
+       return start_time;
+}
+
+/**
+ * bio_start_io_acct_time - start I/O accounting for bio based drivers
+ * @bio:       bio to start account for
+ * @start_time:        start time that should be passed back to bio_end_io_acct().
+ */
+void bio_start_io_acct_time(struct bio *bio, unsigned long start_time)
+{
+       __part_start_io_acct(bio->bi_bdev, bio_sectors(bio),
+                            bio_op(bio), start_time);
 }
+EXPORT_SYMBOL_GPL(bio_start_io_acct_time);
 
 /**
  * bio_start_io_acct - start I/O accounting for bio based drivers
@@ -1084,14 +1090,15 @@ static unsigned long __part_start_io_acct(struct block_device *part,
  */
 unsigned long bio_start_io_acct(struct bio *bio)
 {
-       return __part_start_io_acct(bio->bi_bdev, bio_sectors(bio), bio_op(bio));
+       return __part_start_io_acct(bio->bi_bdev, bio_sectors(bio),
+                                   bio_op(bio), jiffies);
 }
 EXPORT_SYMBOL_GPL(bio_start_io_acct);
 
 unsigned long disk_start_io_acct(struct gendisk *disk, unsigned int sectors,
                                 unsigned int op)
 {
-       return __part_start_io_acct(disk->part0, sectors, op);
+       return __part_start_io_acct(disk->part0, sectors, op, jiffies);
 }
 EXPORT_SYMBOL(disk_start_io_acct);
 
index b925f3d..18c68d8 100644 (file)
@@ -144,7 +144,7 @@ int disk_register_independent_access_ranges(struct gendisk *disk,
                                   &q->kobj, "%s", "independent_access_ranges");
        if (ret) {
                q->ia_ranges = NULL;
-               kfree(iars);
+               kobject_put(&iars->kobj);
                return ret;
        }
 
index 4526add..c7f71d8 100644 (file)
@@ -446,7 +446,7 @@ static struct bio *bio_copy_kern(struct request_queue *q, void *data,
                if (bytes > len)
                        bytes = len;
 
-               page = alloc_page(GFP_NOIO | gfp_mask);
+               page = alloc_page(GFP_NOIO | __GFP_ZERO | gfp_mask);
                if (!page)
                        goto cleanup;
 
index f3bf335..d69ca91 100644 (file)
@@ -736,6 +736,10 @@ static void blk_complete_request(struct request *req)
 
                /* Completion has already been traced */
                bio_clear_flag(bio, BIO_TRACE_COMPLETION);
+
+               if (req_op(req) == REQ_OP_ZONE_APPEND)
+                       bio->bi_iter.bi_sector = req->__sector;
+
                if (!is_flush)
                        bio_endio(bio);
                bio = next;
@@ -2922,6 +2926,8 @@ blk_status_t blk_insert_cloned_request(struct request_queue *q, struct request *
         */
        blk_mq_run_dispatch_ops(rq->q,
                        ret = blk_mq_request_issue_directly(rq, true));
+       if (ret)
+               blk_account_io_done(rq, ktime_get_ns());
        return ret;
 }
 EXPORT_SYMBOL_GPL(blk_insert_cloned_request);
index ec98aed..482df2a 100644 (file)
@@ -525,8 +525,6 @@ void elv_unregister_queue(struct request_queue *q)
                kobject_del(&e->kobj);
 
                e->registered = 0;
-               /* Re-enable throttling in case elevator disabled it */
-               wbt_enable_default(q);
        }
 }
 
index 26bf15c..a18e7fb 100644 (file)
@@ -289,6 +289,8 @@ static void blkdev_bio_end_io_async(struct bio *bio)
        struct kiocb *iocb = dio->iocb;
        ssize_t ret;
 
+       WRITE_ONCE(iocb->private, NULL);
+
        if (likely(!bio->bi_status)) {
                ret = dio->size;
                iocb->ki_pos += ret;
@@ -566,34 +568,37 @@ static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
        struct block_device *bdev = iocb->ki_filp->private_data;
        loff_t size = bdev_nr_bytes(bdev);
-       size_t count = iov_iter_count(to);
        loff_t pos = iocb->ki_pos;
        size_t shorted = 0;
        ssize_t ret = 0;
+       size_t count;
 
-       if (unlikely(pos + count > size)) {
+       if (unlikely(pos + iov_iter_count(to) > size)) {
                if (pos >= size)
                        return 0;
                size -= pos;
-               if (count > size) {
-                       shorted = count - size;
-                       iov_iter_truncate(to, size);
-               }
+               shorted = iov_iter_count(to) - size;
+               iov_iter_truncate(to, size);
        }
 
+       count = iov_iter_count(to);
+       if (!count)
+               goto reexpand; /* skip atime */
+
        if (iocb->ki_flags & IOCB_DIRECT) {
                struct address_space *mapping = iocb->ki_filp->f_mapping;
 
                if (iocb->ki_flags & IOCB_NOWAIT) {
-                       if (filemap_range_needs_writeback(mapping, iocb->ki_pos,
-                                               iocb->ki_pos + count - 1))
-                               return -EAGAIN;
+                       if (filemap_range_needs_writeback(mapping, pos,
+                                                         pos + count - 1)) {
+                               ret = -EAGAIN;
+                               goto reexpand;
+                       }
                } else {
-                       ret = filemap_write_and_wait_range(mapping,
-                                               iocb->ki_pos,
-                                               iocb->ki_pos + count - 1);
+                       ret = filemap_write_and_wait_range(mapping, pos,
+                                                          pos + count - 1);
                        if (ret < 0)
-                               return ret;
+                               goto reexpand;
                }
 
                file_accessed(iocb->ki_filp);
@@ -603,12 +608,14 @@ static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
                        iocb->ki_pos += ret;
                        count -= ret;
                }
+               iov_iter_revert(to, count - iov_iter_count(to));
                if (ret < 0 || !count)
-                       return ret;
+                       goto reexpand;
        }
 
        ret = filemap_read(iocb, to, ret);
 
+reexpand:
        if (unlikely(shorted))
                iov_iter_reexpand(to, iov_iter_count(to) + shorted);
        return ret;
index 626c840..9eca1f7 100644 (file)
@@ -548,6 +548,20 @@ out_free_ext_minor:
 }
 EXPORT_SYMBOL(device_add_disk);
 
+/**
+ * blk_mark_disk_dead - mark a disk as dead
+ * @disk: disk to mark as dead
+ *
+ * Mark as disk as dead (e.g. surprise removed) and don't accept any new I/O
+ * to this disk.
+ */
+void blk_mark_disk_dead(struct gendisk *disk)
+{
+       set_bit(GD_DEAD, &disk->state);
+       blk_queue_start_drain(disk->queue);
+}
+EXPORT_SYMBOL_GPL(blk_mark_disk_dead);
+
 /**
  * del_gendisk - remove the gendisk
  * @disk: the struct gendisk to remove
index e1ea185..c8289b7 100644 (file)
@@ -25,12 +25,9 @@ struct alg_type_list {
        struct list_head list;
 };
 
-static atomic_long_t alg_memory_allocated;
-
 static struct proto alg_proto = {
        .name                   = "ALG",
        .owner                  = THIS_MODULE,
-       .memory_allocated       = &alg_memory_allocated,
        .obj_size               = sizeof(struct alg_sock),
 };
 
index a366cb3..76fdaa1 100644 (file)
@@ -1324,3 +1324,4 @@ module_exit(crypto_algapi_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Cryptographic algorithms API");
+MODULE_SOFTDEP("pre: cryptomgr");
index cf0869d..7ddfe94 100644 (file)
@@ -643,4 +643,3 @@ EXPORT_SYMBOL_GPL(crypto_req_done);
 
 MODULE_DESCRIPTION("Cryptographic core API");
 MODULE_LICENSE("GPL");
-MODULE_SOFTDEP("pre: cryptomgr");
index 72fe480..5f96a21 100644 (file)
 static int crypto_blake2s_update_generic(struct shash_desc *desc,
                                         const u8 *in, unsigned int inlen)
 {
-       return crypto_blake2s_update(desc, in, inlen, blake2s_compress_generic);
+       return crypto_blake2s_update(desc, in, inlen, true);
 }
 
 static int crypto_blake2s_final_generic(struct shash_desc *desc, u8 *out)
 {
-       return crypto_blake2s_final(desc, out, blake2s_compress_generic);
+       return crypto_blake2s_final(desc, out, true);
 }
 
 #define BLAKE2S_ALG(name, driver_name, digest_size)                    \
index 0d399dd..8d6cd5d 100644 (file)
@@ -236,4 +236,7 @@ source "drivers/interconnect/Kconfig"
 source "drivers/counter/Kconfig"
 
 source "drivers/most/Kconfig"
+
+source "drivers/peci/Kconfig"
+
 endmenu
index a110338..020780b 100644 (file)
@@ -187,3 +187,4 @@ obj-$(CONFIG_GNSS)          += gnss/
 obj-$(CONFIG_INTERCONNECT)     += interconnect/
 obj-$(CONFIG_COUNTER)          += counter/
 obj-$(CONFIG_MOST)             += most/
+obj-$(CONFIG_PECI)             += peci/
index e89fd72..a0c3b8a 100644 (file)
@@ -126,20 +126,22 @@ static void synth_flush(struct spk_synth *synth)
 
 static void synth_version(struct spk_synth *synth)
 {
-       unsigned char test = 0;
-       char synth_id[40] = "";
+       unsigned i;
+       char synth_id[33];
 
        synth->synth_immediate(synth, "\x05[Q]");
-       synth_id[test] = synth->io_ops->synth_in(synth);
-       if (synth_id[test] == 'A') {
-               do {
-                       /* read version string from synth */
-                       synth_id[++test] = synth->io_ops->synth_in(synth);
-               } while (synth_id[test] != '\n' && test < 32);
-               synth_id[++test] = 0x00;
+       synth_id[0] = synth->io_ops->synth_in(synth);
+       if (synth_id[0] != 'A')
+               return;
+
+       for (i = 1; i < sizeof(synth_id) - 1; i++) {
+               /* read version string from synth */
+               synth_id[i] = synth->io_ops->synth_in(synth);
+               if (synth_id[i] == '\n')
+                       break;
        }
-       if (synth_id[0] == 'A')
-               pr_info("%s version: %s", synth->long_name, synth_id);
+       synth_id[i] = '\0';
+       pr_info("%s version: %s", synth->long_name, synth_id);
 }
 
 static int synth_probe(struct spk_synth *synth)
index 580ec79..78ca498 100644 (file)
@@ -44,6 +44,7 @@ static struct var_t vars[] = {
        { CAPS_START, .u.s = {"[:dv ap 160] " } },
        { CAPS_STOP, .u.s = {"[:dv ap 100 ] " } },
        { RATE, .u.n = {"[:ra %d] ", 180, 75, 650, 0, 0, NULL } },
+       { PITCH, .u.n = {"[:dv ap %d] ", 122, 50, 350, 0, 0, NULL } },
        { INFLECTION, .u.n = {"[:dv pr %d] ", 100, 0, 10000, 0, 0, NULL } },
        { VOL, .u.n = {"[:dv g5 %d] ", 86, 60, 86, 0, 0, NULL } },
        { PUNCT, .u.n = {"[:pu %c] ", 0, 0, 2, 0, 0, "nsa" } },
index 2b86996..eea2a2f 100644 (file)
@@ -348,7 +348,7 @@ struct var_t synth_time_vars[] = {
        { TRIGGER, .u.n = {NULL, 20, 10, 2000, 0, 0, NULL } },
        { JIFFY, .u.n = {NULL, 50, 20, 200, 0, 0, NULL } },
        { FULL, .u.n = {NULL, 400, 200, 60000, 0, 0, NULL } },
-       { FLUSH, .u.n = {NULL, 4000, 100, 4000, 0, 0, NULL } },
+       { FLUSH, .u.n = {NULL, 4000, 10, 4000, 0, 0, NULL } },
        V_LAST_VAR
 };
 
index ba45541..273741d 100644 (file)
@@ -11,6 +11,7 @@ menuconfig ACPI
        depends on ARCH_SUPPORTS_ACPI
        select PNP
        select NLS
+       select CRC32
        default y if X86
        help
          Advanced Configuration and Power Interface (ACPI) support for 
index 3b23fb7..f2f8f05 100644 (file)
@@ -1361,9 +1361,17 @@ static void __init arm_smmu_v3_pmcg_init_resources(struct resource *res,
        res[0].start = pmcg->page0_base_address;
        res[0].end = pmcg->page0_base_address + SZ_4K - 1;
        res[0].flags = IORESOURCE_MEM;
-       res[1].start = pmcg->page1_base_address;
-       res[1].end = pmcg->page1_base_address + SZ_4K - 1;
-       res[1].flags = IORESOURCE_MEM;
+       /*
+        * The initial version in DEN0049C lacked a way to describe register
+        * page 1, which makes it broken for most PMCG implementations; in
+        * that case, just let the driver fail gracefully if it expects to
+        * find a second memory resource.
+        */
+       if (node->revision > 0) {
+               res[1].start = pmcg->page1_base_address;
+               res[1].end = pmcg->page1_base_address + SZ_4K - 1;
+               res[1].flags = IORESOURCE_MEM;
+       }
 
        if (pmcg->overflow_gsiv)
                acpi_iort_register_irq(pmcg->overflow_gsiv, "overflow",
index 0077d2c..4671038 100644 (file)
@@ -2065,6 +2065,16 @@ bool acpi_ec_dispatch_gpe(void)
        if (acpi_any_gpe_status_set(first_ec->gpe))
                return true;
 
+       /*
+        * Cancel the SCI wakeup and process all pending events in case there
+        * are any wakeup ones in there.
+        *
+        * Note that if any non-EC GPEs are active at this point, the SCI will
+        * retrigger after the rearming in acpi_s2idle_wake(), so no events
+        * should be missed by canceling the wakeup here.
+        */
+       pm_system_cancel_wakeup();
+
        /*
         * Dispatch the EC GPE in-band, but do not report wakeup in any case
         * to allow the caller to process events properly after that.
index 86560a2..f8e9fa8 100644 (file)
@@ -96,6 +96,11 @@ static const struct dmi_system_id processor_power_dmi_table[] = {
          DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
          DMI_MATCH(DMI_PRODUCT_NAME,"L8400B series Notebook PC")},
         (void *)1},
+       /* T40 can not handle C3 idle state */
+       { set_max_cstate, "IBM ThinkPad T40", {
+         DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "23737CU")},
+        (void *)2},
        {},
 };
 
index a60ff5d..d4fbea9 100644 (file)
@@ -736,21 +736,15 @@ bool acpi_s2idle_wake(void)
                        return true;
                }
 
-               /* Check non-EC GPE wakeups and dispatch the EC GPE. */
+               /*
+                * Check non-EC GPE wakeups and if there are none, cancel the
+                * SCI-related wakeup and dispatch the EC GPE.
+                */
                if (acpi_ec_dispatch_gpe()) {
                        pm_pr_dbg("ACPI non-EC GPE wakeup\n");
                        return true;
                }
 
-               /*
-                * Cancel the SCI wakeup and process all pending events in case
-                * there are any wakeup ones in there.
-                *
-                * Note that if any non-EC GPEs are active at this point, the
-                * SCI will retrigger after the rearming below, so no events
-                * should be missed by canceling the wakeup here.
-                */
-               pm_system_cancel_wakeup();
                acpi_os_wait_events_complete();
 
                /*
@@ -764,6 +758,7 @@ bool acpi_s2idle_wake(void)
                        return true;
                }
 
+               pm_wakeup_clear(acpi_sci_irq);
                rearm_wake_irq(acpi_sci_irq);
        }
 
index 0741a49..34600b5 100644 (file)
@@ -400,7 +400,7 @@ int __init_or_acpilib acpi_table_parse_entries_array(
 
        acpi_get_table(id, instance, &table_header);
        if (!table_header) {
-               pr_warn("%4.4s not present\n", id);
+               pr_debug("%4.4s not present\n", id);
                return -ENODEV;
        }
 
index abc06e7..ed889f8 100644 (file)
@@ -424,15 +424,11 @@ static int lps0_device_attach(struct acpi_device *adev,
                mem_sleep_current = PM_SUSPEND_TO_IDLE;
 
        /*
-        * Some Intel based LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U don't
-        * use intel-hid or intel-vbtn but require the EC GPE to be enabled while
-        * suspended for certain wakeup devices to work, so mark it as wakeup-capable.
-        *
-        * Only enable on !AMD as enabling this universally causes problems for a number
-        * of AMD based systems.
+        * Some LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U, require the
+        * EC GPE to be enabled while suspended for certain wakeup devices to
+        * work, so mark it as wakeup-capable.
         */
-       if (!acpi_s2idle_vendor_amd())
-               acpi_ec_mark_gpe_for_wake();
+       acpi_ec_mark_gpe_for_wake();
 
        return 0;
 }
index 47bc74a..2ac1008 100644 (file)
@@ -1049,18 +1049,14 @@ err_get_alloc_mutex_failed:
 static unsigned long
 binder_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
 {
-       unsigned long ret = list_lru_count(&binder_alloc_lru);
-       return ret;
+       return list_lru_count(&binder_alloc_lru);
 }
 
 static unsigned long
 binder_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
 {
-       unsigned long ret;
-
-       ret = list_lru_walk(&binder_alloc_lru, binder_alloc_free_page,
+       return list_lru_walk(&binder_alloc_lru, binder_alloc_free_page,
                            NULL, sc->nr_to_scan);
-       return ret;
 }
 
 static struct shrinker binder_shrinker = {
index 67f8802..0c854ae 100644 (file)
@@ -2007,6 +2007,9 @@ static bool ata_log_supported(struct ata_device *dev, u8 log)
 {
        struct ata_port *ap = dev->link->ap;
 
+       if (dev->horkage & ATA_HORKAGE_NO_LOG_DIR)
+               return false;
+
        if (ata_read_log_page(dev, ATA_LOG_DIRECTORY, 0, ap->sector_buf, 1))
                return false;
        return get_unaligned_le16(&ap->sector_buf[log * 2]) ? true : false;
@@ -2445,23 +2448,21 @@ static void ata_dev_config_cpr(struct ata_device *dev)
        struct ata_cpr_log *cpr_log = NULL;
        u8 *desc, *buf = NULL;
 
-       if (!ata_identify_page_supported(dev,
-                                ATA_LOG_CONCURRENT_POSITIONING_RANGES))
+       if (ata_id_major_version(dev->id) < 11 ||
+           !ata_log_supported(dev, ATA_LOG_CONCURRENT_POSITIONING_RANGES))
                goto out;
 
        /*
-        * Read IDENTIFY DEVICE data log, page 0x47
-        * (concurrent positioning ranges). We can have at most 255 32B range
-        * descriptors plus a 64B header.
+        * Read the concurrent positioning ranges log (0x47). We can have at
+        * most 255 32B range descriptors plus a 64B header.
         */
        buf_len = (64 + 255 * 32 + 511) & ~511;
        buf = kzalloc(buf_len, GFP_KERNEL);
        if (!buf)
                goto out;
 
-       err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE,
-                                    ATA_LOG_CONCURRENT_POSITIONING_RANGES,
-                                    buf, buf_len >> 9);
+       err_mask = ata_read_log_page(dev, ATA_LOG_CONCURRENT_POSITIONING_RANGES,
+                                    0, buf, buf_len >> 9);
        if (err_mask)
                goto out;
 
@@ -4028,6 +4029,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
 
        /* devices that don't properly handle TRIM commands */
        { "SuperSSpeed S238*",          NULL,   ATA_HORKAGE_NOTRIM, },
+       { "M88V29*",                    NULL,   ATA_HORKAGE_NOTRIM, },
 
        /*
         * As defined, the DRAT (Deterministic Read After Trim) and RZAT
@@ -4073,6 +4075,13 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "WDC WD3000JD-*",             NULL,   ATA_HORKAGE_WD_BROKEN_LPM },
        { "WDC WD3200JD-*",             NULL,   ATA_HORKAGE_WD_BROKEN_LPM },
 
+       /*
+        * This sata dom device goes on a walkabout when the ATA_LOG_DIRECTORY
+        * log page is accessed. Ensure we never ask for this log page with
+        * these devices.
+        */
+       { "SATADOM-ML 3ME",             NULL,   ATA_HORKAGE_NO_LOG_DIR },
+
        /* End Marker */
        { }
 };
index 7abc7e0..6fa4a2f 100644 (file)
@@ -919,6 +919,20 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        irqmask &= ~0x10;
        pci_write_config_byte(dev, 0x5a, irqmask);
 
+       /*
+        * HPT371 chips physically have only one channel, the secondary one,
+        * but the primary channel registers do exist!  Go figure...
+        * So,  we manually disable the non-existing channel here
+        * (if the BIOS hasn't done this already).
+        */
+       if (dev->device == PCI_DEVICE_ID_TTI_HPT371) {
+               u8 mcr1;
+
+               pci_read_config_byte(dev, 0x50, &mcr1);
+               mcr1 &= ~0x04;
+               pci_write_config_byte(dev, 0x50, mcr1);
+       }
+
        /*
         * default to pci clock. make sure MA15/16 are set to output
         * to prevent drives having problems with 40-pin cables. Needed
@@ -950,14 +964,14 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 
        if ((freq >> 12) != 0xABCDE) {
                int i;
-               u8 sr;
+               u16 sr;
                u32 total = 0;
 
                dev_warn(&dev->dev, "BIOS has not set timing clocks\n");
 
                /* This is the process the HPT371 BIOS is reported to use */
                for (i = 0; i < 128; i++) {
-                       pci_read_config_byte(dev, 0x78, &sr);
+                       pci_read_config_word(dev, 0x78, &sr);
                        total += sr & 0x1FF;
                        udelay(15);
                }
index 0283294..87c7c90 100644 (file)
@@ -128,6 +128,8 @@ int __pata_platform_probe(struct device *dev, struct resource *io_res,
        ap = host->ports[0];
 
        ap->ops = devm_kzalloc(dev, sizeof(*ap->ops), GFP_KERNEL);
+       if (!ap->ops)
+               return -ENOMEM;
        ap->ops->inherits = &ata_sff_port_ops;
        ap->ops->cable_detect = ata_cable_unknown;
        ap->ops->set_mode = pata_platform_set_mode;
index da01521..556034a 100644 (file)
@@ -322,7 +322,7 @@ static void fsl_sata_set_irq_coalescing(struct ata_host *host,
 static ssize_t fsl_sata_intr_coalescing_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       return sysfs_emit(buf, "%d      %d\n",
+       return sysfs_emit(buf, "%u      %u\n",
                        intr_coalescing_count, intr_coalescing_ticks);
 }
 
@@ -332,10 +332,8 @@ static ssize_t fsl_sata_intr_coalescing_store(struct device *dev,
 {
        unsigned int coalescing_count,  coalescing_ticks;
 
-       if (sscanf(buf, "%d%d",
-                               &coalescing_count,
-                               &coalescing_ticks) != 2) {
-               printk(KERN_ERR "fsl-sata: wrong parameter format.\n");
+       if (sscanf(buf, "%u%u", &coalescing_count, &coalescing_ticks) != 2) {
+               dev_err(dev, "fsl-sata: wrong parameter format.\n");
                return -EINVAL;
        }
 
@@ -359,7 +357,7 @@ static ssize_t fsl_sata_rx_watermark_show(struct device *dev,
        rx_watermark &= 0x1f;
        spin_unlock_irqrestore(&host->lock, flags);
 
-       return sysfs_emit(buf, "%d\n", rx_watermark);
+       return sysfs_emit(buf, "%u\n", rx_watermark);
 }
 
 static ssize_t fsl_sata_rx_watermark_store(struct device *dev,
@@ -373,8 +371,8 @@ static ssize_t fsl_sata_rx_watermark_store(struct device *dev,
        void __iomem *csr_base = host_priv->csr_base;
        u32 temp;
 
-       if (sscanf(buf, "%d", &rx_watermark) != 1) {
-               printk(KERN_ERR "fsl-sata: wrong parameter format.\n");
+       if (kstrtouint(buf, 10, &rx_watermark) < 0) {
+               dev_err(dev, "fsl-sata: wrong parameter format.\n");
                return -EINVAL;
        }
 
@@ -382,8 +380,8 @@ static ssize_t fsl_sata_rx_watermark_store(struct device *dev,
        temp = ioread32(csr_base + TRANSCFG);
        temp &= 0xffffffe0;
        iowrite32(temp | rx_watermark, csr_base + TRANSCFG);
-
        spin_unlock_irqrestore(&host->lock, flags);
+
        return strlen(buf);
 }
 
index 9eaaff2..f47cab2 100644 (file)
@@ -629,6 +629,9 @@ re_probe:
                        drv->remove(dev);
 
                devres_release_all(dev);
+               arch_teardown_dma_ops(dev);
+               kfree(dev->dma_range_map);
+               dev->dma_range_map = NULL;
                driver_sysfs_remove(dev);
                dev->driver = NULL;
                dev_set_drvdata(dev, NULL);
@@ -1209,6 +1212,8 @@ static void __device_release_driver(struct device *dev, struct device *parent)
 
                devres_release_all(dev);
                arch_teardown_dma_ops(dev);
+               kfree(dev->dma_range_map);
+               dev->dma_range_map = NULL;
                dev->driver = NULL;
                dev_set_drvdata(dev, NULL);
                if (dev->pm_domain && dev->pm_domain->dismiss)
index 99bda0d..8666590 100644 (file)
@@ -34,7 +34,8 @@ suspend_state_t pm_suspend_target_state;
 bool events_check_enabled __read_mostly;
 
 /* First wakeup IRQ seen by the kernel in the last cycle. */
-unsigned int pm_wakeup_irq __read_mostly;
+static unsigned int wakeup_irq[2] __read_mostly;
+static DEFINE_RAW_SPINLOCK(wakeup_irq_lock);
 
 /* If greater than 0 and the system is suspending, terminate the suspend. */
 static atomic_t pm_abort_suspend __read_mostly;
@@ -942,19 +943,45 @@ void pm_system_cancel_wakeup(void)
        atomic_dec_if_positive(&pm_abort_suspend);
 }
 
-void pm_wakeup_clear(bool reset)
+void pm_wakeup_clear(unsigned int irq_number)
 {
-       pm_wakeup_irq = 0;
-       if (reset)
+       raw_spin_lock_irq(&wakeup_irq_lock);
+
+       if (irq_number && wakeup_irq[0] == irq_number)
+               wakeup_irq[0] = wakeup_irq[1];
+       else
+               wakeup_irq[0] = 0;
+
+       wakeup_irq[1] = 0;
+
+       raw_spin_unlock_irq(&wakeup_irq_lock);
+
+       if (!irq_number)
                atomic_set(&pm_abort_suspend, 0);
 }
 
 void pm_system_irq_wakeup(unsigned int irq_number)
 {
-       if (pm_wakeup_irq == 0) {
-               pm_wakeup_irq = irq_number;
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&wakeup_irq_lock, flags);
+
+       if (wakeup_irq[0] == 0)
+               wakeup_irq[0] = irq_number;
+       else if (wakeup_irq[1] == 0)
+               wakeup_irq[1] = irq_number;
+       else
+               irq_number = 0;
+
+       raw_spin_unlock_irqrestore(&wakeup_irq_lock, flags);
+
+       if (irq_number)
                pm_system_wakeup();
-       }
+}
+
+unsigned int pm_wakeup_irq(void)
+{
+       return wakeup_irq[0];
 }
 
 /**
index d265658..4a44625 100644 (file)
@@ -189,11 +189,9 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
                                ret = regmap_write(map, reg, d->mask_buf[i]);
                        if (d->chip->clear_ack) {
                                if (d->chip->ack_invert && !ret)
-                                       ret = regmap_write(map, reg,
-                                                          d->mask_buf[i]);
+                                       ret = regmap_write(map, reg, UINT_MAX);
                                else if (!ret)
-                                       ret = regmap_write(map, reg,
-                                                          ~d->mask_buf[i]);
+                                       ret = regmap_write(map, reg, 0);
                        }
                        if (ret != 0)
                                dev_err(d->map->dev, "Failed to ack 0x%x: %d\n",
@@ -556,11 +554,9 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                                                data->status_buf[i]);
                        if (chip->clear_ack) {
                                if (chip->ack_invert && !ret)
-                                       ret = regmap_write(map, reg,
-                                                       data->status_buf[i]);
+                                       ret = regmap_write(map, reg, UINT_MAX);
                                else if (!ret)
-                                       ret = regmap_write(map, reg,
-                                                       ~data->status_buf[i]);
+                                       ret = regmap_write(map, reg, 0);
                        }
                        if (ret != 0)
                                dev_err(map->dev, "Failed to ack 0x%x: %d\n",
@@ -817,13 +813,9 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
                                        d->status_buf[i] & d->mask_buf[i]);
                        if (chip->clear_ack) {
                                if (chip->ack_invert && !ret)
-                                       ret = regmap_write(map, reg,
-                                               (d->status_buf[i] &
-                                                d->mask_buf[i]));
+                                       ret = regmap_write(map, reg, UINT_MAX);
                                else if (!ret)
-                                       ret = regmap_write(map, reg,
-                                               ~(d->status_buf[i] &
-                                                 d->mask_buf[i]));
+                                       ret = regmap_write(map, reg, 0);
                        }
                        if (ret != 0) {
                                dev_err(map->dev, "Failed to ack 0x%x: %d\n",
index 01cbbfc..19fe19e 100644 (file)
@@ -79,6 +79,7 @@
 #include <linux/ioprio.h>
 #include <linux/blk-cgroup.h>
 #include <linux/sched/mm.h>
+#include <linux/statfs.h>
 
 #include "loop.h"
 
@@ -774,8 +775,13 @@ static void loop_config_discard(struct loop_device *lo)
                granularity = 0;
 
        } else {
+               struct kstatfs sbuf;
+
                max_discard_sectors = UINT_MAX >> 9;
-               granularity = inode->i_sb->s_blocksize;
+               if (!vfs_statfs(&file->f_path, &sbuf))
+                       granularity = sbuf.f_bsize;
+               else
+                       max_discard_sectors = 0;
        }
 
        if (max_discard_sectors) {
@@ -1082,7 +1088,7 @@ out_putf:
        return error;
 }
 
-static void __loop_clr_fd(struct loop_device *lo)
+static void __loop_clr_fd(struct loop_device *lo, bool release)
 {
        struct file *filp;
        gfp_t gfp = lo->old_gfp_mask;
@@ -1144,6 +1150,8 @@ static void __loop_clr_fd(struct loop_device *lo)
        /* let user-space know about this change */
        kobject_uevent(&disk_to_dev(lo->lo_disk)->kobj, KOBJ_CHANGE);
        mapping_set_gfp_mask(filp->f_mapping, gfp);
+       /* This is safe: open() is still holding a reference. */
+       module_put(THIS_MODULE);
        blk_mq_unfreeze_queue(lo->lo_queue);
 
        disk_force_media_change(lo->lo_disk, DISK_EVENT_MEDIA_CHANGE);
@@ -1151,52 +1159,44 @@ static void __loop_clr_fd(struct loop_device *lo)
        if (lo->lo_flags & LO_FLAGS_PARTSCAN) {
                int err;
 
-               mutex_lock(&lo->lo_disk->open_mutex);
+               /*
+                * open_mutex has been held already in release path, so don't
+                * acquire it if this function is called in such case.
+                *
+                * If the reread partition isn't from release path, lo_refcnt
+                * must be at least one and it can only become zero when the
+                * current holder is released.
+                */
+               if (!release)
+                       mutex_lock(&lo->lo_disk->open_mutex);
                err = bdev_disk_changed(lo->lo_disk, false);
-               mutex_unlock(&lo->lo_disk->open_mutex);
+               if (!release)
+                       mutex_unlock(&lo->lo_disk->open_mutex);
                if (err)
                        pr_warn("%s: partition scan of loop%d failed (rc=%d)\n",
                                __func__, lo->lo_number, err);
                /* Device is gone, no point in returning error */
        }
 
+       /*
+        * lo->lo_state is set to Lo_unbound here after above partscan has
+        * finished. There cannot be anybody else entering __loop_clr_fd() as
+        * Lo_rundown state protects us from all the other places trying to
+        * change the 'lo' device.
+        */
        lo->lo_flags = 0;
        if (!part_shift)
                lo->lo_disk->flags |= GENHD_FL_NO_PART;
-
-       fput(filp);
-}
-
-static void loop_rundown_completed(struct loop_device *lo)
-{
        mutex_lock(&lo->lo_mutex);
        lo->lo_state = Lo_unbound;
        mutex_unlock(&lo->lo_mutex);
-       module_put(THIS_MODULE);
-}
-
-static void loop_rundown_workfn(struct work_struct *work)
-{
-       struct loop_device *lo = container_of(work, struct loop_device,
-                                             rundown_work);
-       struct block_device *bdev = lo->lo_device;
-       struct gendisk *disk = lo->lo_disk;
-
-       __loop_clr_fd(lo);
-       kobject_put(&bdev->bd_device.kobj);
-       module_put(disk->fops->owner);
-       loop_rundown_completed(lo);
-}
-
-static void loop_schedule_rundown(struct loop_device *lo)
-{
-       struct block_device *bdev = lo->lo_device;
-       struct gendisk *disk = lo->lo_disk;
 
-       __module_get(disk->fops->owner);
-       kobject_get(&bdev->bd_device.kobj);
-       INIT_WORK(&lo->rundown_work, loop_rundown_workfn);
-       queue_work(system_long_wq, &lo->rundown_work);
+       /*
+        * Need not hold lo_mutex to fput backing file. Calling fput holding
+        * lo_mutex triggers a circular lock dependency possibility warning as
+        * fput can take open_mutex which is usually taken before lo_mutex.
+        */
+       fput(filp);
 }
 
 static int loop_clr_fd(struct loop_device *lo)
@@ -1228,8 +1228,7 @@ static int loop_clr_fd(struct loop_device *lo)
        lo->lo_state = Lo_rundown;
        mutex_unlock(&lo->lo_mutex);
 
-       __loop_clr_fd(lo);
-       loop_rundown_completed(lo);
+       __loop_clr_fd(lo, false);
        return 0;
 }
 
@@ -1754,7 +1753,7 @@ static void lo_release(struct gendisk *disk, fmode_t mode)
                 * In autoclear mode, stop the loop thread
                 * and remove configuration after last close.
                 */
-               loop_schedule_rundown(lo);
+               __loop_clr_fd(lo, true);
                return;
        } else if (lo->lo_state == Lo_bound) {
                /*
index 918a7a2..082d4b6 100644 (file)
@@ -56,7 +56,6 @@ struct loop_device {
        struct gendisk          *lo_disk;
        struct mutex            lo_mutex;
        bool                    idr_visible;
-       struct work_struct      rundown_work;
 };
 
 struct loop_cmd {
index e6005c2..2b588b6 100644 (file)
@@ -4112,7 +4112,7 @@ static void mtip_pci_remove(struct pci_dev *pdev)
                        "Completion workers still active!\n");
        }
 
-       blk_set_queue_dying(dd->queue);
+       blk_mark_disk_dead(dd->disk);
        set_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag);
 
        /* Clean up the block layer. */
index 4203cda..b844432 100644 (file)
@@ -7185,7 +7185,7 @@ static ssize_t do_rbd_remove(struct bus_type *bus,
                 * IO to complete/fail.
                 */
                blk_mq_freeze_queue(rbd_dev->disk->queue);
-               blk_set_queue_dying(rbd_dev->disk->queue);
+               blk_mark_disk_dead(rbd_dev->disk);
        }
 
        del_gendisk(rbd_dev->disk);
index ccd0dd0..ca71a05 100644 (file)
@@ -2126,7 +2126,7 @@ static void blkfront_closing(struct blkfront_info *info)
 
        /* No more blkif_request(). */
        blk_mq_stop_hw_queues(info->rq);
-       blk_set_queue_dying(info->rq);
+       blk_mark_disk_dead(info->gd);
        set_capacity(info->gd, 0);
 
        for_each_rinfo(info, rinfo, i) {
index 3a258a6..b798958 100644 (file)
@@ -366,6 +366,7 @@ static const struct mhi_pci_dev_info mhi_foxconn_sdx55_info = {
        .config = &modem_foxconn_sdx55_config,
        .bar_num = MHI_PCI_DEFAULT_BAR_NUM,
        .dma_data_width = 32,
+       .mru_default = 32768,
        .sideband_wake = false,
 };
 
@@ -401,6 +402,7 @@ static const struct mhi_pci_dev_info mhi_mv31_info = {
        .config = &modem_mv31_config,
        .bar_num = MHI_PCI_DEFAULT_BAR_NUM,
        .dma_data_width = 32,
+       .mru_default = 32768,
 };
 
 static const struct mhi_channel_config mhi_sierra_em919x_channels[] = {
index cce2af5..d5f9439 100644 (file)
@@ -60,7 +60,7 @@ struct bsr_dev {
 };
 
 static unsigned total_bsr_devs;
-static struct list_head bsr_devs = LIST_HEAD_INIT(bsr_devs);
+static LIST_HEAD(bsr_devs);
 static struct class *bsr_class;
 static int bsr_major;
 
index 563dfae..ee71376 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/ioport.h>
 #include <linux/fcntl.h>
 #include <linux/init.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 #include <linux/poll.h>
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
@@ -120,22 +121,6 @@ static struct hpets *hpets;
 #define        HPET_PERIODIC           0x0004
 #define        HPET_SHARED_IRQ         0x0008
 
-
-#ifndef readq
-static inline unsigned long long readq(void __iomem *addr)
-{
-       return readl(addr) | (((unsigned long long)readl(addr + 4)) << 32LL);
-}
-#endif
-
-#ifndef writeq
-static inline void writeq(unsigned long long v, void __iomem *addr)
-{
-       writel(v & 0xffffffff, addr);
-       writel(v >> 32, addr + 4);
-}
-#endif
-
 static irqreturn_t hpet_interrupt(int irq, void *data)
 {
        struct hpet_dev *devp;
@@ -268,9 +253,9 @@ static int hpet_open(struct inode *inode, struct file *file)
 
        for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next)
                for (i = 0; i < hpetp->hp_ntimer; i++)
-                       if (hpetp->hp_dev[i].hd_flags & HPET_OPEN)
+                       if (hpetp->hp_dev[i].hd_flags & HPET_OPEN) {
                                continue;
-                       else {
+                       else {
                                devp = &hpetp->hp_dev[i];
                                break;
                        }
@@ -317,9 +302,9 @@ hpet_read(struct file *file, char __user *buf, size_t count, loff_t * ppos)
                devp->hd_irqdata = 0;
                spin_unlock_irq(&hpet_lock);
 
-               if (data)
+               if (data) {
                        break;
-               else if (file->f_flags & O_NONBLOCK) {
+               else if (file->f_flags & O_NONBLOCK) {
                        retval = -EAGAIN;
                        goto out;
                } else if (signal_pending(current)) {
@@ -982,7 +967,8 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
                                break;
 
                        irq = acpi_register_gsi(NULL, irqp->interrupts[i],
-                                     irqp->triggering, irqp->polarity);
+                                               irqp->triggering,
+                                               irqp->polarity);
                        if (irq < 0)
                                return AE_ERROR;
 
index 68613f0..3404a91 100644 (file)
@@ -762,7 +762,7 @@ static bool crng_init_try_arch(struct crng_state *crng)
        return arch_init;
 }
 
-static bool __init crng_init_try_arch_early(struct crng_state *crng)
+static bool __init crng_init_try_arch_early(void)
 {
        int i;
        bool arch_init = true;
@@ -774,7 +774,7 @@ static bool __init crng_init_try_arch_early(struct crng_state *crng)
                        rv = random_get_entropy();
                        arch_init = false;
                }
-               crng->state[i] ^= rv;
+               primary_crng.state[i] ^= rv;
        }
 
        return arch_init;
@@ -788,22 +788,20 @@ static void crng_initialize_secondary(struct crng_state *crng)
        crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1;
 }
 
-static void __init crng_initialize_primary(struct crng_state *crng)
+static void __init crng_initialize_primary(void)
 {
-       _extract_entropy(&crng->state[4], sizeof(u32) * 12);
-       if (crng_init_try_arch_early(crng) && trust_cpu && crng_init < 2) {
+       _extract_entropy(&primary_crng.state[4], sizeof(u32) * 12);
+       if (crng_init_try_arch_early() && trust_cpu && crng_init < 2) {
                invalidate_batched_entropy();
                numa_crng_init();
                crng_init = 2;
                pr_notice("crng init done (trusting CPU's manufacturer)\n");
        }
-       crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1;
+       primary_crng.init_time = jiffies - CRNG_RESEED_INTERVAL - 1;
 }
 
-static void crng_finalize_init(struct crng_state *crng)
+static void crng_finalize_init(void)
 {
-       if (crng != &primary_crng || crng_init >= 2)
-               return;
        if (!system_wq) {
                /* We can't call numa_crng_init until we have workqueues,
                 * so mark this for processing later. */
@@ -814,6 +812,7 @@ static void crng_finalize_init(struct crng_state *crng)
        invalidate_batched_entropy();
        numa_crng_init();
        crng_init = 2;
+       crng_need_final_init = false;
        process_random_ready_list();
        wake_up_interruptible(&crng_init_wait);
        kill_fasync(&fasync, SIGIO, POLL_IN);
@@ -980,7 +979,8 @@ static void crng_reseed(struct crng_state *crng, bool use_input_pool)
        memzero_explicit(&buf, sizeof(buf));
        WRITE_ONCE(crng->init_time, jiffies);
        spin_unlock_irqrestore(&crng->lock, flags);
-       crng_finalize_init(crng);
+       if (crng == &primary_crng && crng_init < 2)
+               crng_finalize_init();
 }
 
 static void _extract_crng(struct crng_state *crng, u8 out[CHACHA_BLOCK_SIZE])
@@ -1697,8 +1697,8 @@ int __init rand_initialize(void)
 {
        init_std_data();
        if (crng_need_final_init)
-               crng_finalize_init(&primary_crng);
-       crng_initialize_primary(&primary_crng);
+               crng_finalize_init();
+       crng_initialize_primary();
        crng_global_init_time = jiffies;
        if (ratelimit_disable) {
                urandom_warning.interval = 0;
@@ -1856,7 +1856,10 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
                 */
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               input_pool.entropy_count = 0;
+               if (xchg(&input_pool.entropy_count, 0) && random_write_wakeup_bits) {
+                       wake_up_interruptible(&random_write_wait);
+                       kill_fasync(&fasync, SIGIO, POLL_OUT);
+               }
                return 0;
        case RNDRESEEDCRNG:
                if (!capable(CAP_SYS_ADMIN))
@@ -2205,13 +2208,15 @@ void add_hwgenerator_randomness(const char *buffer, size_t count,
                        return;
        }
 
-       /* Suspend writing if we're above the trickle threshold.
+       /* Throttle writing if we're above the trickle threshold.
         * We'll be woken up again once below random_write_wakeup_thresh,
-        * or when the calling thread is about to terminate.
+        * when the calling thread is about to terminate, or once
+        * CRNG_RESEED_INTERVAL has lapsed.
         */
-       wait_event_interruptible(random_write_wait,
+       wait_event_interruptible_timeout(random_write_wait,
                        !system_wq || kthread_should_stop() ||
-                       POOL_ENTROPY_BITS() <= random_write_wakeup_bits);
+                       POOL_ENTROPY_BITS() <= random_write_wakeup_bits,
+                       CRNG_RESEED_INTERVAL);
        mix_pool_bytes(buffer, count);
        credit_entropy_bits(entropy);
 }
index 02225eb..619f3a3 100644 (file)
@@ -111,7 +111,7 @@ static inline u32 fifo_icap_fifo_read(struct hwicap_drvdata *drvdata)
 }
 
 /**
- * fifo_icap_set_read_size - Set the the size register.
+ * fifo_icap_set_read_size - Set the size register.
  * @drvdata: a pointer to the drvdata.
  * @data: the size of the following read transaction, in words.
  **/
index 067396b..74a4928 100644 (file)
@@ -241,7 +241,7 @@ static int hwicap_command_desync(struct hwicap_drvdata *drvdata)
        buffer[index++] = XHI_NOOP_PACKET;
 
        /*
-        * Write the data to the FIFO and intiate the transfer of data present
+        * Write the data to the FIFO and initiate the transfer of data present
         * in the FIFO to the ICAP device.
         */
        return drvdata->config->set_configuration(drvdata,
@@ -297,7 +297,7 @@ static int hwicap_get_configuration_register(struct hwicap_drvdata *drvdata,
        buffer[index++] = XHI_NOOP_PACKET;
 
        /*
-        * Write the data to the FIFO and intiate the transfer of data present
+        * Write the data to the FIFO and initiate the transfer of data present
         * in the FIFO to the ICAP device.
         */
        status = drvdata->config->set_configuration(drvdata,
@@ -384,7 +384,7 @@ hwicap_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
                       drvdata->read_buffer + bytes_to_read,
                       4 - bytes_to_read);
        } else {
-               /* Get new data from the ICAP, and return was was requested. */
+               /* Get new data from the ICAP, and return what was requested. */
                kbuf = (u32 *) get_zeroed_page(GFP_KERNEL);
                if (!kbuf) {
                        status = -ENOMEM;
index 744d136..15d6179 100644 (file)
@@ -139,11 +139,10 @@ static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
        },
 
        [JZ4725B_CLK_I2S] = {
-               "i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
+               "i2s", CGU_CLK_MUX | CGU_CLK_DIV,
                .parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 },
                .mux = { CGU_REG_CPCCR, 31, 1 },
                .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
-               .gate = { CGU_REG_CLKGR, 6 },
        },
 
        [JZ4725B_CLK_SPI] = {
index 71aa630..f094999 100644 (file)
@@ -108,42 +108,6 @@ static const struct clk_parent_data gcc_xo_gpll0_gpll4[] = {
        { .hw = &gpll4.clkr.hw },
 };
 
-static struct clk_rcg2 system_noc_clk_src = {
-       .cmd_rcgr = 0x0120,
-       .hid_width = 5,
-       .parent_map = gcc_xo_gpll0_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "system_noc_clk_src",
-               .parent_data = gcc_xo_gpll0,
-               .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
-               .ops = &clk_rcg2_ops,
-       },
-};
-
-static struct clk_rcg2 config_noc_clk_src = {
-       .cmd_rcgr = 0x0150,
-       .hid_width = 5,
-       .parent_map = gcc_xo_gpll0_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "config_noc_clk_src",
-               .parent_data = gcc_xo_gpll0,
-               .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
-               .ops = &clk_rcg2_ops,
-       },
-};
-
-static struct clk_rcg2 periph_noc_clk_src = {
-       .cmd_rcgr = 0x0190,
-       .hid_width = 5,
-       .parent_map = gcc_xo_gpll0_map,
-       .clkr.hw.init = &(struct clk_init_data){
-               .name = "periph_noc_clk_src",
-               .parent_data = gcc_xo_gpll0,
-               .num_parents = ARRAY_SIZE(gcc_xo_gpll0),
-               .ops = &clk_rcg2_ops,
-       },
-};
-
 static struct freq_tbl ftbl_ufs_axi_clk_src[] = {
        F(50000000, P_GPLL0, 12, 0, 0),
        F(100000000, P_GPLL0, 6, 0, 0),
@@ -1150,8 +1114,6 @@ static struct clk_branch gcc_blsp1_ahb_clk = {
                .enable_mask = BIT(17),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_blsp1_ahb_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &periph_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -1435,8 +1397,6 @@ static struct clk_branch gcc_blsp2_ahb_clk = {
                .enable_mask = BIT(15),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_blsp2_ahb_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &periph_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -1764,8 +1724,6 @@ static struct clk_branch gcc_lpass_q6_axi_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_lpass_q6_axi_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &system_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -1778,8 +1736,6 @@ static struct clk_branch gcc_mss_q6_bimc_axi_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_mss_q6_bimc_axi_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &system_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -1807,9 +1763,6 @@ static struct clk_branch gcc_pcie_0_cfg_ahb_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_pcie_0_cfg_ahb_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &config_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -1822,9 +1775,6 @@ static struct clk_branch gcc_pcie_0_mstr_axi_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_pcie_0_mstr_axi_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &system_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -1854,9 +1804,6 @@ static struct clk_branch gcc_pcie_0_slv_axi_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_pcie_0_slv_axi_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &system_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -1884,9 +1831,6 @@ static struct clk_branch gcc_pcie_1_cfg_ahb_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_pcie_1_cfg_ahb_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &config_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -1899,9 +1843,6 @@ static struct clk_branch gcc_pcie_1_mstr_axi_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_pcie_1_mstr_axi_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &system_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -1930,9 +1871,6 @@ static struct clk_branch gcc_pcie_1_slv_axi_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_pcie_1_slv_axi_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &system_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -1960,8 +1898,6 @@ static struct clk_branch gcc_pdm_ahb_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_pdm_ahb_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &periph_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -1989,9 +1925,6 @@ static struct clk_branch gcc_sdcc1_ahb_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_sdcc1_ahb_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &periph_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -2004,9 +1937,6 @@ static struct clk_branch gcc_sdcc2_ahb_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_sdcc2_ahb_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &periph_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -2034,9 +1964,6 @@ static struct clk_branch gcc_sdcc3_ahb_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_sdcc3_ahb_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &periph_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -2064,9 +1991,6 @@ static struct clk_branch gcc_sdcc4_ahb_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_sdcc4_ahb_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &periph_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
-                       .flags = CLK_SET_RATE_PARENT,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -2124,8 +2048,6 @@ static struct clk_branch gcc_tsif_ahb_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_tsif_ahb_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &periph_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -2153,8 +2075,6 @@ static struct clk_branch gcc_ufs_ahb_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_ufs_ahb_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &config_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -2198,8 +2118,6 @@ static struct clk_branch gcc_ufs_rx_symbol_0_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_ufs_rx_symbol_0_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &system_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -2213,8 +2131,6 @@ static struct clk_branch gcc_ufs_rx_symbol_1_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_ufs_rx_symbol_1_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &system_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -2243,8 +2159,6 @@ static struct clk_branch gcc_ufs_tx_symbol_0_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_ufs_tx_symbol_0_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &system_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -2258,8 +2172,6 @@ static struct clk_branch gcc_ufs_tx_symbol_1_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_ufs_tx_symbol_1_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &system_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -2364,8 +2276,6 @@ static struct clk_branch gcc_usb_hs_ahb_clk = {
                .enable_mask = BIT(0),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_usb_hs_ahb_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &periph_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -2488,8 +2398,6 @@ static struct clk_branch gcc_boot_rom_ahb_clk = {
                .enable_mask = BIT(10),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_boot_rom_ahb_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &config_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -2503,8 +2411,6 @@ static struct clk_branch gcc_prng_ahb_clk = {
                .enable_mask = BIT(13),
                .hw.init = &(struct clk_init_data){
                        .name = "gcc_prng_ahb_clk",
-                       .parent_hws = (const struct clk_hw *[]){ &periph_noc_clk_src.clkr.hw },
-                       .num_parents = 1,
                        .ops = &clk_branch2_ops,
                },
        },
@@ -2547,9 +2453,6 @@ static struct clk_regmap *gcc_msm8994_clocks[] = {
        [GPLL0] = &gpll0.clkr,
        [GPLL4_EARLY] = &gpll4_early.clkr,
        [GPLL4] = &gpll4.clkr,
-       [CONFIG_NOC_CLK_SRC] = &config_noc_clk_src.clkr,
-       [PERIPH_NOC_CLK_SRC] = &periph_noc_clk_src.clkr,
-       [SYSTEM_NOC_CLK_SRC] = &system_noc_clk_src.clkr,
        [UFS_AXI_CLK_SRC] = &ufs_axi_clk_src.clkr,
        [USB30_MASTER_CLK_SRC] = &usb30_master_clk_src.clkr,
        [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr,
@@ -2696,6 +2599,15 @@ static struct clk_regmap *gcc_msm8994_clocks[] = {
        [USB_SS_PHY_LDO] = &usb_ss_phy_ldo.clkr,
        [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
        [GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr,
+
+       /*
+        * The following clocks should NOT be managed by this driver, but they once were
+        * mistakengly added. Now they are only here to indicate that they are not defined
+        * on purpose, even though the names will stay in the header file (for ABI sanity).
+        */
+       [CONFIG_NOC_CLK_SRC] = NULL,
+       [PERIPH_NOC_CLK_SRC] = NULL,
+       [SYSTEM_NOC_CLK_SRC] = NULL,
 };
 
 static struct gdsc *gcc_msm8994_gdscs[] = {
index b6f9796..5c40ca1 100644 (file)
@@ -241,7 +241,7 @@ static void __init dmtimer_systimer_assign_alwon(void)
        bool quirk_unreliable_oscillator = false;
 
        /* Quirk unreliable 32 KiHz oscillator with incomplete dts */
-       if (of_machine_is_compatible("ti,omap3-beagle") ||
+       if (of_machine_is_compatible("ti,omap3-beagle-ab4") ||
            of_machine_is_compatible("timll,omap3-devkit8000")) {
                quirk_unreliable_oscillator = true;
                counter_32k = -ENODEV;
index 937a69c..728dc02 100644 (file)
@@ -961,7 +961,7 @@ static const struct comedi_lrange *das16_ai_range(struct comedi_device *dev,
 
                /* allocate single-range range table */
                lrange = comedi_alloc_spriv(s,
-                                           sizeof(*lrange) + sizeof(*krange));
+                                           struct_size(lrange, range, 1));
                if (!lrange)
                        return &range_unknown;
 
@@ -995,7 +995,7 @@ static const struct comedi_lrange *das16_ao_range(struct comedi_device *dev,
 
                /* allocate single-range range table */
                lrange = comedi_alloc_spriv(s,
-                                           sizeof(*lrange) + sizeof(*krange));
+                                           struct_size(lrange, range, 1));
                if (!lrange)
                        return &range_unknown;
 
index f24eeb4..295a3a9 100644 (file)
@@ -56,8 +56,7 @@ static const u8 *ni_find_route_values(const char *device_family)
        int i;
 
        for (i = 0; ni_all_route_values[i]; ++i) {
-               if (memcmp(ni_all_route_values[i]->family, device_family,
-                          strnlen(device_family, 30)) == 0) {
+               if (!strcmp(ni_all_route_values[i]->family, device_family)) {
                        rv = &ni_all_route_values[i]->register_values[0][0];
                        break;
                }
@@ -75,8 +74,7 @@ ni_find_valid_routes(const char *board_name)
        int i;
 
        for (i = 0; ni_device_routes_list[i]; ++i) {
-               if (memcmp(ni_device_routes_list[i]->device, board_name,
-                          strnlen(board_name, 30)) == 0) {
+               if (!strcmp(ni_device_routes_list[i]->device, board_name)) {
                        dr = ni_device_routes_list[i];
                        break;
                }
index e4103f9..ca8bef5 100644 (file)
@@ -93,7 +93,6 @@ static void do_3724_config(struct comedi_device *dev,
        unsigned long port_8255_cfg;
 
        config = I8255_CTRL_CW;
-       buffer_config = 0;
 
        /* 1 in io_bits indicates output, 1 in config indicates input */
        if (!(s->io_bits & 0x0000ff))
index 646ad38..ccac1c4 100644 (file)
@@ -358,7 +358,7 @@ static void cn_proc_mcast_ctl(struct cn_msg *msg,
         * other namespaces.
         */
        if ((current_user_ns() != &init_user_ns) ||
-           (task_active_pid_ns(current) != &init_pid_ns))
+           !task_is_in_init_pid_ns(current))
                return;
 
        /* Can only change if privileged. */
index 7e0957e..869894b 100644 (file)
@@ -90,10 +90,8 @@ struct counter_device *counter_alloc(size_t sizeof_priv)
        int err;
 
        ch = kzalloc(sizeof(*ch) + sizeof_priv, GFP_KERNEL);
-       if (!ch) {
-               err = -ENOMEM;
-               goto err_alloc_ch;
-       }
+       if (!ch)
+               return NULL;
 
        counter = &ch->counter;
        dev = &counter->dev;
@@ -123,9 +121,8 @@ err_chrdev_add:
 err_ida_alloc:
 
        kfree(ch);
-err_alloc_ch:
 
-       return ERR_PTR(err);
+       return NULL;
 }
 EXPORT_SYMBOL_GPL(counter_alloc);
 
@@ -208,12 +205,12 @@ struct counter_device *devm_counter_alloc(struct device *dev, size_t sizeof_priv
        int err;
 
        counter = counter_alloc(sizeof_priv);
-       if (IS_ERR(counter))
-               return counter;
+       if (!counter)
+               return NULL;
 
        err = devm_add_action_or_reset(dev, devm_counter_put, counter);
        if (err < 0)
-               return ERR_PTR(err);
+               return NULL;
 
        return counter;
 }
index b8d9553..80f535c 100644 (file)
@@ -1518,6 +1518,10 @@ static int cpufreq_online(unsigned int cpu)
 
        kobject_uevent(&policy->kobj, KOBJ_ADD);
 
+       /* Callback for handling stuff after policy is ready */
+       if (cpufreq_driver->ready)
+               cpufreq_driver->ready(policy);
+
        if (cpufreq_thermal_control_enabled(cpufreq_driver))
                policy->cdev = of_cpufreq_cooling_register(policy);
 
index 05f3d78..effbb68 100644 (file)
@@ -388,7 +388,7 @@ static int qcom_cpufreq_hw_lmh_init(struct cpufreq_policy *policy, int index)
 
        snprintf(data->irq_name, sizeof(data->irq_name), "dcvsh-irq-%u", policy->cpu);
        ret = request_threaded_irq(data->throttle_irq, NULL, qcom_lmh_dcvs_handle_irq,
-                                  IRQF_ONESHOT, data->irq_name, data);
+                                  IRQF_ONESHOT | IRQF_NO_AUTOEN, data->irq_name, data);
        if (ret) {
                dev_err(&pdev->dev, "Error registering %s: %d\n", data->irq_name, ret);
                return 0;
@@ -542,6 +542,14 @@ static int qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
        return 0;
 }
 
+static void qcom_cpufreq_ready(struct cpufreq_policy *policy)
+{
+       struct qcom_cpufreq_data *data = policy->driver_data;
+
+       if (data->throttle_irq >= 0)
+               enable_irq(data->throttle_irq);
+}
+
 static struct freq_attr *qcom_cpufreq_hw_attr[] = {
        &cpufreq_freq_attr_scaling_available_freqs,
        &cpufreq_freq_attr_scaling_boost_freqs,
@@ -561,6 +569,7 @@ static struct cpufreq_driver cpufreq_qcom_hw_driver = {
        .fast_switch    = qcom_cpufreq_hw_fast_switch,
        .name           = "qcom-cpufreq-hw",
        .attr           = qcom_cpufreq_hw_attr,
+       .ready          = qcom_cpufreq_ready,
 };
 
 static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev)
index 4c8ebdf..1b4d425 100644 (file)
@@ -1753,7 +1753,6 @@ void otx2_cpt_print_uc_dbg_info(struct otx2_cptpf_dev *cptpf)
        char engs_info[2 * OTX2_CPT_NAME_LENGTH];
        struct otx2_cpt_eng_grp_info *grp;
        struct otx2_cpt_engs_rsvd *engs;
-       u32 mask[4];
        int i, j;
 
        pr_debug("Engine groups global info");
@@ -1785,6 +1784,8 @@ void otx2_cpt_print_uc_dbg_info(struct otx2_cptpf_dev *cptpf)
                for (j = 0; j < OTX2_CPT_MAX_ETYPES_PER_GRP; j++) {
                        engs = &grp->engs[j];
                        if (engs->type) {
+                               u32 mask[5] = { };
+
                                get_engs_info(grp, engs_info,
                                              2 * OTX2_CPT_NAME_LENGTH, j);
                                pr_debug("Slot%d: %s", j, engs_info);
index 4c06c93..005a82f 100644 (file)
@@ -2,27 +2,27 @@
 /* Code to support devices on the DIO and DIO-II bus
  * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
  * Copyright (C) 2004 Jochen Friedrich <jochen@scram.de>
- * 
+ *
  * This code has basically these routines at the moment:
  * int dio_find(u_int deviceid)
  *    Search the list of DIO devices and return the select code
  *    of the next unconfigured device found that matches the given device ID.
  *    Note that the deviceid parameter should be the encoded ID.
- *    This means that framebuffers should pass it as 
+ *    This means that framebuffers should pass it as
  *    DIO_ENCODE_ID(DIO_ID_FBUFFER,DIO_ID2_TOPCAT)
  *    (or whatever); everybody else just uses DIO_ID_FOOBAR.
  * unsigned long dio_scodetophysaddr(int scode)
  *    Return the physical address corresponding to the given select code.
  * int dio_scodetoipl(int scode)
- *    Every DIO card has a fixed interrupt priority level. This function 
+ *    Every DIO card has a fixed interrupt priority level. This function
  *    returns it, whatever it is.
  * const char *dio_scodetoname(int scode)
- *    Return a character string describing this board [might be "" if 
+ *    Return a character string describing this board [might be "" if
  *    not CONFIG_DIO_CONSTANTS]
  * void dio_config_board(int scode)     mark board as configured in the list
  * void dio_unconfig_board(int scode)   mark board as no longer configured
  *
- * This file is based on the way the Amiga port handles Zorro II cards, 
+ * This file is based on the way the Amiga port handles Zorro II cards,
  * although we aren't so complicated...
  */
 #include <linux/module.h>
@@ -33,7 +33,7 @@
 #include <linux/dio.h>
 #include <linux/slab.h>                         /* kmalloc() */
 #include <linux/uaccess.h>
-#include <asm/io.h>                             /* readb() */
+#include <linux/io.h>                           /* readb() */
 
 struct dio_bus dio_bus = {
        .resources = {
@@ -52,38 +52,36 @@ struct dio_bus dio_bus = {
 /* We associate each numeric ID with an appropriate descriptive string
  * using a constant array of these structs.
  * FIXME: we should be able to arrange to throw away most of the strings
- * using the initdata stuff. Then we wouldn't need to worry about 
+ * using the initdata stuff. Then we wouldn't need to worry about
  * carrying them around...
- * I think we do this by copying them into newly kmalloc()ed memory and 
+ * I think we do this by copying them into newly kmalloc()ed memory and
  * marking the names[] array as .initdata ?
  */
-struct dioname
-{
-        int id;
-        const char *name;
+struct dioname {
+       int id;
+       const char *name;
 };
 
 /* useful macro */
 #define DIONAME(x) { DIO_ID_##x, DIO_DESC_##x }
-#define DIOFBNAME(x) { DIO_ENCODE_ID( DIO_ID_FBUFFER, DIO_ID2_##x), DIO_DESC2_##x }
-
-static struct dioname names[] = 
-{
-        DIONAME(DCA0), DIONAME(DCA0REM), DIONAME(DCA1), DIONAME(DCA1REM),
-        DIONAME(DCM), DIONAME(DCMREM),
-        DIONAME(LAN),
-        DIONAME(FHPIB), DIONAME(NHPIB),
-        DIONAME(SCSI0), DIONAME(SCSI1), DIONAME(SCSI2), DIONAME(SCSI3),
-        DIONAME(FBUFFER),
-        DIONAME(PARALLEL), DIONAME(VME), DIONAME(DCL), DIONAME(DCLREM),
-        DIONAME(MISC0), DIONAME(MISC1), DIONAME(MISC2), DIONAME(MISC3),
-        DIONAME(MISC4), DIONAME(MISC5), DIONAME(MISC6), DIONAME(MISC7),
-        DIONAME(MISC8), DIONAME(MISC9), DIONAME(MISC10), DIONAME(MISC11), 
-        DIONAME(MISC12), DIONAME(MISC13),
-        DIOFBNAME(GATORBOX), DIOFBNAME(TOPCAT), DIOFBNAME(RENAISSANCE),
-        DIOFBNAME(LRCATSEYE), DIOFBNAME(HRCCATSEYE), DIOFBNAME(HRMCATSEYE),
-        DIOFBNAME(DAVINCI), DIOFBNAME(XXXCATSEYE), DIOFBNAME(HYPERION),
-        DIOFBNAME(XGENESIS), DIOFBNAME(TIGER), DIOFBNAME(YGENESIS)   
+#define DIOFBNAME(x) { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_##x), DIO_DESC2_##x }
+
+static struct dioname names[] = {
+       DIONAME(DCA0), DIONAME(DCA0REM), DIONAME(DCA1), DIONAME(DCA1REM),
+       DIONAME(DCM), DIONAME(DCMREM),
+       DIONAME(LAN),
+       DIONAME(FHPIB), DIONAME(NHPIB),
+       DIONAME(SCSI0), DIONAME(SCSI1), DIONAME(SCSI2), DIONAME(SCSI3),
+       DIONAME(FBUFFER),
+       DIONAME(PARALLEL), DIONAME(VME), DIONAME(DCL), DIONAME(DCLREM),
+       DIONAME(MISC0), DIONAME(MISC1), DIONAME(MISC2), DIONAME(MISC3),
+       DIONAME(MISC4), DIONAME(MISC5), DIONAME(MISC6), DIONAME(MISC7),
+       DIONAME(MISC8), DIONAME(MISC9), DIONAME(MISC10), DIONAME(MISC11),
+       DIONAME(MISC12), DIONAME(MISC13),
+       DIOFBNAME(GATORBOX), DIOFBNAME(TOPCAT), DIOFBNAME(RENAISSANCE),
+       DIOFBNAME(LRCATSEYE), DIOFBNAME(HRCCATSEYE), DIOFBNAME(HRMCATSEYE),
+       DIOFBNAME(DAVINCI), DIOFBNAME(XXXCATSEYE), DIOFBNAME(HYPERION),
+       DIOFBNAME(XGENESIS), DIOFBNAME(TIGER), DIOFBNAME(YGENESIS)
 };
 
 #undef DIONAME
@@ -94,13 +92,14 @@ static const char unknowndioname[]
 
 static const char *dio_getname(int id)
 {
-        /* return pointer to a constant string describing the board with given ID */
+       /* return pointer to a constant string describing the board with given ID */
        unsigned int i;
+
        for (i = 0; i < ARRAY_SIZE(names); i++)
-                if (names[i].id == id) 
-                        return names[i].name;
+               if (names[i].id == id)
+                       return names[i].name;
 
-        return unknowndioname;
+       return unknowndioname;
 }
 
 #else
@@ -122,10 +121,10 @@ int __init dio_find(int deviceid)
                void *va;
                unsigned long pa;
 
-                if (DIO_SCINHOLE(scode))
-                        continue;
+               if (DIO_SCINHOLE(scode))
+                       continue;
 
-                pa = dio_scodetophysaddr(scode);
+               pa = dio_scodetophysaddr(scode);
 
                if (!pa)
                        continue;
@@ -139,15 +138,15 @@ int __init dio_find(int deviceid)
                                (unsigned char *)va + DIO_IDOFF, 1)) {
                        if (scode >= DIOII_SCBASE)
                                iounmap(va);
-                        continue;             /* no board present at that select code */
+                       continue;            /* no board present at that select code */
                }
 
                prid = DIO_ID(va);
 
-                if (DIO_NEEDSSECID(prid)) {
-                        secid = DIO_SECID(va);
-                        id = DIO_ENCODE_ID(prid, secid);
-                } else
+               if (DIO_NEEDSSECID(prid)) {
+                       secid = DIO_SECID(va);
+                       id = DIO_ENCODE_ID(prid, secid);
+               } else
                        id = prid;
 
                if (id == deviceid) {
@@ -175,7 +174,7 @@ static int __init dio_init(void)
 
         printk(KERN_INFO "Scanning for DIO devices...\n");
 
-       /* Initialize the DIO bus */ 
+       /* Initialize the DIO bus */
        INIT_LIST_HEAD(&dio_bus.devices);
        dev_set_name(&dio_bus.dev, "dio");
        error = device_register(&dio_bus.dev);
@@ -190,14 +189,13 @@ static int __init dio_init(void)
                request_resource(&iomem_resource, &dio_bus.resources[i]);
 
        /* Register all devices */
-        for (scode = 0; scode < DIO_SCMAX; ++scode)
-        {
-                u_char prid, secid = 0;        /* primary, secondary ID bytes */
-                u_char *va;
+       for (scode = 0; scode < DIO_SCMAX; ++scode) {
+               u_char prid, secid = 0; /* primary, secondary ID bytes */
+               u_char *va;
                unsigned long pa;
-                
-                if (DIO_SCINHOLE(scode))
-                        continue;
+
+               if (DIO_SCINHOLE(scode))
+                       continue;
 
                pa = dio_scodetophysaddr(scode);
 
@@ -213,10 +211,10 @@ static int __init dio_init(void)
                                (unsigned char *)va + DIO_IDOFF, 1)) {
                        if (scode >= DIOII_SCBASE)
                                iounmap(va);
-                        continue;              /* no board present at that select code */
+                       continue;             /* no board present at that select code */
                }
 
-                /* Found a board, allocate it an entry in the list */
+               /* Found a board, allocate it an entry in the list */
                dev = kzalloc(sizeof(struct dio_dev), GFP_KERNEL);
                if (!dev)
                        return -ENOMEM;
@@ -229,19 +227,19 @@ static int __init dio_init(void)
                dev->resource.end = pa + DIO_SIZE(scode, va);
                dev_set_name(&dev->dev, "%02x", scode);
 
-                /* read the ID byte(s) and encode if necessary. */
+               /* read the ID byte(s) and encode if necessary. */
                prid = DIO_ID(va);
 
-                if (DIO_NEEDSSECID(prid)) {
-                        secid = DIO_SECID(va);
-                        dev->id = DIO_ENCODE_ID(prid, secid);
-                } else
-                        dev->id = prid;
+               if (DIO_NEEDSSECID(prid)) {
+                       secid = DIO_SECID(va);
+                       dev->id = DIO_ENCODE_ID(prid, secid);
+               } else
+                       dev->id = prid;
 
-                dev->ipl = DIO_IPL(va);
-                strcpy(dev->name,dio_getname(dev->id));
+               dev->ipl = DIO_IPL(va);
+               strcpy(dev->name, dio_getname(dev->id));
                 printk(KERN_INFO "select code %3d: ipl %d: ID %02X", dev->scode, dev->ipl, prid);
-                if (DIO_NEEDSSECID(prid))
+               if (DIO_NEEDSSECID(prid))
                         printk(":%02X", secid);
                 printk(": %s\n", dev->name);
 
@@ -256,7 +254,7 @@ static int __init dio_init(void)
                error = dio_create_sysfs_dev_files(dev);
                if (error)
                        dev_err(&dev->dev, "Error creating sysfs files\n");
-        }
+       }
        return 0;
 }
 
@@ -267,12 +265,12 @@ subsys_initcall(dio_init);
  */
 unsigned long dio_scodetophysaddr(int scode)
 {
-        if (scode >= DIOII_SCBASE) {
-                return (DIOII_BASE + (scode - 132) * DIOII_DEVSIZE);
-        } else if (scode > DIO_SCMAX || scode < 0)
-                return 0;
-        else if (DIO_SCINHOLE(scode))
-                return 0;
-
-        return (DIO_BASE + scode * DIO_DEVSIZE);
+       if (scode >= DIOII_SCBASE)
+               return (DIOII_BASE + (scode - 132) * DIOII_DEVSIZE);
+       else if (scode > DIO_SCMAX || scode < 0)
+               return 0;
+       else if (DIO_SCINHOLE(scode))
+               return 0;
+
+       return (DIO_BASE + scode * DIO_DEVSIZE);
 }
index 56bf5ad..8f5848a 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/xarray.h>
 #include <linux/list.h>
 #include <linux/slab.h>
+#include <linux/nospec.h>
 #include <linux/uaccess.h>
 #include <linux/syscalls.h>
 #include <linux/dma-heap.h>
@@ -135,6 +136,7 @@ static long dma_heap_ioctl(struct file *file, unsigned int ucmd,
        if (nr >= ARRAY_SIZE(dma_heap_ioctl_cmds))
                return -EINVAL;
 
+       nr = array_index_nospec(nr, ARRAY_SIZE(dma_heap_ioctl_cmds));
        /* Get the kernel ioctl cmd that matches */
        kcmd = dma_heap_ioctl_cmds[nr];
 
index a1da2b4..1476156 100644 (file)
@@ -1681,8 +1681,10 @@ static void at_xdmac_tasklet(struct tasklet_struct *t)
                __func__, atchan->irq_status);
 
        if (!(atchan->irq_status & AT_XDMAC_CIS_LIS) &&
-           !(atchan->irq_status & error_mask))
+           !(atchan->irq_status & error_mask)) {
+               spin_unlock_irq(&atchan->lock);
                return;
+       }
 
        if (atchan->irq_status & error_mask)
                at_xdmac_handle_error(atchan);
index 8a6bf29..daafea5 100644 (file)
@@ -207,7 +207,7 @@ int pt_core_init(struct pt_device *pt)
        if (!cmd_q->qbase) {
                dev_err(dev, "unable to allocate command queue\n");
                ret = -ENOMEM;
-               goto e_dma_alloc;
+               goto e_destroy_pool;
        }
 
        cmd_q->qidx = 0;
@@ -229,8 +229,10 @@ int pt_core_init(struct pt_device *pt)
 
        /* Request an irq */
        ret = request_irq(pt->pt_irq, pt_core_irq_handler, 0, dev_name(pt->dev), pt);
-       if (ret)
-               goto e_pool;
+       if (ret) {
+               dev_err(dev, "unable to allocate an IRQ\n");
+               goto e_free_dma;
+       }
 
        /* Update the device registers with queue information. */
        cmd_q->qcontrol &= ~CMD_Q_SIZE;
@@ -250,21 +252,20 @@ int pt_core_init(struct pt_device *pt)
        /* Register the DMA engine support */
        ret = pt_dmaengine_register(pt);
        if (ret)
-               goto e_dmaengine;
+               goto e_free_irq;
 
        /* Set up debugfs entries */
        ptdma_debugfs_setup(pt);
 
        return 0;
 
-e_dmaengine:
+e_free_irq:
        free_irq(pt->pt_irq, pt);
 
-e_dma_alloc:
+e_free_dma:
        dma_free_coherent(dev, cmd_q->qsize, cmd_q->qbase, cmd_q->qbase_dma);
 
-e_pool:
-       dev_err(dev, "unable to allocate an IRQ\n");
+e_destroy_pool:
        dma_pool_destroy(pt->cmd_q.dma_pool);
 
        return ret;
index 481f45c..13d12d6 100644 (file)
@@ -1868,8 +1868,13 @@ static int rcar_dmac_probe(struct platform_device *pdev)
 
        dmac->dev = &pdev->dev;
        platform_set_drvdata(pdev, dmac);
-       dma_set_max_seg_size(dmac->dev, RCAR_DMATCR_MASK);
-       dma_set_mask_and_coherent(dmac->dev, DMA_BIT_MASK(40));
+       ret = dma_set_max_seg_size(dmac->dev, RCAR_DMATCR_MASK);
+       if (ret)
+               return ret;
+
+       ret = dma_set_mask_and_coherent(dmac->dev, DMA_BIT_MASK(40));
+       if (ret)
+               return ret;
 
        ret = rcar_dmac_parse_of(&pdev->dev, dmac);
        if (ret < 0)
index 158e5e7..b26ed69 100644 (file)
@@ -115,8 +115,10 @@ static dma_cookie_t shdma_tx_submit(struct dma_async_tx_descriptor *tx)
                ret = pm_runtime_get(schan->dev);
 
                spin_unlock_irq(&schan->chan_lock);
-               if (ret < 0)
+               if (ret < 0) {
                        dev_err(schan->dev, "%s(): GET = %d\n", __func__, ret);
+                       pm_runtime_put(schan->dev);
+               }
 
                pm_runtime_barrier(schan->dev);
 
index a421643..d5d5573 100644 (file)
@@ -292,10 +292,12 @@ static int stm32_dmamux_probe(struct platform_device *pdev)
        ret = of_dma_router_register(node, stm32_dmamux_route_allocate,
                                     &stm32_dmamux->dmarouter);
        if (ret)
-               goto err_clk;
+               goto pm_disable;
 
        return 0;
 
+pm_disable:
+       pm_runtime_disable(&pdev->dev);
 err_clk:
        clk_disable_unprepare(stm32_dmamux->clk);
 
index 3a6d241..5dd2978 100644 (file)
@@ -350,7 +350,7 @@ static int altr_sdram_probe(struct platform_device *pdev)
        if (irq < 0) {
                edac_printk(KERN_ERR, EDAC_MC,
                            "No irq %d in DT\n", irq);
-               return -ENODEV;
+               return irq;
        }
 
        /* Arria10 has a 2nd IRQ */
index 9d9aabd..f5677d8 100644 (file)
@@ -215,7 +215,7 @@ void *edac_align_ptr(void **p, unsigned int size, int n_elems)
        else
                return (char *)ptr;
 
-       r = (unsigned long)p % align;
+       r = (unsigned long)ptr % align;
 
        if (r == 0)
                return (char *)ptr;
index 2ccd1db..7197f9f 100644 (file)
@@ -1919,7 +1919,7 @@ static int xgene_edac_probe(struct platform_device *pdev)
                        irq = platform_get_irq_optional(pdev, i);
                        if (irq < 0) {
                                dev_err(&pdev->dev, "No IRQ resource\n");
-                               rc = -EINVAL;
+                               rc = irq;
                                goto out_err;
                        }
                        rc = devm_request_irq(&pdev->dev, irq,
index ae79c33..7de3f5b 100644 (file)
@@ -722,6 +722,13 @@ void __init efi_systab_report_header(const efi_table_hdr_t *systab_hdr,
                systab_hdr->revision >> 16,
                systab_hdr->revision & 0xffff,
                vendor);
+
+       if (IS_ENABLED(CONFIG_X86_64) &&
+           systab_hdr->revision > EFI_1_10_SYSTEM_TABLE_REVISION &&
+           !strcmp(vendor, "Apple")) {
+               pr_info("Apple Mac detected, using EFI v1.10 runtime services only\n");
+               efi.runtime_version = EFI_1_10_SYSTEM_TABLE_REVISION;
+       }
 }
 
 static __initdata char memory_type_name[][13] = {
index 2363fee..9cc5560 100644 (file)
@@ -119,9 +119,9 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
        if (image->image_base != _text)
                efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n");
 
-       if (!IS_ALIGNED((u64)_text, EFI_KIMG_ALIGN))
-               efi_err("FIRMWARE BUG: kernel image not aligned on %ldk boundary\n",
-                       EFI_KIMG_ALIGN >> 10);
+       if (!IS_ALIGNED((u64)_text, SEGMENT_ALIGN))
+               efi_err("FIRMWARE BUG: kernel image not aligned on %dk boundary\n",
+                       SEGMENT_ALIGN >> 10);
 
        kernel_size = _edata - _text;
        kernel_memsize = kernel_size + (_end - _edata);
index 29c0a61..4bd57a9 100644 (file)
@@ -306,6 +306,7 @@ static void svc_thread_recv_status_ok(struct stratix10_svc_data *p_data,
                break;
        case COMMAND_RSU_RETRY:
        case COMMAND_RSU_MAX_RETRY:
+       case COMMAND_FIRMWARE_VERSION:
                cb_data->status = BIT(SVC_STATUS_OK);
                cb_data->kaddr1 = &res.a1;
                break;
@@ -422,6 +423,11 @@ static int svc_normal_to_secure_thread(void *data)
                        a1 = 0;
                        a2 = 0;
                        break;
+               case COMMAND_FIRMWARE_VERSION:
+                       a0 = INTEL_SIP_SMC_FIRMWARE_VERSION;
+                       a1 = 0;
+                       a2 = 0;
+                       break;
                default:
                        pr_warn("it shouldn't happen\n");
                        break;
@@ -491,7 +497,8 @@ static int svc_normal_to_secure_thread(void *data)
                         */
                        if ((pdata->command == COMMAND_RSU_RETRY) ||
                            (pdata->command == COMMAND_RSU_MAX_RETRY) ||
-                               (pdata->command == COMMAND_RSU_NOTIFY)) {
+                           (pdata->command == COMMAND_RSU_NOTIFY) ||
+                           (pdata->command == COMMAND_FIRMWARE_VERSION)) {
                                cbdata->status =
                                        BIT(SVC_STATUS_NO_SUPPORT);
                                cbdata->kaddr1 = NULL;
index 450c5f6..7d8cb2e 100644 (file)
@@ -41,6 +41,16 @@ static DEFINE_HASHTABLE(pm_api_features_map, PM_API_FEATURE_CHECK_MAX_ORDER);
 
 static struct platform_device *em_dev;
 
+/**
+ * struct zynqmp_devinfo - Structure for Zynqmp device instance
+ * @dev:               Device Pointer
+ * @feature_conf_id:   Feature conf id
+ */
+struct zynqmp_devinfo {
+       struct device *dev;
+       u32 feature_conf_id;
+};
+
 /**
  * struct pm_api_feature_data - PM API Feature data
  * @pm_api_id:         PM API Id, used as key to index into hashmap
@@ -1156,6 +1166,33 @@ int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype)
                                   0, 0, NULL);
 }
 
+/**
+ * zynqmp_pm_set_feature_config - PM call to request IOCTL for feature config
+ * @id:         The config ID of the feature to be configured
+ * @value:      The config value of the feature to be configured
+ *
+ * Return:      Returns 0 on success or error value on failure.
+ */
+int zynqmp_pm_set_feature_config(enum pm_feature_config_id id, u32 value)
+{
+       return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_FEATURE_CONFIG,
+                                  id, value, NULL);
+}
+
+/**
+ * zynqmp_pm_get_feature_config - PM call to get value of configured feature
+ * @id:         The config id of the feature to be queried
+ * @payload:    Returned value array
+ *
+ * Return:      Returns 0 on success or error value on failure.
+ */
+int zynqmp_pm_get_feature_config(enum pm_feature_config_id id,
+                                u32 *payload)
+{
+       return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_GET_FEATURE_CONFIG,
+                                  id, 0, payload);
+}
+
 /**
  * struct zynqmp_pm_shutdown_scope - Struct for shutdown scope
  * @subtype:   Shutdown subtype
@@ -1424,6 +1461,78 @@ static DEVICE_ATTR_RW(pggs1);
 static DEVICE_ATTR_RW(pggs2);
 static DEVICE_ATTR_RW(pggs3);
 
+static ssize_t feature_config_id_show(struct device *device,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       struct zynqmp_devinfo *devinfo = dev_get_drvdata(device);
+
+       return sysfs_emit(buf, "%d\n", devinfo->feature_conf_id);
+}
+
+static ssize_t feature_config_id_store(struct device *device,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t count)
+{
+       u32 config_id;
+       int ret;
+       struct zynqmp_devinfo *devinfo = dev_get_drvdata(device);
+
+       if (!buf)
+               return -EINVAL;
+
+       ret = kstrtou32(buf, 10, &config_id);
+       if (ret)
+               return ret;
+
+       devinfo->feature_conf_id = config_id;
+
+       return count;
+}
+
+static DEVICE_ATTR_RW(feature_config_id);
+
+static ssize_t feature_config_value_show(struct device *device,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       int ret;
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+       struct zynqmp_devinfo *devinfo = dev_get_drvdata(device);
+
+       ret = zynqmp_pm_get_feature_config(devinfo->feature_conf_id,
+                                          ret_payload);
+       if (ret)
+               return ret;
+
+       return sysfs_emit(buf, "%d\n", ret_payload[1]);
+}
+
+static ssize_t feature_config_value_store(struct device *device,
+                                         struct device_attribute *attr,
+                                         const char *buf, size_t count)
+{
+       u32 value;
+       int ret;
+       struct zynqmp_devinfo *devinfo = dev_get_drvdata(device);
+
+       if (!buf)
+               return -EINVAL;
+
+       ret = kstrtou32(buf, 10, &value);
+       if (ret)
+               return ret;
+
+       ret = zynqmp_pm_set_feature_config(devinfo->feature_conf_id,
+                                          value);
+       if (ret)
+               return ret;
+
+       return count;
+}
+
+static DEVICE_ATTR_RW(feature_config_value);
+
 static struct attribute *zynqmp_firmware_attrs[] = {
        &dev_attr_ggs0.attr,
        &dev_attr_ggs1.attr,
@@ -1435,6 +1544,8 @@ static struct attribute *zynqmp_firmware_attrs[] = {
        &dev_attr_pggs3.attr,
        &dev_attr_shutdown_scope.attr,
        &dev_attr_health_status.attr,
+       &dev_attr_feature_config_id.attr,
+       &dev_attr_feature_config_value.attr,
        NULL,
 };
 
@@ -1444,6 +1555,7 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *np;
+       struct zynqmp_devinfo *devinfo;
        int ret;
 
        np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp");
@@ -1460,6 +1572,14 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       devinfo = devm_kzalloc(dev, sizeof(*devinfo), GFP_KERNEL);
+       if (!devinfo)
+               return -ENOMEM;
+
+       devinfo->dev = dev;
+
+       platform_set_drvdata(pdev, devinfo);
+
        /* Check PM API version number */
        ret = zynqmp_pm_get_api_version(&pm_api_version);
        if (ret)
index 4d68719..717ac97 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -354,16 +355,10 @@ int cci_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *pcidevid)
 
        pci_set_master(pcidev);
 
-       if (!pci_set_dma_mask(pcidev, DMA_BIT_MASK(64))) {
-               ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64));
-               if (ret)
-                       goto disable_error_report_exit;
-       } else if (!pci_set_dma_mask(pcidev, DMA_BIT_MASK(32))) {
-               ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32));
-               if (ret)
-                       goto disable_error_report_exit;
-       } else {
-               ret = -EIO;
+       ret = dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(64));
+       if (ret)
+               ret = dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32));
+       if (ret) {
                dev_err(&pcidev->dev, "No suitable DMA support available.\n");
                goto disable_error_report_exit;
        }
index 59ddc9f..3a7b78e 100644 (file)
@@ -24,9 +24,6 @@
 
 #include "fsi-master.h"
 
-#define CREATE_TRACE_POINTS
-#include <trace/events/fsi.h>
-
 #define FSI_SLAVE_CONF_NEXT_MASK       GENMASK(31, 31)
 #define FSI_SLAVE_CONF_SLOTS_MASK      GENMASK(23, 16)
 #define FSI_SLAVE_CONF_SLOTS_SHIFT     16
@@ -95,6 +92,9 @@ struct fsi_slave {
        u8                      t_echo_delay;
 };
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/fsi.h>
+
 #define to_fsi_master(d) container_of(d, struct fsi_master, dev)
 #define to_fsi_slave(d) container_of(d, struct fsi_slave, dev)
 
@@ -524,6 +524,8 @@ static int fsi_slave_scan(struct fsi_slave *slave)
                        dev->addr = engine_addr;
                        dev->size = slots * engine_page_size;
 
+                       trace_fsi_dev_init(dev);
+
                        dev_dbg(&slave->dev,
                        "engine[%i]: type %x, version %x, addr %x size %x\n",
                                        dev->unit, dev->engine_type, version,
@@ -1006,6 +1008,7 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
 
        crc = crc4(0, cfam_id, 32);
        if (crc) {
+               trace_fsi_slave_invalid_cfam(master, link, cfam_id);
                dev_warn(&master->dev, "slave %02x:%02x invalid cfam id CRC!\n",
                                link, id);
                return -EIO;
@@ -1080,6 +1083,8 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
        if (rc)
                goto err_free;
 
+       trace_fsi_slave_init(slave);
+
        /* Create chardev for userspace access */
        cdev_init(&slave->cdev, &cfam_fops);
        rc = cdev_device_add(&slave->cdev, &slave->dev);
index 8606e55..7cec177 100644 (file)
@@ -449,11 +449,13 @@ static ssize_t cfam_reset_store(struct device *dev, struct device_attribute *att
 {
        struct fsi_master_aspeed *aspeed = dev_get_drvdata(dev);
 
+       trace_fsi_master_aspeed_cfam_reset(true);
        mutex_lock(&aspeed->lock);
        gpiod_set_value(aspeed->cfam_reset_gpio, 1);
        usleep_range(900, 1000);
        gpiod_set_value(aspeed->cfam_reset_gpio, 0);
        mutex_unlock(&aspeed->lock);
+       trace_fsi_master_aspeed_cfam_reset(false);
 
        return count;
 }
@@ -542,25 +544,28 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev)
                return rc;
        }
 
-       aspeed = devm_kzalloc(&pdev->dev, sizeof(*aspeed), GFP_KERNEL);
+       aspeed = kzalloc(sizeof(*aspeed), GFP_KERNEL);
        if (!aspeed)
                return -ENOMEM;
 
        aspeed->dev = &pdev->dev;
 
        aspeed->base = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(aspeed->base))
-               return PTR_ERR(aspeed->base);
+       if (IS_ERR(aspeed->base)) {
+               rc = PTR_ERR(aspeed->base);
+               goto err_free_aspeed;
+       }
 
        aspeed->clk = devm_clk_get(aspeed->dev, NULL);
        if (IS_ERR(aspeed->clk)) {
                dev_err(aspeed->dev, "couldn't get clock\n");
-               return PTR_ERR(aspeed->clk);
+               rc = PTR_ERR(aspeed->clk);
+               goto err_free_aspeed;
        }
        rc = clk_prepare_enable(aspeed->clk);
        if (rc) {
                dev_err(aspeed->dev, "couldn't enable clock\n");
-               return rc;
+               goto err_free_aspeed;
        }
 
        rc = setup_cfam_reset(aspeed);
@@ -595,7 +600,7 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev)
        rc = opb_readl(aspeed, ctrl_base + FSI_MVER, &raw);
        if (rc) {
                dev_err(&pdev->dev, "failed to read hub version\n");
-               return rc;
+               goto err_release;
        }
 
        reg = be32_to_cpu(raw);
@@ -634,6 +639,8 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev)
 
 err_release:
        clk_disable_unprepare(aspeed->clk);
+err_free_aspeed:
+       kfree(aspeed);
        return rc;
 }
 
index 7eaab1b..c9cc75f 100644 (file)
@@ -451,6 +451,14 @@ static int occ_trigger_attn(struct occ *occ)
        return rc;
 }
 
+static bool fsi_occ_response_not_ready(struct occ_response *resp, u8 seq_no,
+                                      u8 cmd_type)
+{
+       return resp->return_status == OCC_RESP_CMD_IN_PRG ||
+               resp->return_status == OCC_RESP_CRIT_INIT ||
+               resp->seq_no != seq_no || resp->cmd_type != cmd_type;
+}
+
 int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
                   void *response, size_t *resp_len)
 {
@@ -461,10 +469,11 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
        struct occ_response *resp = response;
        size_t user_resp_len = *resp_len;
        u8 seq_no;
+       u8 cmd_type;
        u16 checksum = 0;
        u16 resp_data_length;
        const u8 *byte_request = (const u8 *)request;
-       unsigned long start;
+       unsigned long end;
        int rc;
        size_t i;
 
@@ -478,6 +487,8 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
                return -EINVAL;
        }
 
+       cmd_type = byte_request[1];
+
        /* Checksum the request, ignoring first byte (sequence number). */
        for (i = 1; i < req_len - 2; ++i)
                checksum += byte_request[i];
@@ -509,51 +520,61 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
        if (rc)
                goto done;
 
-       /* Read occ response header */
-       start = jiffies;
-       do {
+       end = jiffies + timeout;
+       while (true) {
+               /* Read occ response header */
                rc = occ_getsram(occ, 0, resp, 8);
                if (rc)
                        goto done;
 
-               if (resp->return_status == OCC_RESP_CMD_IN_PRG ||
-                   resp->return_status == OCC_RESP_CRIT_INIT ||
-                   resp->seq_no != seq_no) {
-                       rc = -ETIMEDOUT;
-
-                       if (time_after(jiffies, start + timeout)) {
-                               dev_err(occ->dev, "resp timeout status=%02x "
-                                       "resp seq_no=%d our seq_no=%d\n",
+               if (fsi_occ_response_not_ready(resp, seq_no, cmd_type)) {
+                       if (time_after(jiffies, end)) {
+                               dev_err(occ->dev,
+                                       "resp timeout status=%02x seq=%d cmd=%d, our seq=%d cmd=%d\n",
                                        resp->return_status, resp->seq_no,
-                                       seq_no);
+                                       resp->cmd_type, seq_no, cmd_type);
+                               rc = -ETIMEDOUT;
                                goto done;
                        }
 
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        schedule_timeout(wait_time);
-               }
-       } while (rc);
-
-       /* Extract size of response data */
-       resp_data_length = get_unaligned_be16(&resp->data_length);
+               } else {
+                       /* Extract size of response data */
+                       resp_data_length =
+                               get_unaligned_be16(&resp->data_length);
+
+                       /*
+                        * Message size is data length + 5 bytes header + 2
+                        * bytes checksum
+                        */
+                       if ((resp_data_length + 7) > user_resp_len) {
+                               rc = -EMSGSIZE;
+                               goto done;
+                       }
 
-       /* Message size is data length + 5 bytes header + 2 bytes checksum */
-       if ((resp_data_length + 7) > user_resp_len) {
-               rc = -EMSGSIZE;
-               goto done;
+                       /*
+                        * Get the entire response including the header again,
+                        * in case it changed
+                        */
+                       if (resp_data_length > 1) {
+                               rc = occ_getsram(occ, 0, resp,
+                                                resp_data_length + 7);
+                               if (rc)
+                                       goto done;
+
+                               if (!fsi_occ_response_not_ready(resp, seq_no,
+                                                               cmd_type))
+                                       break;
+                       } else {
+                               break;
+                       }
+               }
        }
 
        dev_dbg(dev, "resp_status=%02x resp_data_len=%d\n",
                resp->return_status, resp_data_length);
 
-       /* Grab the rest */
-       if (resp_data_length > 1) {
-               /* already got 3 bytes resp, also need 2 bytes checksum */
-               rc = occ_getsram(occ, 8, &resp->data[3], resp_data_length - 1);
-               if (rc)
-                       goto done;
-       }
-
        occ->client_response_size = resp_data_length + 7;
        rc = occ_verify_checksum(occ, resp, resp_data_length);
 
@@ -598,7 +619,11 @@ static int occ_probe(struct platform_device *pdev)
        occ->version = (uintptr_t)of_device_get_match_data(dev);
        occ->dev = dev;
        occ->sbefifo = dev->parent;
-       occ->sequence_number = 1;
+       /*
+        * Quickly derive a pseudo-random number from jiffies so that
+        * re-probing the driver doesn't accidentally overlap sequence numbers.
+        */
+       occ->sequence_number = (u8)((jiffies % 0xff) + 1);
        mutex_init(&occ->occ_lock);
 
        if (dev->of_node) {
index 52328ad..f52a912 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/vmalloc.h>
 #include <linux/mm.h>
 
+#include <uapi/linux/fsi.h>
+
 /*
  * The SBEFIFO is a pipe-like FSI device for communicating with
  * the self boot engine on POWER processors.
@@ -125,6 +127,7 @@ struct sbefifo {
        bool                    dead;
        bool                    async_ffdc;
        bool                    timed_out;
+       u32                     timeout_start_rsp_ms;
 };
 
 struct sbefifo_user {
@@ -133,6 +136,7 @@ struct sbefifo_user {
        void                    *cmd_page;
        void                    *pending_cmd;
        size_t                  pending_len;
+       u32                     read_timeout_ms;
 };
 
 static DEFINE_MUTEX(sbefifo_ffdc_mutex);
@@ -549,7 +553,7 @@ static int sbefifo_read_response(struct sbefifo *sbefifo, struct iov_iter *respo
 
        dev_vdbg(dev, "reading response, buflen = %zd\n", iov_iter_count(response));
 
-       timeout = msecs_to_jiffies(SBEFIFO_TIMEOUT_START_RSP);
+       timeout = msecs_to_jiffies(sbefifo->timeout_start_rsp_ms);
        for (;;) {
                /* Grab FIFO status (this will handle parity errors) */
                rc = sbefifo_wait(sbefifo, false, &status, timeout);
@@ -795,6 +799,7 @@ static int sbefifo_user_open(struct inode *inode, struct file *file)
                return -ENOMEM;
        }
        mutex_init(&user->file_lock);
+       user->read_timeout_ms = SBEFIFO_TIMEOUT_START_RSP;
 
        return 0;
 }
@@ -837,7 +842,9 @@ static ssize_t sbefifo_user_read(struct file *file, char __user *buf,
        rc = mutex_lock_interruptible(&sbefifo->lock);
        if (rc)
                goto bail;
+       sbefifo->timeout_start_rsp_ms = user->read_timeout_ms;
        rc = __sbefifo_submit(sbefifo, user->pending_cmd, cmd_len, &resp_iter);
+       sbefifo->timeout_start_rsp_ms = SBEFIFO_TIMEOUT_START_RSP;
        mutex_unlock(&sbefifo->lock);
        if (rc < 0)
                goto bail;
@@ -927,12 +934,55 @@ static int sbefifo_user_release(struct inode *inode, struct file *file)
        return 0;
 }
 
+static int sbefifo_read_timeout(struct sbefifo_user *user, void __user *argp)
+{
+       struct device *dev = &user->sbefifo->dev;
+       u32 timeout;
+
+       if (get_user(timeout, (__u32 __user *)argp))
+               return -EFAULT;
+
+       if (timeout == 0) {
+               user->read_timeout_ms = SBEFIFO_TIMEOUT_START_RSP;
+               dev_dbg(dev, "Timeout reset to %d\n", user->read_timeout_ms);
+               return 0;
+       }
+
+       if (timeout < 10 || timeout > 120)
+               return -EINVAL;
+
+       user->read_timeout_ms = timeout * 1000; /* user timeout is in sec */
+
+       dev_dbg(dev, "Timeout set to %d\n", user->read_timeout_ms);
+
+       return 0;
+}
+
+static long sbefifo_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct sbefifo_user *user = file->private_data;
+       int rc = -ENOTTY;
+
+       if (!user)
+               return -EINVAL;
+
+       mutex_lock(&user->file_lock);
+       switch (cmd) {
+       case FSI_SBEFIFO_READ_TIMEOUT_SECONDS:
+               rc = sbefifo_read_timeout(user, (void __user *)arg);
+               break;
+       }
+       mutex_unlock(&user->file_lock);
+       return rc;
+}
+
 static const struct file_operations sbefifo_fops = {
        .owner          = THIS_MODULE,
        .open           = sbefifo_user_open,
        .read           = sbefifo_user_read,
        .write          = sbefifo_user_write,
        .release        = sbefifo_user_release,
+       .unlocked_ioctl = sbefifo_user_ioctl,
 };
 
 static void sbefifo_free(struct device *dev)
@@ -972,6 +1022,7 @@ static int sbefifo_probe(struct device *dev)
        sbefifo->fsi_dev = fsi_dev;
        dev_set_drvdata(dev, sbefifo);
        mutex_init(&sbefifo->lock);
+       sbefifo->timeout_start_rsp_ms = SBEFIFO_TIMEOUT_START_RSP;
 
        /*
         * Try cleaning up the FIFO. If this fails, we still register the
index da1486b..bcb756d 100644 (file)
@@ -145,7 +145,7 @@ static int put_indirect_scom_form0(struct scom_device *scom, uint64_t value,
                                   uint64_t addr, uint32_t *status)
 {
        uint64_t ind_data, ind_addr;
-       int rc, retries, err = 0;
+       int rc, err;
 
        if (value & ~XSCOM_DATA_IND_DATA)
                return -EINVAL;
@@ -156,19 +156,14 @@ static int put_indirect_scom_form0(struct scom_device *scom, uint64_t value,
        if (rc || (*status & SCOM_STATUS_ANY_ERR))
                return rc;
 
-       for (retries = 0; retries < SCOM_MAX_IND_RETRIES; retries++) {
-               rc = __get_scom(scom, &ind_data, addr, status);
-               if (rc || (*status & SCOM_STATUS_ANY_ERR))
-                       return rc;
+       rc = __get_scom(scom, &ind_data, addr, status);
+       if (rc || (*status & SCOM_STATUS_ANY_ERR))
+               return rc;
 
-               err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT;
-               *status = err << SCOM_STATUS_PIB_RESP_SHIFT;
-               if ((ind_data & XSCOM_DATA_IND_COMPLETE) || (err != SCOM_PIB_BLOCKED))
-                       return 0;
+       err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT;
+       *status = err << SCOM_STATUS_PIB_RESP_SHIFT;
 
-               msleep(1);
-       }
-       return rc;
+       return 0;
 }
 
 static int put_indirect_scom_form1(struct scom_device *scom, uint64_t value,
@@ -188,7 +183,7 @@ static int get_indirect_scom_form0(struct scom_device *scom, uint64_t *value,
                                   uint64_t addr, uint32_t *status)
 {
        uint64_t ind_data, ind_addr;
-       int rc, retries, err = 0;
+       int rc, err;
 
        ind_addr = addr & XSCOM_ADDR_DIRECT_PART;
        ind_data = (addr & XSCOM_ADDR_INDIRECT_PART) | XSCOM_DATA_IND_READ;
@@ -196,21 +191,15 @@ static int get_indirect_scom_form0(struct scom_device *scom, uint64_t *value,
        if (rc || (*status & SCOM_STATUS_ANY_ERR))
                return rc;
 
-       for (retries = 0; retries < SCOM_MAX_IND_RETRIES; retries++) {
-               rc = __get_scom(scom, &ind_data, addr, status);
-               if (rc || (*status & SCOM_STATUS_ANY_ERR))
-                       return rc;
-
-               err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT;
-               *status = err << SCOM_STATUS_PIB_RESP_SHIFT;
-               *value = ind_data & XSCOM_DATA_IND_DATA;
+       rc = __get_scom(scom, &ind_data, addr, status);
+       if (rc || (*status & SCOM_STATUS_ANY_ERR))
+               return rc;
 
-               if ((ind_data & XSCOM_DATA_IND_COMPLETE) || (err != SCOM_PIB_BLOCKED))
-                       return 0;
+       err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT;
+       *status = err << SCOM_STATUS_PIB_RESP_SHIFT;
+       *value = ind_data & XSCOM_DATA_IND_DATA;
 
-               msleep(1);
-       }
-       return rc;
+       return 0;
 }
 
 static int raw_put_scom(struct scom_device *scom, uint64_t value,
@@ -289,7 +278,7 @@ static int put_scom(struct scom_device *scom, uint64_t value,
        int rc;
 
        rc = raw_put_scom(scom, value, addr, &status);
-       if (rc == -ENODEV)
+       if (rc)
                return rc;
 
        rc = handle_fsi2pib_status(scom, status);
@@ -308,7 +297,7 @@ static int get_scom(struct scom_device *scom, uint64_t *value,
        int rc;
 
        rc = raw_get_scom(scom, value, addr, &status);
-       if (rc == -ENODEV)
+       if (rc)
                return rc;
 
        rc = handle_fsi2pib_status(scom, status);
index 1c211b4..c822cf6 100644 (file)
@@ -1346,6 +1346,18 @@ config GPIO_TIMBERDALE
        help
        Add support for the GPIO IP in the timberdale FPGA.
 
+config GPIO_TN48M_CPLD
+       tristate "Delta Networks TN48M switch CPLD GPIO driver"
+       depends on MFD_TN48M_CPLD
+       select GPIO_REGMAP
+       help
+         This enables support for the GPIOs found on the Delta
+         Networks TN48M switch Lattice CPLD. It provides 12 pins in total,
+         they are input-only or output-only type.
+
+         This driver can also be built as a module. If so, the
+         module will be called gpio-tn48m.
+
 config GPIO_TPS65086
        tristate "TI TPS65086 GPO"
        depends on MFD_TPS65086
index edbaa3c..3b68a98 100644 (file)
@@ -148,6 +148,7 @@ obj-$(CONFIG_GPIO_TEGRA186)         += gpio-tegra186.o
 obj-$(CONFIG_GPIO_TEGRA)               += gpio-tegra.o
 obj-$(CONFIG_GPIO_THUNDERX)            += gpio-thunderx.o
 obj-$(CONFIG_GPIO_TIMBERDALE)          += gpio-timberdale.o
+obj-$(CONFIG_GPIO_TN48M_CPLD)          += gpio-tn48m.o
 obj-$(CONFIG_GPIO_TPIC2810)            += gpio-tpic2810.o
 obj-$(CONFIG_GPIO_TPS65086)            += gpio-tps65086.o
 obj-$(CONFIG_GPIO_TPS65218)            += gpio-tps65218.o
index 869dc95..0cb2664 100644 (file)
@@ -278,7 +278,8 @@ static int gpio_fwd_get(struct gpio_chip *chip, unsigned int offset)
 {
        struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
 
-       return gpiod_get_value(fwd->descs[offset]);
+       return chip->can_sleep ? gpiod_get_value_cansleep(fwd->descs[offset])
+                              : gpiod_get_value(fwd->descs[offset]);
 }
 
 static int gpio_fwd_get_multiple(struct gpiochip_fwd *fwd, unsigned long *mask,
@@ -293,7 +294,10 @@ static int gpio_fwd_get_multiple(struct gpiochip_fwd *fwd, unsigned long *mask,
        for_each_set_bit(i, mask, fwd->chip.ngpio)
                descs[j++] = fwd->descs[i];
 
-       error = gpiod_get_array_value(j, descs, NULL, values);
+       if (fwd->chip.can_sleep)
+               error = gpiod_get_array_value_cansleep(j, descs, NULL, values);
+       else
+               error = gpiod_get_array_value(j, descs, NULL, values);
        if (error)
                return error;
 
@@ -328,7 +332,10 @@ static void gpio_fwd_set(struct gpio_chip *chip, unsigned int offset, int value)
 {
        struct gpiochip_fwd *fwd = gpiochip_get_data(chip);
 
-       gpiod_set_value(fwd->descs[offset], value);
+       if (chip->can_sleep)
+               gpiod_set_value_cansleep(fwd->descs[offset], value);
+       else
+               gpiod_set_value(fwd->descs[offset], value);
 }
 
 static void gpio_fwd_set_multiple(struct gpiochip_fwd *fwd, unsigned long *mask,
@@ -343,7 +350,10 @@ static void gpio_fwd_set_multiple(struct gpiochip_fwd *fwd, unsigned long *mask,
                descs[j++] = fwd->descs[i];
        }
 
-       gpiod_set_array_value(j, descs, NULL, values);
+       if (fwd->chip.can_sleep)
+               gpiod_set_array_value_cansleep(j, descs, NULL, values);
+       else
+               gpiod_set_array_value(j, descs, NULL, values);
 }
 
 static void gpio_fwd_set_multiple_locked(struct gpio_chip *chip,
index a4c4e45..099e358 100644 (file)
@@ -410,10 +410,8 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
        level = rockchip_gpio_readl(bank, bank->gpio_regs->int_type);
        polarity = rockchip_gpio_readl(bank, bank->gpio_regs->int_polarity);
 
-       switch (type) {
-       case IRQ_TYPE_EDGE_BOTH:
+       if (type == IRQ_TYPE_EDGE_BOTH) {
                if (bank->gpio_type == GPIO_TYPE_V2) {
-                       bank->toggle_edge_mode &= ~mask;
                        rockchip_gpio_writel_bit(bank, d->hwirq, 1,
                                                 bank->gpio_regs->int_bothedge);
                        goto out;
@@ -431,30 +429,34 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
                        else
                                polarity |= mask;
                }
-               break;
-       case IRQ_TYPE_EDGE_RISING:
-               bank->toggle_edge_mode &= ~mask;
-               level |= mask;
-               polarity |= mask;
-               break;
-       case IRQ_TYPE_EDGE_FALLING:
-               bank->toggle_edge_mode &= ~mask;
-               level |= mask;
-               polarity &= ~mask;
-               break;
-       case IRQ_TYPE_LEVEL_HIGH:
-               bank->toggle_edge_mode &= ~mask;
-               level &= ~mask;
-               polarity |= mask;
-               break;
-       case IRQ_TYPE_LEVEL_LOW:
-               bank->toggle_edge_mode &= ~mask;
-               level &= ~mask;
-               polarity &= ~mask;
-               break;
-       default:
-               ret = -EINVAL;
-               goto out;
+       } else {
+               if (bank->gpio_type == GPIO_TYPE_V2) {
+                       rockchip_gpio_writel_bit(bank, d->hwirq, 0,
+                                                bank->gpio_regs->int_bothedge);
+               } else {
+                       bank->toggle_edge_mode &= ~mask;
+               }
+               switch (type) {
+               case IRQ_TYPE_EDGE_RISING:
+                       level |= mask;
+                       polarity |= mask;
+                       break;
+               case IRQ_TYPE_EDGE_FALLING:
+                       level |= mask;
+                       polarity &= ~mask;
+                       break;
+               case IRQ_TYPE_LEVEL_HIGH:
+                       level &= ~mask;
+                       polarity |= mask;
+                       break;
+               case IRQ_TYPE_LEVEL_LOW:
+                       level &= ~mask;
+                       polarity &= ~mask;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto out;
+               }
        }
 
        rockchip_gpio_writel(bank, level, bank->gpio_regs->int_type);
index 403f9e8..7d82388 100644 (file)
@@ -223,7 +223,7 @@ static int sifive_gpio_probe(struct platform_device *pdev)
                         NULL,
                         chip->base + SIFIVE_GPIO_OUTPUT_EN,
                         chip->base + SIFIVE_GPIO_INPUT_EN,
-                        0);
+                        BGPIOF_READ_OUTPUT_REG_SET);
        if (ret) {
                dev_err(dev, "unable to init generic GPIO\n");
                return ret;
index 838bbfe..153fe79 100644 (file)
@@ -570,6 +570,11 @@ static struct gpio_sim_bank *to_gpio_sim_bank(struct config_item *item)
        return container_of(group, struct gpio_sim_bank, group);
 }
 
+static bool gpio_sim_bank_has_label(struct gpio_sim_bank *bank)
+{
+       return bank->label && *bank->label;
+}
+
 static struct gpio_sim_device *
 gpio_sim_bank_get_device(struct gpio_sim_bank *bank)
 {
@@ -770,9 +775,15 @@ static int gpio_sim_add_hogs(struct gpio_sim_device *dev)
                         * point the device doesn't exist yet and so dev_name()
                         * is not available.
                         */
-                       hog->chip_label = kasprintf(GFP_KERNEL,
-                                                   "gpio-sim.%u-%s", dev->id,
-                                                   fwnode_get_name(bank->swnode));
+                       if (gpio_sim_bank_has_label(bank))
+                               hog->chip_label = kstrdup(bank->label,
+                                                         GFP_KERNEL);
+                       else
+                               hog->chip_label = kasprintf(GFP_KERNEL,
+                                                       "gpio-sim.%u-%s",
+                                                       dev->id,
+                                                       fwnode_get_name(
+                                                               bank->swnode));
                        if (!hog->chip_label) {
                                gpio_sim_remove_hogs(dev);
                                return -ENOMEM;
@@ -816,7 +827,7 @@ gpio_sim_make_bank_swnode(struct gpio_sim_bank *bank,
 
        properties[prop_idx++] = PROPERTY_ENTRY_U32("ngpios", bank->num_lines);
 
-       if (bank->label)
+       if (gpio_sim_bank_has_label(bank))
                properties[prop_idx++] = PROPERTY_ENTRY_STRING("gpio-sim,label",
                                                               bank->label);
 
index 34b36a8..8d298be 100644 (file)
@@ -343,9 +343,12 @@ static int tegra186_gpio_of_xlate(struct gpio_chip *chip,
        return offset + pin;
 }
 
+#define to_tegra_gpio(x) container_of((x), struct tegra_gpio, gpio)
+
 static void tegra186_irq_ack(struct irq_data *data)
 {
-       struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+       struct tegra_gpio *gpio = to_tegra_gpio(gc);
        void __iomem *base;
 
        base = tegra186_gpio_get_base(gpio, data->hwirq);
@@ -357,7 +360,8 @@ static void tegra186_irq_ack(struct irq_data *data)
 
 static void tegra186_irq_mask(struct irq_data *data)
 {
-       struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+       struct tegra_gpio *gpio = to_tegra_gpio(gc);
        void __iomem *base;
        u32 value;
 
@@ -372,7 +376,8 @@ static void tegra186_irq_mask(struct irq_data *data)
 
 static void tegra186_irq_unmask(struct irq_data *data)
 {
-       struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+       struct tegra_gpio *gpio = to_tegra_gpio(gc);
        void __iomem *base;
        u32 value;
 
@@ -387,7 +392,8 @@ static void tegra186_irq_unmask(struct irq_data *data)
 
 static int tegra186_irq_set_type(struct irq_data *data, unsigned int type)
 {
-       struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+       struct tegra_gpio *gpio = to_tegra_gpio(gc);
        void __iomem *base;
        u32 value;
 
diff --git a/drivers/gpio/gpio-tn48m.c b/drivers/gpio/gpio-tn48m.c
new file mode 100644 (file)
index 0000000..cd4a80b
--- /dev/null
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Delta TN48M CPLD GPIO driver
+ *
+ * Copyright (C) 2021 Sartura Ltd.
+ *
+ * Author: Robert Marko <robert.marko@sartura.hr>
+ */
+
+#include <linux/device.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio/regmap.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+enum tn48m_gpio_type {
+       TN48M_GP0 = 1,
+       TN48M_GPI,
+};
+
+struct tn48m_gpio_config {
+       int ngpio;
+       int ngpio_per_reg;
+       enum tn48m_gpio_type type;
+};
+
+static const struct tn48m_gpio_config tn48m_gpo_config = {
+       .ngpio = 4,
+       .ngpio_per_reg = 4,
+       .type = TN48M_GP0,
+};
+
+static const struct tn48m_gpio_config tn48m_gpi_config = {
+       .ngpio = 4,
+       .ngpio_per_reg = 4,
+       .type = TN48M_GPI,
+};
+
+static int tn48m_gpio_probe(struct platform_device *pdev)
+{
+       const struct tn48m_gpio_config *gpio_config;
+       struct gpio_regmap_config config = {};
+       struct regmap *regmap;
+       u32 base;
+       int ret;
+
+       if (!pdev->dev.parent)
+               return -ENODEV;
+
+       gpio_config = device_get_match_data(&pdev->dev);
+       if (!gpio_config)
+               return -ENODEV;
+
+       ret = device_property_read_u32(&pdev->dev, "reg", &base);
+       if (ret)
+               return ret;
+
+       regmap = dev_get_regmap(pdev->dev.parent, NULL);
+       if (!regmap)
+               return -ENODEV;
+
+       config.regmap = regmap;
+       config.parent = &pdev->dev;
+       config.ngpio = gpio_config->ngpio;
+       config.ngpio_per_reg = gpio_config->ngpio_per_reg;
+       switch (gpio_config->type) {
+       case TN48M_GP0:
+               config.reg_set_base = base;
+               break;
+       case TN48M_GPI:
+               config.reg_dat_base = base;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(&pdev->dev, &config));
+}
+
+static const struct of_device_id tn48m_gpio_of_match[] = {
+       { .compatible = "delta,tn48m-gpo", .data = &tn48m_gpo_config },
+       { .compatible = "delta,tn48m-gpi", .data = &tn48m_gpi_config },
+       { }
+};
+MODULE_DEVICE_TABLE(of, tn48m_gpio_of_match);
+
+static struct platform_driver tn48m_gpio_driver = {
+       .driver = {
+               .name = "delta-tn48m-gpio",
+               .of_match_table = tn48m_gpio_of_match,
+       },
+       .probe = tn48m_gpio_probe,
+};
+module_platform_driver(tn48m_gpio_driver);
+
+MODULE_AUTHOR("Robert Marko <robert.marko@sartura.hr>");
+MODULE_DESCRIPTION("Delta TN48M CPLD GPIO driver");
+MODULE_LICENSE("GPL");
index c7b5446..ffa0256 100644 (file)
@@ -330,7 +330,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
                        goto out_free_lh;
                }
 
-               ret = gpiod_request(desc, lh->label);
+               ret = gpiod_request_user(desc, lh->label);
                if (ret)
                        goto out_free_lh;
                lh->descs[i] = desc;
@@ -1378,7 +1378,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
                        goto out_free_linereq;
                }
 
-               ret = gpiod_request(desc, lr->label);
+               ret = gpiod_request_user(desc, lr->label);
                if (ret)
                        goto out_free_linereq;
 
@@ -1764,7 +1764,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
                }
        }
 
-       ret = gpiod_request(desc, le->label);
+       ret = gpiod_request_user(desc, le->label);
        if (ret)
                goto out_free_le;
        le->desc = desc;
index 4098bc7..44c1ad5 100644 (file)
@@ -475,12 +475,9 @@ static ssize_t export_store(struct class *class,
         * they may be undone on its behalf too.
         */
 
-       status = gpiod_request(desc, "sysfs");
-       if (status) {
-               if (status == -EPROBE_DEFER)
-                       status = -ENODEV;
+       status = gpiod_request_user(desc, "sysfs");
+       if (status)
                goto done;
-       }
 
        status = gpiod_set_transitory(desc, false);
        if (!status) {
index 3859911..a3d1427 100644 (file)
@@ -3147,6 +3147,16 @@ int gpiod_to_irq(const struct gpio_desc *desc)
 
                return retirq;
        }
+#ifdef CONFIG_GPIOLIB_IRQCHIP
+       if (gc->irq.chip) {
+               /*
+                * Avoid race condition with other code, which tries to lookup
+                * an IRQ before the irqchip has been properly registered,
+                * i.e. while gpiochip is still being brought up.
+                */
+               return -EPROBE_DEFER;
+       }
+#endif
        return -ENXIO;
 }
 EXPORT_SYMBOL_GPL(gpiod_to_irq);
index 30bc3f8..c31f462 100644 (file)
@@ -135,6 +135,18 @@ struct gpio_desc {
 
 int gpiod_request(struct gpio_desc *desc, const char *label);
 void gpiod_free(struct gpio_desc *desc);
+
+static inline int gpiod_request_user(struct gpio_desc *desc, const char *label)
+{
+       int ret;
+
+       ret = gpiod_request(desc, label);
+       if (ret == -EPROBE_DEFER)
+               ret = -ENODEV;
+
+       return ret;
+}
+
 int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
                unsigned long lflags, enum gpiod_flags dflags);
 int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce);
index d8b854f..9a53a4d 100644 (file)
@@ -1408,12 +1408,10 @@ int amdgpu_acpi_smart_shift_update(struct drm_device *dev, enum amdgpu_ss ss_sta
 int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev);
 
 void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps);
-bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev);
 void amdgpu_acpi_detect(void);
 #else
 static inline int amdgpu_acpi_init(struct amdgpu_device *adev) { return 0; }
 static inline void amdgpu_acpi_fini(struct amdgpu_device *adev) { }
-static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { return false; }
 static inline void amdgpu_acpi_detect(void) { }
 static inline bool amdgpu_acpi_is_power_shift_control_supported(void) { return false; }
 static inline int amdgpu_acpi_power_shift_control(struct amdgpu_device *adev,
@@ -1422,6 +1420,14 @@ static inline int amdgpu_acpi_smart_shift_update(struct drm_device *dev,
                                                 enum amdgpu_ss ss_state) { return 0; }
 #endif
 
+#if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND)
+bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev);
+bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev);
+#else
+static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { return false; }
+static inline bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev) { return false; }
+#endif
+
 int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
                           uint64_t addr, struct amdgpu_bo **bo,
                           struct amdgpu_bo_va_mapping **mapping);
index 4811b0f..0e12315 100644 (file)
@@ -1031,6 +1031,20 @@ void amdgpu_acpi_detect(void)
        }
 }
 
+#if IS_ENABLED(CONFIG_SUSPEND)
+/**
+ * amdgpu_acpi_is_s3_active
+ *
+ * @adev: amdgpu_device_pointer
+ *
+ * returns true if supported, false if not.
+ */
+bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev)
+{
+       return !(adev->flags & AMD_IS_APU) ||
+               (pm_suspend_target_state == PM_SUSPEND_MEM);
+}
+
 /**
  * amdgpu_acpi_is_s0ix_active
  *
@@ -1040,11 +1054,24 @@ void amdgpu_acpi_detect(void)
  */
 bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev)
 {
-#if IS_ENABLED(CONFIG_AMD_PMC) && IS_ENABLED(CONFIG_SUSPEND)
-       if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) {
-               if (adev->flags & AMD_IS_APU)
-                       return pm_suspend_target_state == PM_SUSPEND_TO_IDLE;
+       if (!(adev->flags & AMD_IS_APU) ||
+           (pm_suspend_target_state != PM_SUSPEND_TO_IDLE))
+               return false;
+
+       if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) {
+               dev_warn_once(adev->dev,
+                             "Power consumption will be higher as BIOS has not been configured for suspend-to-idle.\n"
+                             "To use suspend-to-idle change the sleep mode in BIOS setup.\n");
+               return false;
        }
-#endif
+
+#if !IS_ENABLED(CONFIG_AMD_PMC)
+       dev_warn_once(adev->dev,
+                     "Power consumption will be higher as the kernel has not been compiled with CONFIG_AMD_PMC.\n");
        return false;
+#else
+       return true;
+#endif /* CONFIG_AMD_PMC */
 }
+
+#endif /* CONFIG_SUSPEND */
index 82011e7..c4387b3 100644 (file)
@@ -1141,7 +1141,7 @@ int amdgpu_display_framebuffer_init(struct drm_device *dev,
        if (ret)
                return ret;
 
-       if (!dev->mode_config.allow_fb_modifiers) {
+       if (!dev->mode_config.allow_fb_modifiers && !adev->enable_virtual_display) {
                drm_WARN_ONCE(dev, adev->family >= AMDGPU_FAMILY_AI,
                              "GFX9+ requires FB check based on format modifier\n");
                ret = check_tiling_flags_gfx6(rfb);
index b21bcdc..0ead08b 100644 (file)
@@ -1525,6 +1525,87 @@ static const u16 amdgpu_unsupported_pciidlist[] = {
        0x99A0,
        0x99A2,
        0x99A4,
+       /* radeon secondary ids */
+       0x3171,
+       0x3e70,
+       0x4164,
+       0x4165,
+       0x4166,
+       0x4168,
+       0x4170,
+       0x4171,
+       0x4172,
+       0x4173,
+       0x496e,
+       0x4a69,
+       0x4a6a,
+       0x4a6b,
+       0x4a70,
+       0x4a74,
+       0x4b69,
+       0x4b6b,
+       0x4b6c,
+       0x4c6e,
+       0x4e64,
+       0x4e65,
+       0x4e66,
+       0x4e67,
+       0x4e68,
+       0x4e69,
+       0x4e6a,
+       0x4e71,
+       0x4f73,
+       0x5569,
+       0x556b,
+       0x556d,
+       0x556f,
+       0x5571,
+       0x5854,
+       0x5874,
+       0x5940,
+       0x5941,
+       0x5b72,
+       0x5b73,
+       0x5b74,
+       0x5b75,
+       0x5d44,
+       0x5d45,
+       0x5d6d,
+       0x5d6f,
+       0x5d72,
+       0x5d77,
+       0x5e6b,
+       0x5e6d,
+       0x7120,
+       0x7124,
+       0x7129,
+       0x712e,
+       0x712f,
+       0x7162,
+       0x7163,
+       0x7166,
+       0x7167,
+       0x7172,
+       0x7173,
+       0x71a0,
+       0x71a1,
+       0x71a3,
+       0x71a7,
+       0x71bb,
+       0x71e0,
+       0x71e1,
+       0x71e2,
+       0x71e6,
+       0x71e7,
+       0x71f2,
+       0x7269,
+       0x726b,
+       0x726e,
+       0x72a0,
+       0x72a8,
+       0x72b1,
+       0x72b3,
+       0x793f,
 };
 
 static const struct pci_device_id pciidlist[] = {
@@ -1930,6 +2011,9 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
                        return -ENODEV;
        }
 
+       if (amdgpu_aspm == -1 && !pcie_aspm_enabled(pdev))
+               amdgpu_aspm = 0;
+
        if (amdgpu_virtual_display ||
            amdgpu_device_asic_has_dc_support(flags & AMD_ASIC_MASK))
                supports_atomic = true;
@@ -2165,13 +2249,20 @@ static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work)
 static int amdgpu_pmops_prepare(struct device *dev)
 {
        struct drm_device *drm_dev = dev_get_drvdata(dev);
+       struct amdgpu_device *adev = drm_to_adev(drm_dev);
 
        /* Return a positive number here so
         * DPM_FLAG_SMART_SUSPEND works properly
         */
        if (amdgpu_device_supports_boco(drm_dev))
-               return pm_runtime_suspended(dev) &&
-                       pm_suspend_via_firmware();
+               return pm_runtime_suspended(dev);
+
+       /* if we will not support s3 or s2i for the device
+        *  then skip suspend
+        */
+       if (!amdgpu_acpi_is_s0ix_active(adev) &&
+           !amdgpu_acpi_is_s3_active(adev))
+               return 1;
 
        return 0;
 }
index 5c3f240..4655702 100644 (file)
@@ -1904,7 +1904,7 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset,
        unsigned i;
        int r;
 
-       if (direct_submit && !ring->sched.ready) {
+       if (!direct_submit && !ring->sched.ready) {
                DRM_ERROR("Trying to move memory with ring turned off.\n");
                return -EINVAL;
        }
index d99c877..5224d9a 100644 (file)
@@ -391,7 +391,6 @@ static struct drm_plane *amdgpu_vkms_plane_init(struct drm_device *dev,
                                                int index)
 {
        struct drm_plane *plane;
-       uint64_t modifiers[] = {DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID};
        int ret;
 
        plane = kzalloc(sizeof(*plane), GFP_KERNEL);
@@ -402,7 +401,7 @@ static struct drm_plane *amdgpu_vkms_plane_init(struct drm_device *dev,
                                       &amdgpu_vkms_plane_funcs,
                                       amdgpu_vkms_formats,
                                       ARRAY_SIZE(amdgpu_vkms_formats),
-                                      modifiers, type, NULL);
+                                      NULL, type, NULL);
        if (ret) {
                kfree(plane);
                return ERR_PTR(ret);
index b37fc7d..d62190b 100644 (file)
@@ -768,11 +768,16 @@ int amdgpu_vm_validate_pt_bos(struct amdgpu_device *adev, struct amdgpu_vm *vm,
  * Check if all VM PDs/PTs are ready for updates
  *
  * Returns:
- * True if eviction list is empty.
+ * True if VM is not evicting.
  */
 bool amdgpu_vm_ready(struct amdgpu_vm *vm)
 {
-       return list_empty(&vm->evicted);
+       bool ret;
+
+       amdgpu_vm_eviction_lock(vm);
+       ret = !vm->evicting;
+       amdgpu_vm_eviction_unlock(vm);
+       return ret;
 }
 
 /**
index b4eddf6..ff738e9 100644 (file)
@@ -543,7 +543,9 @@ static void gfxhub_v2_1_utcl2_harvest(struct amdgpu_device *adev)
                adev->gfx.config.max_sh_per_se *
                adev->gfx.config.max_shader_engines);
 
-       if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 3, 3)) {
+       switch (adev->ip_versions[GC_HWIP][0]) {
+       case IP_VERSION(10, 3, 1):
+       case IP_VERSION(10, 3, 3):
                /* Get SA disabled bitmap from eFuse setting */
                efuse_setting = RREG32_SOC15(GC, 0, mmCC_GC_SA_UNIT_DISABLE);
                efuse_setting &= CC_GC_SA_UNIT_DISABLE__SA_DISABLE_MASK;
@@ -566,6 +568,9 @@ static void gfxhub_v2_1_utcl2_harvest(struct amdgpu_device *adev)
                disabled_sa = tmp;
 
                WREG32_SOC15(GC, 0, mmGCUTCL2_HARVEST_BYPASS_GROUPS_YELLOW_CARP, disabled_sa);
+               break;
+       default:
+               break;
        }
 }
 
index 38bb427..a2f8ed0 100644 (file)
@@ -1140,6 +1140,9 @@ static void gmc_v10_0_get_clockgating_state(void *handle, u32 *flags)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       if (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 1, 3))
+               return;
+
        adev->mmhub.funcs->get_clockgating(adev, flags);
 
        if (adev->ip_versions[ATHUB_HWIP][0] >= IP_VERSION(2, 1, 0))
index e8e4749..f0638db 100644 (file)
@@ -2057,6 +2057,10 @@ static int sdma_v4_0_suspend(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       /* SMU saves SDMA state for us */
+       if (adev->in_s0ix)
+               return 0;
+
        return sdma_v4_0_hw_fini(adev);
 }
 
@@ -2064,6 +2068,10 @@ static int sdma_v4_0_resume(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       /* SMU restores SDMA state for us */
+       if (adev->in_s0ix)
+               return 0;
+
        return sdma_v4_0_hw_init(adev);
 }
 
index 0fc1747..12f80fd 100644 (file)
@@ -619,8 +619,8 @@ soc15_asic_reset_method(struct amdgpu_device *adev)
 static int soc15_asic_reset(struct amdgpu_device *adev)
 {
        /* original raven doesn't have full asic reset */
-       if ((adev->apu_flags & AMD_APU_IS_RAVEN) &&
-           !(adev->apu_flags & AMD_APU_IS_RAVEN2))
+       if ((adev->apu_flags & AMD_APU_IS_RAVEN) ||
+           (adev->apu_flags & AMD_APU_IS_RAVEN2))
                return 0;
 
        switch (soc15_asic_reset_method(adev)) {
@@ -1114,8 +1114,11 @@ static int soc15_common_early_init(void *handle)
                                AMD_CG_SUPPORT_SDMA_LS |
                                AMD_CG_SUPPORT_VCN_MGCG;
 
+                       /*
+                        * MMHUB PG needs to be disabled for Picasso for
+                        * stability reasons.
+                        */
                        adev->pg_flags = AMD_PG_SUPPORT_SDMA |
-                               AMD_PG_SUPPORT_MMHUB |
                                AMD_PG_SUPPORT_VCN;
                } else {
                        adev->cg_flags = AMD_CG_SUPPORT_GFX_MGCG |
index 7f9773f..075429b 100644 (file)
@@ -3653,7 +3653,7 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
 
        /* Use GRPH_PFLIP interrupt */
        for (i = DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT;
-                       i <= DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT + adev->mode_info.num_crtc - 1;
+                       i <= DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT + dc->caps.max_otg_num - 1;
                        i++) {
                r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->pageflip_irq);
                if (r) {
@@ -4256,6 +4256,9 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
        }
 #endif
 
+       /* Disable vblank IRQs aggressively for power-saving. */
+       adev_to_drm(adev)->vblank_disable_immediate = true;
+
        /* loops over all connectors on the board */
        for (i = 0; i < link_cnt; i++) {
                struct dc_link *link = NULL;
@@ -4301,19 +4304,17 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
                                update_connector_ext_caps(aconnector);
                        if (psr_feature_enabled)
                                amdgpu_dm_set_psr_caps(link);
+
+                       /* TODO: Fix vblank control helpers to delay PSR entry to allow this when
+                        * PSR is also supported.
+                        */
+                       if (link->psr_settings.psr_feature_enabled)
+                               adev_to_drm(adev)->vblank_disable_immediate = false;
                }
 
 
        }
 
-       /*
-        * Disable vblank IRQs aggressively for power-saving.
-        *
-        * TODO: Fix vblank control helpers to delay PSR entry to allow this when PSR
-        * is also supported.
-        */
-       adev_to_drm(adev)->vblank_disable_immediate = !psr_feature_enabled;
-
        /* Software is initialized. Now we can register interrupt handlers. */
        switch (adev->asic_type) {
 #if defined(CONFIG_DRM_AMD_DC_SI)
index ff5bb15..e6ef36d 100644 (file)
@@ -2033,10 +2033,10 @@ static void calculate_bandwidth(
        kfree(surface_type);
 free_tiling_mode:
        kfree(tiling_mode);
-free_yclk:
-       kfree(yclk);
 free_sclk:
        kfree(sclk);
+free_yclk:
+       kfree(yclk);
 }
 
 /*******************************************************************************
index ec19678..e447c74 100644 (file)
@@ -503,7 +503,6 @@ static void dcn_bw_calc_rq_dlg_ttu(
        //input[in_idx].dout.output_standard;
 
        /*todo: soc->sr_enter_plus_exit_time??*/
-       dlg_sys_param->t_srx_delay_us = dc->dcn_ip->dcfclk_cstate_latency / v->dcf_clk_deep_sleep;
 
        dml1_rq_dlg_get_rq_params(dml, rq_param, &input->pipe.src);
        dml1_extract_rq_regs(dml, rq_regs, rq_param);
index f977f29..10c7be4 100644 (file)
@@ -473,8 +473,10 @@ static void dcn3_get_memclk_states_from_smu(struct clk_mgr *clk_mgr_base)
        clk_mgr_base->bw_params->dc_mode_softmax_memclk = dcn30_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_UCLK);
 
        /* Refresh bounding box */
+       DC_FP_START();
        clk_mgr_base->ctx->dc->res_pool->funcs->update_bw_bounding_box(
                        clk_mgr->base.ctx->dc, clk_mgr_base->bw_params);
+       DC_FP_END();
 }
 
 static bool dcn3_is_smu_present(struct clk_mgr *clk_mgr_base)
index 48005de..bc4ddc3 100644 (file)
@@ -570,32 +570,32 @@ static struct wm_table lpddr5_wm_table = {
                        .wm_inst = WM_A,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.65333,
-                       .sr_exit_time_us = 7.95,
-                       .sr_enter_plus_exit_time_us = 9,
+                       .sr_exit_time_us = 13.5,
+                       .sr_enter_plus_exit_time_us = 16.5,
                        .valid = true,
                },
                {
                        .wm_inst = WM_B,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.65333,
-                       .sr_exit_time_us = 9.82,
-                       .sr_enter_plus_exit_time_us = 11.196,
+                       .sr_exit_time_us = 13.5,
+                       .sr_enter_plus_exit_time_us = 16.5,
                        .valid = true,
                },
                {
                        .wm_inst = WM_C,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.65333,
-                       .sr_exit_time_us = 9.89,
-                       .sr_enter_plus_exit_time_us = 11.24,
+                       .sr_exit_time_us = 13.5,
+                       .sr_enter_plus_exit_time_us = 16.5,
                        .valid = true,
                },
                {
                        .wm_inst = WM_D,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.65333,
-                       .sr_exit_time_us = 9.748,
-                       .sr_enter_plus_exit_time_us = 11.102,
+                       .sr_exit_time_us = 13.5,
+                       .sr_enter_plus_exit_time_us = 16.5,
                        .valid = true,
                },
        }
index 4162ce4..9d17c5a 100644 (file)
@@ -329,38 +329,38 @@ static struct clk_bw_params dcn31_bw_params = {
 
 };
 
-static struct wm_table ddr4_wm_table = {
+static struct wm_table ddr5_wm_table = {
        .entries = {
                {
                        .wm_inst = WM_A,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.72,
-                       .sr_exit_time_us = 6.09,
-                       .sr_enter_plus_exit_time_us = 7.14,
+                       .sr_exit_time_us = 9,
+                       .sr_enter_plus_exit_time_us = 11,
                        .valid = true,
                },
                {
                        .wm_inst = WM_B,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.72,
-                       .sr_exit_time_us = 10.12,
-                       .sr_enter_plus_exit_time_us = 11.48,
+                       .sr_exit_time_us = 9,
+                       .sr_enter_plus_exit_time_us = 11,
                        .valid = true,
                },
                {
                        .wm_inst = WM_C,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.72,
-                       .sr_exit_time_us = 10.12,
-                       .sr_enter_plus_exit_time_us = 11.48,
+                       .sr_exit_time_us = 9,
+                       .sr_enter_plus_exit_time_us = 11,
                        .valid = true,
                },
                {
                        .wm_inst = WM_D,
                        .wm_type = WM_TYPE_PSTATE_CHG,
                        .pstate_latency_us = 11.72,
-                       .sr_exit_time_us = 10.12,
-                       .sr_enter_plus_exit_time_us = 11.48,
+                       .sr_exit_time_us = 9,
+                       .sr_enter_plus_exit_time_us = 11,
                        .valid = true,
                },
        }
@@ -687,7 +687,7 @@ void dcn31_clk_mgr_construct(
                if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) {
                        dcn31_bw_params.wm_table = lpddr5_wm_table;
                } else {
-                       dcn31_bw_params.wm_table = ddr4_wm_table;
+                       dcn31_bw_params.wm_table = ddr5_wm_table;
                }
                /* Saved clocks configured at boot for debug purposes */
                 dcn31_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, &clk_mgr->base.base, &log_info);
index a1011f3..de3f464 100644 (file)
@@ -120,7 +120,11 @@ static int dcn31_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr,
        result = dcn31_smu_wait_for_response(clk_mgr, 10, 200000);
 
        if (result == VBIOSSMC_Result_Failed) {
-               ASSERT(0);
+               if (msg_id == VBIOSSMC_MSG_TransferTableDram2Smu &&
+                   param == TABLE_WATERMARKS)
+                       DC_LOG_WARNING("Watermarks table not configured properly by SMU");
+               else
+                       ASSERT(0);
                REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Result_OK);
                return -1;
        }
index 01c8849..ba1aa99 100644 (file)
@@ -985,10 +985,13 @@ static bool dc_construct(struct dc *dc,
                goto fail;
 #ifdef CONFIG_DRM_AMD_DC_DCN
        dc->clk_mgr->force_smu_not_present = init_params->force_smu_not_present;
-#endif
 
-       if (dc->res_pool->funcs->update_bw_bounding_box)
+       if (dc->res_pool->funcs->update_bw_bounding_box) {
+               DC_FP_START();
                dc->res_pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params);
+               DC_FP_END();
+       }
+#endif
 
        /* Creation of current_state must occur after dc->dml
         * is initialized in dc_create_resource_pool because
@@ -1220,6 +1223,8 @@ struct dc *dc_create(const struct dc_init_data *init_params)
 
                dc->caps.max_dp_protocol_version = DP_VERSION_1_4;
 
+               dc->caps.max_otg_num = dc->res_pool->res_cap->num_timing_generator;
+
                if (dc->res_pool->dmcu != NULL)
                        dc->versions.dmcu_version = dc->res_pool->dmcu->dmcu_version;
        }
@@ -1404,20 +1409,34 @@ static void program_timing_sync(
                                status->timing_sync_info.master = false;
 
                }
-               /* remove any other unblanked pipes as they have already been synced */
-               for (j = j + 1; j < group_size; j++) {
-                       bool is_blanked;
 
-                       if (pipe_set[j]->stream_res.opp->funcs->dpg_is_blanked)
-                               is_blanked =
-                                       pipe_set[j]->stream_res.opp->funcs->dpg_is_blanked(pipe_set[j]->stream_res.opp);
-                       else
-                               is_blanked =
-                                       pipe_set[j]->stream_res.tg->funcs->is_blanked(pipe_set[j]->stream_res.tg);
-                       if (!is_blanked) {
-                               group_size--;
-                               pipe_set[j] = pipe_set[group_size];
-                               j--;
+               /* remove any other pipes that are already been synced */
+               if (dc->config.use_pipe_ctx_sync_logic) {
+                       /* check pipe's syncd to decide which pipe to be removed */
+                       for (j = 1; j < group_size; j++) {
+                               if (pipe_set[j]->pipe_idx_syncd == pipe_set[0]->pipe_idx_syncd) {
+                                       group_size--;
+                                       pipe_set[j] = pipe_set[group_size];
+                                       j--;
+                               } else
+                                       /* link slave pipe's syncd with master pipe */
+                                       pipe_set[j]->pipe_idx_syncd = pipe_set[0]->pipe_idx_syncd;
+                       }
+               } else {
+                       for (j = j + 1; j < group_size; j++) {
+                               bool is_blanked;
+
+                               if (pipe_set[j]->stream_res.opp->funcs->dpg_is_blanked)
+                                       is_blanked =
+                                               pipe_set[j]->stream_res.opp->funcs->dpg_is_blanked(pipe_set[j]->stream_res.opp);
+                               else
+                                       is_blanked =
+                                               pipe_set[j]->stream_res.tg->funcs->is_blanked(pipe_set[j]->stream_res.tg);
+                               if (!is_blanked) {
+                                       group_size--;
+                                       pipe_set[j] = pipe_set[group_size];
+                                       j--;
+                               }
                        }
                }
 
index 05e2165..61b8f29 100644 (file)
@@ -202,7 +202,7 @@ void dp_wait_for_training_aux_rd_interval(
        uint32_t wait_in_micro_secs)
 {
 #if defined(CONFIG_DRM_AMD_DC_DCN)
-       if (wait_in_micro_secs > 16000)
+       if (wait_in_micro_secs > 1000)
                msleep(wait_in_micro_secs/1000);
        else
                udelay(wait_in_micro_secs);
@@ -5597,6 +5597,26 @@ static bool retrieve_link_cap(struct dc_link *link)
                dp_hw_fw_revision.ieee_fw_rev,
                sizeof(dp_hw_fw_revision.ieee_fw_rev));
 
+       /* Quirk for Apple MBP 2018 15" Retina panels: wrong DP_MAX_LINK_RATE */
+       {
+               uint8_t str_mbp_2018[] = { 101, 68, 21, 103, 98, 97 };
+               uint8_t fwrev_mbp_2018[] = { 7, 4 };
+               uint8_t fwrev_mbp_2018_vega[] = { 8, 4 };
+
+               /* We also check for the firmware revision as 16,1 models have an
+                * identical device id and are incorrectly quirked otherwise.
+                */
+               if ((link->dpcd_caps.sink_dev_id == 0x0010fa) &&
+                   !memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2018,
+                            sizeof(str_mbp_2018)) &&
+                   (!memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018,
+                            sizeof(fwrev_mbp_2018)) ||
+                   !memcmp(link->dpcd_caps.sink_fw_revision, fwrev_mbp_2018_vega,
+                            sizeof(fwrev_mbp_2018_vega)))) {
+                       link->reported_link_cap.link_rate = LINK_RATE_RBR2;
+               }
+       }
+
        memset(&link->dpcd_caps.dsc_caps, '\0',
                        sizeof(link->dpcd_caps.dsc_caps));
        memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap));
@@ -6935,7 +6955,7 @@ bool dpcd_write_128b_132b_sst_payload_allocation_table(
                        }
                }
                retries++;
-               udelay(5000);
+               msleep(5);
        }
 
        if (!result && retries == max_retries) {
@@ -6987,7 +7007,7 @@ bool dpcd_poll_for_allocation_change_trigger(struct dc_link *link)
                        break;
                }
 
-               udelay(5000);
+               msleep(5);
        }
 
        if (result == ACT_FAILED) {
index d4ff6cc..18757c1 100644 (file)
@@ -1964,10 +1964,6 @@ enum dc_status dc_remove_stream_from_ctx(
                                dc->res_pool,
                        del_pipe->stream_res.stream_enc,
                        false);
-       /* Release link encoder from stream in new dc_state. */
-       if (dc->res_pool->funcs->link_enc_unassign)
-               dc->res_pool->funcs->link_enc_unassign(new_ctx, del_pipe->stream);
-
 #if defined(CONFIG_DRM_AMD_DC_DCN)
        if (is_dp_128b_132b_signal(del_pipe)) {
                update_hpo_dp_stream_engine_usage(
@@ -3217,6 +3213,60 @@ struct hpo_dp_link_encoder *resource_get_hpo_dp_link_enc_for_det_lt(
 }
 #endif
 
+void reset_syncd_pipes_from_disabled_pipes(struct dc *dc,
+               struct dc_state *context)
+{
+       int i, j;
+       struct pipe_ctx *pipe_ctx_old, *pipe_ctx, *pipe_ctx_syncd;
+
+       /* If pipe backend is reset, need to reset pipe syncd status */
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               pipe_ctx_old =  &dc->current_state->res_ctx.pipe_ctx[i];
+               pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+               if (!pipe_ctx_old->stream)
+                       continue;
+
+               if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
+                       continue;
+
+               if (!pipe_ctx->stream ||
+                               pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
+
+                       /* Reset all the syncd pipes from the disabled pipe */
+                       for (j = 0; j < dc->res_pool->pipe_count; j++) {
+                               pipe_ctx_syncd = &context->res_ctx.pipe_ctx[j];
+                               if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_syncd) == pipe_ctx_old->pipe_idx) ||
+                                       !IS_PIPE_SYNCD_VALID(pipe_ctx_syncd))
+                                       SET_PIPE_SYNCD_TO_PIPE(pipe_ctx_syncd, j);
+                       }
+               }
+       }
+}
+
+void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc,
+       struct dc_state *context,
+       uint8_t disabled_master_pipe_idx)
+{
+       int i;
+       struct pipe_ctx *pipe_ctx, *pipe_ctx_check;
+
+       pipe_ctx = &context->res_ctx.pipe_ctx[disabled_master_pipe_idx];
+       if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx) != disabled_master_pipe_idx) ||
+               !IS_PIPE_SYNCD_VALID(pipe_ctx))
+               SET_PIPE_SYNCD_TO_PIPE(pipe_ctx, disabled_master_pipe_idx);
+
+       /* for the pipe disabled, check if any slave pipe exists and assert */
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               pipe_ctx_check = &context->res_ctx.pipe_ctx[i];
+
+               if ((GET_PIPE_SYNCD_FROM_PIPE(pipe_ctx_check) == disabled_master_pipe_idx) &&
+                       IS_PIPE_SYNCD_VALID(pipe_ctx_check) && (i != disabled_master_pipe_idx))
+                       DC_ERR("DC: Failure: pipe_idx[%d] syncd with disabled master pipe_idx[%d]\n",
+                               i, disabled_master_pipe_idx);
+       }
+}
+
 uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter)
 {
        /* TODO - get transmitter to phy idx mapping from DMUB */
index da2c78c..b518648 100644 (file)
@@ -202,6 +202,7 @@ struct dc_caps {
        bool edp_dsc_support;
        bool vbios_lttpr_aware;
        bool vbios_lttpr_enable;
+       uint32_t max_otg_num;
 };
 
 struct dc_bug_wa {
@@ -344,6 +345,7 @@ struct dc_config {
        uint8_t  vblank_alignment_max_frame_time_diff;
        bool is_asymmetric_memory;
        bool is_single_rank_dimm;
+       bool use_pipe_ctx_sync_logic;
 };
 
 enum visual_confirm {
index 78192ec..eb2755b 100644 (file)
@@ -1566,6 +1566,10 @@ static enum dc_status apply_single_controller_ctx_to_hw(
                                &pipe_ctx->stream->audio_info);
        }
 
+       /* make sure no pipes syncd to the pipe being enabled */
+       if (!pipe_ctx->stream->apply_seamless_boot_optimization && dc->config.use_pipe_ctx_sync_logic)
+               check_syncd_pipes_for_disabled_master_pipe(dc, context, pipe_ctx->pipe_idx);
+
 #if defined(CONFIG_DRM_AMD_DC_DCN)
        /* DCN3.1 FPGA Workaround
         * Need to enable HPO DP Stream Encoder before setting OTG master enable.
@@ -1604,11 +1608,6 @@ static enum dc_status apply_single_controller_ctx_to_hw(
                        pipe_ctx->stream_res.stream_enc,
                        pipe_ctx->stream_res.tg->inst);
 
-       if (dc_is_dp_signal(pipe_ctx->stream->signal) &&
-               pipe_ctx->stream_res.stream_enc->funcs->reset_fifo)
-               pipe_ctx->stream_res.stream_enc->funcs->reset_fifo(
-                       pipe_ctx->stream_res.stream_enc);
-
        if (dc_is_dp_signal(pipe_ctx->stream->signal))
                dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG);
 
@@ -1835,9 +1834,29 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
                                break;
                        }
                }
-               // We are trying to enable eDP, don't power down VDD
-               if (can_apply_edp_fast_boot)
+
+               /*
+                * TO-DO: So far the code logic below only addresses single eDP case.
+                * For dual eDP case, there are a few things that need to be
+                * implemented first:
+                *
+                * 1. Change the fastboot logic above, so eDP link[0 or 1]'s
+                * stream[0 or 1] will all be checked.
+                *
+                * 2. Change keep_edp_vdd_on to an array, and maintain keep_edp_vdd_on
+                * for each eDP.
+                *
+                * Once above 2 things are completed, we can then change the logic below
+                * correspondingly, so dual eDP case will be fully covered.
+                */
+
+               // We are trying to enable eDP, don't power down VDD if eDP stream is existing
+               if ((edp_stream_num == 1 && edp_streams[0] != NULL) || can_apply_edp_fast_boot) {
                        keep_edp_vdd_on = true;
+                       DC_LOG_EVENT_LINK_TRAINING("Keep eDP Vdd on\n");
+               } else {
+                       DC_LOG_EVENT_LINK_TRAINING("No eDP stream enabled, turn eDP Vdd off\n");
+               }
        }
 
        // Check seamless boot support
@@ -2297,6 +2316,10 @@ enum dc_status dce110_apply_ctx_to_hw(
        enum dc_status status;
        int i;
 
+       /* reset syncd pipes from disabled pipes */
+       if (dc->config.use_pipe_ctx_sync_logic)
+               reset_syncd_pipes_from_disabled_pipes(dc, context);
+
        /* Reset old context */
        /* look up the targets that have been removed since last commit */
        hws->funcs.reset_hw_ctx_wrap(dc, context);
index bf4436d..b0c08ee 100644 (file)
@@ -902,19 +902,6 @@ void enc1_stream_encoder_stop_dp_info_packets(
 
 }
 
-void enc1_stream_encoder_reset_fifo(
-       struct stream_encoder *enc)
-{
-       struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
-
-       /* set DIG_START to 0x1 to reset FIFO */
-       REG_UPDATE(DIG_FE_CNTL, DIG_START, 1);
-       udelay(100);
-
-       /* write 0 to take the FIFO out of reset */
-       REG_UPDATE(DIG_FE_CNTL, DIG_START, 0);
-}
-
 void enc1_stream_encoder_dp_blank(
        struct dc_link *link,
        struct stream_encoder *enc)
@@ -1600,8 +1587,6 @@ static const struct stream_encoder_funcs dcn10_str_enc_funcs = {
                enc1_stream_encoder_send_immediate_sdp_message,
        .stop_dp_info_packets =
                enc1_stream_encoder_stop_dp_info_packets,
-       .reset_fifo =
-               enc1_stream_encoder_reset_fifo,
        .dp_blank =
                enc1_stream_encoder_dp_blank,
        .dp_unblank =
index a146a41..687d7e4 100644 (file)
@@ -626,9 +626,6 @@ void enc1_stream_encoder_send_immediate_sdp_message(
 void enc1_stream_encoder_stop_dp_info_packets(
        struct stream_encoder *enc);
 
-void enc1_stream_encoder_reset_fifo(
-       struct stream_encoder *enc);
-
 void enc1_stream_encoder_dp_blank(
        struct dc_link *link,
        struct stream_encoder *enc);
index 2bc93df..2a72517 100644 (file)
@@ -1069,7 +1069,7 @@ static const struct dc_debug_options debug_defaults_drv = {
                .timing_trace = false,
                .clock_trace = true,
                .disable_pplib_clock_request = true,
-               .pipe_split_policy = MPC_SPLIT_DYNAMIC,
+               .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP,
                .force_single_disp_pipe_split = false,
                .disable_dcc = DCC_ENABLE,
                .vsr_support = true,
index 8a70f92..aab25ca 100644 (file)
@@ -593,8 +593,6 @@ static const struct stream_encoder_funcs dcn20_str_enc_funcs = {
                enc1_stream_encoder_send_immediate_sdp_message,
        .stop_dp_info_packets =
                enc1_stream_encoder_stop_dp_info_packets,
-       .reset_fifo =
-               enc1_stream_encoder_reset_fifo,
        .dp_blank =
                enc1_stream_encoder_dp_blank,
        .dp_unblank =
index 8daa127..a04ca4a 100644 (file)
@@ -789,8 +789,6 @@ static const struct stream_encoder_funcs dcn30_str_enc_funcs = {
                enc3_stream_encoder_update_dp_info_packets,
        .stop_dp_info_packets =
                enc1_stream_encoder_stop_dp_info_packets,
-       .reset_fifo =
-               enc1_stream_encoder_reset_fifo,
        .dp_blank =
                enc1_stream_encoder_dp_blank,
        .dp_unblank =
index 602ec9a..8ca2638 100644 (file)
@@ -1878,7 +1878,6 @@ noinline bool dcn30_internal_validate_bw(
        dc->res_pool->funcs->update_soc_for_wm_a(dc, context);
        pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate);
 
-       DC_FP_START();
        if (!pipe_cnt) {
                out = true;
                goto validate_out;
@@ -2104,7 +2103,6 @@ validate_fail:
        out = false;
 
 validate_out:
-       DC_FP_END();
        return out;
 }
 
@@ -2306,7 +2304,9 @@ bool dcn30_validate_bandwidth(struct dc *dc,
 
        BW_VAL_TRACE_COUNT();
 
+       DC_FP_START();
        out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate);
+       DC_FP_END();
 
        if (pipe_cnt == 0)
                goto validate_out;
index c1c6e60..5d9637b 100644 (file)
@@ -686,7 +686,7 @@ static const struct dc_debug_options debug_defaults_drv = {
        .disable_clock_gate = true,
        .disable_pplib_clock_request = true,
        .disable_pplib_wm_range = true,
-       .pipe_split_policy = MPC_SPLIT_DYNAMIC,
+       .pipe_split_policy = MPC_SPLIT_AVOID,
        .force_single_disp_pipe_split = false,
        .disable_dcc = DCC_ENABLE,
        .vsr_support = true,
@@ -1380,6 +1380,17 @@ static void set_wm_ranges(
        pp_smu->nv_funcs.set_wm_ranges(&pp_smu->nv_funcs.pp_smu, &ranges);
 }
 
+static void dcn301_calculate_wm_and_dlg(
+               struct dc *dc, struct dc_state *context,
+               display_e2e_pipe_params_st *pipes,
+               int pipe_cnt,
+               int vlevel)
+{
+       DC_FP_START();
+       dcn301_calculate_wm_and_dlg_fp(dc, context, pipes, pipe_cnt, vlevel);
+       DC_FP_END();
+}
+
 static struct resource_funcs dcn301_res_pool_funcs = {
        .destroy = dcn301_destroy_resource_pool,
        .link_enc_create = dcn301_link_encoder_create,
index 90c73a1..5e3bcaf 100644 (file)
@@ -138,8 +138,11 @@ static uint32_t convert_and_clamp(
        ret_val = wm_ns * refclk_mhz;
        ret_val /= 1000;
 
-       if (ret_val > clamp_value)
+       if (ret_val > clamp_value) {
+               /* clamping WMs is abnormal, unexpected and may lead to underflow*/
+               ASSERT(0);
                ret_val = clamp_value;
+       }
 
        return ret_val;
 }
@@ -159,7 +162,7 @@ static bool hubbub31_program_urgent_watermarks(
        if (safe_to_lower || watermarks->a.urgent_ns > hubbub2->watermarks.a.urgent_ns) {
                hubbub2->watermarks.a.urgent_ns = watermarks->a.urgent_ns;
                prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0x3fff);
                REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0,
                                DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value);
 
@@ -193,7 +196,7 @@ static bool hubbub31_program_urgent_watermarks(
        if (safe_to_lower || watermarks->a.urgent_latency_ns > hubbub2->watermarks.a.urgent_latency_ns) {
                hubbub2->watermarks.a.urgent_latency_ns = watermarks->a.urgent_latency_ns;
                prog_wm_value = convert_and_clamp(watermarks->a.urgent_latency_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0x3fff);
                REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, 0,
                                DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, prog_wm_value);
        } else if (watermarks->a.urgent_latency_ns < hubbub2->watermarks.a.urgent_latency_ns)
@@ -203,7 +206,7 @@ static bool hubbub31_program_urgent_watermarks(
        if (safe_to_lower || watermarks->b.urgent_ns > hubbub2->watermarks.b.urgent_ns) {
                hubbub2->watermarks.b.urgent_ns = watermarks->b.urgent_ns;
                prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0x3fff);
                REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0,
                                DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value);
 
@@ -237,7 +240,7 @@ static bool hubbub31_program_urgent_watermarks(
        if (safe_to_lower || watermarks->b.urgent_latency_ns > hubbub2->watermarks.b.urgent_latency_ns) {
                hubbub2->watermarks.b.urgent_latency_ns = watermarks->b.urgent_latency_ns;
                prog_wm_value = convert_and_clamp(watermarks->b.urgent_latency_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0x3fff);
                REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, 0,
                                DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, prog_wm_value);
        } else if (watermarks->b.urgent_latency_ns < hubbub2->watermarks.b.urgent_latency_ns)
@@ -247,7 +250,7 @@ static bool hubbub31_program_urgent_watermarks(
        if (safe_to_lower || watermarks->c.urgent_ns > hubbub2->watermarks.c.urgent_ns) {
                hubbub2->watermarks.c.urgent_ns = watermarks->c.urgent_ns;
                prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0x3fff);
                REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, 0,
                                DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value);
 
@@ -281,7 +284,7 @@ static bool hubbub31_program_urgent_watermarks(
        if (safe_to_lower || watermarks->c.urgent_latency_ns > hubbub2->watermarks.c.urgent_latency_ns) {
                hubbub2->watermarks.c.urgent_latency_ns = watermarks->c.urgent_latency_ns;
                prog_wm_value = convert_and_clamp(watermarks->c.urgent_latency_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0x3fff);
                REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, 0,
                                DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, prog_wm_value);
        } else if (watermarks->c.urgent_latency_ns < hubbub2->watermarks.c.urgent_latency_ns)
@@ -291,7 +294,7 @@ static bool hubbub31_program_urgent_watermarks(
        if (safe_to_lower || watermarks->d.urgent_ns > hubbub2->watermarks.d.urgent_ns) {
                hubbub2->watermarks.d.urgent_ns = watermarks->d.urgent_ns;
                prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0x3fff);
                REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, 0,
                                DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value);
 
@@ -325,7 +328,7 @@ static bool hubbub31_program_urgent_watermarks(
        if (safe_to_lower || watermarks->d.urgent_latency_ns > hubbub2->watermarks.d.urgent_latency_ns) {
                hubbub2->watermarks.d.urgent_latency_ns = watermarks->d.urgent_latency_ns;
                prog_wm_value = convert_and_clamp(watermarks->d.urgent_latency_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0x3fff);
                REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, 0,
                                DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, prog_wm_value);
        } else if (watermarks->d.urgent_latency_ns < hubbub2->watermarks.d.urgent_latency_ns)
@@ -351,7 +354,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0,
                                DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n"
@@ -367,7 +370,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->a.cstate_pstate.cstate_exit_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->a.cstate_pstate.cstate_exit_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0,
                                DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n"
@@ -383,7 +386,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A, 0,
                                DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_A calculated =%d\n"
@@ -399,7 +402,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->a.cstate_pstate.cstate_exit_z8_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->a.cstate_pstate.cstate_exit_z8_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A, 0,
                                DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_A calculated =%d\n"
@@ -416,7 +419,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0,
                                DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n"
@@ -432,7 +435,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->b.cstate_pstate.cstate_exit_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->b.cstate_pstate.cstate_exit_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0,
                                DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n"
@@ -448,7 +451,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B, 0,
                                DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_B calculated =%d\n"
@@ -464,7 +467,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->b.cstate_pstate.cstate_exit_z8_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->b.cstate_pstate.cstate_exit_z8_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B, 0,
                                DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_B calculated =%d\n"
@@ -481,7 +484,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0,
                                DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n"
@@ -497,7 +500,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->c.cstate_pstate.cstate_exit_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->c.cstate_pstate.cstate_exit_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0,
                                DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n"
@@ -513,7 +516,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C, 0,
                                DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_C calculated =%d\n"
@@ -529,7 +532,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->c.cstate_pstate.cstate_exit_z8_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->c.cstate_pstate.cstate_exit_z8_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C, 0,
                                DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_C calculated =%d\n"
@@ -546,7 +549,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0,
                                DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n"
@@ -562,7 +565,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->d.cstate_pstate.cstate_exit_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->d.cstate_pstate.cstate_exit_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0,
                                DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n"
@@ -578,7 +581,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D, 0,
                                DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_D calculated =%d\n"
@@ -594,7 +597,7 @@ static bool hubbub31_program_stutter_watermarks(
                                watermarks->d.cstate_pstate.cstate_exit_z8_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->d.cstate_pstate.cstate_exit_z8_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, 0,
                                DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_D calculated =%d\n"
@@ -625,7 +628,7 @@ static bool hubbub31_program_pstate_watermarks(
                                watermarks->a.cstate_pstate.pstate_change_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->a.cstate_pstate.pstate_change_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, 0,
                                DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n"
@@ -642,7 +645,7 @@ static bool hubbub31_program_pstate_watermarks(
                                watermarks->b.cstate_pstate.pstate_change_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->b.cstate_pstate.pstate_change_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, 0,
                                DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n"
@@ -659,7 +662,7 @@ static bool hubbub31_program_pstate_watermarks(
                                watermarks->c.cstate_pstate.pstate_change_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->c.cstate_pstate.pstate_change_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, 0,
                                DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n"
@@ -676,7 +679,7 @@ static bool hubbub31_program_pstate_watermarks(
                                watermarks->d.cstate_pstate.pstate_change_ns;
                prog_wm_value = convert_and_clamp(
                                watermarks->d.cstate_pstate.pstate_change_ns,
-                               refclk_mhz, 0x1fffff);
+                               refclk_mhz, 0xffff);
                REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, 0,
                                DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value);
                DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n"
index 42ed47e..8d64187 100644 (file)
@@ -2260,6 +2260,9 @@ static bool dcn31_resource_construct(
        dc->caps.color.mpc.ogam_rom_caps.hlg = 0;
        dc->caps.color.mpc.ocsc = 1;
 
+       /* Use pipe context based otg sync logic */
+       dc->config.use_pipe_ctx_sync_logic = true;
+
        /* read VBIOS LTTPR caps */
        {
                if (ctx->dc_bios->funcs->get_lttpr_caps) {
index 246071c..548cdef 100644 (file)
@@ -1576,8 +1576,6 @@ void dml20_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib,
        dlg_sys_param.total_flip_bytes = get_total_immediate_flip_bytes(mode_lib,
                        e2e_pipe_param,
                        num_pipes);
-       dlg_sys_param.t_srx_delay_us = mode_lib->ip.dcfclk_cstate_latency
-                       / dlg_sys_param.deepsleep_dcfclk_mhz; // TODO: Deprecated
 
        print__dlg_sys_params_st(mode_lib, &dlg_sys_param);
 
index 015e7f2..0fc9f3e 100644 (file)
@@ -1577,8 +1577,6 @@ void dml20v2_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib,
        dlg_sys_param.total_flip_bytes = get_total_immediate_flip_bytes(mode_lib,
                        e2e_pipe_param,
                        num_pipes);
-       dlg_sys_param.t_srx_delay_us = mode_lib->ip.dcfclk_cstate_latency
-                       / dlg_sys_param.deepsleep_dcfclk_mhz; // TODO: Deprecated
 
        print__dlg_sys_params_st(mode_lib, &dlg_sys_param);
 
index 8bc27de..618f4b6 100644 (file)
@@ -1688,8 +1688,6 @@ void dml21_rq_dlg_get_dlg_reg(
                        mode_lib,
                        e2e_pipe_param,
                        num_pipes);
-       dlg_sys_param.t_srx_delay_us = mode_lib->ip.dcfclk_cstate_latency
-                       / dlg_sys_param.deepsleep_dcfclk_mhz; // TODO: Deprecated
 
        print__dlg_sys_params_st(mode_lib, &dlg_sys_param);
 
index aef8542..7471670 100644 (file)
@@ -1858,8 +1858,6 @@ void dml30_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib,
        dlg_sys_param.total_flip_bytes = get_total_immediate_flip_bytes(mode_lib,
                e2e_pipe_param,
                num_pipes);
-       dlg_sys_param.t_srx_delay_us = mode_lib->ip.dcfclk_cstate_latency
-               / dlg_sys_param.deepsleep_dcfclk_mhz; // TODO: Deprecated
 
        print__dlg_sys_params_st(mode_lib, &dlg_sys_param);
 
index 94c3283..0a7a338 100644 (file)
@@ -327,7 +327,7 @@ void dcn301_fpu_init_soc_bounding_box(struct bp_soc_bb_info bb_info)
                dcn3_01_soc.sr_exit_time_us = bb_info.dram_sr_exit_latency_100ns * 10;
 }
 
-void dcn301_calculate_wm_and_dlg(struct dc *dc,
+void dcn301_calculate_wm_and_dlg_fp(struct dc *dc,
                struct dc_state *context,
                display_e2e_pipe_params_st *pipes,
                int pipe_cnt,
index fc7065d..774b0fd 100644 (file)
@@ -34,7 +34,7 @@ void dcn301_fpu_set_wm_ranges(int i,
 
 void dcn301_fpu_init_soc_bounding_box(struct bp_soc_bb_info bb_info);
 
-void dcn301_calculate_wm_and_dlg(struct dc *dc,
+void dcn301_calculate_wm_and_dlg_fp(struct dc *dc,
                struct dc_state *context,
                display_e2e_pipe_params_st *pipes,
                int pipe_cnt,
index d46a273..8f9f1d6 100644 (file)
@@ -546,7 +546,6 @@ struct _vcs_dpi_display_dlg_sys_params_st {
        double t_sr_wm_us;
        double t_extra_us;
        double mem_trip_us;
-       double t_srx_delay_us;
        double deepsleep_dcfclk_mhz;
        double total_flip_bw;
        unsigned int total_flip_bytes;
index 71ea503..412e75e 100644 (file)
@@ -141,9 +141,6 @@ void print__dlg_sys_params_st(struct display_mode_lib *mode_lib, const struct _v
        dml_print("DML_RQ_DLG_CALC:    t_urg_wm_us          = %3.2f\n", dlg_sys_param->t_urg_wm_us);
        dml_print("DML_RQ_DLG_CALC:    t_sr_wm_us           = %3.2f\n", dlg_sys_param->t_sr_wm_us);
        dml_print("DML_RQ_DLG_CALC:    t_extra_us           = %3.2f\n", dlg_sys_param->t_extra_us);
-       dml_print(
-                       "DML_RQ_DLG_CALC:    t_srx_delay_us       = %3.2f\n",
-                       dlg_sys_param->t_srx_delay_us);
        dml_print(
                        "DML_RQ_DLG_CALC:    deepsleep_dcfclk_mhz = %3.2f\n",
                        dlg_sys_param->deepsleep_dcfclk_mhz);
index 59dc2c5..3df559c 100644 (file)
@@ -1331,10 +1331,6 @@ void dml1_rq_dlg_get_dlg_params(
        if (dual_plane)
                DTRACE("DLG: %s: swath_height_c     = %d", __func__, swath_height_c);
 
-       DTRACE(
-                       "DLG: %s: t_srx_delay_us     = %3.2f",
-                       __func__,
-                       (double) dlg_sys_param->t_srx_delay_us);
        DTRACE("DLG: %s: line_time_in_us    = %3.2f", __func__, (double) line_time_in_us);
        DTRACE("DLG: %s: vupdate_offset     = %d", __func__, vupdate_offset);
        DTRACE("DLG: %s: vupdate_width      = %d", __func__, vupdate_width);
index 8902800..943240e 100644 (file)
@@ -382,6 +382,7 @@ struct pipe_ctx {
        struct pll_settings pll_settings;
 
        uint8_t pipe_idx;
+       uint8_t pipe_idx_syncd;
 
        struct pipe_ctx *top_pipe;
        struct pipe_ctx *bottom_pipe;
index 073f8b6..c88e113 100644 (file)
@@ -164,10 +164,6 @@ struct stream_encoder_funcs {
        void (*stop_dp_info_packets)(
                struct stream_encoder *enc);
 
-       void (*reset_fifo)(
-               struct stream_encoder *enc
-       );
-
        void (*dp_blank)(
                struct dc_link *link,
                struct stream_encoder *enc);
index 4249bf3..dbfe669 100644 (file)
 #define MEMORY_TYPE_HBM 2
 
 
+#define IS_PIPE_SYNCD_VALID(pipe) ((((pipe)->pipe_idx_syncd) & 0x80)?1:0)
+#define GET_PIPE_SYNCD_FROM_PIPE(pipe) ((pipe)->pipe_idx_syncd & 0x7F)
+#define SET_PIPE_SYNCD_TO_PIPE(pipe, pipe_syncd) ((pipe)->pipe_idx_syncd = (0x80 | pipe_syncd))
+
 enum dce_version resource_parse_asic_id(
                struct hw_asic_id asic_id);
 
@@ -208,6 +212,13 @@ struct hpo_dp_link_encoder *resource_get_hpo_dp_link_enc_for_det_lt(
                const struct dc_link *link);
 #endif
 
+void reset_syncd_pipes_from_disabled_pipes(struct dc *dc,
+       struct dc_state *context);
+
+void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc,
+       struct dc_state *context,
+       uint8_t disabled_master_pipe_idx);
+
 uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter);
 
 #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_RESOURCE_H_ */
index e2cae97..48cc009 100644 (file)
@@ -3462,8 +3462,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
             attr == &sensor_dev_attr_power2_cap_min.dev_attr.attr ||
                 attr == &sensor_dev_attr_power2_cap.dev_attr.attr ||
                 attr == &sensor_dev_attr_power2_cap_default.dev_attr.attr ||
-                attr == &sensor_dev_attr_power2_label.dev_attr.attr ||
-                attr == &sensor_dev_attr_power1_label.dev_attr.attr))
+                attr == &sensor_dev_attr_power2_label.dev_attr.attr))
                return 0;
 
        return effective_mode;
index 777f717..5488a0e 100644 (file)
@@ -421,6 +421,36 @@ static int sienna_cichlid_store_powerplay_table(struct smu_context *smu)
        return 0;
 }
 
+static int sienna_cichlid_patch_pptable_quirk(struct smu_context *smu)
+{
+       struct amdgpu_device *adev = smu->adev;
+       uint32_t *board_reserved;
+       uint16_t *freq_table_gfx;
+       uint32_t i;
+
+       /* Fix some OEM SKU specific stability issues */
+       GET_PPTABLE_MEMBER(BoardReserved, &board_reserved);
+       if ((adev->pdev->device == 0x73DF) &&
+           (adev->pdev->revision == 0XC3) &&
+           (adev->pdev->subsystem_device == 0x16C2) &&
+           (adev->pdev->subsystem_vendor == 0x1043))
+               board_reserved[0] = 1387;
+
+       GET_PPTABLE_MEMBER(FreqTableGfx, &freq_table_gfx);
+       if ((adev->pdev->device == 0x73DF) &&
+           (adev->pdev->revision == 0XC3) &&
+           ((adev->pdev->subsystem_device == 0x16C2) ||
+           (adev->pdev->subsystem_device == 0x133C)) &&
+           (adev->pdev->subsystem_vendor == 0x1043)) {
+               for (i = 0; i < NUM_GFXCLK_DPM_LEVELS; i++) {
+                       if (freq_table_gfx[i] > 2500)
+                               freq_table_gfx[i] = 2500;
+               }
+       }
+
+       return 0;
+}
+
 static int sienna_cichlid_setup_pptable(struct smu_context *smu)
 {
        int ret = 0;
@@ -441,7 +471,7 @@ static int sienna_cichlid_setup_pptable(struct smu_context *smu)
        if (ret)
                return ret;
 
-       return ret;
+       return sienna_cichlid_patch_pptable_quirk(smu);
 }
 
 static int sienna_cichlid_tables_init(struct smu_context *smu)
@@ -1238,21 +1268,37 @@ static int sienna_cichlid_populate_umd_state_clk(struct smu_context *smu)
                                &dpm_context->dpm_tables.soc_table;
        struct smu_umd_pstate_table *pstate_table =
                                &smu->pstate_table;
+       struct amdgpu_device *adev = smu->adev;
 
        pstate_table->gfxclk_pstate.min = gfx_table->min;
        pstate_table->gfxclk_pstate.peak = gfx_table->max;
-       if (gfx_table->max >= SIENNA_CICHLID_UMD_PSTATE_PROFILING_GFXCLK)
-               pstate_table->gfxclk_pstate.standard = SIENNA_CICHLID_UMD_PSTATE_PROFILING_GFXCLK;
 
        pstate_table->uclk_pstate.min = mem_table->min;
        pstate_table->uclk_pstate.peak = mem_table->max;
-       if (mem_table->max >= SIENNA_CICHLID_UMD_PSTATE_PROFILING_MEMCLK)
-               pstate_table->uclk_pstate.standard = SIENNA_CICHLID_UMD_PSTATE_PROFILING_MEMCLK;
 
        pstate_table->socclk_pstate.min = soc_table->min;
        pstate_table->socclk_pstate.peak = soc_table->max;
-       if (soc_table->max >= SIENNA_CICHLID_UMD_PSTATE_PROFILING_SOCCLK)
+
+       switch (adev->asic_type) {
+       case CHIP_SIENNA_CICHLID:
+       case CHIP_NAVY_FLOUNDER:
+               pstate_table->gfxclk_pstate.standard = SIENNA_CICHLID_UMD_PSTATE_PROFILING_GFXCLK;
+               pstate_table->uclk_pstate.standard = SIENNA_CICHLID_UMD_PSTATE_PROFILING_MEMCLK;
                pstate_table->socclk_pstate.standard = SIENNA_CICHLID_UMD_PSTATE_PROFILING_SOCCLK;
+               break;
+       case CHIP_DIMGREY_CAVEFISH:
+               pstate_table->gfxclk_pstate.standard = DIMGREY_CAVEFISH_UMD_PSTATE_PROFILING_GFXCLK;
+               pstate_table->uclk_pstate.standard = DIMGREY_CAVEFISH_UMD_PSTATE_PROFILING_MEMCLK;
+               pstate_table->socclk_pstate.standard = DIMGREY_CAVEFISH_UMD_PSTATE_PROFILING_SOCCLK;
+               break;
+       case CHIP_BEIGE_GOBY:
+               pstate_table->gfxclk_pstate.standard = BEIGE_GOBY_UMD_PSTATE_PROFILING_GFXCLK;
+               pstate_table->uclk_pstate.standard = BEIGE_GOBY_UMD_PSTATE_PROFILING_MEMCLK;
+               pstate_table->socclk_pstate.standard = BEIGE_GOBY_UMD_PSTATE_PROFILING_SOCCLK;
+               break;
+       default:
+               break;
+       }
 
        return 0;
 }
@@ -3696,14 +3742,14 @@ static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu,
 
 static int sienna_cichlid_enable_mgpu_fan_boost(struct smu_context *smu)
 {
-       struct smu_table_context *table_context = &smu->smu_table;
-       PPTable_t *smc_pptable = table_context->driver_pptable;
+       uint16_t *mgpu_fan_boost_limit_rpm;
 
+       GET_PPTABLE_MEMBER(MGpuFanBoostLimitRpm, &mgpu_fan_boost_limit_rpm);
        /*
         * Skip the MGpuFanBoost setting for those ASICs
         * which do not support it
         */
-       if (!smc_pptable->MGpuFanBoostLimitRpm)
+       if (*mgpu_fan_boost_limit_rpm == 0)
                return 0;
 
        return smu_cmn_send_smc_msg_with_param(smu,
index 38cd0ec..42f705c 100644 (file)
@@ -33,6 +33,14 @@ typedef enum {
 #define SIENNA_CICHLID_UMD_PSTATE_PROFILING_SOCCLK    960
 #define SIENNA_CICHLID_UMD_PSTATE_PROFILING_MEMCLK    1000
 
+#define DIMGREY_CAVEFISH_UMD_PSTATE_PROFILING_GFXCLK 1950
+#define DIMGREY_CAVEFISH_UMD_PSTATE_PROFILING_SOCCLK 960
+#define DIMGREY_CAVEFISH_UMD_PSTATE_PROFILING_MEMCLK 676
+
+#define BEIGE_GOBY_UMD_PSTATE_PROFILING_GFXCLK 2200
+#define BEIGE_GOBY_UMD_PSTATE_PROFILING_SOCCLK 960
+#define BEIGE_GOBY_UMD_PSTATE_PROFILING_MEMCLK 1000
+
 extern void sienna_cichlid_set_ppt_funcs(struct smu_context *smu);
 
 #endif
index caf1775..0bc84b7 100644 (file)
@@ -282,14 +282,9 @@ static int yellow_carp_post_smu_init(struct smu_context *smu)
 
 static int yellow_carp_mode_reset(struct smu_context *smu, int type)
 {
-       int ret = 0, index = 0;
-
-       index = smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG,
-                               SMU_MSG_GfxDeviceDriverReset);
-       if (index < 0)
-               return index == -EACCES ? 0 : index;
+       int ret = 0;
 
-       ret = smu_cmn_send_smc_msg_with_param(smu, (uint16_t)index, type, NULL);
+       ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, type, NULL);
        if (ret)
                dev_err(smu->adev->dev, "Failed to mode reset!\n");
 
index d9eb353..dbe1cc6 100644 (file)
@@ -282,8 +282,6 @@ static const struct ast_vbios_enhtable res_1360x768[] = {
 };
 
 static const struct ast_vbios_enhtable res_1600x900[] = {
-       {1800, 1600, 24, 80, 1000,  900, 1, 3, VCLK108,         /* 60Hz */
-        (SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 60, 3, 0x3A },
        {1760, 1600, 48, 32, 926, 900, 3, 5, VCLK97_75,         /* 60Hz CVT RB */
         (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo |
          AST2500PreCatchCRT), 60, 1, 0x3A },
index 21174ef..88cd992 100644 (file)
@@ -1327,8 +1327,10 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
 
        drm_dbg_atomic(dev, "checking %p\n", state);
 
-       for_each_new_crtc_in_state(state, crtc, new_crtc_state, i)
-               requested_crtc |= drm_crtc_mask(crtc);
+       for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+               if (new_crtc_state->enable)
+                       requested_crtc |= drm_crtc_mask(crtc);
+       }
 
        for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
                ret = drm_atomic_plane_check(old_plane_state, new_plane_state);
@@ -1377,8 +1379,10 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
                }
        }
 
-       for_each_new_crtc_in_state(state, crtc, new_crtc_state, i)
-               affected_crtc |= drm_crtc_mask(crtc);
+       for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+               if (new_crtc_state->enable)
+                       affected_crtc |= drm_crtc_mask(crtc);
+       }
 
        /*
         * For commits that allow modesets drivers can add other CRTCs to the
index 9781722..54d62fd 100644 (file)
@@ -76,15 +76,17 @@ int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
        state->mode_blob = NULL;
 
        if (mode) {
+               struct drm_property_blob *blob;
+
                drm_mode_convert_to_umode(&umode, mode);
-               state->mode_blob =
-                       drm_property_create_blob(state->crtc->dev,
-                                                sizeof(umode),
-                                                &umode);
-               if (IS_ERR(state->mode_blob))
-                       return PTR_ERR(state->mode_blob);
+               blob = drm_property_create_blob(crtc->dev,
+                                               sizeof(umode), &umode);
+               if (IS_ERR(blob))
+                       return PTR_ERR(blob);
 
                drm_mode_copy(&state->mode, mode);
+
+               state->mode_blob = blob;
                state->enable = true;
                drm_dbg_atomic(crtc->dev,
                               "Set [MODE:%s] for [CRTC:%d:%s] state %p\n",
index 12893e7..f5f5de3 100644 (file)
@@ -5345,6 +5345,7 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi
        if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
                return quirks;
 
+       info->color_formats |= DRM_COLOR_FORMAT_RGB444;
        drm_parse_cea_ext(connector, edid);
 
        /*
@@ -5393,7 +5394,6 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi
        DRM_DEBUG("%s: Assigning EDID-1.4 digital sink color depth as %d bpc.\n",
                          connector->name, info->bpc);
 
-       info->color_formats |= DRM_COLOR_FORMAT_RGB444;
        if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444)
                info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
        if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
index cefd0cb..dc275c4 100644 (file)
@@ -512,6 +512,7 @@ int drm_gem_cma_mmap(struct drm_gem_cma_object *cma_obj, struct vm_area_struct *
         */
        vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
        vma->vm_flags &= ~VM_PFNMAP;
+       vma->vm_flags |= VM_DONTEXPAND;
 
        if (cma_obj->map_noncoherent) {
                vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
index 042bb80..b910978 100644 (file)
@@ -115,6 +115,12 @@ static const struct drm_dmi_panel_orientation_data lcd1280x1920_rightside_up = {
        .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
 };
 
+static const struct drm_dmi_panel_orientation_data lcd1600x2560_leftside_up = {
+       .width = 1600,
+       .height = 2560,
+       .orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP,
+};
+
 static const struct dmi_system_id orientation_data[] = {
        {       /* Acer One 10 (S1003) */
                .matches = {
@@ -275,6 +281,12 @@ static const struct dmi_system_id orientation_data[] = {
                  DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Default string"),
                },
                .driver_data = (void *)&onegx1_pro,
+       }, {    /* OneXPlayer */
+               .matches = {
+                 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ONE-NETBOOK TECHNOLOGY CO., LTD."),
+                 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ONE XPLAYER"),
+               },
+               .driver_data = (void *)&lcd1600x2560_leftside_up,
        }, {    /* Samsung GalaxyBook 10.6 */
                .matches = {
                  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
index beaf99e..b688841 100644 (file)
@@ -269,7 +269,7 @@ EXPORT_SYMBOL(drm_privacy_screen_get_state);
  *
  * The notifier is called with no locks held. The new hw_state and sw_state
  * can be retrieved using the drm_privacy_screen_get_state() function.
- * A pointer to the drm_privacy_screen's struct is passed as the void *data
+ * A pointer to the drm_privacy_screen's struct is passed as the ``void *data``
  * argument of the notifier_block's notifier_call.
  *
  * The notifier will NOT be called when changes are made through
index a2cafb2..e7aa74a 100644 (file)
@@ -33,6 +33,9 @@ static bool __init detect_thinkpad_privacy_screen(void)
        unsigned long long output;
        acpi_status status;
 
+       if (acpi_disabled)
+               return false;
+
        /* Get embedded-controller handle */
        status = acpi_get_devices("PNP0C09", acpi_set_handle, NULL, &ec_handle);
        if (ACPI_FAILURE(status) || !ec_handle)
index b03c20c..a173132 100644 (file)
@@ -469,8 +469,8 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
-       if (args->stream_size > SZ_64K || args->nr_relocs > SZ_64K ||
-           args->nr_bos > SZ_64K || args->nr_pmrs > 128) {
+       if (args->stream_size > SZ_128K || args->nr_relocs > SZ_128K ||
+           args->nr_bos > SZ_128K || args->nr_pmrs > 128) {
                DRM_ERROR("submit arguments out of size limits\n");
                return -EINVAL;
        }
index a4c94dc..cfd9325 100644 (file)
@@ -101,6 +101,7 @@ config DRM_I915_USERPTR
 config DRM_I915_GVT
        bool "Enable Intel GVT-g graphics virtualization host support"
        depends on DRM_I915
+       depends on X86
        depends on 64BIT
        default n
        help
index 2da4aac..8ac196e 100644 (file)
@@ -825,6 +825,7 @@ int intel_bw_atomic_check(struct intel_atomic_state *state)
        unsigned int max_bw_point = 0, max_bw = 0;
        unsigned int num_qgv_points = dev_priv->max_bw[0].num_qgv_points;
        unsigned int num_psf_gv_points = dev_priv->max_bw[0].num_psf_gv_points;
+       bool changed = false;
        u32 mask = 0;
 
        /* FIXME earlier gens need some checks too */
@@ -868,6 +869,8 @@ int intel_bw_atomic_check(struct intel_atomic_state *state)
                new_bw_state->data_rate[crtc->pipe] = new_data_rate;
                new_bw_state->num_active_planes[crtc->pipe] = new_active_planes;
 
+               changed = true;
+
                drm_dbg_kms(&dev_priv->drm,
                            "pipe %c data rate %u num active planes %u\n",
                            pipe_name(crtc->pipe),
@@ -875,7 +878,19 @@ int intel_bw_atomic_check(struct intel_atomic_state *state)
                            new_bw_state->num_active_planes[crtc->pipe]);
        }
 
-       if (!new_bw_state)
+       old_bw_state = intel_atomic_get_old_bw_state(state);
+       new_bw_state = intel_atomic_get_new_bw_state(state);
+
+       if (new_bw_state &&
+           intel_can_enable_sagv(dev_priv, old_bw_state) !=
+           intel_can_enable_sagv(dev_priv, new_bw_state))
+               changed = true;
+
+       /*
+        * If none of our inputs (data rates, number of active
+        * planes, SAGV yes/no) changed then nothing to do here.
+        */
+       if (!changed)
                return 0;
 
        ret = intel_atomic_lock_global_state(&new_bw_state->base);
@@ -961,7 +976,6 @@ int intel_bw_atomic_check(struct intel_atomic_state *state)
         */
        new_bw_state->qgv_points_mask = ~allowed_points & mask;
 
-       old_bw_state = intel_atomic_get_old_bw_state(state);
        /*
         * If the actual mask had changed we need to make sure that
         * the commits are serialized(in case this is a nomodeset, nonblocking)
index 46c6eec..0ceaed1 100644 (file)
@@ -30,19 +30,19 @@ struct intel_bw_state {
         */
        u8 pipe_sagv_reject;
 
+       /* bitmask of active pipes */
+       u8 active_pipes;
+
        /*
         * Current QGV points mask, which restricts
         * some particular SAGV states, not to confuse
         * with pipe_sagv_mask.
         */
-       u8 qgv_points_mask;
+       u16 qgv_points_mask;
 
        unsigned int data_rate[I915_MAX_PIPES];
        u8 num_active_planes[I915_MAX_PIPES];
 
-       /* bitmask of active pipes */
-       u8 active_pipes;
-
        int min_cdclk;
 };
 
index bf7ce68..bb4a854 100644 (file)
@@ -10673,6 +10673,7 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
                vlv_wm_sanitize(dev_priv);
        } else if (DISPLAY_VER(dev_priv) >= 9) {
                skl_wm_get_hw_state(dev_priv);
+               skl_wm_sanitize(dev_priv);
        } else if (HAS_PCH_SPLIT(dev_priv)) {
                ilk_wm_get_hw_state(dev_priv);
        }
index c1439fc..3ff149d 100644 (file)
@@ -405,6 +405,7 @@ intel_drrs_init(struct intel_connector *connector,
                struct drm_display_mode *fixed_mode)
 {
        struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+       struct intel_encoder *encoder = connector->encoder;
        struct drm_display_mode *downclock_mode = NULL;
 
        INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_drrs_downclock_work);
@@ -416,6 +417,13 @@ intel_drrs_init(struct intel_connector *connector,
                return NULL;
        }
 
+       if ((DISPLAY_VER(dev_priv) < 8 && !HAS_GMCH(dev_priv)) &&
+           encoder->port != PORT_A) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "DRRS only supported on eDP port A\n");
+               return NULL;
+       }
+
        if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) {
                drm_dbg_kms(&dev_priv->drm, "VBT doesn't support DRRS\n");
                return NULL;
index 160fd2b..957feec 100644 (file)
@@ -1115,7 +1115,8 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state,
 
        /* Wa_22010751166: icl, ehl, tgl, dg1, rkl */
        if (DISPLAY_VER(i915) >= 11 &&
-           (plane_state->view.color_plane[0].y + drm_rect_height(&plane_state->uapi.src)) & 3) {
+           (plane_state->view.color_plane[0].y +
+            (drm_rect_height(&plane_state->uapi.src) >> 16)) & 3) {
                plane_state->no_fbc_reason = "plane end Y offset misaligned";
                return false;
        }
index 0065111..4a26628 100644 (file)
@@ -360,6 +360,21 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder,
                port++;
        }
 
+       /*
+        * The port numbering and mapping here is bizarre. The now-obsolete
+        * swsci spec supports ports numbered [0..4]. Port E is handled as a
+        * special case, but port F and beyond are not. The functionality is
+        * supposed to be obsolete for new platforms. Just bail out if the port
+        * number is out of bounds after mapping.
+        */
+       if (port > 4) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "[ENCODER:%d:%s] port %c (index %u) out of bounds for display power state notification\n",
+                           intel_encoder->base.base.id, intel_encoder->base.name,
+                           port_name(intel_encoder->port), port);
+               return -EINVAL;
+       }
+
        if (!enable)
                parm |= 4 << 8;
 
index 1a376e9..d610e48 100644 (file)
@@ -959,6 +959,9 @@ static int check_overlay_dst(struct intel_overlay *overlay,
        const struct intel_crtc_state *pipe_config =
                overlay->crtc->config;
 
+       if (rec->dst_height == 0 || rec->dst_width == 0)
+               return -EINVAL;
+
        if (rec->dst_x < pipe_config->pipe_src_w &&
            rec->dst_x + rec->dst_width <= pipe_config->pipe_src_w &&
            rec->dst_y < pipe_config->pipe_src_h &&
index 09f405e..92ff654 100644 (file)
@@ -34,7 +34,7 @@ void intel_snps_phy_wait_for_calibration(struct drm_i915_private *dev_priv)
                if (intel_de_wait_for_clear(dev_priv, ICL_PHY_MISC(phy),
                                            DG2_PHY_DP_TX_ACK_MASK, 25))
                        DRM_ERROR("SNPS PHY %c failed to calibrate after 25ms.\n",
-                                 phy);
+                                 phy_name(phy));
        }
 }
 
index 40faa18..7784c30 100644 (file)
@@ -345,10 +345,11 @@ static bool icl_tc_phy_status_complete(struct intel_digital_port *dig_port)
 static bool adl_tc_phy_status_complete(struct intel_digital_port *dig_port)
 {
        struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
+       enum tc_port tc_port = intel_port_to_tc(i915, dig_port->base.port);
        struct intel_uncore *uncore = &i915->uncore;
        u32 val;
 
-       val = intel_uncore_read(uncore, TCSS_DDI_STATUS(dig_port->tc_phy_fia_idx));
+       val = intel_uncore_read(uncore, TCSS_DDI_STATUS(tc_port));
        if (val == 0xffffffff) {
                drm_dbg_kms(&i915->drm,
                            "Port %s: PHY in TCCOLD, assuming not complete\n",
@@ -690,6 +691,8 @@ void intel_tc_port_sanitize(struct intel_digital_port *dig_port)
 {
        struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev);
        struct intel_encoder *encoder = &dig_port->base;
+       intel_wakeref_t tc_cold_wref;
+       enum intel_display_power_domain domain;
        int active_links = 0;
 
        mutex_lock(&dig_port->tc_lock);
@@ -701,12 +704,11 @@ void intel_tc_port_sanitize(struct intel_digital_port *dig_port)
 
        drm_WARN_ON(&i915->drm, dig_port->tc_mode != TC_PORT_DISCONNECTED);
        drm_WARN_ON(&i915->drm, dig_port->tc_lock_wakeref);
-       if (active_links) {
-               enum intel_display_power_domain domain;
-               intel_wakeref_t tc_cold_wref = tc_cold_block(dig_port, &domain);
 
-               dig_port->tc_mode = intel_tc_port_get_current_mode(dig_port);
+       tc_cold_wref = tc_cold_block(dig_port, &domain);
 
+       dig_port->tc_mode = intel_tc_port_get_current_mode(dig_port);
+       if (active_links) {
                if (!icl_tc_phy_is_connected(dig_port))
                        drm_dbg_kms(&i915->drm,
                                    "Port %s: PHY disconnected with %d active link(s)\n",
@@ -715,10 +717,23 @@ void intel_tc_port_sanitize(struct intel_digital_port *dig_port)
 
                dig_port->tc_lock_wakeref = tc_cold_block(dig_port,
                                                          &dig_port->tc_lock_power_domain);
-
-               tc_cold_unblock(dig_port, domain, tc_cold_wref);
+       } else {
+               /*
+                * TBT-alt is the default mode in any case the PHY ownership is not
+                * held (regardless of the sink's connected live state), so
+                * we'll just switch to disconnected mode from it here without
+                * a note.
+                */
+               if (dig_port->tc_mode != TC_PORT_TBT_ALT)
+                       drm_dbg_kms(&i915->drm,
+                                   "Port %s: PHY left in %s mode on disabled port, disconnecting it\n",
+                                   dig_port->tc_port_name,
+                                   tc_port_mode_name(dig_port->tc_mode));
+               icl_tc_phy_disconnect(dig_port);
        }
 
+       tc_cold_unblock(dig_port, domain, tc_cold_wref);
+
        drm_dbg_kms(&i915->drm, "Port %s: sanitize mode (%s)\n",
                    dig_port->tc_port_name,
                    tc_port_mode_name(dig_port->tc_mode));
index 3a5b247..1736efa 100644 (file)
@@ -2505,9 +2505,14 @@ static int eb_pin_timeline(struct i915_execbuffer *eb, struct intel_context *ce,
                                      timeout) < 0) {
                        i915_request_put(rq);
 
-                       tl = intel_context_timeline_lock(ce);
+                       /*
+                        * Error path, cannot use intel_context_timeline_lock as
+                        * that is user interruptable and this clean up step
+                        * must be done.
+                        */
+                       mutex_lock(&ce->timeline->mutex);
                        intel_context_exit(ce);
-                       intel_context_timeline_unlock(tl);
+                       mutex_unlock(&ce->timeline->mutex);
 
                        if (nonblock)
                                return -EWOULDBLOCK;
index 4b4829e..0dd107d 100644 (file)
@@ -311,6 +311,7 @@ struct drm_i915_gem_object {
 #define I915_BO_READONLY          BIT(6)
 #define I915_TILING_QUIRK_BIT     7 /* unknown swizzling; do not release! */
 #define I915_BO_PROTECTED         BIT(8)
+#define I915_BO_WAS_BOUND_BIT     9
        /**
         * @mem_flags - Mutable placement-related flags
         *
index 9f429ed..a50f884 100644 (file)
@@ -10,6 +10,8 @@
 #include "i915_gem_lmem.h"
 #include "i915_gem_mman.h"
 
+#include "gt/intel_gt.h"
+
 void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj,
                                 struct sg_table *pages,
                                 unsigned int sg_page_sizes)
@@ -221,6 +223,14 @@ __i915_gem_object_unset_pages(struct drm_i915_gem_object *obj)
        __i915_gem_object_reset_page_iter(obj);
        obj->mm.page_sizes.phys = obj->mm.page_sizes.sg = 0;
 
+       if (test_and_clear_bit(I915_BO_WAS_BOUND_BIT, &obj->flags)) {
+               struct drm_i915_private *i915 = to_i915(obj->base.dev);
+               intel_wakeref_t wakeref;
+
+               with_intel_runtime_pm_if_active(&i915->runtime_pm, wakeref)
+                       intel_gt_invalidate_tlbs(to_gt(i915));
+       }
+
        return pages;
 }
 
index de3fe79..1f880c8 100644 (file)
@@ -842,11 +842,9 @@ void i915_ttm_adjust_lru(struct drm_i915_gem_object *obj)
        } else if (obj->mm.madv != I915_MADV_WILLNEED) {
                bo->priority = I915_TTM_PRIO_PURGE;
        } else if (!i915_gem_object_has_pages(obj)) {
-               if (bo->priority < I915_TTM_PRIO_HAS_PAGES)
-                       bo->priority = I915_TTM_PRIO_HAS_PAGES;
+               bo->priority = I915_TTM_PRIO_NO_PAGES;
        } else {
-               if (bo->priority > I915_TTM_PRIO_NO_PAGES)
-                       bo->priority = I915_TTM_PRIO_NO_PAGES;
+               bo->priority = I915_TTM_PRIO_HAS_PAGES;
        }
 
        ttm_bo_move_to_lru_tail(bo, bo->resource, NULL);
index ee9612a..e130c82 100644 (file)
@@ -427,11 +427,17 @@ __i915_ttm_move(struct ttm_buffer_object *bo,
 
                if (!IS_ERR(fence))
                        goto out;
-       } else if (move_deps) {
-               int err = i915_deps_sync(move_deps, ctx);
+       } else {
+               int err = PTR_ERR(fence);
+
+               if (err == -EINTR || err == -ERESTARTSYS || err == -EAGAIN)
+                       return fence;
 
-               if (err)
-                       return ERR_PTR(err);
+               if (move_deps) {
+                       err = i915_deps_sync(move_deps, ctx);
+                       if (err)
+                               return ERR_PTR(err);
+               }
        }
 
        /* Error intercept failed or no accelerated migration to start with */
index f98f0fb..35d0fcd 100644 (file)
@@ -29,6 +29,8 @@ void __intel_gt_init_early(struct intel_gt *gt, struct drm_i915_private *i915)
 {
        spin_lock_init(&gt->irq_lock);
 
+       mutex_init(&gt->tlb_invalidate_lock);
+
        INIT_LIST_HEAD(&gt->closed_vma);
        spin_lock_init(&gt->closed_lock);
 
@@ -912,3 +914,109 @@ void intel_gt_info_print(const struct intel_gt_info *info,
 
        intel_sseu_dump(&info->sseu, p);
 }
+
+struct reg_and_bit {
+       i915_reg_t reg;
+       u32 bit;
+};
+
+static struct reg_and_bit
+get_reg_and_bit(const struct intel_engine_cs *engine, const bool gen8,
+               const i915_reg_t *regs, const unsigned int num)
+{
+       const unsigned int class = engine->class;
+       struct reg_and_bit rb = { };
+
+       if (drm_WARN_ON_ONCE(&engine->i915->drm,
+                            class >= num || !regs[class].reg))
+               return rb;
+
+       rb.reg = regs[class];
+       if (gen8 && class == VIDEO_DECODE_CLASS)
+               rb.reg.reg += 4 * engine->instance; /* GEN8_M2TCR */
+       else
+               rb.bit = engine->instance;
+
+       rb.bit = BIT(rb.bit);
+
+       return rb;
+}
+
+void intel_gt_invalidate_tlbs(struct intel_gt *gt)
+{
+       static const i915_reg_t gen8_regs[] = {
+               [RENDER_CLASS]                  = GEN8_RTCR,
+               [VIDEO_DECODE_CLASS]            = GEN8_M1TCR, /* , GEN8_M2TCR */
+               [VIDEO_ENHANCEMENT_CLASS]       = GEN8_VTCR,
+               [COPY_ENGINE_CLASS]             = GEN8_BTCR,
+       };
+       static const i915_reg_t gen12_regs[] = {
+               [RENDER_CLASS]                  = GEN12_GFX_TLB_INV_CR,
+               [VIDEO_DECODE_CLASS]            = GEN12_VD_TLB_INV_CR,
+               [VIDEO_ENHANCEMENT_CLASS]       = GEN12_VE_TLB_INV_CR,
+               [COPY_ENGINE_CLASS]             = GEN12_BLT_TLB_INV_CR,
+       };
+       struct drm_i915_private *i915 = gt->i915;
+       struct intel_uncore *uncore = gt->uncore;
+       struct intel_engine_cs *engine;
+       enum intel_engine_id id;
+       const i915_reg_t *regs;
+       unsigned int num = 0;
+
+       if (I915_SELFTEST_ONLY(gt->awake == -ENODEV))
+               return;
+
+       if (GRAPHICS_VER(i915) == 12) {
+               regs = gen12_regs;
+               num = ARRAY_SIZE(gen12_regs);
+       } else if (GRAPHICS_VER(i915) >= 8 && GRAPHICS_VER(i915) <= 11) {
+               regs = gen8_regs;
+               num = ARRAY_SIZE(gen8_regs);
+       } else if (GRAPHICS_VER(i915) < 8) {
+               return;
+       }
+
+       if (drm_WARN_ONCE(&i915->drm, !num,
+                         "Platform does not implement TLB invalidation!"))
+               return;
+
+       GEM_TRACE("\n");
+
+       assert_rpm_wakelock_held(&i915->runtime_pm);
+
+       mutex_lock(&gt->tlb_invalidate_lock);
+       intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
+
+       for_each_engine(engine, gt, id) {
+               /*
+                * HW architecture suggest typical invalidation time at 40us,
+                * with pessimistic cases up to 100us and a recommendation to
+                * cap at 1ms. We go a bit higher just in case.
+                */
+               const unsigned int timeout_us = 100;
+               const unsigned int timeout_ms = 4;
+               struct reg_and_bit rb;
+
+               rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num);
+               if (!i915_mmio_reg_offset(rb.reg))
+                       continue;
+
+               intel_uncore_write_fw(uncore, rb.reg, rb.bit);
+               if (__intel_wait_for_register_fw(uncore,
+                                                rb.reg, rb.bit, 0,
+                                                timeout_us, timeout_ms,
+                                                NULL))
+                       drm_err_ratelimited(&gt->i915->drm,
+                                           "%s TLB invalidation did not complete in %ums!\n",
+                                           engine->name, timeout_ms);
+       }
+
+       /*
+        * Use delayed put since a) we mostly expect a flurry of TLB
+        * invalidations so it is good to avoid paying the forcewake cost and
+        * b) it works around a bug in Icelake which cannot cope with too rapid
+        * transitions.
+        */
+       intel_uncore_forcewake_put_delayed(uncore, FORCEWAKE_ALL);
+       mutex_unlock(&gt->tlb_invalidate_lock);
+}
index 3ace129..a913fb6 100644 (file)
@@ -91,4 +91,6 @@ void intel_gt_info_print(const struct intel_gt_info *info,
 
 void intel_gt_watchdog_work(struct work_struct *work);
 
+void intel_gt_invalidate_tlbs(struct intel_gt *gt);
+
 #endif /* __INTEL_GT_H__ */
index 14216cc..f206877 100644 (file)
@@ -73,6 +73,8 @@ struct intel_gt {
 
        struct intel_uc uc;
 
+       struct mutex tlb_invalidate_lock;
+
        struct i915_wa_list wa_list;
 
        struct intel_gt_timelines {
index f9240d4..3aabe16 100644 (file)
@@ -206,6 +206,11 @@ struct intel_guc {
                 * context usage for overflows.
                 */
                struct delayed_work work;
+
+               /**
+                * @shift: Right shift value for the gpm timestamp
+                */
+               u32 shift;
        } timestamp;
 
 #ifdef CONFIG_DRM_I915_SELFTEST
index e751720..154ad72 100644 (file)
@@ -1113,6 +1113,19 @@ __extend_last_switch(struct intel_guc *guc, u64 *prev_start, u32 new_start)
        if (new_start == lower_32_bits(*prev_start))
                return;
 
+       /*
+        * When gt is unparked, we update the gt timestamp and start the ping
+        * worker that updates the gt_stamp every POLL_TIME_CLKS. As long as gt
+        * is unparked, all switched in contexts will have a start time that is
+        * within +/- POLL_TIME_CLKS of the most recent gt_stamp.
+        *
+        * If neither gt_stamp nor new_start has rolled over, then the
+        * gt_stamp_hi does not need to be adjusted, however if one of them has
+        * rolled over, we need to adjust gt_stamp_hi accordingly.
+        *
+        * The below conditions address the cases of new_start rollover and
+        * gt_stamp_last rollover respectively.
+        */
        if (new_start < gt_stamp_last &&
            (new_start - gt_stamp_last) <= POLL_TIME_CLKS)
                gt_stamp_hi++;
@@ -1124,17 +1137,45 @@ __extend_last_switch(struct intel_guc *guc, u64 *prev_start, u32 new_start)
        *prev_start = ((u64)gt_stamp_hi << 32) | new_start;
 }
 
-static void guc_update_engine_gt_clks(struct intel_engine_cs *engine)
+/*
+ * GuC updates shared memory and KMD reads it. Since this is not synchronized,
+ * we run into a race where the value read is inconsistent. Sometimes the
+ * inconsistency is in reading the upper MSB bytes of the last_in value when
+ * this race occurs. 2 types of cases are seen - upper 8 bits are zero and upper
+ * 24 bits are zero. Since these are non-zero values, it is non-trivial to
+ * determine validity of these values. Instead we read the values multiple times
+ * until they are consistent. In test runs, 3 attempts results in consistent
+ * values. The upper bound is set to 6 attempts and may need to be tuned as per
+ * any new occurences.
+ */
+static void __get_engine_usage_record(struct intel_engine_cs *engine,
+                                     u32 *last_in, u32 *id, u32 *total)
 {
        struct guc_engine_usage_record *rec = intel_guc_engine_usage(engine);
+       int i = 0;
+
+       do {
+               *last_in = READ_ONCE(rec->last_switch_in_stamp);
+               *id = READ_ONCE(rec->current_context_index);
+               *total = READ_ONCE(rec->total_runtime);
+
+               if (READ_ONCE(rec->last_switch_in_stamp) == *last_in &&
+                   READ_ONCE(rec->current_context_index) == *id &&
+                   READ_ONCE(rec->total_runtime) == *total)
+                       break;
+       } while (++i < 6);
+}
+
+static void guc_update_engine_gt_clks(struct intel_engine_cs *engine)
+{
        struct intel_engine_guc_stats *stats = &engine->stats.guc;
        struct intel_guc *guc = &engine->gt->uc.guc;
-       u32 last_switch = rec->last_switch_in_stamp;
-       u32 ctx_id = rec->current_context_index;
-       u32 total = rec->total_runtime;
+       u32 last_switch, ctx_id, total;
 
        lockdep_assert_held(&guc->timestamp.lock);
 
+       __get_engine_usage_record(engine, &last_switch, &ctx_id, &total);
+
        stats->running = ctx_id != ~0U && last_switch;
        if (stats->running)
                __extend_last_switch(guc, &stats->start_gt_clk, last_switch);
@@ -1149,23 +1190,51 @@ static void guc_update_engine_gt_clks(struct intel_engine_cs *engine)
        }
 }
 
-static void guc_update_pm_timestamp(struct intel_guc *guc,
-                                   struct intel_engine_cs *engine,
-                                   ktime_t *now)
+static u32 gpm_timestamp_shift(struct intel_gt *gt)
+{
+       intel_wakeref_t wakeref;
+       u32 reg, shift;
+
+       with_intel_runtime_pm(gt->uncore->rpm, wakeref)
+               reg = intel_uncore_read(gt->uncore, RPM_CONFIG0);
+
+       shift = (reg & GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_MASK) >>
+               GEN10_RPM_CONFIG0_CTC_SHIFT_PARAMETER_SHIFT;
+
+       return 3 - shift;
+}
+
+static u64 gpm_timestamp(struct intel_gt *gt)
+{
+       u32 lo, hi, old_hi, loop = 0;
+
+       hi = intel_uncore_read(gt->uncore, MISC_STATUS1);
+       do {
+               lo = intel_uncore_read(gt->uncore, MISC_STATUS0);
+               old_hi = hi;
+               hi = intel_uncore_read(gt->uncore, MISC_STATUS1);
+       } while (old_hi != hi && loop++ < 2);
+
+       return ((u64)hi << 32) | lo;
+}
+
+static void guc_update_pm_timestamp(struct intel_guc *guc, ktime_t *now)
 {
-       u32 gt_stamp_now, gt_stamp_hi;
+       struct intel_gt *gt = guc_to_gt(guc);
+       u32 gt_stamp_lo, gt_stamp_hi;
+       u64 gpm_ts;
 
        lockdep_assert_held(&guc->timestamp.lock);
 
        gt_stamp_hi = upper_32_bits(guc->timestamp.gt_stamp);
-       gt_stamp_now = intel_uncore_read(engine->uncore,
-                                        RING_TIMESTAMP(engine->mmio_base));
+       gpm_ts = gpm_timestamp(gt) >> guc->timestamp.shift;
+       gt_stamp_lo = lower_32_bits(gpm_ts);
        *now = ktime_get();
 
-       if (gt_stamp_now < lower_32_bits(guc->timestamp.gt_stamp))
+       if (gt_stamp_lo < lower_32_bits(guc->timestamp.gt_stamp))
                gt_stamp_hi++;
 
-       guc->timestamp.gt_stamp = ((u64)gt_stamp_hi << 32) | gt_stamp_now;
+       guc->timestamp.gt_stamp = ((u64)gt_stamp_hi << 32) | gt_stamp_lo;
 }
 
 /*
@@ -1208,8 +1277,12 @@ static ktime_t guc_engine_busyness(struct intel_engine_cs *engine, ktime_t *now)
        if (!in_reset && intel_gt_pm_get_if_awake(gt)) {
                stats_saved = *stats;
                gt_stamp_saved = guc->timestamp.gt_stamp;
+               /*
+                * Update gt_clks, then gt timestamp to simplify the 'gt_stamp -
+                * start_gt_clk' calculation below for active engines.
+                */
                guc_update_engine_gt_clks(engine);
-               guc_update_pm_timestamp(guc, engine, now);
+               guc_update_pm_timestamp(guc, now);
                intel_gt_pm_put_async(gt);
                if (i915_reset_count(gpu_error) != reset_count) {
                        *stats = stats_saved;
@@ -1241,8 +1314,8 @@ static void __reset_guc_busyness_stats(struct intel_guc *guc)
 
        spin_lock_irqsave(&guc->timestamp.lock, flags);
 
+       guc_update_pm_timestamp(guc, &unused);
        for_each_engine(engine, gt, id) {
-               guc_update_pm_timestamp(guc, engine, &unused);
                guc_update_engine_gt_clks(engine);
                engine->stats.guc.prev_total = 0;
        }
@@ -1259,10 +1332,11 @@ static void __update_guc_busyness_stats(struct intel_guc *guc)
        ktime_t unused;
 
        spin_lock_irqsave(&guc->timestamp.lock, flags);
-       for_each_engine(engine, gt, id) {
-               guc_update_pm_timestamp(guc, engine, &unused);
+
+       guc_update_pm_timestamp(guc, &unused);
+       for_each_engine(engine, gt, id)
                guc_update_engine_gt_clks(engine);
-       }
+
        spin_unlock_irqrestore(&guc->timestamp.lock, flags);
 }
 
@@ -1335,10 +1409,15 @@ void intel_guc_busyness_park(struct intel_gt *gt)
 void intel_guc_busyness_unpark(struct intel_gt *gt)
 {
        struct intel_guc *guc = &gt->uc.guc;
+       unsigned long flags;
+       ktime_t unused;
 
        if (!guc_submission_initialized(guc))
                return;
 
+       spin_lock_irqsave(&guc->timestamp.lock, flags);
+       guc_update_pm_timestamp(guc, &unused);
+       spin_unlock_irqrestore(&guc->timestamp.lock, flags);
        mod_delayed_work(system_highpri_wq, &guc->timestamp.work,
                         guc->timestamp.ping_delay);
 }
@@ -1783,6 +1862,7 @@ int intel_guc_submission_init(struct intel_guc *guc)
        spin_lock_init(&guc->timestamp.lock);
        INIT_DELAYED_WORK(&guc->timestamp.work, guc_timestamp_ping);
        guc->timestamp.ping_delay = (POLL_TIME_CLKS / gt->clock_frequency + 1) * HZ;
+       guc->timestamp.shift = gpm_timestamp_shift(gt);
 
        return 0;
 }
index 99d1781..af79b39 100644 (file)
@@ -1148,7 +1148,7 @@ static inline void ppgtt_generate_shadow_entry(struct intel_gvt_gtt_entry *se,
        ops->set_pfn(se, s->shadow_page.mfn);
 }
 
-/**
+/*
  * Check if can do 2M page
  * @vgpu: target vgpu
  * @entry: target pfn's gtt entry
@@ -2193,7 +2193,7 @@ static int emulate_ggtt_mmio_read(struct intel_vgpu *vgpu,
 }
 
 /**
- * intel_vgpu_emulate_gtt_mmio_read - emulate GTT MMIO register read
+ * intel_vgpu_emulate_ggtt_mmio_read - emulate GTT MMIO register read
  * @vgpu: a vGPU
  * @off: register offset
  * @p_data: data will be returned to guest
index 5ae812d..0633888 100644 (file)
@@ -1522,7 +1522,7 @@ capture_engine(struct intel_engine_cs *engine,
        struct i915_request *rq = NULL;
        unsigned long flags;
 
-       ee = intel_engine_coredump_alloc(engine, GFP_KERNEL);
+       ee = intel_engine_coredump_alloc(engine, ALLOW_FAIL);
        if (!ee)
                return NULL;
 
index 76f1d53..3ad22bb 100644 (file)
@@ -6,6 +6,7 @@
 #ifndef __I915_MM_H__
 #define __I915_MM_H__
 
+#include <linux/bug.h>
 #include <linux/types.h>
 
 struct vm_area_struct;
index 971d601..c2bb33f 100644 (file)
@@ -2684,7 +2684,8 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
 #define   RING_WAIT            (1 << 11) /* gen3+, PRBx_CTL */
 #define   RING_WAIT_SEMAPHORE  (1 << 10) /* gen6+ */
 
-#define GUCPMTIMESTAMP          _MMIO(0xC3E8)
+#define MISC_STATUS0           _MMIO(0xA500)
+#define MISC_STATUS1           _MMIO(0xA504)
 
 /* There are 16 64-bit CS General Purpose Registers per-engine on Gen8+ */
 #define GEN8_RING_CS_GPR(base, n)      _MMIO((base) + 0x600 + (n) * 8)
@@ -2721,6 +2722,12 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
 #define   GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING     (1 << 28)
 #define   GAMT_CHKN_DISABLE_I2M_CYCLE_ON_WR_PORT       (1 << 24)
 
+#define GEN8_RTCR      _MMIO(0x4260)
+#define GEN8_M1TCR     _MMIO(0x4264)
+#define GEN8_M2TCR     _MMIO(0x4268)
+#define GEN8_BTCR      _MMIO(0x426c)
+#define GEN8_VTCR      _MMIO(0x4270)
+
 #if 0
 #define PRB0_TAIL      _MMIO(0x2030)
 #define PRB0_HEAD      _MMIO(0x2034)
@@ -2819,6 +2826,11 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
 #define   FAULT_VA_HIGH_BITS           (0xf << 0)
 #define   FAULT_GTT_SEL                        (1 << 4)
 
+#define GEN12_GFX_TLB_INV_CR   _MMIO(0xced8)
+#define GEN12_VD_TLB_INV_CR    _MMIO(0xcedc)
+#define GEN12_VE_TLB_INV_CR    _MMIO(0xcee0)
+#define GEN12_BLT_TLB_INV_CR   _MMIO(0xcee4)
+
 #define GEN12_AUX_ERR_DBG              _MMIO(0x43f4)
 
 #define FPGA_DBG               _MMIO(0x42300)
index 29a858c..c0d6d55 100644 (file)
@@ -457,6 +457,9 @@ int i915_vma_bind(struct i915_vma *vma,
                vma->ops->bind_vma(vma->vm, NULL, vma, cache_level, bind_flags);
        }
 
+       if (vma->obj)
+               set_bit(I915_BO_WAS_BOUND_BIT, &vma->obj->flags);
+
        atomic_or(bind_flags, &vma->flags);
        return 0;
 }
index 434b1f8..fae4f78 100644 (file)
@@ -4029,6 +4029,17 @@ static int intel_compute_sagv_mask(struct intel_atomic_state *state)
                        return ret;
        }
 
+       if (intel_can_enable_sagv(dev_priv, new_bw_state) !=
+           intel_can_enable_sagv(dev_priv, old_bw_state)) {
+               ret = intel_atomic_serialize_global_state(&new_bw_state->base);
+               if (ret)
+                       return ret;
+       } else if (new_bw_state->pipe_sagv_reject != old_bw_state->pipe_sagv_reject) {
+               ret = intel_atomic_lock_global_state(&new_bw_state->base);
+               if (ret)
+                       return ret;
+       }
+
        for_each_new_intel_crtc_in_state(state, crtc,
                                         new_crtc_state, i) {
                struct skl_pipe_wm *pipe_wm = &new_crtc_state->wm.skl.optimal;
@@ -4044,17 +4055,6 @@ static int intel_compute_sagv_mask(struct intel_atomic_state *state)
                        intel_can_enable_sagv(dev_priv, new_bw_state);
        }
 
-       if (intel_can_enable_sagv(dev_priv, new_bw_state) !=
-           intel_can_enable_sagv(dev_priv, old_bw_state)) {
-               ret = intel_atomic_serialize_global_state(&new_bw_state->base);
-               if (ret)
-                       return ret;
-       } else if (new_bw_state->pipe_sagv_reject != old_bw_state->pipe_sagv_reject) {
-               ret = intel_atomic_lock_global_state(&new_bw_state->base);
-               if (ret)
-                       return ret;
-       }
-
        return 0;
 }
 
@@ -4717,6 +4717,10 @@ static const struct dbuf_slice_conf_entry dg2_allowed_dbufs[] = {
 };
 
 static const struct dbuf_slice_conf_entry adlp_allowed_dbufs[] = {
+       /*
+        * Keep the join_mbus cases first so check_mbus_joined()
+        * will prefer them over the !join_mbus cases.
+        */
        {
                .active_pipes = BIT(PIPE_A),
                .dbuf_mask = {
@@ -4731,6 +4735,20 @@ static const struct dbuf_slice_conf_entry adlp_allowed_dbufs[] = {
                },
                .join_mbus = true,
        },
+       {
+               .active_pipes = BIT(PIPE_A),
+               .dbuf_mask = {
+                       [PIPE_A] = BIT(DBUF_S1) | BIT(DBUF_S2),
+               },
+               .join_mbus = false,
+       },
+       {
+               .active_pipes = BIT(PIPE_B),
+               .dbuf_mask = {
+                       [PIPE_B] = BIT(DBUF_S3) | BIT(DBUF_S4),
+               },
+               .join_mbus = false,
+       },
        {
                .active_pipes = BIT(PIPE_A) | BIT(PIPE_B),
                .dbuf_mask = {
@@ -4835,7 +4853,7 @@ static bool check_mbus_joined(u8 active_pipes,
 {
        int i;
 
-       for (i = 0; i < dbuf_slices[i].active_pipes; i++) {
+       for (i = 0; dbuf_slices[i].active_pipes != 0; i++) {
                if (dbuf_slices[i].active_pipes == active_pipes)
                        return dbuf_slices[i].join_mbus;
        }
@@ -4847,13 +4865,14 @@ static bool adlp_check_mbus_joined(u8 active_pipes)
        return check_mbus_joined(active_pipes, adlp_allowed_dbufs);
 }
 
-static u8 compute_dbuf_slices(enum pipe pipe, u8 active_pipes,
+static u8 compute_dbuf_slices(enum pipe pipe, u8 active_pipes, bool join_mbus,
                              const struct dbuf_slice_conf_entry *dbuf_slices)
 {
        int i;
 
-       for (i = 0; i < dbuf_slices[i].active_pipes; i++) {
-               if (dbuf_slices[i].active_pipes == active_pipes)
+       for (i = 0; dbuf_slices[i].active_pipes != 0; i++) {
+               if (dbuf_slices[i].active_pipes == active_pipes &&
+                   dbuf_slices[i].join_mbus == join_mbus)
                        return dbuf_slices[i].dbuf_mask[pipe];
        }
        return 0;
@@ -4864,7 +4883,7 @@ static u8 compute_dbuf_slices(enum pipe pipe, u8 active_pipes,
  * returns correspondent DBuf slice mask as stated in BSpec for particular
  * platform.
  */
-static u8 icl_compute_dbuf_slices(enum pipe pipe, u8 active_pipes)
+static u8 icl_compute_dbuf_slices(enum pipe pipe, u8 active_pipes, bool join_mbus)
 {
        /*
         * FIXME: For ICL this is still a bit unclear as prev BSpec revision
@@ -4878,37 +4897,41 @@ static u8 icl_compute_dbuf_slices(enum pipe pipe, u8 active_pipes)
         * still here - we will need it once those additional constraints
         * pop up.
         */
-       return compute_dbuf_slices(pipe, active_pipes, icl_allowed_dbufs);
+       return compute_dbuf_slices(pipe, active_pipes, join_mbus,
+                                  icl_allowed_dbufs);
 }
 
-static u8 tgl_compute_dbuf_slices(enum pipe pipe, u8 active_pipes)
+static u8 tgl_compute_dbuf_slices(enum pipe pipe, u8 active_pipes, bool join_mbus)
 {
-       return compute_dbuf_slices(pipe, active_pipes, tgl_allowed_dbufs);
+       return compute_dbuf_slices(pipe, active_pipes, join_mbus,
+                                  tgl_allowed_dbufs);
 }
 
-static u32 adlp_compute_dbuf_slices(enum pipe pipe, u32 active_pipes)
+static u8 adlp_compute_dbuf_slices(enum pipe pipe, u8 active_pipes, bool join_mbus)
 {
-       return compute_dbuf_slices(pipe, active_pipes, adlp_allowed_dbufs);
+       return compute_dbuf_slices(pipe, active_pipes, join_mbus,
+                                  adlp_allowed_dbufs);
 }
 
-static u32 dg2_compute_dbuf_slices(enum pipe pipe, u32 active_pipes)
+static u8 dg2_compute_dbuf_slices(enum pipe pipe, u8 active_pipes, bool join_mbus)
 {
-       return compute_dbuf_slices(pipe, active_pipes, dg2_allowed_dbufs);
+       return compute_dbuf_slices(pipe, active_pipes, join_mbus,
+                                  dg2_allowed_dbufs);
 }
 
-static u8 skl_compute_dbuf_slices(struct intel_crtc *crtc, u8 active_pipes)
+static u8 skl_compute_dbuf_slices(struct intel_crtc *crtc, u8 active_pipes, bool join_mbus)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        enum pipe pipe = crtc->pipe;
 
        if (IS_DG2(dev_priv))
-               return dg2_compute_dbuf_slices(pipe, active_pipes);
+               return dg2_compute_dbuf_slices(pipe, active_pipes, join_mbus);
        else if (IS_ALDERLAKE_P(dev_priv))
-               return adlp_compute_dbuf_slices(pipe, active_pipes);
+               return adlp_compute_dbuf_slices(pipe, active_pipes, join_mbus);
        else if (DISPLAY_VER(dev_priv) == 12)
-               return tgl_compute_dbuf_slices(pipe, active_pipes);
+               return tgl_compute_dbuf_slices(pipe, active_pipes, join_mbus);
        else if (DISPLAY_VER(dev_priv) == 11)
-               return icl_compute_dbuf_slices(pipe, active_pipes);
+               return icl_compute_dbuf_slices(pipe, active_pipes, join_mbus);
        /*
         * For anything else just return one slice yet.
         * Should be extended for other platforms.
@@ -6127,11 +6150,16 @@ skl_compute_ddb(struct intel_atomic_state *state)
                        return ret;
        }
 
+       if (IS_ALDERLAKE_P(dev_priv))
+               new_dbuf_state->joined_mbus =
+                       adlp_check_mbus_joined(new_dbuf_state->active_pipes);
+
        for_each_intel_crtc(&dev_priv->drm, crtc) {
                enum pipe pipe = crtc->pipe;
 
                new_dbuf_state->slices[pipe] =
-                       skl_compute_dbuf_slices(crtc, new_dbuf_state->active_pipes);
+                       skl_compute_dbuf_slices(crtc, new_dbuf_state->active_pipes,
+                                               new_dbuf_state->joined_mbus);
 
                if (old_dbuf_state->slices[pipe] == new_dbuf_state->slices[pipe])
                        continue;
@@ -6143,9 +6171,6 @@ skl_compute_ddb(struct intel_atomic_state *state)
 
        new_dbuf_state->enabled_slices = intel_dbuf_enabled_slices(new_dbuf_state);
 
-       if (IS_ALDERLAKE_P(dev_priv))
-               new_dbuf_state->joined_mbus = adlp_check_mbus_joined(new_dbuf_state->active_pipes);
-
        if (old_dbuf_state->enabled_slices != new_dbuf_state->enabled_slices ||
            old_dbuf_state->joined_mbus != new_dbuf_state->joined_mbus) {
                ret = intel_atomic_serialize_global_state(&new_dbuf_state->base);
@@ -6626,6 +6651,7 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv)
                enum pipe pipe = crtc->pipe;
                unsigned int mbus_offset;
                enum plane_id plane_id;
+               u8 slices;
 
                skl_pipe_wm_get_hw_state(crtc, &crtc_state->wm.skl.optimal);
                crtc_state->wm.skl.raw = crtc_state->wm.skl.optimal;
@@ -6645,19 +6671,22 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv)
                        skl_ddb_entry_union(&dbuf_state->ddb[pipe], ddb_uv);
                }
 
-               dbuf_state->slices[pipe] =
-                       skl_compute_dbuf_slices(crtc, dbuf_state->active_pipes);
-
                dbuf_state->weight[pipe] = intel_crtc_ddb_weight(crtc_state);
 
                /*
                 * Used for checking overlaps, so we need absolute
                 * offsets instead of MBUS relative offsets.
                 */
-               mbus_offset = mbus_ddb_offset(dev_priv, dbuf_state->slices[pipe]);
+               slices = skl_compute_dbuf_slices(crtc, dbuf_state->active_pipes,
+                                                dbuf_state->joined_mbus);
+               mbus_offset = mbus_ddb_offset(dev_priv, slices);
                crtc_state->wm.skl.ddb.start = mbus_offset + dbuf_state->ddb[pipe].start;
                crtc_state->wm.skl.ddb.end = mbus_offset + dbuf_state->ddb[pipe].end;
 
+               /* The slices actually used by the planes on the pipe */
+               dbuf_state->slices[pipe] =
+                       skl_ddb_dbuf_slice_mask(dev_priv, &crtc_state->wm.skl.ddb);
+
                drm_dbg_kms(&dev_priv->drm,
                            "[CRTC:%d:%s] dbuf slices 0x%x, ddb (%d - %d), active pipes 0x%x, mbus joined: %s\n",
                            crtc->base.base.id, crtc->base.name,
@@ -6669,6 +6698,74 @@ void skl_wm_get_hw_state(struct drm_i915_private *dev_priv)
        dbuf_state->enabled_slices = dev_priv->dbuf.enabled_slices;
 }
 
+static bool skl_dbuf_is_misconfigured(struct drm_i915_private *i915)
+{
+       const struct intel_dbuf_state *dbuf_state =
+               to_intel_dbuf_state(i915->dbuf.obj.state);
+       struct skl_ddb_entry entries[I915_MAX_PIPES] = {};
+       struct intel_crtc *crtc;
+
+       for_each_intel_crtc(&i915->drm, crtc) {
+               const struct intel_crtc_state *crtc_state =
+                       to_intel_crtc_state(crtc->base.state);
+
+               entries[crtc->pipe] = crtc_state->wm.skl.ddb;
+       }
+
+       for_each_intel_crtc(&i915->drm, crtc) {
+               const struct intel_crtc_state *crtc_state =
+                       to_intel_crtc_state(crtc->base.state);
+               u8 slices;
+
+               slices = skl_compute_dbuf_slices(crtc, dbuf_state->active_pipes,
+                                                dbuf_state->joined_mbus);
+               if (dbuf_state->slices[crtc->pipe] & ~slices)
+                       return true;
+
+               if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.ddb, entries,
+                                               I915_MAX_PIPES, crtc->pipe))
+                       return true;
+       }
+
+       return false;
+}
+
+void skl_wm_sanitize(struct drm_i915_private *i915)
+{
+       struct intel_crtc *crtc;
+
+       /*
+        * On TGL/RKL (at least) the BIOS likes to assign the planes
+        * to the wrong DBUF slices. This will cause an infinite loop
+        * in skl_commit_modeset_enables() as it can't find a way to
+        * transition between the old bogus DBUF layout to the new
+        * proper DBUF layout without DBUF allocation overlaps between
+        * the planes (which cannot be allowed or else the hardware
+        * may hang). If we detect a bogus DBUF layout just turn off
+        * all the planes so that skl_commit_modeset_enables() can
+        * simply ignore them.
+        */
+       if (!skl_dbuf_is_misconfigured(i915))
+               return;
+
+       drm_dbg_kms(&i915->drm, "BIOS has misprogrammed the DBUF, disabling all planes\n");
+
+       for_each_intel_crtc(&i915->drm, crtc) {
+               struct intel_plane *plane = to_intel_plane(crtc->base.primary);
+               const struct intel_plane_state *plane_state =
+                       to_intel_plane_state(plane->base.state);
+               struct intel_crtc_state *crtc_state =
+                       to_intel_crtc_state(crtc->base.state);
+
+               if (plane_state->uapi.visible)
+                       intel_plane_disable_noatomic(crtc, plane);
+
+               drm_WARN_ON(&i915->drm, crtc_state->active_planes != 0);
+
+               memset(&crtc_state->wm.skl.ddb, 0, sizeof(crtc_state->wm.skl.ddb));
+       }
+}
+
 static void ilk_pipe_wm_get_hw_state(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
index 990cdca..d224365 100644 (file)
@@ -47,6 +47,7 @@ void skl_pipe_wm_get_hw_state(struct intel_crtc *crtc,
                              struct skl_pipe_wm *out);
 void g4x_wm_sanitize(struct drm_i915_private *dev_priv);
 void vlv_wm_sanitize(struct drm_i915_private *dev_priv);
+void skl_wm_sanitize(struct drm_i915_private *dev_priv);
 bool intel_can_enable_sagv(struct drm_i915_private *dev_priv,
                           const struct intel_bw_state *bw_state);
 void intel_sagv_pre_plane_update(struct intel_atomic_state *state);
index 53f1ccb..64c2708 100644 (file)
@@ -68,9 +68,7 @@ static noinline depot_stack_handle_t __save_depot_stack(void)
 static void init_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm)
 {
        spin_lock_init(&rpm->debug.lock);
-
-       if (rpm->available)
-               stack_depot_init();
+       stack_depot_init();
 }
 
 static noinline depot_stack_handle_t
index fc25ebf..778da31 100644 (file)
@@ -724,7 +724,8 @@ void intel_uncore_forcewake_get__locked(struct intel_uncore *uncore,
 }
 
 static void __intel_uncore_forcewake_put(struct intel_uncore *uncore,
-                                        enum forcewake_domains fw_domains)
+                                        enum forcewake_domains fw_domains,
+                                        bool delayed)
 {
        struct intel_uncore_forcewake_domain *domain;
        unsigned int tmp;
@@ -739,7 +740,11 @@ static void __intel_uncore_forcewake_put(struct intel_uncore *uncore,
                        continue;
                }
 
-               fw_domains_put(uncore, domain->mask);
+               if (delayed &&
+                   !(domain->uncore->fw_domains_timer & domain->mask))
+                       fw_domain_arm_timer(domain);
+               else
+                       fw_domains_put(uncore, domain->mask);
        }
 }
 
@@ -760,7 +765,20 @@ void intel_uncore_forcewake_put(struct intel_uncore *uncore,
                return;
 
        spin_lock_irqsave(&uncore->lock, irqflags);
-       __intel_uncore_forcewake_put(uncore, fw_domains);
+       __intel_uncore_forcewake_put(uncore, fw_domains, false);
+       spin_unlock_irqrestore(&uncore->lock, irqflags);
+}
+
+void intel_uncore_forcewake_put_delayed(struct intel_uncore *uncore,
+                                       enum forcewake_domains fw_domains)
+{
+       unsigned long irqflags;
+
+       if (!uncore->fw_get_funcs)
+               return;
+
+       spin_lock_irqsave(&uncore->lock, irqflags);
+       __intel_uncore_forcewake_put(uncore, fw_domains, true);
        spin_unlock_irqrestore(&uncore->lock, irqflags);
 }
 
@@ -802,7 +820,7 @@ void intel_uncore_forcewake_put__locked(struct intel_uncore *uncore,
        if (!uncore->fw_get_funcs)
                return;
 
-       __intel_uncore_forcewake_put(uncore, fw_domains);
+       __intel_uncore_forcewake_put(uncore, fw_domains, false);
 }
 
 void assert_forcewakes_inactive(struct intel_uncore *uncore)
index 210fe2a..2a15b2b 100644 (file)
@@ -246,6 +246,8 @@ void intel_uncore_forcewake_get(struct intel_uncore *uncore,
                                enum forcewake_domains domains);
 void intel_uncore_forcewake_put(struct intel_uncore *uncore,
                                enum forcewake_domains domains);
+void intel_uncore_forcewake_put_delayed(struct intel_uncore *uncore,
+                                       enum forcewake_domains domains);
 void intel_uncore_forcewake_flush(struct intel_uncore *uncore,
                                  enum forcewake_domains fw_domains);
 
index 7374f19..5c2b227 100644 (file)
@@ -2,6 +2,7 @@ config DRM_IMX_DCSS
        tristate "i.MX8MQ DCSS"
        select IMX_IRQSTEER
        select DRM_KMS_HELPER
+       select DRM_GEM_CMA_HELPER
        select VIDEOMODE_HELPERS
        depends on DRM && ARCH_MXC && ARM64
        help
index 00404ba..2735b8e 100644 (file)
@@ -158,12 +158,6 @@ static void kmb_plane_atomic_disable(struct drm_plane *plane,
        case LAYER_1:
                kmb->plane_status[plane_id].ctrl = LCD_CTRL_VL2_ENABLE;
                break;
-       case LAYER_2:
-               kmb->plane_status[plane_id].ctrl = LCD_CTRL_GL1_ENABLE;
-               break;
-       case LAYER_3:
-               kmb->plane_status[plane_id].ctrl = LCD_CTRL_GL2_ENABLE;
-               break;
        }
 
        kmb->plane_status[plane_id].disable = true;
index 5d90d2e..bced4c7 100644 (file)
@@ -786,18 +786,101 @@ void mtk_dsi_ddp_stop(struct device *dev)
        mtk_dsi_poweroff(dsi);
 }
 
+static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi)
+{
+       int ret;
+
+       ret = drm_simple_encoder_init(drm, &dsi->encoder,
+                                     DRM_MODE_ENCODER_DSI);
+       if (ret) {
+               DRM_ERROR("Failed to encoder init to drm\n");
+               return ret;
+       }
+
+       dsi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm, dsi->host.dev);
+
+       ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL,
+                               DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+       if (ret)
+               goto err_cleanup_encoder;
+
+       dsi->connector = drm_bridge_connector_init(drm, &dsi->encoder);
+       if (IS_ERR(dsi->connector)) {
+               DRM_ERROR("Unable to create bridge connector\n");
+               ret = PTR_ERR(dsi->connector);
+               goto err_cleanup_encoder;
+       }
+       drm_connector_attach_encoder(dsi->connector, &dsi->encoder);
+
+       return 0;
+
+err_cleanup_encoder:
+       drm_encoder_cleanup(&dsi->encoder);
+       return ret;
+}
+
+static int mtk_dsi_bind(struct device *dev, struct device *master, void *data)
+{
+       int ret;
+       struct drm_device *drm = data;
+       struct mtk_dsi *dsi = dev_get_drvdata(dev);
+
+       ret = mtk_dsi_encoder_init(drm, dsi);
+       if (ret)
+               return ret;
+
+       return device_reset_optional(dev);
+}
+
+static void mtk_dsi_unbind(struct device *dev, struct device *master,
+                          void *data)
+{
+       struct mtk_dsi *dsi = dev_get_drvdata(dev);
+
+       drm_encoder_cleanup(&dsi->encoder);
+}
+
+static const struct component_ops mtk_dsi_component_ops = {
+       .bind = mtk_dsi_bind,
+       .unbind = mtk_dsi_unbind,
+};
+
 static int mtk_dsi_host_attach(struct mipi_dsi_host *host,
                               struct mipi_dsi_device *device)
 {
        struct mtk_dsi *dsi = host_to_dsi(host);
+       struct device *dev = host->dev;
+       int ret;
 
        dsi->lanes = device->lanes;
        dsi->format = device->format;
        dsi->mode_flags = device->mode_flags;
+       dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);
+       if (IS_ERR(dsi->next_bridge))
+               return PTR_ERR(dsi->next_bridge);
+
+       drm_bridge_add(&dsi->bridge);
+
+       ret = component_add(host->dev, &mtk_dsi_component_ops);
+       if (ret) {
+               DRM_ERROR("failed to add dsi_host component: %d\n", ret);
+               drm_bridge_remove(&dsi->bridge);
+               return ret;
+       }
 
        return 0;
 }
 
+static int mtk_dsi_host_detach(struct mipi_dsi_host *host,
+                              struct mipi_dsi_device *device)
+{
+       struct mtk_dsi *dsi = host_to_dsi(host);
+
+       component_del(host->dev, &mtk_dsi_component_ops);
+       drm_bridge_remove(&dsi->bridge);
+       return 0;
+}
+
 static void mtk_dsi_wait_for_idle(struct mtk_dsi *dsi)
 {
        int ret;
@@ -938,73 +1021,14 @@ static ssize_t mtk_dsi_host_transfer(struct mipi_dsi_host *host,
 
 static const struct mipi_dsi_host_ops mtk_dsi_ops = {
        .attach = mtk_dsi_host_attach,
+       .detach = mtk_dsi_host_detach,
        .transfer = mtk_dsi_host_transfer,
 };
 
-static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi)
-{
-       int ret;
-
-       ret = drm_simple_encoder_init(drm, &dsi->encoder,
-                                     DRM_MODE_ENCODER_DSI);
-       if (ret) {
-               DRM_ERROR("Failed to encoder init to drm\n");
-               return ret;
-       }
-
-       dsi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm, dsi->host.dev);
-
-       ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL,
-                               DRM_BRIDGE_ATTACH_NO_CONNECTOR);
-       if (ret)
-               goto err_cleanup_encoder;
-
-       dsi->connector = drm_bridge_connector_init(drm, &dsi->encoder);
-       if (IS_ERR(dsi->connector)) {
-               DRM_ERROR("Unable to create bridge connector\n");
-               ret = PTR_ERR(dsi->connector);
-               goto err_cleanup_encoder;
-       }
-       drm_connector_attach_encoder(dsi->connector, &dsi->encoder);
-
-       return 0;
-
-err_cleanup_encoder:
-       drm_encoder_cleanup(&dsi->encoder);
-       return ret;
-}
-
-static int mtk_dsi_bind(struct device *dev, struct device *master, void *data)
-{
-       int ret;
-       struct drm_device *drm = data;
-       struct mtk_dsi *dsi = dev_get_drvdata(dev);
-
-       ret = mtk_dsi_encoder_init(drm, dsi);
-       if (ret)
-               return ret;
-
-       return device_reset_optional(dev);
-}
-
-static void mtk_dsi_unbind(struct device *dev, struct device *master,
-                          void *data)
-{
-       struct mtk_dsi *dsi = dev_get_drvdata(dev);
-
-       drm_encoder_cleanup(&dsi->encoder);
-}
-
-static const struct component_ops mtk_dsi_component_ops = {
-       .bind = mtk_dsi_bind,
-       .unbind = mtk_dsi_unbind,
-};
-
 static int mtk_dsi_probe(struct platform_device *pdev)
 {
        struct mtk_dsi *dsi;
        struct device *dev = &pdev->dev;
-       struct drm_panel *panel;
        struct resource *regs;
        int irq_num;
        int ret;
@@ -1021,19 +1045,6 @@ static int mtk_dsi_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
-                                         &panel, &dsi->next_bridge);
-       if (ret)
-               goto err_unregister_host;
-
-       if (panel) {
-               dsi->next_bridge = devm_drm_panel_bridge_add(dev, panel);
-               if (IS_ERR(dsi->next_bridge)) {
-                       ret = PTR_ERR(dsi->next_bridge);
-                       goto err_unregister_host;
-               }
-       }
-
        dsi->driver_data = of_device_get_match_data(dev);
 
        dsi->engine_clk = devm_clk_get(dev, "engine");
@@ -1098,14 +1109,6 @@ static int mtk_dsi_probe(struct platform_device *pdev)
        dsi->bridge.of_node = dev->of_node;
        dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
 
-       drm_bridge_add(&dsi->bridge);
-
-       ret = component_add(&pdev->dev, &mtk_dsi_component_ops);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to add component: %d\n", ret);
-               goto err_unregister_host;
-       }
-
        return 0;
 
 err_unregister_host:
@@ -1118,8 +1121,6 @@ static int mtk_dsi_remove(struct platform_device *pdev)
        struct mtk_dsi *dsi = platform_get_drvdata(pdev);
 
        mtk_output_dsi_disable(dsi);
-       drm_bridge_remove(&dsi->bridge);
-       component_del(&pdev->dev, &mtk_dsi_component_ops);
        mipi_dsi_host_unregister(&dsi->host);
 
        return 0;
index 51b8377..17cfad6 100644 (file)
@@ -1560,6 +1560,8 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu)
                for (i = 0; i < gpu->nr_rings; i++)
                        a6xx_gpu->shadow[i] = 0;
 
+       gpu->suspend_count++;
+
        return 0;
 }
 
index 9300583..fb26193 100644 (file)
@@ -608,9 +608,27 @@ static int adreno_resume(struct device *dev)
        return gpu->funcs->pm_resume(gpu);
 }
 
+static int active_submits(struct msm_gpu *gpu)
+{
+       int active_submits;
+       mutex_lock(&gpu->active_lock);
+       active_submits = gpu->active_submits;
+       mutex_unlock(&gpu->active_lock);
+       return active_submits;
+}
+
 static int adreno_suspend(struct device *dev)
 {
        struct msm_gpu *gpu = dev_to_gpu(dev);
+       int remaining;
+
+       remaining = wait_event_timeout(gpu->retire_event,
+                                      active_submits(gpu) == 0,
+                                      msecs_to_jiffies(1000));
+       if (remaining == 0) {
+               dev_err(dev, "Timeout waiting for GPU to suspend\n");
+               return -EBUSY;
+       }
 
        return gpu->funcs->pm_suspend(gpu);
 }
index a98e964..355894a 100644 (file)
@@ -26,9 +26,16 @@ static void dpu_setup_dspp_pcc(struct dpu_hw_dspp *ctx,
                struct dpu_hw_pcc_cfg *cfg)
 {
 
-       u32 base = ctx->cap->sblk->pcc.base;
+       u32 base;
 
-       if (!ctx || !base) {
+       if (!ctx) {
+               DRM_ERROR("invalid ctx %pK\n", ctx);
+               return;
+       }
+
+       base = ctx->cap->sblk->pcc.base;
+
+       if (!base) {
                DRM_ERROR("invalid ctx %pK pcc base 0x%x\n", ctx, base);
                return;
        }
index 0525488..0fe0252 100644 (file)
@@ -40,7 +40,12 @@ static int dsi_get_phy(struct msm_dsi *msm_dsi)
 
        of_node_put(phy_node);
 
-       if (!phy_pdev || !msm_dsi->phy) {
+       if (!phy_pdev) {
+               DRM_DEV_ERROR(&pdev->dev, "%s: phy driver is not ready\n", __func__);
+               return -EPROBE_DEFER;
+       }
+       if (!msm_dsi->phy) {
+               put_device(&phy_pdev->dev);
                DRM_DEV_ERROR(&pdev->dev, "%s: phy driver is not ready\n", __func__);
                return -EPROBE_DEFER;
        }
index c2ed177..2027b38 100644 (file)
@@ -808,12 +808,14 @@ int msm_dsi_phy_enable(struct msm_dsi_phy *phy,
                        struct msm_dsi_phy_clk_request *clk_req,
                        struct msm_dsi_phy_shared_timings *shared_timings)
 {
-       struct device *dev = &phy->pdev->dev;
+       struct device *dev;
        int ret;
 
        if (!phy || !phy->cfg->ops.enable)
                return -EINVAL;
 
+       dev = &phy->pdev->dev;
+
        ret = dsi_phy_enable_resource(phy);
        if (ret) {
                DRM_DEV_ERROR(dev, "%s: resource enable failed, %d\n",
index 3acdeae..7197207 100644 (file)
@@ -97,10 +97,15 @@ static int msm_hdmi_get_phy(struct hdmi *hdmi)
 
        of_node_put(phy_node);
 
-       if (!phy_pdev || !hdmi->phy) {
+       if (!phy_pdev) {
                DRM_DEV_ERROR(&pdev->dev, "phy driver is not ready\n");
                return -EPROBE_DEFER;
        }
+       if (!hdmi->phy) {
+               DRM_DEV_ERROR(&pdev->dev, "phy driver is not ready\n");
+               put_device(&phy_pdev->dev);
+               return -EPROBE_DEFER;
+       }
 
        hdmi->phy_dev = get_device(&phy_pdev->dev);
 
index ad35a5d..555666e 100644 (file)
@@ -461,7 +461,7 @@ static int msm_init_vram(struct drm_device *dev)
                of_node_put(node);
                if (ret)
                        return ret;
-               size = r.end - r.start;
+               size = r.end - r.start + 1;
                DRM_INFO("using VRAM carveout: %lx@%pa\n", size, &r.start);
 
                /* if we have no IOMMU, then we need to use carveout allocator.
@@ -510,7 +510,6 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv)
        struct msm_drm_private *priv = dev_get_drvdata(dev);
        struct drm_device *ddev;
        struct msm_kms *kms;
-       struct msm_mdss *mdss;
        int ret, i;
 
        ddev = drm_dev_alloc(drv, dev);
@@ -521,8 +520,6 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv)
        ddev->dev_private = priv;
        priv->dev = ddev;
 
-       mdss = priv->mdss;
-
        priv->wq = alloc_ordered_workqueue("msm", 0);
        priv->hangcheck_period = DRM_MSM_HANGCHECK_DEFAULT_PERIOD;
 
index 0f78c26..2c1049c 100644 (file)
@@ -703,6 +703,8 @@ static void retire_submits(struct msm_gpu *gpu)
                        }
                }
        }
+
+       wake_up_all(&gpu->retire_event);
 }
 
 static void retire_worker(struct kthread_work *work)
@@ -848,6 +850,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
        INIT_LIST_HEAD(&gpu->active_list);
        mutex_init(&gpu->active_lock);
        mutex_init(&gpu->lock);
+       init_waitqueue_head(&gpu->retire_event);
        kthread_init_work(&gpu->retire_work, retire_worker);
        kthread_init_work(&gpu->recover_work, recover_worker);
        kthread_init_work(&gpu->fault_work, fault_worker);
index 445c6bf..92aa1e9 100644 (file)
@@ -230,6 +230,9 @@ struct msm_gpu {
        /* work for handling GPU recovery: */
        struct kthread_work recover_work;
 
+       /** retire_event: notified when submits are retired: */
+       wait_queue_head_t retire_event;
+
        /* work for handling active-list retiring: */
        struct kthread_work retire_work;
 
index 62405e9..9bf319b 100644 (file)
@@ -133,6 +133,18 @@ void msm_devfreq_init(struct msm_gpu *gpu)
                              CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 }
 
+static void cancel_idle_work(struct msm_gpu_devfreq *df)
+{
+       hrtimer_cancel(&df->idle_work.timer);
+       kthread_cancel_work_sync(&df->idle_work.work);
+}
+
+static void cancel_boost_work(struct msm_gpu_devfreq *df)
+{
+       hrtimer_cancel(&df->boost_work.timer);
+       kthread_cancel_work_sync(&df->boost_work.work);
+}
+
 void msm_devfreq_cleanup(struct msm_gpu *gpu)
 {
        struct msm_gpu_devfreq *df = &gpu->devfreq;
@@ -152,7 +164,12 @@ void msm_devfreq_resume(struct msm_gpu *gpu)
 
 void msm_devfreq_suspend(struct msm_gpu *gpu)
 {
-       devfreq_suspend_device(gpu->devfreq.devfreq);
+       struct msm_gpu_devfreq *df = &gpu->devfreq;
+
+       devfreq_suspend_device(df->devfreq);
+
+       cancel_idle_work(df);
+       cancel_boost_work(df);
 }
 
 static void msm_devfreq_boost_work(struct kthread_work *work)
@@ -196,7 +213,7 @@ void msm_devfreq_active(struct msm_gpu *gpu)
        /*
         * Cancel any pending transition to idle frequency:
         */
-       hrtimer_cancel(&df->idle_work.timer);
+       cancel_idle_work(df);
 
        idle_time = ktime_to_ms(ktime_sub(ktime_get(), df->idle_time));
 
index 0655582..4cfb6c0 100644 (file)
@@ -361,7 +361,11 @@ static void mxsfb_crtc_atomic_enable(struct drm_crtc *crtc,
                bridge_state =
                        drm_atomic_get_new_bridge_state(state,
                                                        mxsfb->bridge);
-               bus_format = bridge_state->input_bus_cfg.format;
+               if (!bridge_state)
+                       bus_format = MEDIA_BUS_FMT_FIXED;
+               else
+                       bus_format = bridge_state->input_bus_cfg.format;
+
                if (bus_format == MEDIA_BUS_FMT_FIXED) {
                        dev_warn_once(drm->dev,
                                      "Bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n"
index d0f52d5..64e423d 100644 (file)
@@ -38,7 +38,7 @@ nvbios_addr(struct nvkm_bios *bios, u32 *addr, u8 size)
                *addr += bios->imaged_addr;
        }
 
-       if (unlikely(*addr + size >= bios->size)) {
+       if (unlikely(*addr + size > bios->size)) {
                nvkm_error(&bios->subdev, "OOB %d %08x %08x\n", size, p, *addr);
                return false;
        }
index 9e46db5..3c08f98 100644 (file)
@@ -588,6 +588,7 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
                err = panel_dpi_probe(dev, panel);
                if (err)
                        goto free_ddc;
+               desc = panel->desc;
        } else {
                if (!of_get_display_timing(dev->of_node, "panel-timing", &dt))
                        panel_simple_parse_panel_timing_node(dev, panel, &dt);
index 0fce73b..70bd84b 100644 (file)
@@ -198,7 +198,8 @@ void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder,
         * so don't register a backlight device
         */
        if ((rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) &&
-           (rdev->pdev->device == 0x6741))
+           (rdev->pdev->device == 0x6741) &&
+           !dmi_match(DMI_PRODUCT_NAME, "iMac12,1"))
                return;
 
        if (!radeon_encoder->enc_priv)
index 377f9cd..84013fa 100644 (file)
@@ -470,8 +470,8 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
        int32_t *msg, msg_type, handle;
        unsigned img_size = 0;
        void *ptr;
-
-       int i, r;
+       long r;
+       int i;
 
        if (offset & 0x3F) {
                DRM_ERROR("UVD messages must be 64 byte aligned!\n");
@@ -481,13 +481,13 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
        r = dma_resv_wait_timeout(bo->tbo.base.resv, false, false,
                                  MAX_SCHEDULE_TIMEOUT);
        if (r <= 0) {
-               DRM_ERROR("Failed waiting for UVD message (%d)!\n", r);
+               DRM_ERROR("Failed waiting for UVD message (%ld)!\n", r);
                return r ? r : -ETIME;
        }
 
        r = radeon_bo_kmap(bo, &ptr);
        if (r) {
-               DRM_ERROR("Failed mapping the UVD message (%d)!\n", r);
+               DRM_ERROR("Failed mapping the UVD message (%ld)!\n", r);
                return r;
        }
 
index 830bdd5..8677c82 100644 (file)
@@ -529,13 +529,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
                return ret;
        }
 
-       ret = clk_prepare_enable(hdmi->vpll_clk);
-       if (ret) {
-               DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
-                             ret);
-               return ret;
-       }
-
        hdmi->phy = devm_phy_optional_get(dev, "hdmi");
        if (IS_ERR(hdmi->phy)) {
                ret = PTR_ERR(hdmi->phy);
@@ -544,6 +537,13 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
                return ret;
        }
 
+       ret = clk_prepare_enable(hdmi->vpll_clk);
+       if (ret) {
+               DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
+                             ret);
+               return ret;
+       }
+
        drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
        drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
 
index 1f7353f..798b542 100644 (file)
@@ -902,6 +902,7 @@ static const struct vop_win_phy rk3399_win01_data = {
        .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
        .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
        .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
+       .x_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 21),
        .y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22),
        .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
        .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
@@ -912,6 +913,7 @@ static const struct vop_win_phy rk3399_win01_data = {
        .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
        .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
        .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0),
+       .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0),
 };
 
 /*
@@ -922,11 +924,11 @@ static const struct vop_win_phy rk3399_win01_data = {
 static const struct vop_win_data rk3399_vop_win_data[] = {
        { .base = 0x00, .phy = &rk3399_win01_data,
          .type = DRM_PLANE_TYPE_PRIMARY },
-       { .base = 0x40, .phy = &rk3288_win01_data,
+       { .base = 0x40, .phy = &rk3368_win01_data,
          .type = DRM_PLANE_TYPE_OVERLAY },
-       { .base = 0x00, .phy = &rk3288_win23_data,
+       { .base = 0x00, .phy = &rk3368_win23_data,
          .type = DRM_PLANE_TYPE_OVERLAY },
-       { .base = 0x50, .phy = &rk3288_win23_data,
+       { .base = 0x50, .phy = &rk3368_win23_data,
          .type = DRM_PLANE_TYPE_CURSOR },
 };
 
index 8cf5aeb..201f517 100644 (file)
@@ -5,6 +5,7 @@ config DRM_TEGRA
        depends on COMMON_CLK
        depends on DRM
        depends on OF
+       select DRM_DP_AUX_BUS
        select DRM_KMS_HELPER
        select DRM_MIPI_DSI
        select DRM_PANEL
index 1f96e41..d7a731d 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/workqueue.h>
 
 #include <drm/drm_dp_helper.h>
+#include <drm/drm_dp_aux_bus.h>
 #include <drm/drm_panel.h>
 
 #include "dp.h"
@@ -570,6 +571,12 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
        list_add_tail(&dpaux->list, &dpaux_list);
        mutex_unlock(&dpaux_lock);
 
+       err = devm_of_dp_aux_populate_ep_devices(&dpaux->aux);
+       if (err < 0) {
+               dev_err(dpaux->dev, "failed to populate AUX bus: %d\n", err);
+               return err;
+       }
+
        return 0;
 }
 
index 223ab2c..3762d87 100644 (file)
@@ -63,7 +63,7 @@ static void falcon_copy_firmware_image(struct falcon *falcon,
 
        /* copy the whole thing taking into account endianness */
        for (i = 0; i < firmware->size / sizeof(u32); i++)
-               virt[i] = le32_to_cpu(((u32 *)firmware->data)[i]);
+               virt[i] = le32_to_cpu(((__le32 *)firmware->data)[i]);
 }
 
 static int falcon_parse_firmware_image(struct falcon *falcon)
index 287dbc8..783890e 100644 (file)
@@ -525,9 +525,11 @@ int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
        if (ret)
                return ret;
 
-       ret = pm_runtime_put(&vc4_hdmi->pdev->dev);
-       if (ret)
-               return ret;
+       /*
+        * post_crtc_powerdown will have called pm_runtime_put, so we
+        * don't need it here otherwise we'll get the reference counting
+        * wrong.
+        */
 
        return 0;
 }
@@ -671,7 +673,6 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
                const struct drm_display_mode *mode = &crtc_state->adjusted_mode;
                struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
 
-               mode = &crtc_state->adjusted_mode;
                if (vc4_encoder->type == VC4_ENCODER_TYPE_HDMI0) {
                        vc4_state->hvs_load = max(mode->clock * mode->hdisplay / mode->htotal + 1000,
                                                  mode->clock * 9 / 10) * 1000;
index a229da5..9300d33 100644 (file)
@@ -1262,7 +1262,6 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host,
                               struct mipi_dsi_device *device)
 {
        struct vc4_dsi *dsi = host_to_dsi(host);
-       int ret;
 
        dsi->lanes = device->lanes;
        dsi->channel = device->channel;
@@ -1297,18 +1296,15 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host,
                return 0;
        }
 
-       ret = component_add(&dsi->pdev->dev, &vc4_dsi_ops);
-       if (ret) {
-               mipi_dsi_host_unregister(&dsi->dsi_host);
-               return ret;
-       }
-
-       return 0;
+       return component_add(&dsi->pdev->dev, &vc4_dsi_ops);
 }
 
 static int vc4_dsi_host_detach(struct mipi_dsi_host *host,
                               struct mipi_dsi_device *device)
 {
+       struct vc4_dsi *dsi = host_to_dsi(host);
+
+       component_del(&dsi->pdev->dev, &vc4_dsi_ops);
        return 0;
 }
 
@@ -1686,9 +1682,7 @@ static int vc4_dsi_dev_remove(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct vc4_dsi *dsi = dev_get_drvdata(dev);
 
-       component_del(&pdev->dev, &vc4_dsi_ops);
        mipi_dsi_host_unregister(&dsi->dsi_host);
-
        return 0;
 }
 
index 053fbaf..3a1626f 100644 (file)
@@ -196,14 +196,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
                if (gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio))
                        connected = true;
        } else {
-               unsigned long flags;
-               u32 hotplug;
-
-               spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
-               hotplug = HDMI_READ(HDMI_HOTPLUG);
-               spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
-
-               if (hotplug & VC4_HDMI_HOTPLUG_CONNECTED)
+               if (vc4_hdmi->variant->hp_detect &&
+                   vc4_hdmi->variant->hp_detect(vc4_hdmi))
                        connected = true;
        }
 
@@ -1251,6 +1245,7 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
        unsigned long long tmds_rate;
 
        if (vc4_hdmi->variant->unsupported_odd_h_timings &&
+           !(mode->flags & DRM_MODE_FLAG_DBLCLK) &&
            ((mode->hdisplay % 2) || (mode->hsync_start % 2) ||
             (mode->hsync_end % 2) || (mode->htotal % 2)))
                return -EINVAL;
@@ -1298,6 +1293,7 @@ vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder,
        struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
 
        if (vc4_hdmi->variant->unsupported_odd_h_timings &&
+           !(mode->flags & DRM_MODE_FLAG_DBLCLK) &&
            ((mode->hdisplay % 2) || (mode->hsync_start % 2) ||
             (mode->hsync_end % 2) || (mode->htotal % 2)))
                return MODE_H_ILLEGAL;
@@ -1343,6 +1339,18 @@ static u32 vc5_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask)
        return channel_map;
 }
 
+static bool vc5_hdmi_hp_detect(struct vc4_hdmi *vc4_hdmi)
+{
+       unsigned long flags;
+       u32 hotplug;
+
+       spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
+       hotplug = HDMI_READ(HDMI_HOTPLUG);
+       spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
+
+       return !!(hotplug & VC4_HDMI_HOTPLUG_CONNECTED);
+}
+
 /* HDMI audio codec callbacks */
 static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *vc4_hdmi,
                                         unsigned int samplerate)
@@ -1741,6 +1749,7 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
                dev_err(dev, "Couldn't register the HDMI codec: %ld\n", PTR_ERR(codec_pdev));
                return PTR_ERR(codec_pdev);
        }
+       vc4_hdmi->audio.codec_pdev = codec_pdev;
 
        dai_link->cpus          = &vc4_hdmi->audio.cpu;
        dai_link->codecs        = &vc4_hdmi->audio.codec;
@@ -1780,6 +1789,12 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
 
 }
 
+static void vc4_hdmi_audio_exit(struct vc4_hdmi *vc4_hdmi)
+{
+       platform_device_unregister(vc4_hdmi->audio.codec_pdev);
+       vc4_hdmi->audio.codec_pdev = NULL;
+}
+
 static irqreturn_t vc4_hdmi_hpd_irq_thread(int irq, void *priv)
 {
        struct vc4_hdmi *vc4_hdmi = priv;
@@ -2504,7 +2519,8 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
         * vc4_hdmi_disable_scrambling() will thus run at boot, make
         * sure it's disabled, and avoid any inconsistency.
         */
-       vc4_hdmi->scdc_enabled = true;
+       if (variant->max_pixel_clock > HDMI_14_MAX_TMDS_CLK)
+               vc4_hdmi->scdc_enabled = true;
 
        ret = variant->init_resources(vc4_hdmi);
        if (ret)
@@ -2651,6 +2667,7 @@ static void vc4_hdmi_unbind(struct device *dev, struct device *master,
        kfree(vc4_hdmi->hdmi_regset.regs);
        kfree(vc4_hdmi->hd_regset.regs);
 
+       vc4_hdmi_audio_exit(vc4_hdmi);
        vc4_hdmi_cec_exit(vc4_hdmi);
        vc4_hdmi_hotplug_exit(vc4_hdmi);
        vc4_hdmi_connector_destroy(&vc4_hdmi->connector);
@@ -2723,6 +2740,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
        .phy_rng_disable        = vc5_hdmi_phy_rng_disable,
        .channel_map            = vc5_hdmi_channel_map,
        .supports_hdr           = true,
+       .hp_detect              = vc5_hdmi_hp_detect,
 };
 
 static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
@@ -2751,6 +2769,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
        .phy_rng_disable        = vc5_hdmi_phy_rng_disable,
        .channel_map            = vc5_hdmi_channel_map,
        .supports_hdr           = true,
+       .hp_detect              = vc5_hdmi_hp_detect,
 };
 
 static const struct of_device_id vc4_hdmi_dt_match[] = {
index 36c0b08..6ffdd4e 100644 (file)
@@ -102,6 +102,9 @@ struct vc4_hdmi_variant {
 
        /* Enables HDR metadata */
        bool supports_hdr;
+
+       /* Callback for hardware specific hotplug detect */
+       bool (*hp_detect)(struct vc4_hdmi *vc4_hdmi);
 };
 
 /* HDMI audio information */
@@ -113,6 +116,7 @@ struct vc4_hdmi_audio {
        struct snd_soc_dai_link_component platform;
        struct snd_dmaengine_dai_dma_data dma_data;
        struct hdmi_audio_infoframe infoframe;
+       struct platform_device *codec_pdev;
        bool streaming;
 };
 
index d6b6663..ea3ecdd 100644 (file)
@@ -1140,15 +1140,14 @@ extern int vmw_execbuf_fence_commands(struct drm_file *file_priv,
                                      struct vmw_private *dev_priv,
                                      struct vmw_fence_obj **p_fence,
                                      uint32_t *p_handle);
-extern void vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
+extern int vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
                                        struct vmw_fpriv *vmw_fp,
                                        int ret,
                                        struct drm_vmw_fence_rep __user
                                        *user_fence_rep,
                                        struct vmw_fence_obj *fence,
                                        uint32_t fence_handle,
-                                       int32_t out_fence_fd,
-                                       struct sync_file *sync_file);
+                                       int32_t out_fence_fd);
 bool vmw_cmd_describe(const void *buf, u32 *size, char const **cmd);
 
 /**
index 44ca23b..dd2ff44 100644 (file)
@@ -3879,17 +3879,17 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv,
  * Also if copying fails, user-space will be unable to signal the fence object
  * so we wait for it immediately, and then unreference the user-space reference.
  */
-void
+int
 vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
                            struct vmw_fpriv *vmw_fp, int ret,
                            struct drm_vmw_fence_rep __user *user_fence_rep,
                            struct vmw_fence_obj *fence, uint32_t fence_handle,
-                           int32_t out_fence_fd, struct sync_file *sync_file)
+                           int32_t out_fence_fd)
 {
        struct drm_vmw_fence_rep fence_rep;
 
        if (user_fence_rep == NULL)
-               return;
+               return 0;
 
        memset(&fence_rep, 0, sizeof(fence_rep));
 
@@ -3917,19 +3917,13 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
         * handle.
         */
        if (unlikely(ret != 0) && (fence_rep.error == 0)) {
-               if (sync_file)
-                       fput(sync_file->file);
-
-               if (fence_rep.fd != -1) {
-                       put_unused_fd(fence_rep.fd);
-                       fence_rep.fd = -1;
-               }
-
                ttm_ref_object_base_unref(vmw_fp->tfile, fence_handle);
                VMW_DEBUG_USER("Fence copy error. Syncing.\n");
                (void) vmw_fence_obj_wait(fence, false, false,
                                          VMW_FENCE_WAIT_TIMEOUT);
        }
+
+       return ret ? -EFAULT : 0;
 }
 
 /**
@@ -4266,16 +4260,23 @@ int vmw_execbuf_process(struct drm_file *file_priv,
 
                        (void) vmw_fence_obj_wait(fence, false, false,
                                                  VMW_FENCE_WAIT_TIMEOUT);
+               }
+       }
+
+       ret = vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
+                                   user_fence_rep, fence, handle, out_fence_fd);
+
+       if (sync_file) {
+               if (ret) {
+                       /* usercopy of fence failed, put the file object */
+                       fput(sync_file->file);
+                       put_unused_fd(out_fence_fd);
                } else {
                        /* Link the fence with the FD created earlier */
                        fd_install(out_fence_fd, sync_file->file);
                }
        }
 
-       vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
-                                   user_fence_rep, fence, handle, out_fence_fd,
-                                   sync_file);
-
        /* Don't unreference when handing fence out */
        if (unlikely(out_fence != NULL)) {
                *out_fence = fence;
@@ -4293,7 +4294,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
         */
        vmw_validation_unref_lists(&val_ctx);
 
-       return 0;
+       return ret;
 
 out_unlock_binding:
        mutex_unlock(&dev_priv->binding_mutex);
index c60d395..5001b87 100644 (file)
@@ -1128,7 +1128,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
        }
 
        vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence,
-                                   handle, -1, NULL);
+                                   handle, -1);
        vmw_fence_obj_unreference(&fence);
        return 0;
 out_no_create:
index 4e693e8..bbd2f4e 100644 (file)
@@ -2501,7 +2501,7 @@ void vmw_kms_helper_validation_finish(struct vmw_private *dev_priv,
        if (file_priv)
                vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv),
                                            ret, user_fence_rep, fence,
-                                           handle, -1, NULL);
+                                           handle, -1);
        if (out_fence)
                *out_fence = fence;
        else
index e08e331..f87a870 100644 (file)
@@ -137,8 +137,15 @@ void host1x_syncpt_restore(struct host1x *host)
        struct host1x_syncpt *sp_base = host->syncpt;
        unsigned int i;
 
-       for (i = 0; i < host1x_syncpt_nb_pts(host); i++)
+       for (i = 0; i < host1x_syncpt_nb_pts(host); i++) {
+               /*
+                * Unassign syncpt from channels for purposes of Tegra186
+                * syncpoint protection. This prevents any channel from
+                * accessing it until it is reassigned.
+                */
+               host1x_hw_syncpt_assign_to_channel(host, sp_base + i, NULL);
                host1x_hw_syncpt_restore(host, sp_base + i);
+       }
 
        for (i = 0; i < host1x_syncpt_nb_bases(host); i++)
                host1x_hw_syncpt_restore_wait_base(host, sp_base + i);
@@ -227,27 +234,12 @@ int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
        void *ref;
        struct host1x_waitlist *waiter;
        int err = 0, check_count = 0;
-       u32 val;
 
        if (value)
-               *value = 0;
-
-       /* first check cache */
-       if (host1x_syncpt_is_expired(sp, thresh)) {
-               if (value)
-                       *value = host1x_syncpt_load(sp);
+               *value = host1x_syncpt_load(sp);
 
+       if (host1x_syncpt_is_expired(sp, thresh))
                return 0;
-       }
-
-       /* try to read from register */
-       val = host1x_hw_syncpt_load(sp->host, sp);
-       if (host1x_syncpt_is_expired(sp, thresh)) {
-               if (value)
-                       *value = val;
-
-               goto done;
-       }
 
        if (!timeout) {
                err = -EAGAIN;
@@ -352,13 +344,6 @@ int host1x_syncpt_init(struct host1x *host)
        for (i = 0; i < host->info->nb_pts; i++) {
                syncpt[i].id = i;
                syncpt[i].host = host;
-
-               /*
-                * Unassign syncpt from channels for purposes of Tegra186
-                * syncpoint protection. This prevents any channel from
-                * accessing it until it is reassigned.
-                */
-               host1x_hw_syncpt_assign_to_channel(host, &syncpt[i], NULL);
        }
 
        for (i = 0; i < host->info->nb_bases; i++)
index ce7740e..56d2b44 100644 (file)
@@ -861,16 +861,26 @@ static int gb_svc_hello(struct gb_operation *op)
        ret = gb_svc_watchdog_create(svc);
        if (ret) {
                dev_err(&svc->dev, "failed to create watchdog: %d\n", ret);
-               goto err_unregister_device;
+               goto err_deregister_svc;
        }
 
+       /*
+        * FIXME: This is a temporary hack to reconfigure the link at HELLO
+        * (which abuses the deferred request processing mechanism).
+        */
+       ret = gb_svc_queue_deferred_request(op);
+       if (ret)
+               goto err_destroy_watchdog;
+
        gb_svc_debugfs_init(svc);
 
-       return gb_svc_queue_deferred_request(op);
+       return 0;
 
-err_unregister_device:
+err_destroy_watchdog:
        gb_svc_watchdog_destroy(svc);
+err_deregister_svc:
        device_del(&svc->dev);
+
        return ret;
 }
 
index 2503be0..19fa734 100644 (file)
@@ -37,11 +37,11 @@ static int amd_sfh_wait_response_v2(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_
 {
        union cmd_response cmd_resp;
 
-       /* Get response with status within a max of 800 ms timeout */
+       /* Get response with status within a max of 1600 ms timeout */
        if (!readl_poll_timeout(mp2->mmio + AMD_P2C_MSG(0), cmd_resp.resp,
                                (cmd_resp.response_v2.response == sensor_sts &&
                                cmd_resp.response_v2.status == 0 && (sid == 0xff ||
-                               cmd_resp.response_v2.sensor_id == sid)), 500, 800000))
+                               cmd_resp.response_v2.sensor_id == sid)), 500, 1600000))
                return cmd_resp.response_v2.response;
 
        return SENSOR_DISABLED;
@@ -53,6 +53,7 @@ static void amd_start_sensor_v2(struct amd_mp2_dev *privdata, struct amd_mp2_sen
 
        cmd_base.ul = 0;
        cmd_base.cmd_v2.cmd_id = ENABLE_SENSOR;
+       cmd_base.cmd_v2.intr_disable = 1;
        cmd_base.cmd_v2.period = info.period;
        cmd_base.cmd_v2.sensor_id = info.sensor_idx;
        cmd_base.cmd_v2.length = 16;
@@ -70,6 +71,7 @@ static void amd_stop_sensor_v2(struct amd_mp2_dev *privdata, u16 sensor_idx)
 
        cmd_base.ul = 0;
        cmd_base.cmd_v2.cmd_id = DISABLE_SENSOR;
+       cmd_base.cmd_v2.intr_disable = 1;
        cmd_base.cmd_v2.period = 0;
        cmd_base.cmd_v2.sensor_id = sensor_idx;
        cmd_base.cmd_v2.length  = 16;
@@ -83,12 +85,51 @@ static void amd_stop_all_sensor_v2(struct amd_mp2_dev *privdata)
        union sfh_cmd_base cmd_base;
 
        cmd_base.cmd_v2.cmd_id = STOP_ALL_SENSORS;
+       cmd_base.cmd_v2.intr_disable = 1;
        cmd_base.cmd_v2.period = 0;
        cmd_base.cmd_v2.sensor_id = 0;
 
        writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
 }
 
+static void amd_sfh_clear_intr_v2(struct amd_mp2_dev *privdata)
+{
+       if (readl(privdata->mmio + AMD_P2C_MSG(4))) {
+               writel(0, privdata->mmio + AMD_P2C_MSG(4));
+               writel(0xf, privdata->mmio + AMD_P2C_MSG(5));
+       }
+}
+
+static void amd_sfh_clear_intr(struct amd_mp2_dev *privdata)
+{
+       if (privdata->mp2_ops->clear_intr)
+               privdata->mp2_ops->clear_intr(privdata);
+}
+
+static irqreturn_t amd_sfh_irq_handler(int irq, void *data)
+{
+       amd_sfh_clear_intr(data);
+
+       return IRQ_HANDLED;
+}
+
+static int amd_sfh_irq_init_v2(struct amd_mp2_dev *privdata)
+{
+       int rc;
+
+       pci_intx(privdata->pdev, true);
+
+       rc = devm_request_irq(&privdata->pdev->dev, privdata->pdev->irq,
+                             amd_sfh_irq_handler, 0, DRIVER_NAME, privdata);
+       if (rc) {
+               dev_err(&privdata->pdev->dev, "failed to request irq %d err=%d\n",
+                       privdata->pdev->irq, rc);
+               return rc;
+       }
+
+       return 0;
+}
+
 void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
 {
        union sfh_cmd_param cmd_param;
@@ -193,6 +234,8 @@ static void amd_mp2_pci_remove(void *privdata)
        struct amd_mp2_dev *mp2 = privdata;
        amd_sfh_hid_client_deinit(privdata);
        mp2->mp2_ops->stop_all(mp2);
+       pci_intx(mp2->pdev, false);
+       amd_sfh_clear_intr(mp2);
 }
 
 static const struct amd_mp2_ops amd_sfh_ops_v2 = {
@@ -200,6 +243,8 @@ static const struct amd_mp2_ops amd_sfh_ops_v2 = {
        .stop = amd_stop_sensor_v2,
        .stop_all = amd_stop_all_sensor_v2,
        .response = amd_sfh_wait_response_v2,
+       .clear_intr = amd_sfh_clear_intr_v2,
+       .init_intr = amd_sfh_irq_init_v2,
 };
 
 static const struct amd_mp2_ops amd_sfh_ops = {
@@ -225,6 +270,14 @@ static void mp2_select_ops(struct amd_mp2_dev *privdata)
        }
 }
 
+static int amd_sfh_irq_init(struct amd_mp2_dev *privdata)
+{
+       if (privdata->mp2_ops->init_intr)
+               return privdata->mp2_ops->init_intr(privdata);
+
+       return 0;
+}
+
 static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct amd_mp2_dev *privdata;
@@ -261,9 +314,20 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
 
        mp2_select_ops(privdata);
 
+       rc = amd_sfh_irq_init(privdata);
+       if (rc) {
+               dev_err(&pdev->dev, "amd_sfh_irq_init failed\n");
+               return rc;
+       }
+
        rc = amd_sfh_hid_client_init(privdata);
-       if (rc)
+       if (rc) {
+               amd_sfh_clear_intr(privdata);
+               dev_err(&pdev->dev, "amd_sfh_hid_client_init failed\n");
                return rc;
+       }
+
+       amd_sfh_clear_intr(privdata);
 
        return devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata);
 }
@@ -290,6 +354,9 @@ static int __maybe_unused amd_mp2_pci_resume(struct device *dev)
                }
        }
 
+       schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
+       amd_sfh_clear_intr(mp2);
+
        return 0;
 }
 
@@ -312,6 +379,9 @@ static int __maybe_unused amd_mp2_pci_suspend(struct device *dev)
                }
        }
 
+       cancel_delayed_work_sync(&cl_data->work_buffer);
+       amd_sfh_clear_intr(mp2);
+
        return 0;
 }
 
index ae30e05..97b9986 100644 (file)
@@ -49,7 +49,7 @@ union sfh_cmd_base {
        } s;
        struct {
                u32 cmd_id : 4;
-               u32 intr_enable : 1;
+               u32 intr_disable : 1;
                u32 rsvd1 : 3;
                u32 length : 7;
                u32 mem_type : 1;
@@ -141,5 +141,7 @@ struct amd_mp2_ops {
         void (*stop)(struct amd_mp2_dev *privdata, u16 sensor_idx);
         void (*stop_all)(struct amd_mp2_dev *privdata);
         int (*response)(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts);
+        void (*clear_intr)(struct amd_mp2_dev *privdata);
+        int (*init_intr)(struct amd_mp2_dev *privdata);
 };
 #endif
index be41f83..76095bd 100644 (file)
@@ -27,6 +27,7 @@
 #define HID_USAGE_SENSOR_STATE_READY_ENUM                             0x02
 #define HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM                      0x05
 #define HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM                      0x04
+#define ILLUMINANCE_MASK                                       GENMASK(14, 0)
 
 int get_report_descriptor(int sensor_idx, u8 *rep_desc)
 {
@@ -246,7 +247,8 @@ u8 get_input_report(u8 current_index, int sensor_idx, int report_id, struct amd_
                get_common_inputs(&als_input.common_property, report_id);
                /* For ALS ,V2 Platforms uses C2P_MSG5 register instead of DRAM access method */
                if (supported_input == V2_STATUS)
-                       als_input.illuminance_value = (int)readl(privdata->mmio + AMD_C2P_MSG(5));
+                       als_input.illuminance_value =
+                               readl(privdata->mmio + AMD_C2P_MSG(5)) & ILLUMINANCE_MASK;
                else
                        als_input.illuminance_value =
                                (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER;
index 24802a4..7dc89dc 100644 (file)
@@ -691,49 +691,49 @@ static const struct hid_device_id apple_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI),
                .driver_data = APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO),
-               .driver_data = APPLE_HAS_FN },
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI),
                .driver_data = APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO),
-               .driver_data = APPLE_HAS_FN },
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI),
                .driver_data = APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO),
-               .driver_data = APPLE_HAS_FN },
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI),
                .driver_data = APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO),
-               .driver_data = APPLE_HAS_FN },
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI),
                .driver_data = APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO),
-               .driver_data = APPLE_HAS_FN },
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI),
                .driver_data = APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO),
-               .driver_data = APPLE_HAS_FN },
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI),
                .driver_data = APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO),
-               .driver_data = APPLE_HAS_FN },
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI),
                .driver_data = APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO),
-               .driver_data = APPLE_HAS_FN },
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
index 8e960d7..9b42b0c 100644 (file)
@@ -262,6 +262,7 @@ static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        return 0;
 err_free:
+       usb_put_dev(udev);
        kfree(priv);
        return ret;
 }
index 8597503..78bd3dd 100644 (file)
 #define USB_VENDOR_ID_UGTIZER                  0x2179
 #define USB_DEVICE_ID_UGTIZER_TABLET_GP0610    0x0053
 #define USB_DEVICE_ID_UGTIZER_TABLET_GT5040    0x0077
+#define USB_DEVICE_ID_UGTIZER_TABLET_WP5540    0x0004
 
 #define USB_VENDOR_ID_VIEWSONIC                        0x0543
 #define USB_DEVICE_ID_VIEWSONIC_PD1011         0xe621
index 9af1dc8..c066ba9 100644 (file)
@@ -187,6 +187,7 @@ static const struct hid_device_id hid_quirks[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD), HID_QUIRK_NOGET },
        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60), HID_QUIRK_MULTI_INPUT },
+       { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_WP5540), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET), HID_QUIRK_MULTI_INPUT },
index b4dad66..ec6c73f 100644 (file)
@@ -27,7 +27,6 @@ struct i2c_hid_of_goodix {
 
        struct regulator *vdd;
        struct notifier_block nb;
-       struct mutex regulator_mutex;
        struct gpio_desc *reset_gpio;
        const struct goodix_i2c_hid_timing_data *timings;
 };
@@ -67,8 +66,6 @@ static int ihid_goodix_vdd_notify(struct notifier_block *nb,
                container_of(nb, struct i2c_hid_of_goodix, nb);
        int ret = NOTIFY_OK;
 
-       mutex_lock(&ihid_goodix->regulator_mutex);
-
        switch (event) {
        case REGULATOR_EVENT_PRE_DISABLE:
                gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1);
@@ -87,8 +84,6 @@ static int ihid_goodix_vdd_notify(struct notifier_block *nb,
                break;
        }
 
-       mutex_unlock(&ihid_goodix->regulator_mutex);
-
        return ret;
 }
 
@@ -102,8 +97,6 @@ static int i2c_hid_of_goodix_probe(struct i2c_client *client,
        if (!ihid_goodix)
                return -ENOMEM;
 
-       mutex_init(&ihid_goodix->regulator_mutex);
-
        ihid_goodix->ops.power_up = goodix_i2c_hid_power_up;
        ihid_goodix->ops.power_down = goodix_i2c_hid_power_down;
 
@@ -130,25 +123,28 @@ static int i2c_hid_of_goodix_probe(struct i2c_client *client,
         *   long. Holding the controller in reset apparently draws extra
         *   power.
         */
-       mutex_lock(&ihid_goodix->regulator_mutex);
        ihid_goodix->nb.notifier_call = ihid_goodix_vdd_notify;
        ret = devm_regulator_register_notifier(ihid_goodix->vdd, &ihid_goodix->nb);
-       if (ret) {
-               mutex_unlock(&ihid_goodix->regulator_mutex);
+       if (ret)
                return dev_err_probe(&client->dev, ret,
                        "regulator notifier request failed\n");
-       }
 
        /*
         * If someone else is holding the regulator on (or the regulator is
         * an always-on one) we might never be told to deassert reset. Do it
-        * now. Here we'll assume that someone else might have _just
-        * barely_ turned the regulator on so we'll do the full
-        * "post_power_delay" just in case.
+        * now... and temporarily bump the regulator reference count just to
+        * make sure it is impossible for this to race with our own notifier!
+        * We also assume that someone else might have _just barely_ turned
+        * the regulator on so we'll do the full "post_power_delay" just in
+        * case.
         */
-       if (ihid_goodix->reset_gpio && regulator_is_enabled(ihid_goodix->vdd))
+       if (ihid_goodix->reset_gpio && regulator_is_enabled(ihid_goodix->vdd)) {
+               ret = regulator_enable(ihid_goodix->vdd);
+               if (ret)
+                       return ret;
                goodix_i2c_hid_deassert_reset(ihid_goodix, true);
-       mutex_unlock(&ihid_goodix->regulator_mutex);
+               regulator_disable(ihid_goodix->vdd);
+       }
 
        return i2c_hid_core_probe(client, &ihid_goodix->ops, 0x0001, 0);
 }
index ca873a3..f2d05bf 100644 (file)
@@ -1660,6 +1660,13 @@ static int balloon_connect_vsp(struct hv_device *dev)
        unsigned long t;
        int ret;
 
+       /*
+        * max_pkt_size should be large enough for one vmbus packet header plus
+        * our receive buffer size. Hyper-V sends messages up to
+        * HV_HYP_PAGE_SIZE bytes long on balloon channel.
+        */
+       dev->channel->max_pkt_size = HV_HYP_PAGE_SIZE * 2;
+
        ret = vmbus_open(dev->channel, dm_ring_size, dm_ring_size, NULL, 0,
                         balloon_onchannelcallback, dev);
        if (ret)
index eb2833d..8328851 100644 (file)
@@ -13,7 +13,7 @@
 #include "hv_utils_transport.h"
 
 static DEFINE_SPINLOCK(hvt_list_lock);
-static struct list_head hvt_list = LIST_HEAD_INIT(hvt_list);
+static LIST_HEAD(hvt_list);
 
 static void hvt_reset(struct hvutil_transport *hvt)
 {
index 17bf55f..12a2b37 100644 (file)
@@ -2028,8 +2028,10 @@ int vmbus_add_channel_kobj(struct hv_device *dev, struct vmbus_channel *channel)
        kobj->kset = dev->channels_kset;
        ret = kobject_init_and_add(kobj, &vmbus_chan_ktype, NULL,
                                   "%u", relid);
-       if (ret)
+       if (ret) {
+               kobject_put(kobj);
                return ret;
+       }
 
        ret = sysfs_create_group(kobj, &vmbus_chan_group);
 
@@ -2038,6 +2040,7 @@ int vmbus_add_channel_kobj(struct hv_device *dev, struct vmbus_channel *channel)
                 * The calling functions' error handling paths will cleanup the
                 * empty channel directory.
                 */
+               kobject_put(kobj);
                dev_err(device, "Unable to set up channel sysfs files\n");
                return ret;
        }
@@ -2079,7 +2082,6 @@ struct hv_device *vmbus_device_create(const guid_t *type,
        return child_device_obj;
 }
 
-static u64 vmbus_dma_mask = DMA_BIT_MASK(64);
 /*
  * vmbus_device_register - Register the child device
  */
@@ -2120,8 +2122,9 @@ int vmbus_device_register(struct hv_device *child_device_obj)
        }
        hv_debug_add_dev_dir(child_device_obj);
 
-       child_device_obj->device.dma_mask = &vmbus_dma_mask;
        child_device_obj->device.dma_parms = &child_device_obj->dma_parms;
+       child_device_obj->device.dma_mask = &child_device_obj->dma_mask;
+       dma_set_mask(&child_device_obj->device, DMA_BIT_MASK(64));
        return 0;
 
 err_kset_unregister:
index 8df25f1..af6c3bd 100644 (file)
@@ -1538,6 +1538,8 @@ config SENSORS_PCF8591
          These devices are hard to detect and rarely found on mainstream
          hardware. If unsure, say N.
 
+source "drivers/hwmon/peci/Kconfig"
+
 source "drivers/hwmon/pmbus/Kconfig"
 
 config SENSORS_PWM_FAN
index 185f946..6139e5a 100644 (file)
@@ -208,6 +208,7 @@ obj-$(CONFIG_SENSORS_WM8350)        += wm8350-hwmon.o
 obj-$(CONFIG_SENSORS_XGENE)    += xgene-hwmon.o
 
 obj-$(CONFIG_SENSORS_OCC)      += occ/
+obj-$(CONFIG_SENSORS_PECI)     += peci/
 obj-$(CONFIG_PMBUS)            += pmbus/
 
 ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG
index d519aca..fb6d14d 100644 (file)
@@ -662,6 +662,9 @@ static int adt7470_fan_write(struct device *dev, u32 attr, int channel, long val
        struct adt7470_data *data = dev_get_drvdata(dev);
        int err;
 
+       if (val <= 0)
+               return -EINVAL;
+
        val = FAN_RPM_TO_PERIOD(val);
        val = clamp_val(val, 1, 65534);
 
index 3501a3e..3ae9619 100644 (file)
@@ -214,12 +214,14 @@ static int hwmon_thermal_add_sensor(struct device *dev, int index)
 
        tzd = devm_thermal_zone_of_sensor_register(dev, index, tdata,
                                                   &hwmon_thermal_ops);
-       /*
-        * If CONFIG_THERMAL_OF is disabled, this returns -ENODEV,
-        * so ignore that error but forward any other error.
-        */
-       if (IS_ERR(tzd) && (PTR_ERR(tzd) != -ENODEV))
-               return PTR_ERR(tzd);
+       if (IS_ERR(tzd)) {
+               if (PTR_ERR(tzd) != -ENODEV)
+                       return PTR_ERR(tzd);
+               dev_info(dev, "temp%d_input not attached to any thermal zone\n",
+                        index + 1);
+               devm_kfree(dev, tdata);
+               return 0;
+       }
 
        err = devm_add_action(dev, hwmon_thermal_remove_sensor, &tdata->node);
        if (err)
index 74019df..1c9493c 100644 (file)
@@ -373,7 +373,7 @@ static const struct lm90_params lm90_params[] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
                  | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT,
                .alert_alarms = 0x7c,
-               .max_convrate = 8,
+               .max_convrate = 7,
        },
        [lm86] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
@@ -394,12 +394,13 @@ static const struct lm90_params lm90_params[] = {
                .max_convrate = 9,
        },
        [max6646] = {
-               .flags = LM90_HAVE_CRIT,
+               .flags = LM90_HAVE_CRIT | LM90_HAVE_BROKEN_ALERT,
                .alert_alarms = 0x7c,
                .max_convrate = 6,
                .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
        },
        [max6654] = {
+               .flags = LM90_HAVE_BROKEN_ALERT,
                .alert_alarms = 0x7c,
                .max_convrate = 7,
                .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
@@ -418,7 +419,7 @@ static const struct lm90_params lm90_params[] = {
        },
        [max6680] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_CRIT
-                 | LM90_HAVE_CRIT_ALRM_SWP,
+                 | LM90_HAVE_CRIT_ALRM_SWP | LM90_HAVE_BROKEN_ALERT,
                .alert_alarms = 0x7c,
                .max_convrate = 7,
        },
@@ -848,7 +849,7 @@ static int lm90_update_device(struct device *dev)
                 * Re-enable ALERT# output if it was originally enabled and
                 * relevant alarms are all clear
                 */
-               if (!(data->config_orig & 0x80) &&
+               if ((client->irq || !(data->config_orig & 0x80)) &&
                    !(data->alarms & data->alert_alarms)) {
                        if (data->config & 0x80) {
                                dev_dbg(&client->dev, "Re-enabling ALERT#\n");
@@ -1807,22 +1808,22 @@ static bool lm90_is_tripped(struct i2c_client *client, u16 *status)
 
        if (st & LM90_STATUS_LLOW)
                hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_min, 0);
+                                  hwmon_temp_min_alarm, 0);
        if (st & LM90_STATUS_RLOW)
                hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_min, 1);
+                                  hwmon_temp_min_alarm, 1);
        if (st2 & MAX6696_STATUS2_R2LOW)
                hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_min, 2);
+                                  hwmon_temp_min_alarm, 2);
        if (st & LM90_STATUS_LHIGH)
                hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_max, 0);
+                                  hwmon_temp_max_alarm, 0);
        if (st & LM90_STATUS_RHIGH)
                hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_max, 1);
+                                  hwmon_temp_max_alarm, 1);
        if (st2 & MAX6696_STATUS2_R2HIGH)
                hwmon_notify_event(data->hwmon_dev, hwmon_temp,
-                                  hwmon_temp_max, 2);
+                                  hwmon_temp_max_alarm, 2);
 
        return true;
 }
index fd3f91c..098d12b 100644 (file)
@@ -1175,7 +1175,7 @@ static inline u8 in_to_reg(u32 val, u8 nr)
 
 struct nct6775_data {
        int addr;       /* IO base of hw monitor block */
-       int sioreg;     /* SIO register address */
+       struct nct6775_sio_data *sio_data;
        enum kinds kind;
        const char *name;
 
@@ -3559,7 +3559,7 @@ clear_caseopen(struct device *dev, struct device_attribute *attr,
               const char *buf, size_t count)
 {
        struct nct6775_data *data = dev_get_drvdata(dev);
-       struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
+       struct nct6775_sio_data *sio_data = data->sio_data;
        int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
        unsigned long val;
        u8 reg;
@@ -3967,7 +3967,7 @@ static int nct6775_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        data->kind = sio_data->kind;
-       data->sioreg = sio_data->sioreg;
+       data->sio_data = sio_data;
 
        if (sio_data->access == access_direct) {
                data->addr = res->start;
index 414204f..9c9e9f4 100644 (file)
@@ -59,7 +59,7 @@ static const struct platform_device_id ntc_thermistor_id[] = {
        [NTC_NCP15XH103]      = { "ncp15xh103",      TYPE_NCPXXXH103 },
        [NTC_NCP18WB473]      = { "ncp18wb473",      TYPE_NCPXXWB473 },
        [NTC_NCP21WB473]      = { "ncp21wb473",      TYPE_NCPXXWB473 },
-       [NTC_SSG1404001221]   = { "ssg1404-001221",  TYPE_NCPXXWB473 },
+       [NTC_SSG1404001221]   = { "ssg1404_001221",  TYPE_NCPXXWB473 },
        [NTC_LAST]            = { },
 };
 
diff --git a/drivers/hwmon/peci/Kconfig b/drivers/hwmon/peci/Kconfig
new file mode 100644 (file)
index 0000000..9d32a57
--- /dev/null
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config SENSORS_PECI_CPUTEMP
+       tristate "PECI CPU temperature monitoring client"
+       depends on PECI
+       select SENSORS_PECI
+       select PECI_CPU
+       help
+         If you say yes here you get support for the generic Intel PECI
+         cputemp driver which provides Digital Thermal Sensor (DTS) thermal
+         readings of the CPU package and CPU cores that are accessible via
+         the processor PECI interface.
+
+         This driver can also be built as a module. If so, the module
+         will be called peci-cputemp.
+
+config SENSORS_PECI_DIMMTEMP
+       tristate "PECI DIMM temperature monitoring client"
+       depends on PECI
+       select SENSORS_PECI
+       select PECI_CPU
+       help
+         If you say yes here you get support for the generic Intel PECI hwmon
+         driver which provides Temperature Sensor on DIMM readings that are
+         accessible via the processor PECI interface.
+
+         This driver can also be built as a module. If so, the module
+         will be called peci-dimmtemp.
+
+config SENSORS_PECI
+       tristate
diff --git a/drivers/hwmon/peci/Makefile b/drivers/hwmon/peci/Makefile
new file mode 100644 (file)
index 0000000..191cfa0
--- /dev/null
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+peci-cputemp-y := cputemp.o
+peci-dimmtemp-y := dimmtemp.o
+
+obj-$(CONFIG_SENSORS_PECI_CPUTEMP)     += peci-cputemp.o
+obj-$(CONFIG_SENSORS_PECI_DIMMTEMP)    += peci-dimmtemp.o
diff --git a/drivers/hwmon/peci/common.h b/drivers/hwmon/peci/common.h
new file mode 100644 (file)
index 0000000..734506b
--- /dev/null
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2021 Intel Corporation */
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+#ifndef __PECI_HWMON_COMMON_H
+#define __PECI_HWMON_COMMON_H
+
+#define PECI_HWMON_UPDATE_INTERVAL     HZ
+
+/**
+ * struct peci_sensor_state - PECI state information
+ * @valid: flag to indicate the sensor value is valid
+ * @last_updated: time of the last update in jiffies
+ * @lock: mutex to protect sensor access
+ */
+struct peci_sensor_state {
+       bool valid;
+       unsigned long last_updated;
+       struct mutex lock; /* protect sensor access */
+};
+
+/**
+ * struct peci_sensor_data - PECI sensor information
+ * @value: sensor value in milli units
+ * @state: sensor update state
+ */
+
+struct peci_sensor_data {
+       s32 value;
+       struct peci_sensor_state state;
+};
+
+/**
+ * peci_sensor_need_update() - check whether sensor update is needed or not
+ * @sensor: pointer to sensor data struct
+ *
+ * Return: true if update is needed, false if not.
+ */
+
+static inline bool peci_sensor_need_update(struct peci_sensor_state *state)
+{
+       return !state->valid ||
+              time_after(jiffies, state->last_updated + PECI_HWMON_UPDATE_INTERVAL);
+}
+
+/**
+ * peci_sensor_mark_updated() - mark the sensor is updated
+ * @sensor: pointer to sensor data struct
+ */
+static inline void peci_sensor_mark_updated(struct peci_sensor_state *state)
+{
+       state->valid = true;
+       state->last_updated = jiffies;
+}
+
+#endif /* __PECI_HWMON_COMMON_H */
diff --git a/drivers/hwmon/peci/cputemp.c b/drivers/hwmon/peci/cputemp.c
new file mode 100644 (file)
index 0000000..1215632
--- /dev/null
@@ -0,0 +1,592 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018-2021 Intel Corporation
+
+#include <linux/auxiliary_bus.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/hwmon.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/peci.h>
+#include <linux/peci-cpu.h>
+#include <linux/units.h>
+
+#include "common.h"
+
+#define CORE_NUMS_MAX          64
+
+#define BASE_CHANNEL_NUMS      5
+#define CPUTEMP_CHANNEL_NUMS   (BASE_CHANNEL_NUMS + CORE_NUMS_MAX)
+
+#define TEMP_TARGET_FAN_TEMP_MASK      GENMASK(15, 8)
+#define TEMP_TARGET_REF_TEMP_MASK      GENMASK(23, 16)
+#define TEMP_TARGET_TJ_OFFSET_MASK     GENMASK(29, 24)
+
+#define DTS_MARGIN_MASK                GENMASK(15, 0)
+#define PCS_MODULE_TEMP_MASK   GENMASK(15, 0)
+
+struct resolved_cores_reg {
+       u8 bus;
+       u8 dev;
+       u8 func;
+       u8 offset;
+};
+
+struct cpu_info {
+       struct resolved_cores_reg *reg;
+       u8 min_peci_revision;
+       s32 (*thermal_margin_to_millidegree)(u16 val);
+};
+
+struct peci_temp_target {
+       s32 tcontrol;
+       s32 tthrottle;
+       s32 tjmax;
+       struct peci_sensor_state state;
+};
+
+enum peci_temp_target_type {
+       tcontrol_type,
+       tthrottle_type,
+       tjmax_type,
+       crit_hyst_type,
+};
+
+struct peci_cputemp {
+       struct peci_device *peci_dev;
+       struct device *dev;
+       const char *name;
+       const struct cpu_info *gen_info;
+       struct {
+               struct peci_temp_target target;
+               struct peci_sensor_data die;
+               struct peci_sensor_data dts;
+               struct peci_sensor_data core[CORE_NUMS_MAX];
+       } temp;
+       const char **coretemp_label;
+       DECLARE_BITMAP(core_mask, CORE_NUMS_MAX);
+};
+
+enum cputemp_channels {
+       channel_die,
+       channel_dts,
+       channel_tcontrol,
+       channel_tthrottle,
+       channel_tjmax,
+       channel_core,
+};
+
+static const char * const cputemp_label[BASE_CHANNEL_NUMS] = {
+       "Die",
+       "DTS",
+       "Tcontrol",
+       "Tthrottle",
+       "Tjmax",
+};
+
+static int update_temp_target(struct peci_cputemp *priv)
+{
+       s32 tthrottle_offset, tcontrol_margin;
+       u32 pcs;
+       int ret;
+
+       if (!peci_sensor_need_update(&priv->temp.target.state))
+               return 0;
+
+       ret = peci_pcs_read(priv->peci_dev, PECI_PCS_TEMP_TARGET, 0, &pcs);
+       if (ret)
+               return ret;
+
+       priv->temp.target.tjmax =
+               FIELD_GET(TEMP_TARGET_REF_TEMP_MASK, pcs) * MILLIDEGREE_PER_DEGREE;
+
+       tcontrol_margin = FIELD_GET(TEMP_TARGET_FAN_TEMP_MASK, pcs);
+       tcontrol_margin = sign_extend32(tcontrol_margin, 7) * MILLIDEGREE_PER_DEGREE;
+       priv->temp.target.tcontrol = priv->temp.target.tjmax - tcontrol_margin;
+
+       tthrottle_offset = FIELD_GET(TEMP_TARGET_TJ_OFFSET_MASK, pcs) * MILLIDEGREE_PER_DEGREE;
+       priv->temp.target.tthrottle = priv->temp.target.tjmax - tthrottle_offset;
+
+       peci_sensor_mark_updated(&priv->temp.target.state);
+
+       return 0;
+}
+
+static int get_temp_target(struct peci_cputemp *priv, enum peci_temp_target_type type, long *val)
+{
+       int ret;
+
+       mutex_lock(&priv->temp.target.state.lock);
+
+       ret = update_temp_target(priv);
+       if (ret)
+               goto unlock;
+
+       switch (type) {
+       case tcontrol_type:
+               *val = priv->temp.target.tcontrol;
+               break;
+       case tthrottle_type:
+               *val = priv->temp.target.tthrottle;
+               break;
+       case tjmax_type:
+               *val = priv->temp.target.tjmax;
+               break;
+       case crit_hyst_type:
+               *val = priv->temp.target.tjmax - priv->temp.target.tcontrol;
+               break;
+       default:
+               ret = -EOPNOTSUPP;
+               break;
+       }
+unlock:
+       mutex_unlock(&priv->temp.target.state.lock);
+
+       return ret;
+}
+
+/*
+ * Error codes:
+ *   0x8000: General sensor error
+ *   0x8001: Reserved
+ *   0x8002: Underflow on reading value
+ *   0x8003-0x81ff: Reserved
+ */
+static bool dts_valid(u16 val)
+{
+       return val < 0x8000 || val > 0x81ff;
+}
+
+/*
+ * Processors return a value of DTS reading in S10.6 fixed point format
+ * (16 bits: 10-bit signed magnitude, 6-bit fraction).
+ */
+static s32 dts_ten_dot_six_to_millidegree(u16 val)
+{
+       return sign_extend32(val, 15) * MILLIDEGREE_PER_DEGREE / 64;
+}
+
+/*
+ * For older processors, thermal margin reading is returned in S8.8 fixed
+ * point format (16 bits: 8-bit signed magnitude, 8-bit fraction).
+ */
+static s32 dts_eight_dot_eight_to_millidegree(u16 val)
+{
+       return sign_extend32(val, 15) * MILLIDEGREE_PER_DEGREE / 256;
+}
+
+static int get_die_temp(struct peci_cputemp *priv, long *val)
+{
+       int ret = 0;
+       long tjmax;
+       u16 temp;
+
+       mutex_lock(&priv->temp.die.state.lock);
+       if (!peci_sensor_need_update(&priv->temp.die.state))
+               goto skip_update;
+
+       ret = peci_temp_read(priv->peci_dev, &temp);
+       if (ret)
+               goto err_unlock;
+
+       if (!dts_valid(temp)) {
+               ret = -EIO;
+               goto err_unlock;
+       }
+
+       ret = get_temp_target(priv, tjmax_type, &tjmax);
+       if (ret)
+               goto err_unlock;
+
+       priv->temp.die.value = (s32)tjmax + dts_ten_dot_six_to_millidegree(temp);
+
+       peci_sensor_mark_updated(&priv->temp.die.state);
+
+skip_update:
+       *val = priv->temp.die.value;
+err_unlock:
+       mutex_unlock(&priv->temp.die.state.lock);
+       return ret;
+}
+
+static int get_dts(struct peci_cputemp *priv, long *val)
+{
+       int ret = 0;
+       u16 thermal_margin;
+       long tcontrol;
+       u32 pcs;
+
+       mutex_lock(&priv->temp.dts.state.lock);
+       if (!peci_sensor_need_update(&priv->temp.dts.state))
+               goto skip_update;
+
+       ret = peci_pcs_read(priv->peci_dev, PECI_PCS_THERMAL_MARGIN, 0, &pcs);
+       if (ret)
+               goto err_unlock;
+
+       thermal_margin = FIELD_GET(DTS_MARGIN_MASK, pcs);
+       if (!dts_valid(thermal_margin)) {
+               ret = -EIO;
+               goto err_unlock;
+       }
+
+       ret = get_temp_target(priv, tcontrol_type, &tcontrol);
+       if (ret)
+               goto err_unlock;
+
+       /* Note that the tcontrol should be available before calling it */
+       priv->temp.dts.value =
+               (s32)tcontrol - priv->gen_info->thermal_margin_to_millidegree(thermal_margin);
+
+       peci_sensor_mark_updated(&priv->temp.dts.state);
+
+skip_update:
+       *val = priv->temp.dts.value;
+err_unlock:
+       mutex_unlock(&priv->temp.dts.state.lock);
+       return ret;
+}
+
+static int get_core_temp(struct peci_cputemp *priv, int core_index, long *val)
+{
+       int ret = 0;
+       u16 core_dts_margin;
+       long tjmax;
+       u32 pcs;
+
+       mutex_lock(&priv->temp.core[core_index].state.lock);
+       if (!peci_sensor_need_update(&priv->temp.core[core_index].state))
+               goto skip_update;
+
+       ret = peci_pcs_read(priv->peci_dev, PECI_PCS_MODULE_TEMP, core_index, &pcs);
+       if (ret)
+               goto err_unlock;
+
+       core_dts_margin = FIELD_GET(PCS_MODULE_TEMP_MASK, pcs);
+       if (!dts_valid(core_dts_margin)) {
+               ret = -EIO;
+               goto err_unlock;
+       }
+
+       ret = get_temp_target(priv, tjmax_type, &tjmax);
+       if (ret)
+               goto err_unlock;
+
+       /* Note that the tjmax should be available before calling it */
+       priv->temp.core[core_index].value =
+               (s32)tjmax + dts_ten_dot_six_to_millidegree(core_dts_margin);
+
+       peci_sensor_mark_updated(&priv->temp.core[core_index].state);
+
+skip_update:
+       *val = priv->temp.core[core_index].value;
+err_unlock:
+       mutex_unlock(&priv->temp.core[core_index].state.lock);
+       return ret;
+}
+
+static int cputemp_read_string(struct device *dev, enum hwmon_sensor_types type,
+                              u32 attr, int channel, const char **str)
+{
+       struct peci_cputemp *priv = dev_get_drvdata(dev);
+
+       if (attr != hwmon_temp_label)
+               return -EOPNOTSUPP;
+
+       *str = channel < channel_core ?
+               cputemp_label[channel] : priv->coretemp_label[channel - channel_core];
+
+       return 0;
+}
+
+static int cputemp_read(struct device *dev, enum hwmon_sensor_types type,
+                       u32 attr, int channel, long *val)
+{
+       struct peci_cputemp *priv = dev_get_drvdata(dev);
+
+       switch (attr) {
+       case hwmon_temp_input:
+               switch (channel) {
+               case channel_die:
+                       return get_die_temp(priv, val);
+               case channel_dts:
+                       return get_dts(priv, val);
+               case channel_tcontrol:
+                       return get_temp_target(priv, tcontrol_type, val);
+               case channel_tthrottle:
+                       return get_temp_target(priv, tthrottle_type, val);
+               case channel_tjmax:
+                       return get_temp_target(priv, tjmax_type, val);
+               default:
+                       return get_core_temp(priv, channel - channel_core, val);
+               }
+               break;
+       case hwmon_temp_max:
+               return get_temp_target(priv, tcontrol_type, val);
+       case hwmon_temp_crit:
+               return get_temp_target(priv, tjmax_type, val);
+       case hwmon_temp_crit_hyst:
+               return get_temp_target(priv, crit_hyst_type, val);
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+static umode_t cputemp_is_visible(const void *data, enum hwmon_sensor_types type,
+                                 u32 attr, int channel)
+{
+       const struct peci_cputemp *priv = data;
+
+       if (channel > CPUTEMP_CHANNEL_NUMS)
+               return 0;
+
+       if (channel < channel_core)
+               return 0444;
+
+       if (test_bit(channel - channel_core, priv->core_mask))
+               return 0444;
+
+       return 0;
+}
+
+static int init_core_mask(struct peci_cputemp *priv)
+{
+       struct peci_device *peci_dev = priv->peci_dev;
+       struct resolved_cores_reg *reg = priv->gen_info->reg;
+       u64 core_mask;
+       u32 data;
+       int ret;
+
+       /* Get the RESOLVED_CORES register value */
+       switch (peci_dev->info.model) {
+       case INTEL_FAM6_ICELAKE_X:
+       case INTEL_FAM6_ICELAKE_D:
+               ret = peci_ep_pci_local_read(peci_dev, 0, reg->bus, reg->dev,
+                                            reg->func, reg->offset + 4, &data);
+               if (ret)
+                       return ret;
+
+               core_mask = (u64)data << 32;
+
+               ret = peci_ep_pci_local_read(peci_dev, 0, reg->bus, reg->dev,
+                                            reg->func, reg->offset, &data);
+               if (ret)
+                       return ret;
+
+               core_mask |= data;
+
+               break;
+       default:
+               ret = peci_pci_local_read(peci_dev, reg->bus, reg->dev,
+                                         reg->func, reg->offset, &data);
+               if (ret)
+                       return ret;
+
+               core_mask = data;
+
+               break;
+       }
+
+       if (!core_mask)
+               return -EIO;
+
+       bitmap_from_u64(priv->core_mask, core_mask);
+
+       return 0;
+}
+
+static int create_temp_label(struct peci_cputemp *priv)
+{
+       unsigned long core_max = find_last_bit(priv->core_mask, CORE_NUMS_MAX);
+       int i;
+
+       priv->coretemp_label = devm_kzalloc(priv->dev, core_max * sizeof(char *), GFP_KERNEL);
+       if (!priv->coretemp_label)
+               return -ENOMEM;
+
+       for_each_set_bit(i, priv->core_mask, CORE_NUMS_MAX) {
+               priv->coretemp_label[i] = devm_kasprintf(priv->dev, GFP_KERNEL, "Core %d", i);
+               if (!priv->coretemp_label[i])
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void check_resolved_cores(struct peci_cputemp *priv)
+{
+       /*
+        * Failure to resolve cores is non-critical, we're still able to
+        * provide other sensor data.
+        */
+
+       if (init_core_mask(priv))
+               return;
+
+       if (create_temp_label(priv))
+               bitmap_zero(priv->core_mask, CORE_NUMS_MAX);
+}
+
+static void sensor_init(struct peci_cputemp *priv)
+{
+       int i;
+
+       mutex_init(&priv->temp.target.state.lock);
+       mutex_init(&priv->temp.die.state.lock);
+       mutex_init(&priv->temp.dts.state.lock);
+
+       for_each_set_bit(i, priv->core_mask, CORE_NUMS_MAX)
+               mutex_init(&priv->temp.core[i].state.lock);
+}
+
+static const struct hwmon_ops peci_cputemp_ops = {
+       .is_visible = cputemp_is_visible,
+       .read_string = cputemp_read_string,
+       .read = cputemp_read,
+};
+
+static const u32 peci_cputemp_temp_channel_config[] = {
+       /* Die temperature */
+       HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_CRIT_HYST,
+       /* DTS margin */
+       HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_CRIT_HYST,
+       /* Tcontrol temperature */
+       HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_CRIT,
+       /* Tthrottle temperature */
+       HWMON_T_LABEL | HWMON_T_INPUT,
+       /* Tjmax temperature */
+       HWMON_T_LABEL | HWMON_T_INPUT,
+       /* Core temperature - for all core channels */
+       [channel_core ... CPUTEMP_CHANNEL_NUMS - 1] = HWMON_T_LABEL | HWMON_T_INPUT,
+       0
+};
+
+static const struct hwmon_channel_info peci_cputemp_temp_channel = {
+       .type = hwmon_temp,
+       .config = peci_cputemp_temp_channel_config,
+};
+
+static const struct hwmon_channel_info *peci_cputemp_info[] = {
+       &peci_cputemp_temp_channel,
+       NULL
+};
+
+static const struct hwmon_chip_info peci_cputemp_chip_info = {
+       .ops = &peci_cputemp_ops,
+       .info = peci_cputemp_info,
+};
+
+static int peci_cputemp_probe(struct auxiliary_device *adev,
+                             const struct auxiliary_device_id *id)
+{
+       struct device *dev = &adev->dev;
+       struct peci_device *peci_dev = to_peci_device(dev->parent);
+       struct peci_cputemp *priv;
+       struct device *hwmon_dev;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->name = devm_kasprintf(dev, GFP_KERNEL, "peci_cputemp.cpu%d",
+                                   peci_dev->info.socket_id);
+       if (!priv->name)
+               return -ENOMEM;
+
+       priv->dev = dev;
+       priv->peci_dev = peci_dev;
+       priv->gen_info = (const struct cpu_info *)id->driver_data;
+
+       /*
+        * This is just a sanity check. Since we're using commands that are
+        * guaranteed to be supported on a given platform, we should never see
+        * revision lower than expected.
+        */
+       if (peci_dev->info.peci_revision < priv->gen_info->min_peci_revision)
+               dev_warn(priv->dev,
+                        "Unexpected PECI revision %#x, some features may be unavailable\n",
+                        peci_dev->info.peci_revision);
+
+       check_resolved_cores(priv);
+
+       sensor_init(priv);
+
+       hwmon_dev = devm_hwmon_device_register_with_info(priv->dev, priv->name,
+                                                        priv, &peci_cputemp_chip_info, NULL);
+
+       return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+/*
+ * RESOLVED_CORES PCI configuration register may have different location on
+ * different platforms.
+ */
+static struct resolved_cores_reg resolved_cores_reg_hsx = {
+       .bus = 1,
+       .dev = 30,
+       .func = 3,
+       .offset = 0xb4,
+};
+
+static struct resolved_cores_reg resolved_cores_reg_icx = {
+       .bus = 14,
+       .dev = 30,
+       .func = 3,
+       .offset = 0xd0,
+};
+
+static const struct cpu_info cpu_hsx = {
+       .reg            = &resolved_cores_reg_hsx,
+       .min_peci_revision = 0x33,
+       .thermal_margin_to_millidegree = &dts_eight_dot_eight_to_millidegree,
+};
+
+static const struct cpu_info cpu_icx = {
+       .reg            = &resolved_cores_reg_icx,
+       .min_peci_revision = 0x40,
+       .thermal_margin_to_millidegree = &dts_ten_dot_six_to_millidegree,
+};
+
+static const struct auxiliary_device_id peci_cputemp_ids[] = {
+       {
+               .name = "peci_cpu.cputemp.hsx",
+               .driver_data = (kernel_ulong_t)&cpu_hsx,
+       },
+       {
+               .name = "peci_cpu.cputemp.bdx",
+               .driver_data = (kernel_ulong_t)&cpu_hsx,
+       },
+       {
+               .name = "peci_cpu.cputemp.bdxd",
+               .driver_data = (kernel_ulong_t)&cpu_hsx,
+       },
+       {
+               .name = "peci_cpu.cputemp.skx",
+               .driver_data = (kernel_ulong_t)&cpu_hsx,
+       },
+       {
+               .name = "peci_cpu.cputemp.icx",
+               .driver_data = (kernel_ulong_t)&cpu_icx,
+       },
+       {
+               .name = "peci_cpu.cputemp.icxd",
+               .driver_data = (kernel_ulong_t)&cpu_icx,
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(auxiliary, peci_cputemp_ids);
+
+static struct auxiliary_driver peci_cputemp_driver = {
+       .probe          = peci_cputemp_probe,
+       .id_table       = peci_cputemp_ids,
+};
+
+module_auxiliary_driver(peci_cputemp_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_AUTHOR("Iwona Winiarska <iwona.winiarska@intel.com>");
+MODULE_DESCRIPTION("PECI cputemp driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PECI_CPU);
diff --git a/drivers/hwmon/peci/dimmtemp.c b/drivers/hwmon/peci/dimmtemp.c
new file mode 100644 (file)
index 0000000..c822235
--- /dev/null
@@ -0,0 +1,630 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018-2021 Intel Corporation
+
+#include <linux/auxiliary_bus.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/hwmon.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/peci.h>
+#include <linux/peci-cpu.h>
+#include <linux/units.h>
+#include <linux/workqueue.h>
+
+#include "common.h"
+
+#define DIMM_MASK_CHECK_DELAY_JIFFIES  msecs_to_jiffies(5000)
+
+/* Max number of channel ranks and DIMM index per channel */
+#define CHAN_RANK_MAX_ON_HSX   8
+#define DIMM_IDX_MAX_ON_HSX    3
+#define CHAN_RANK_MAX_ON_BDX   4
+#define DIMM_IDX_MAX_ON_BDX    3
+#define CHAN_RANK_MAX_ON_BDXD  2
+#define DIMM_IDX_MAX_ON_BDXD   2
+#define CHAN_RANK_MAX_ON_SKX   6
+#define DIMM_IDX_MAX_ON_SKX    2
+#define CHAN_RANK_MAX_ON_ICX   8
+#define DIMM_IDX_MAX_ON_ICX    2
+#define CHAN_RANK_MAX_ON_ICXD  4
+#define DIMM_IDX_MAX_ON_ICXD   2
+
+#define CHAN_RANK_MAX          CHAN_RANK_MAX_ON_HSX
+#define DIMM_IDX_MAX           DIMM_IDX_MAX_ON_HSX
+#define DIMM_NUMS_MAX          (CHAN_RANK_MAX * DIMM_IDX_MAX)
+
+#define CPU_SEG_MASK           GENMASK(23, 16)
+#define GET_CPU_SEG(x)         (((x) & CPU_SEG_MASK) >> 16)
+#define CPU_BUS_MASK           GENMASK(7, 0)
+#define GET_CPU_BUS(x)         ((x) & CPU_BUS_MASK)
+
+#define DIMM_TEMP_MAX          GENMASK(15, 8)
+#define DIMM_TEMP_CRIT         GENMASK(23, 16)
+#define GET_TEMP_MAX(x)                (((x) & DIMM_TEMP_MAX) >> 8)
+#define GET_TEMP_CRIT(x)       (((x) & DIMM_TEMP_CRIT) >> 16)
+
+#define NO_DIMM_RETRY_COUNT_MAX        5
+
+struct peci_dimmtemp;
+
+struct dimm_info {
+       int chan_rank_max;
+       int dimm_idx_max;
+       u8 min_peci_revision;
+       int (*read_thresholds)(struct peci_dimmtemp *priv, int dimm_order,
+                              int chan_rank, u32 *data);
+};
+
+struct peci_dimm_thresholds {
+       long temp_max;
+       long temp_crit;
+       struct peci_sensor_state state;
+};
+
+enum peci_dimm_threshold_type {
+       temp_max_type,
+       temp_crit_type,
+};
+
+struct peci_dimmtemp {
+       struct peci_device *peci_dev;
+       struct device *dev;
+       const char *name;
+       const struct dimm_info *gen_info;
+       struct delayed_work detect_work;
+       struct {
+               struct peci_sensor_data temp;
+               struct peci_dimm_thresholds thresholds;
+       } dimm[DIMM_NUMS_MAX];
+       char **dimmtemp_label;
+       DECLARE_BITMAP(dimm_mask, DIMM_NUMS_MAX);
+       u8 no_dimm_retry_count;
+};
+
+static u8 __dimm_temp(u32 reg, int dimm_order)
+{
+       return (reg >> (dimm_order * 8)) & 0xff;
+}
+
+static int get_dimm_temp(struct peci_dimmtemp *priv, int dimm_no, long *val)
+{
+       int dimm_order = dimm_no % priv->gen_info->dimm_idx_max;
+       int chan_rank = dimm_no / priv->gen_info->dimm_idx_max;
+       int ret = 0;
+       u32 data;
+
+       mutex_lock(&priv->dimm[dimm_no].temp.state.lock);
+       if (!peci_sensor_need_update(&priv->dimm[dimm_no].temp.state))
+               goto skip_update;
+
+       ret = peci_pcs_read(priv->peci_dev, PECI_PCS_DDR_DIMM_TEMP, chan_rank, &data);
+       if (ret)
+               goto unlock;
+
+       priv->dimm[dimm_no].temp.value = __dimm_temp(data, dimm_order) * MILLIDEGREE_PER_DEGREE;
+
+       peci_sensor_mark_updated(&priv->dimm[dimm_no].temp.state);
+
+skip_update:
+       *val = priv->dimm[dimm_no].temp.value;
+unlock:
+       mutex_unlock(&priv->dimm[dimm_no].temp.state.lock);
+       return ret;
+}
+
+static int update_thresholds(struct peci_dimmtemp *priv, int dimm_no)
+{
+       int dimm_order = dimm_no % priv->gen_info->dimm_idx_max;
+       int chan_rank = dimm_no / priv->gen_info->dimm_idx_max;
+       u32 data;
+       int ret;
+
+       if (!peci_sensor_need_update(&priv->dimm[dimm_no].thresholds.state))
+               return 0;
+
+       ret = priv->gen_info->read_thresholds(priv, dimm_order, chan_rank, &data);
+       if (ret == -ENODATA) /* Use default or previous value */
+               return 0;
+       if (ret)
+               return ret;
+
+       priv->dimm[dimm_no].thresholds.temp_max = GET_TEMP_MAX(data) * MILLIDEGREE_PER_DEGREE;
+       priv->dimm[dimm_no].thresholds.temp_crit = GET_TEMP_CRIT(data) * MILLIDEGREE_PER_DEGREE;
+
+       peci_sensor_mark_updated(&priv->dimm[dimm_no].thresholds.state);
+
+       return 0;
+}
+
+static int get_dimm_thresholds(struct peci_dimmtemp *priv, enum peci_dimm_threshold_type type,
+                              int dimm_no, long *val)
+{
+       int ret;
+
+       mutex_lock(&priv->dimm[dimm_no].thresholds.state.lock);
+       ret = update_thresholds(priv, dimm_no);
+       if (ret)
+               goto unlock;
+
+       switch (type) {
+       case temp_max_type:
+               *val = priv->dimm[dimm_no].thresholds.temp_max;
+               break;
+       case temp_crit_type:
+               *val = priv->dimm[dimm_no].thresholds.temp_crit;
+               break;
+       default:
+               ret = -EOPNOTSUPP;
+               break;
+       }
+unlock:
+       mutex_unlock(&priv->dimm[dimm_no].thresholds.state.lock);
+
+       return ret;
+}
+
+static int dimmtemp_read_string(struct device *dev,
+                               enum hwmon_sensor_types type,
+                               u32 attr, int channel, const char **str)
+{
+       struct peci_dimmtemp *priv = dev_get_drvdata(dev);
+
+       if (attr != hwmon_temp_label)
+               return -EOPNOTSUPP;
+
+       *str = (const char *)priv->dimmtemp_label[channel];
+
+       return 0;
+}
+
+static int dimmtemp_read(struct device *dev, enum hwmon_sensor_types type,
+                        u32 attr, int channel, long *val)
+{
+       struct peci_dimmtemp *priv = dev_get_drvdata(dev);
+
+       switch (attr) {
+       case hwmon_temp_input:
+               return get_dimm_temp(priv, channel, val);
+       case hwmon_temp_max:
+               return get_dimm_thresholds(priv, temp_max_type, channel, val);
+       case hwmon_temp_crit:
+               return get_dimm_thresholds(priv, temp_crit_type, channel, val);
+       default:
+               break;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static umode_t dimmtemp_is_visible(const void *data, enum hwmon_sensor_types type,
+                                  u32 attr, int channel)
+{
+       const struct peci_dimmtemp *priv = data;
+
+       if (test_bit(channel, priv->dimm_mask))
+               return 0444;
+
+       return 0;
+}
+
+static const struct hwmon_ops peci_dimmtemp_ops = {
+       .is_visible = dimmtemp_is_visible,
+       .read_string = dimmtemp_read_string,
+       .read = dimmtemp_read,
+};
+
+static int check_populated_dimms(struct peci_dimmtemp *priv)
+{
+       int chan_rank_max = priv->gen_info->chan_rank_max;
+       int dimm_idx_max = priv->gen_info->dimm_idx_max;
+       u32 chan_rank_empty = 0;
+       u64 dimm_mask = 0;
+       int chan_rank, dimm_idx, ret;
+       u32 pcs;
+
+       BUILD_BUG_ON(BITS_PER_TYPE(chan_rank_empty) < CHAN_RANK_MAX);
+       BUILD_BUG_ON(BITS_PER_TYPE(dimm_mask) < DIMM_NUMS_MAX);
+       if (chan_rank_max * dimm_idx_max > DIMM_NUMS_MAX) {
+               WARN_ONCE(1, "Unsupported number of DIMMs - chan_rank_max: %d, dimm_idx_max: %d",
+                         chan_rank_max, dimm_idx_max);
+               return -EINVAL;
+       }
+
+       for (chan_rank = 0; chan_rank < chan_rank_max; chan_rank++) {
+               ret = peci_pcs_read(priv->peci_dev, PECI_PCS_DDR_DIMM_TEMP, chan_rank, &pcs);
+               if (ret) {
+                       /*
+                        * Overall, we expect either success or -EINVAL in
+                        * order to determine whether DIMM is populated or not.
+                        * For anything else we fall back to deferring the
+                        * detection to be performed at a later point in time.
+                        */
+                       if (ret == -EINVAL) {
+                               chan_rank_empty |= BIT(chan_rank);
+                               continue;
+                       }
+
+                       return -EAGAIN;
+               }
+
+               for (dimm_idx = 0; dimm_idx < dimm_idx_max; dimm_idx++)
+                       if (__dimm_temp(pcs, dimm_idx))
+                               dimm_mask |= BIT(chan_rank * dimm_idx_max + dimm_idx);
+       }
+
+       /*
+        * If we got all -EINVALs, it means that the CPU doesn't have any
+        * DIMMs. Unfortunately, it may also happen at the very start of
+        * host platform boot. Retrying a couple of times lets us make sure
+        * that the state is persistent.
+        */
+       if (chan_rank_empty == GENMASK(chan_rank_max - 1, 0)) {
+               if (priv->no_dimm_retry_count < NO_DIMM_RETRY_COUNT_MAX) {
+                       priv->no_dimm_retry_count++;
+
+                       return -EAGAIN;
+               }
+
+               return -ENODEV;
+       }
+
+       /*
+        * It's possible that memory training is not done yet. In this case we
+        * defer the detection to be performed at a later point in time.
+        */
+       if (!dimm_mask) {
+               priv->no_dimm_retry_count = 0;
+               return -EAGAIN;
+       }
+
+       dev_dbg(priv->dev, "Scanned populated DIMMs: %#llx\n", dimm_mask);
+
+       bitmap_from_u64(priv->dimm_mask, dimm_mask);
+
+       return 0;
+}
+
+static int create_dimm_temp_label(struct peci_dimmtemp *priv, int chan)
+{
+       int rank = chan / priv->gen_info->dimm_idx_max;
+       int idx = chan % priv->gen_info->dimm_idx_max;
+
+       priv->dimmtemp_label[chan] = devm_kasprintf(priv->dev, GFP_KERNEL,
+                                                   "DIMM %c%d", 'A' + rank,
+                                                   idx + 1);
+       if (!priv->dimmtemp_label[chan])
+               return -ENOMEM;
+
+       return 0;
+}
+
+static const u32 peci_dimmtemp_temp_channel_config[] = {
+       [0 ... DIMM_NUMS_MAX - 1] = HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT,
+       0
+};
+
+static const struct hwmon_channel_info peci_dimmtemp_temp_channel = {
+       .type = hwmon_temp,
+       .config = peci_dimmtemp_temp_channel_config,
+};
+
+static const struct hwmon_channel_info *peci_dimmtemp_temp_info[] = {
+       &peci_dimmtemp_temp_channel,
+       NULL
+};
+
+static const struct hwmon_chip_info peci_dimmtemp_chip_info = {
+       .ops = &peci_dimmtemp_ops,
+       .info = peci_dimmtemp_temp_info,
+};
+
+static int create_dimm_temp_info(struct peci_dimmtemp *priv)
+{
+       int ret, i, channels;
+       struct device *dev;
+
+       /*
+        * We expect to either find populated DIMMs and carry on with creating
+        * sensors, or find out that there are no DIMMs populated.
+        * All other states mean that the platform never reached the state that
+        * allows to check DIMM state - causing us to retry later on.
+        */
+       ret = check_populated_dimms(priv);
+       if (ret == -ENODEV) {
+               dev_dbg(priv->dev, "No DIMMs found\n");
+               return 0;
+       } else if (ret) {
+               schedule_delayed_work(&priv->detect_work, DIMM_MASK_CHECK_DELAY_JIFFIES);
+               dev_dbg(priv->dev, "Deferred populating DIMM temp info\n");
+               return ret;
+       }
+
+       channels = priv->gen_info->chan_rank_max * priv->gen_info->dimm_idx_max;
+
+       priv->dimmtemp_label = devm_kzalloc(priv->dev, channels * sizeof(char *), GFP_KERNEL);
+       if (!priv->dimmtemp_label)
+               return -ENOMEM;
+
+       for_each_set_bit(i, priv->dimm_mask, DIMM_NUMS_MAX) {
+               ret = create_dimm_temp_label(priv, i);
+               if (ret)
+                       return ret;
+               mutex_init(&priv->dimm[i].thresholds.state.lock);
+               mutex_init(&priv->dimm[i].temp.state.lock);
+       }
+
+       dev = devm_hwmon_device_register_with_info(priv->dev, priv->name, priv,
+                                                  &peci_dimmtemp_chip_info, NULL);
+       if (IS_ERR(dev)) {
+               dev_err(priv->dev, "Failed to register hwmon device\n");
+               return PTR_ERR(dev);
+       }
+
+       dev_dbg(priv->dev, "%s: sensor '%s'\n", dev_name(dev), priv->name);
+
+       return 0;
+}
+
+static void create_dimm_temp_info_delayed(struct work_struct *work)
+{
+       struct peci_dimmtemp *priv = container_of(to_delayed_work(work),
+                                                 struct peci_dimmtemp,
+                                                 detect_work);
+       int ret;
+
+       ret = create_dimm_temp_info(priv);
+       if (ret && ret != -EAGAIN)
+               dev_err(priv->dev, "Failed to populate DIMM temp info\n");
+}
+
+static void remove_delayed_work(void *_priv)
+{
+       struct peci_dimmtemp *priv = _priv;
+
+       cancel_delayed_work_sync(&priv->detect_work);
+}
+
+static int peci_dimmtemp_probe(struct auxiliary_device *adev, const struct auxiliary_device_id *id)
+{
+       struct device *dev = &adev->dev;
+       struct peci_device *peci_dev = to_peci_device(dev->parent);
+       struct peci_dimmtemp *priv;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->name = devm_kasprintf(dev, GFP_KERNEL, "peci_dimmtemp.cpu%d",
+                                   peci_dev->info.socket_id);
+       if (!priv->name)
+               return -ENOMEM;
+
+       priv->dev = dev;
+       priv->peci_dev = peci_dev;
+       priv->gen_info = (const struct dimm_info *)id->driver_data;
+
+       /*
+        * This is just a sanity check. Since we're using commands that are
+        * guaranteed to be supported on a given platform, we should never see
+        * revision lower than expected.
+        */
+       if (peci_dev->info.peci_revision < priv->gen_info->min_peci_revision)
+               dev_warn(priv->dev,
+                        "Unexpected PECI revision %#x, some features may be unavailable\n",
+                        peci_dev->info.peci_revision);
+
+       INIT_DELAYED_WORK(&priv->detect_work, create_dimm_temp_info_delayed);
+
+       ret = devm_add_action_or_reset(priv->dev, remove_delayed_work, priv);
+       if (ret)
+               return ret;
+
+       ret = create_dimm_temp_info(priv);
+       if (ret && ret != -EAGAIN) {
+               dev_err(dev, "Failed to populate DIMM temp info\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int
+read_thresholds_hsx(struct peci_dimmtemp *priv, int dimm_order, int chan_rank, u32 *data)
+{
+       u8 dev, func;
+       u16 reg;
+       int ret;
+
+       /*
+        * Device 20, Function 0: IMC 0 channel 0 -> rank 0
+        * Device 20, Function 1: IMC 0 channel 1 -> rank 1
+        * Device 21, Function 0: IMC 0 channel 2 -> rank 2
+        * Device 21, Function 1: IMC 0 channel 3 -> rank 3
+        * Device 23, Function 0: IMC 1 channel 0 -> rank 4
+        * Device 23, Function 1: IMC 1 channel 1 -> rank 5
+        * Device 24, Function 0: IMC 1 channel 2 -> rank 6
+        * Device 24, Function 1: IMC 1 channel 3 -> rank 7
+        */
+       dev = 20 + chan_rank / 2 + chan_rank / 4;
+       func = chan_rank % 2;
+       reg = 0x120 + dimm_order * 4;
+
+       ret = peci_pci_local_read(priv->peci_dev, 1, dev, func, reg, data);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int
+read_thresholds_bdxd(struct peci_dimmtemp *priv, int dimm_order, int chan_rank, u32 *data)
+{
+       u8 dev, func;
+       u16 reg;
+       int ret;
+
+       /*
+        * Device 10, Function 2: IMC 0 channel 0 -> rank 0
+        * Device 10, Function 6: IMC 0 channel 1 -> rank 1
+        * Device 12, Function 2: IMC 1 channel 0 -> rank 2
+        * Device 12, Function 6: IMC 1 channel 1 -> rank 3
+        */
+       dev = 10 + chan_rank / 2 * 2;
+       func = (chan_rank % 2) ? 6 : 2;
+       reg = 0x120 + dimm_order * 4;
+
+       ret = peci_pci_local_read(priv->peci_dev, 2, dev, func, reg, data);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int
+read_thresholds_skx(struct peci_dimmtemp *priv, int dimm_order, int chan_rank, u32 *data)
+{
+       u8 dev, func;
+       u16 reg;
+       int ret;
+
+       /*
+        * Device 10, Function 2: IMC 0 channel 0 -> rank 0
+        * Device 10, Function 6: IMC 0 channel 1 -> rank 1
+        * Device 11, Function 2: IMC 0 channel 2 -> rank 2
+        * Device 12, Function 2: IMC 1 channel 0 -> rank 3
+        * Device 12, Function 6: IMC 1 channel 1 -> rank 4
+        * Device 13, Function 2: IMC 1 channel 2 -> rank 5
+        */
+       dev = 10 + chan_rank / 3 * 2 + (chan_rank % 3 == 2 ? 1 : 0);
+       func = chan_rank % 3 == 1 ? 6 : 2;
+       reg = 0x120 + dimm_order * 4;
+
+       ret = peci_pci_local_read(priv->peci_dev, 2, dev, func, reg, data);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int
+read_thresholds_icx(struct peci_dimmtemp *priv, int dimm_order, int chan_rank, u32 *data)
+{
+       u32 reg_val;
+       u64 offset;
+       int ret;
+       u8 dev;
+
+       ret = peci_ep_pci_local_read(priv->peci_dev, 0, 13, 0, 2, 0xd4, &reg_val);
+       if (ret || !(reg_val & BIT(31)))
+               return -ENODATA; /* Use default or previous value */
+
+       ret = peci_ep_pci_local_read(priv->peci_dev, 0, 13, 0, 2, 0xd0, &reg_val);
+       if (ret)
+               return -ENODATA; /* Use default or previous value */
+
+       /*
+        * Device 26, Offset 224e0: IMC 0 channel 0 -> rank 0
+        * Device 26, Offset 264e0: IMC 0 channel 1 -> rank 1
+        * Device 27, Offset 224e0: IMC 1 channel 0 -> rank 2
+        * Device 27, Offset 264e0: IMC 1 channel 1 -> rank 3
+        * Device 28, Offset 224e0: IMC 2 channel 0 -> rank 4
+        * Device 28, Offset 264e0: IMC 2 channel 1 -> rank 5
+        * Device 29, Offset 224e0: IMC 3 channel 0 -> rank 6
+        * Device 29, Offset 264e0: IMC 3 channel 1 -> rank 7
+        */
+       dev = 26 + chan_rank / 2;
+       offset = 0x224e0 + dimm_order * 4 + (chan_rank % 2) * 0x4000;
+
+       ret = peci_mmio_read(priv->peci_dev, 0, GET_CPU_SEG(reg_val), GET_CPU_BUS(reg_val),
+                            dev, 0, offset, data);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static const struct dimm_info dimm_hsx = {
+       .chan_rank_max  = CHAN_RANK_MAX_ON_HSX,
+       .dimm_idx_max   = DIMM_IDX_MAX_ON_HSX,
+       .min_peci_revision = 0x33,
+       .read_thresholds = &read_thresholds_hsx,
+};
+
+static const struct dimm_info dimm_bdx = {
+       .chan_rank_max  = CHAN_RANK_MAX_ON_BDX,
+       .dimm_idx_max   = DIMM_IDX_MAX_ON_BDX,
+       .min_peci_revision = 0x33,
+       .read_thresholds = &read_thresholds_hsx,
+};
+
+static const struct dimm_info dimm_bdxd = {
+       .chan_rank_max  = CHAN_RANK_MAX_ON_BDXD,
+       .dimm_idx_max   = DIMM_IDX_MAX_ON_BDXD,
+       .min_peci_revision = 0x33,
+       .read_thresholds = &read_thresholds_bdxd,
+};
+
+static const struct dimm_info dimm_skx = {
+       .chan_rank_max  = CHAN_RANK_MAX_ON_SKX,
+       .dimm_idx_max   = DIMM_IDX_MAX_ON_SKX,
+       .min_peci_revision = 0x33,
+       .read_thresholds = &read_thresholds_skx,
+};
+
+static const struct dimm_info dimm_icx = {
+       .chan_rank_max  = CHAN_RANK_MAX_ON_ICX,
+       .dimm_idx_max   = DIMM_IDX_MAX_ON_ICX,
+       .min_peci_revision = 0x40,
+       .read_thresholds = &read_thresholds_icx,
+};
+
+static const struct dimm_info dimm_icxd = {
+       .chan_rank_max  = CHAN_RANK_MAX_ON_ICXD,
+       .dimm_idx_max   = DIMM_IDX_MAX_ON_ICXD,
+       .min_peci_revision = 0x40,
+       .read_thresholds = &read_thresholds_icx,
+};
+
+static const struct auxiliary_device_id peci_dimmtemp_ids[] = {
+       {
+               .name = "peci_cpu.dimmtemp.hsx",
+               .driver_data = (kernel_ulong_t)&dimm_hsx,
+       },
+       {
+               .name = "peci_cpu.dimmtemp.bdx",
+               .driver_data = (kernel_ulong_t)&dimm_bdx,
+       },
+       {
+               .name = "peci_cpu.dimmtemp.bdxd",
+               .driver_data = (kernel_ulong_t)&dimm_bdxd,
+       },
+       {
+               .name = "peci_cpu.dimmtemp.skx",
+               .driver_data = (kernel_ulong_t)&dimm_skx,
+       },
+       {
+               .name = "peci_cpu.dimmtemp.icx",
+               .driver_data = (kernel_ulong_t)&dimm_icx,
+       },
+       {
+               .name = "peci_cpu.dimmtemp.icxd",
+               .driver_data = (kernel_ulong_t)&dimm_icxd,
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(auxiliary, peci_dimmtemp_ids);
+
+static struct auxiliary_driver peci_dimmtemp_driver = {
+       .probe          = peci_dimmtemp_probe,
+       .id_table       = peci_dimmtemp_ids,
+};
+
+module_auxiliary_driver(peci_dimmtemp_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_AUTHOR("Iwona Winiarska <iwona.winiarska@intel.com>");
+MODULE_DESCRIPTION("PECI dimmtemp driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PECI_CPU);
index 0ea7e1c..09276e3 100644 (file)
@@ -62,7 +62,7 @@ static const struct i2c_device_id ir38064_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, ir38064_id);
 
-static const struct of_device_id ir38064_of_match[] = {
+static const struct of_device_id __maybe_unused ir38064_of_match[] = {
        { .compatible = "infineon,ir38060" },
        { .compatible = "infineon,ir38064" },
        { .compatible = "infineon,ir38164" },
index 776ee22..ac2fbee 100644 (file)
@@ -911,6 +911,11 @@ static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b,
                pmbus_update_sensor_data(client, s2);
 
        regval = status & mask;
+       if (regval) {
+               ret = pmbus_write_byte_data(client, page, reg, regval);
+               if (ret)
+                       goto unlock;
+       }
        if (s1 && s2) {
                s64 v1, v2;
 
index 42da31c..8a6c6ee 100644 (file)
@@ -488,7 +488,7 @@ config I2C_BRCMSTB
 
 config I2C_CADENCE
        tristate "Cadence I2C Controller"
-       depends on ARCH_ZYNQ || ARM64 || XTENSA
+       depends on ARCH_ZYNQ || ARM64 || XTENSA || COMPILE_TEST
        help
          Say yes here to select Cadence I2C Host Controller. This controller is
          e.g. used by Xilinx Zynq.
@@ -680,7 +680,7 @@ config I2C_IMG
 
 config I2C_IMX
        tristate "IMX I2C interface"
-       depends on ARCH_MXC || ARCH_LAYERSCAPE || COLDFIRE
+       depends on ARCH_MXC || ARCH_LAYERSCAPE || COLDFIRE || COMPILE_TEST
        select I2C_SLAVE
        help
          Say Y here if you want to use the IIC bus controller on
@@ -935,7 +935,7 @@ config I2C_QCOM_GENI
 
 config I2C_QUP
        tristate "Qualcomm QUP based I2C controller"
-       depends on ARCH_QCOM
+       depends on ARCH_QCOM || COMPILE_TEST
        help
          If you say yes to this option, support will be included for the
          built-in I2C interface on the Qualcomm SoCs.
index dfc5340..5149454 100644 (file)
 #define BCM2835_I2C_FIFO       0x10
 #define BCM2835_I2C_DIV                0x14
 #define BCM2835_I2C_DEL                0x18
+/*
+ * 16-bit field for the number of SCL cycles to wait after rising SCL
+ * before deciding the slave is not responding. 0 disables the
+ * timeout detection.
+ */
 #define BCM2835_I2C_CLKT       0x1c
 
 #define BCM2835_I2C_C_READ     BIT(0)
@@ -474,6 +479,12 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
        adap->dev.of_node = pdev->dev.of_node;
        adap->quirks = of_device_get_match_data(&pdev->dev);
 
+       /*
+        * Disable the hardware clock stretching timeout. SMBUS
+        * specifies a limit for how long the device can stretch the
+        * clock, but core I2C doesn't.
+        */
+       bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_CLKT, 0);
        bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, 0);
 
        ret = i2c_add_adapter(adap);
index 490ee39..b00f35c 100644 (file)
@@ -673,7 +673,7 @@ static int brcmstb_i2c_probe(struct platform_device *pdev)
 
        /* set the data in/out register size for compatible SoCs */
        if (of_device_is_compatible(dev->device->of_node,
-                                   "brcmstb,brcmper-i2c"))
+                                   "brcm,brcmper-i2c"))
                dev->data_regsz = sizeof(u8);
        else
                dev->data_regsz = sizeof(u32);
index c1de8eb..cf54f1c 100644 (file)
@@ -558,7 +558,7 @@ static int cci_probe(struct platform_device *pdev)
                cci->master[idx].adap.quirks = &cci->data->quirks;
                cci->master[idx].adap.algo = &cci_algo;
                cci->master[idx].adap.dev.parent = dev;
-               cci->master[idx].adap.dev.of_node = child;
+               cci->master[idx].adap.dev.of_node = of_node_get(child);
                cci->master[idx].master = idx;
                cci->master[idx].cci = cci;
 
@@ -643,8 +643,10 @@ static int cci_probe(struct platform_device *pdev)
                        continue;
 
                ret = i2c_add_adapter(&cci->master[i].adap);
-               if (ret < 0)
+               if (ret < 0) {
+                       of_node_put(cci->master[i].adap.dev.of_node);
                        goto error_i2c;
+               }
        }
 
        pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
@@ -655,9 +657,11 @@ static int cci_probe(struct platform_device *pdev)
        return 0;
 
 error_i2c:
-       for (; i >= 0; i--) {
-               if (cci->master[i].cci)
+       for (--i ; i >= 0; i--) {
+               if (cci->master[i].cci) {
                        i2c_del_adapter(&cci->master[i].adap);
+                       of_node_put(cci->master[i].adap.dev.of_node);
+               }
        }
 error:
        disable_irq(cci->irq);
@@ -673,8 +677,10 @@ static int cci_remove(struct platform_device *pdev)
        int i;
 
        for (i = 0; i < cci->data->num_masters; i++) {
-               if (cci->master[i].cci)
+               if (cci->master[i].cci) {
                        i2c_del_adapter(&cci->master[i].adap);
+                       of_node_put(cci->master[i].adap.dev.of_node);
+               }
                cci_halt(cci, i);
        }
 
index e6081dd..d11f668 100644 (file)
@@ -1783,11 +1783,14 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
        ret = iio_device_register(indio_dev);
        if (ret < 0) {
                dev_err(dev, "Unable to register iio device\n");
-               goto err_trigger_unregister;
+               goto err_pm_cleanup;
        }
 
        return 0;
 
+err_pm_cleanup:
+       pm_runtime_dont_use_autosuspend(dev);
+       pm_runtime_disable(dev);
 err_trigger_unregister:
        bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
 err_buffer_cleanup:
index 32989d9..f7fd9e0 100644 (file)
@@ -173,12 +173,20 @@ struct fxls8962af_data {
        u16 upper_thres;
 };
 
-const struct regmap_config fxls8962af_regmap_conf = {
+const struct regmap_config fxls8962af_i2c_regmap_conf = {
        .reg_bits = 8,
        .val_bits = 8,
        .max_register = FXLS8962AF_MAX_REG,
 };
-EXPORT_SYMBOL_GPL(fxls8962af_regmap_conf);
+EXPORT_SYMBOL_GPL(fxls8962af_i2c_regmap_conf);
+
+const struct regmap_config fxls8962af_spi_regmap_conf = {
+       .reg_bits = 8,
+       .pad_bits = 8,
+       .val_bits = 8,
+       .max_register = FXLS8962AF_MAX_REG,
+};
+EXPORT_SYMBOL_GPL(fxls8962af_spi_regmap_conf);
 
 enum {
        fxls8962af_idx_x,
index cfb004b..6bde989 100644 (file)
@@ -18,7 +18,7 @@ static int fxls8962af_probe(struct i2c_client *client)
 {
        struct regmap *regmap;
 
-       regmap = devm_regmap_init_i2c(client, &fxls8962af_regmap_conf);
+       regmap = devm_regmap_init_i2c(client, &fxls8962af_i2c_regmap_conf);
        if (IS_ERR(regmap)) {
                dev_err(&client->dev, "Failed to initialize i2c regmap\n");
                return PTR_ERR(regmap);
index 57108d3..6f4dff3 100644 (file)
@@ -18,7 +18,7 @@ static int fxls8962af_probe(struct spi_device *spi)
 {
        struct regmap *regmap;
 
-       regmap = devm_regmap_init_spi(spi, &fxls8962af_regmap_conf);
+       regmap = devm_regmap_init_spi(spi, &fxls8962af_spi_regmap_conf);
        if (IS_ERR(regmap)) {
                dev_err(&spi->dev, "Failed to initialize spi regmap\n");
                return PTR_ERR(regmap);
index b67572c..9cbe98c 100644 (file)
@@ -17,6 +17,7 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq);
 int fxls8962af_core_remove(struct device *dev);
 
 extern const struct dev_pm_ops fxls8962af_pm_ops;
-extern const struct regmap_config fxls8962af_regmap_conf;
+extern const struct regmap_config fxls8962af_i2c_regmap_conf;
+extern const struct regmap_config fxls8962af_spi_regmap_conf;
 
 #endif                         /* _FXLS8962AF_H_ */
index 0fe5703..ac74cdc 100644 (file)
@@ -1590,11 +1590,14 @@ static int kxcjk1013_probe(struct i2c_client *client,
        ret = iio_device_register(indio_dev);
        if (ret < 0) {
                dev_err(&client->dev, "unable to register iio device\n");
-               goto err_buffer_cleanup;
+               goto err_pm_cleanup;
        }
 
        return 0;
 
+err_pm_cleanup:
+       pm_runtime_dont_use_autosuspend(&client->dev);
+       pm_runtime_disable(&client->dev);
 err_buffer_cleanup:
        iio_triggered_buffer_cleanup(indio_dev);
 err_trigger_unregister:
index 4c359fb..c53a339 100644 (file)
@@ -495,11 +495,14 @@ static int mma9551_probe(struct i2c_client *client,
        ret = iio_device_register(indio_dev);
        if (ret < 0) {
                dev_err(&client->dev, "unable to register iio device\n");
-               goto out_poweroff;
+               goto err_pm_cleanup;
        }
 
        return 0;
 
+err_pm_cleanup:
+       pm_runtime_dont_use_autosuspend(&client->dev);
+       pm_runtime_disable(&client->dev);
 out_poweroff:
        mma9551_set_device_state(client, false);
 
index 0570ab1..5ff6bc7 100644 (file)
@@ -1134,12 +1134,15 @@ static int mma9553_probe(struct i2c_client *client,
        ret = iio_device_register(indio_dev);
        if (ret < 0) {
                dev_err(&client->dev, "unable to register iio device\n");
-               goto out_poweroff;
+               goto err_pm_cleanup;
        }
 
        dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
        return 0;
 
+err_pm_cleanup:
+       pm_runtime_dont_use_autosuspend(&client->dev);
+       pm_runtime_disable(&client->dev);
 out_poweroff:
        mma9551_set_device_state(client, false);
        return ret;
index bc2cfa5..b400bbe 100644 (file)
@@ -76,7 +76,7 @@
 #define AD7124_CONFIG_REF_SEL(x)       FIELD_PREP(AD7124_CONFIG_REF_SEL_MSK, x)
 #define AD7124_CONFIG_PGA_MSK          GENMASK(2, 0)
 #define AD7124_CONFIG_PGA(x)           FIELD_PREP(AD7124_CONFIG_PGA_MSK, x)
-#define AD7124_CONFIG_IN_BUFF_MSK      GENMASK(7, 6)
+#define AD7124_CONFIG_IN_BUFF_MSK      GENMASK(6, 5)
 #define AD7124_CONFIG_IN_BUFF(x)       FIELD_PREP(AD7124_CONFIG_IN_BUFF_MSK, x)
 
 /* AD7124_FILTER_X */
index 42ea8bc..adc5cea 100644 (file)
@@ -103,6 +103,7 @@ static int men_z188_probe(struct mcb_device *dev,
        struct z188_adc *adc;
        struct iio_dev *indio_dev;
        struct resource *mem;
+       int ret;
 
        indio_dev = devm_iio_device_alloc(&dev->dev, sizeof(struct z188_adc));
        if (!indio_dev)
@@ -128,8 +129,14 @@ static int men_z188_probe(struct mcb_device *dev,
        adc->mem = mem;
        mcb_set_drvdata(dev, indio_dev);
 
-       return iio_device_register(indio_dev);
+       ret = iio_device_register(indio_dev);
+       if (ret)
+               goto err_unmap;
+
+       return 0;
 
+err_unmap:
+       iounmap(adc->base);
 err:
        mcb_release_mem(mem);
        return -ENXIO;
index d84ae6b..e8fc4d0 100644 (file)
@@ -388,7 +388,7 @@ static int tsc2046_adc_update_scan_mode(struct iio_dev *indio_dev,
        mutex_lock(&priv->slock);
 
        size = 0;
-       for_each_set_bit(ch_idx, active_scan_mask, indio_dev->num_channels) {
+       for_each_set_bit(ch_idx, active_scan_mask, ARRAY_SIZE(priv->l)) {
                size += tsc2046_adc_group_set_layout(priv, group, ch_idx);
                tsc2046_adc_group_set_cmd(priv, group, ch_idx);
                group++;
@@ -548,7 +548,7 @@ static int tsc2046_adc_setup_spi_msg(struct tsc2046_adc_priv *priv)
         * enabled.
         */
        size = 0;
-       for (ch_idx = 0; ch_idx < priv->dcfg->num_channels; ch_idx++)
+       for (ch_idx = 0; ch_idx < ARRAY_SIZE(priv->l); ch_idx++)
                size += tsc2046_adc_group_set_layout(priv, ch_idx, ch_idx);
 
        priv->tx = devm_kzalloc(&priv->spi->dev, size, GFP_KERNEL);
index 5271073..acd230a 100644 (file)
@@ -134,7 +134,6 @@ struct ad74413r_state {
 #define AD74413R_CH_EN_MASK(x)         BIT(x)
 
 #define AD74413R_REG_DIN_COMP_OUT              0x25
-#define AD74413R_DIN_COMP_OUT_SHIFT_X(x)       x
 
 #define AD74413R_REG_ADC_RESULT_X(x)   (0x26 + (x))
 #define AD74413R_ADC_RESULT_MAX                GENMASK(15, 0)
@@ -288,7 +287,7 @@ static void ad74413r_gpio_set_multiple(struct gpio_chip *chip,
        unsigned int offset = 0;
        int ret;
 
-       for_each_set_bit_from(offset, mask, AD74413R_CHANNEL_MAX) {
+       for_each_set_bit_from(offset, mask, chip->ngpio) {
                unsigned int real_offset = st->gpo_gpio_offsets[offset];
 
                ret = ad74413r_set_gpo_config(st, real_offset,
@@ -316,7 +315,7 @@ static int ad74413r_gpio_get(struct gpio_chip *chip, unsigned int offset)
        if (ret)
                return ret;
 
-       status &= AD74413R_DIN_COMP_OUT_SHIFT_X(real_offset);
+       status &= BIT(real_offset);
 
        return status ? 1 : 0;
 }
@@ -334,11 +333,10 @@ static int ad74413r_gpio_get_multiple(struct gpio_chip *chip,
        if (ret)
                return ret;
 
-       for_each_set_bit_from(offset, mask, AD74413R_CHANNEL_MAX) {
+       for_each_set_bit_from(offset, mask, chip->ngpio) {
                unsigned int real_offset = st->comp_gpio_offsets[offset];
 
-               if (val & BIT(real_offset))
-                       *bits |= offset;
+               __assign_bit(offset, bits, val & BIT(real_offset));
        }
 
        return ret;
@@ -840,7 +838,7 @@ static int ad74413r_update_scan_mode(struct iio_dev *indio_dev,
 {
        struct ad74413r_state *st = iio_priv(indio_dev);
        struct spi_transfer *xfer = st->adc_samples_xfer;
-       u8 *rx_buf = &st->adc_samples_buf.rx_buf[-1 * AD74413R_FRAME_SIZE];
+       u8 *rx_buf = st->adc_samples_buf.rx_buf;
        u8 *tx_buf = st->adc_samples_tx_buf;
        unsigned int channel;
        int ret = -EINVAL;
@@ -894,9 +892,10 @@ static int ad74413r_update_scan_mode(struct iio_dev *indio_dev,
 
                spi_message_add_tail(xfer, &st->adc_samples_msg);
 
-               xfer++;
                tx_buf += AD74413R_FRAME_SIZE;
-               rx_buf += AD74413R_FRAME_SIZE;
+               if (xfer != st->adc_samples_xfer)
+                       rx_buf += AD74413R_FRAME_SIZE;
+               xfer++;
        }
 
        xfer->rx_buf = rx_buf;
index 6cdeb50..3f3c478 100644 (file)
@@ -348,7 +348,7 @@ static int admv1013_update_mixer_vgate(struct admv1013_state *st)
 
        vcm = regulator_get_voltage(st->reg);
 
-       if (vcm >= 0 && vcm < 1800000)
+       if (vcm < 1800000)
                mixer_vgate = (2389 * vcm / 1000000 + 8100) / 100;
        else if (vcm > 1800000 && vcm < 2600000)
                mixer_vgate = (2375 * vcm / 1000000 + 125) / 100;
index 17b939a..81a6d09 100644 (file)
@@ -1188,11 +1188,14 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
        ret = iio_device_register(indio_dev);
        if (ret < 0) {
                dev_err(dev, "unable to register iio device\n");
-               goto err_buffer_cleanup;
+               goto err_pm_cleanup;
        }
 
        return 0;
 
+err_pm_cleanup:
+       pm_runtime_dont_use_autosuspend(dev);
+       pm_runtime_disable(dev);
 err_buffer_cleanup:
        iio_triggered_buffer_cleanup(indio_dev);
 err_trigger_unregister:
index ed12932..f9b4540 100644 (file)
@@ -1403,6 +1403,7 @@ static int adis16480_probe(struct spi_device *spi)
 {
        const struct spi_device_id *id = spi_get_device_id(spi);
        const struct adis_data *adis16480_data;
+       irq_handler_t trigger_handler = NULL;
        struct iio_dev *indio_dev;
        struct adis16480 *st;
        int ret;
@@ -1474,8 +1475,12 @@ static int adis16480_probe(struct spi_device *spi)
                st->clk_freq = st->chip_info->int_clk;
        }
 
+       /* Only use our trigger handler if burst mode is supported */
+       if (adis16480_data->burst_len)
+               trigger_handler = adis16480_trigger_handler;
+
        ret = devm_adis_setup_buffer_and_trigger(&st->adis, indio_dev,
-                                                adis16480_trigger_handler);
+                                                trigger_handler);
        if (ret)
                return ret;
 
index 1dabfd6..f897244 100644 (file)
@@ -1385,7 +1385,7 @@ static int kmx61_probe(struct i2c_client *client,
        ret = iio_device_register(data->acc_indio_dev);
        if (ret < 0) {
                dev_err(&client->dev, "Failed to register acc iio device\n");
-               goto err_buffer_cleanup_mag;
+               goto err_pm_cleanup;
        }
 
        ret = iio_device_register(data->mag_indio_dev);
@@ -1398,6 +1398,9 @@ static int kmx61_probe(struct i2c_client *client,
 
 err_iio_unregister_acc:
        iio_device_unregister(data->acc_indio_dev);
+err_pm_cleanup:
+       pm_runtime_dont_use_autosuspend(&client->dev);
+       pm_runtime_disable(&client->dev);
 err_buffer_cleanup_mag:
        if (client->irq > 0)
                iio_triggered_buffer_cleanup(data->mag_indio_dev);
index 727b4b6..93f0c6b 100644 (file)
@@ -1374,8 +1374,12 @@ static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor,
        if (err < 0)
                return err;
 
+       /*
+        * we need to wait for sensor settling time before
+        * reading data in order to avoid corrupted samples
+        */
        delay = 1000000000 / sensor->odr;
-       usleep_range(delay, 2 * delay);
+       usleep_range(3 * delay, 4 * delay);
 
        err = st_lsm6dsx_read_locked(hw, addr, &data, sizeof(data));
        if (err < 0)
index 94eb9f6..208b519 100644 (file)
@@ -1569,9 +1569,17 @@ static long iio_device_buffer_getfd(struct iio_dev *indio_dev, unsigned long arg
        }
 
        if (copy_to_user(ival, &fd, sizeof(fd))) {
-               put_unused_fd(fd);
-               ret = -EFAULT;
-               goto error_free_ib;
+               /*
+                * "Leak" the fd, as there's not much we can do about this
+                * anyway. 'fd' might have been closed already, as
+                * anon_inode_getfd() called fd_install() on it, which made
+                * it reachable by userland.
+                *
+                * Instead of allowing a malicious user to play tricks with
+                * us, rely on the process exit path to do any necessary
+                * cleanup, as in releasing the file, if still needed.
+                */
+               return -EFAULT;
        }
 
        return 0;
index f96f531..3d4d21f 100644 (file)
@@ -962,13 +962,14 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap,
        ret = iio_device_register(indio_dev);
        if (ret < 0) {
                dev_err(dev, "unable to register iio device\n");
-               goto err_disable_runtime_pm;
+               goto err_pm_cleanup;
        }
 
        dev_dbg(dev, "Registered device %s\n", name);
        return 0;
 
-err_disable_runtime_pm:
+err_pm_cleanup:
+       pm_runtime_dont_use_autosuspend(dev);
        pm_runtime_disable(dev);
 err_buffer_cleanup:
        iio_triggered_buffer_cleanup(indio_dev);
index c903b74..35f0d5e 100644 (file)
@@ -3322,7 +3322,7 @@ static int cm_lap_handler(struct cm_work *work)
        ret = cm_init_av_by_path(param->alternate_path, NULL, &alt_av);
        if (ret) {
                rdma_destroy_ah_attr(&ah_attr);
-               return -EINVAL;
+               goto deref;
        }
 
        spin_lock_irq(&cm_id_priv->lock);
index 27a00ce..50c5340 100644 (file)
@@ -67,8 +67,8 @@ static const char * const cma_events[] = {
        [RDMA_CM_EVENT_TIMEWAIT_EXIT]    = "timewait exit",
 };
 
-static void cma_set_mgid(struct rdma_id_private *id_priv, struct sockaddr *addr,
-                        union ib_gid *mgid);
+static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid,
+                             enum ib_gid_type gid_type);
 
 const char *__attribute_const__ rdma_event_msg(enum rdma_cm_event_type event)
 {
@@ -1846,17 +1846,19 @@ static void destroy_mc(struct rdma_id_private *id_priv,
                if (dev_addr->bound_dev_if)
                        ndev = dev_get_by_index(dev_addr->net,
                                                dev_addr->bound_dev_if);
-               if (ndev) {
+               if (ndev && !send_only) {
+                       enum ib_gid_type gid_type;
                        union ib_gid mgid;
 
-                       cma_set_mgid(id_priv, (struct sockaddr *)&mc->addr,
-                                    &mgid);
-
-                       if (!send_only)
-                               cma_igmp_send(ndev, &mgid, false);
-
-                       dev_put(ndev);
+                       gid_type = id_priv->cma_dev->default_gid_type
+                                          [id_priv->id.port_num -
+                                           rdma_start_port(
+                                                   id_priv->cma_dev->device)];
+                       cma_iboe_set_mgid((struct sockaddr *)&mc->addr, &mgid,
+                                         gid_type);
+                       cma_igmp_send(ndev, &mgid, false);
                }
+               dev_put(ndev);
 
                cancel_work_sync(&mc->iboe_join.work);
        }
@@ -3368,22 +3370,30 @@ err:
 static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
                         const struct sockaddr *dst_addr)
 {
-       if (!src_addr || !src_addr->sa_family) {
-               src_addr = (struct sockaddr *) &id->route.addr.src_addr;
-               src_addr->sa_family = dst_addr->sa_family;
-               if (IS_ENABLED(CONFIG_IPV6) &&
-                   dst_addr->sa_family == AF_INET6) {
-                       struct sockaddr_in6 *src_addr6 = (struct sockaddr_in6 *) src_addr;
-                       struct sockaddr_in6 *dst_addr6 = (struct sockaddr_in6 *) dst_addr;
-                       src_addr6->sin6_scope_id = dst_addr6->sin6_scope_id;
-                       if (ipv6_addr_type(&dst_addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
-                               id->route.addr.dev_addr.bound_dev_if = dst_addr6->sin6_scope_id;
-               } else if (dst_addr->sa_family == AF_IB) {
-                       ((struct sockaddr_ib *) src_addr)->sib_pkey =
-                               ((struct sockaddr_ib *) dst_addr)->sib_pkey;
-               }
-       }
-       return rdma_bind_addr(id, src_addr);
+       struct sockaddr_storage zero_sock = {};
+
+       if (src_addr && src_addr->sa_family)
+               return rdma_bind_addr(id, src_addr);
+
+       /*
+        * When the src_addr is not specified, automatically supply an any addr
+        */
+       zero_sock.ss_family = dst_addr->sa_family;
+       if (IS_ENABLED(CONFIG_IPV6) && dst_addr->sa_family == AF_INET6) {
+               struct sockaddr_in6 *src_addr6 =
+                       (struct sockaddr_in6 *)&zero_sock;
+               struct sockaddr_in6 *dst_addr6 =
+                       (struct sockaddr_in6 *)dst_addr;
+
+               src_addr6->sin6_scope_id = dst_addr6->sin6_scope_id;
+               if (ipv6_addr_type(&dst_addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
+                       id->route.addr.dev_addr.bound_dev_if =
+                               dst_addr6->sin6_scope_id;
+       } else if (dst_addr->sa_family == AF_IB) {
+               ((struct sockaddr_ib *)&zero_sock)->sib_pkey =
+                       ((struct sockaddr_ib *)dst_addr)->sib_pkey;
+       }
+       return rdma_bind_addr(id, (struct sockaddr *)&zero_sock);
 }
 
 /*
index 2b72c4f..9d6ac9d 100644 (file)
@@ -95,6 +95,7 @@ struct ucma_context {
        u64                     uid;
 
        struct list_head        list;
+       struct list_head        mc_list;
        struct work_struct      close_work;
 };
 
@@ -105,6 +106,7 @@ struct ucma_multicast {
 
        u64                     uid;
        u8                      join_state;
+       struct list_head        list;
        struct sockaddr_storage addr;
 };
 
@@ -198,6 +200,7 @@ static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file)
 
        INIT_WORK(&ctx->close_work, ucma_close_id);
        init_completion(&ctx->comp);
+       INIT_LIST_HEAD(&ctx->mc_list);
        /* So list_del() will work if we don't do ucma_finish_ctx() */
        INIT_LIST_HEAD(&ctx->list);
        ctx->file = file;
@@ -484,19 +487,19 @@ err1:
 
 static void ucma_cleanup_multicast(struct ucma_context *ctx)
 {
-       struct ucma_multicast *mc;
-       unsigned long index;
+       struct ucma_multicast *mc, *tmp;
 
-       xa_for_each(&multicast_table, index, mc) {
-               if (mc->ctx != ctx)
-                       continue;
+       xa_lock(&multicast_table);
+       list_for_each_entry_safe(mc, tmp, &ctx->mc_list, list) {
+               list_del(&mc->list);
                /*
                 * At this point mc->ctx->ref is 0 so the mc cannot leave the
                 * lock on the reader and this is enough serialization
                 */
-               xa_erase(&multicast_table, index);
+               __xa_erase(&multicast_table, mc->id);
                kfree(mc);
        }
+       xa_unlock(&multicast_table);
 }
 
 static void ucma_cleanup_mc_events(struct ucma_multicast *mc)
@@ -1469,12 +1472,16 @@ static ssize_t ucma_process_join(struct ucma_file *file,
        mc->uid = cmd->uid;
        memcpy(&mc->addr, addr, cmd->addr_size);
 
-       if (xa_alloc(&multicast_table, &mc->id, NULL, xa_limit_32b,
+       xa_lock(&multicast_table);
+       if (__xa_alloc(&multicast_table, &mc->id, NULL, xa_limit_32b,
                     GFP_KERNEL)) {
                ret = -ENOMEM;
                goto err_free_mc;
        }
 
+       list_add_tail(&mc->list, &ctx->mc_list);
+       xa_unlock(&multicast_table);
+
        mutex_lock(&ctx->mutex);
        ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *)&mc->addr,
                                  join_state, mc);
@@ -1500,8 +1507,11 @@ err_leave_multicast:
        mutex_unlock(&ctx->mutex);
        ucma_cleanup_mc_events(mc);
 err_xa_erase:
-       xa_erase(&multicast_table, mc->id);
+       xa_lock(&multicast_table);
+       list_del(&mc->list);
+       __xa_erase(&multicast_table, mc->id);
 err_free_mc:
+       xa_unlock(&multicast_table);
        kfree(mc);
 err_put_ctx:
        ucma_put_ctx(ctx);
@@ -1569,15 +1579,17 @@ static ssize_t ucma_leave_multicast(struct ucma_file *file,
                mc = ERR_PTR(-EINVAL);
        else if (!refcount_inc_not_zero(&mc->ctx->ref))
                mc = ERR_PTR(-ENXIO);
-       else
-               __xa_erase(&multicast_table, mc->id);
-       xa_unlock(&multicast_table);
 
        if (IS_ERR(mc)) {
+               xa_unlock(&multicast_table);
                ret = PTR_ERR(mc);
                goto out;
        }
 
+       list_del(&mc->list);
+       __xa_erase(&multicast_table, mc->id);
+       xa_unlock(&multicast_table);
+
        mutex_lock(&mc->ctx->mutex);
        rdma_leave_multicast(mc->ctx->cm_id, (struct sockaddr *) &mc->addr);
        mutex_unlock(&mc->ctx->mutex);
index 9091229..aec60d4 100644 (file)
@@ -55,7 +55,7 @@ union hfi1_ipoib_flow {
  */
 struct ipoib_txreq {
        struct sdma_txreq           txreq;
-       struct hfi1_sdma_header     sdma_hdr;
+       struct hfi1_sdma_header     *sdma_hdr;
        int                         sdma_status;
        int                         complete;
        struct hfi1_ipoib_dev_priv *priv;
index e1a2b02..5d814af 100644 (file)
@@ -22,26 +22,35 @@ static int hfi1_ipoib_dev_init(struct net_device *dev)
        int ret;
 
        dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
+       if (!dev->tstats)
+               return -ENOMEM;
 
        ret = priv->netdev_ops->ndo_init(dev);
        if (ret)
-               return ret;
+               goto out_ret;
 
        ret = hfi1_netdev_add_data(priv->dd,
                                   qpn_from_mac(priv->netdev->dev_addr),
                                   dev);
        if (ret < 0) {
                priv->netdev_ops->ndo_uninit(dev);
-               return ret;
+               goto out_ret;
        }
 
        return 0;
+out_ret:
+       free_percpu(dev->tstats);
+       dev->tstats = NULL;
+       return ret;
 }
 
 static void hfi1_ipoib_dev_uninit(struct net_device *dev)
 {
        struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);
 
+       free_percpu(dev->tstats);
+       dev->tstats = NULL;
+
        hfi1_netdev_remove_data(priv->dd, qpn_from_mac(priv->netdev->dev_addr));
 
        priv->netdev_ops->ndo_uninit(dev);
@@ -166,12 +175,7 @@ static void hfi1_ipoib_netdev_dtor(struct net_device *dev)
        hfi1_ipoib_rxq_deinit(priv->netdev);
 
        free_percpu(dev->tstats);
-}
-
-static void hfi1_ipoib_free_rdma_netdev(struct net_device *dev)
-{
-       hfi1_ipoib_netdev_dtor(dev);
-       free_netdev(dev);
+       dev->tstats = NULL;
 }
 
 static void hfi1_ipoib_set_id(struct net_device *dev, int id)
@@ -211,24 +215,23 @@ static int hfi1_ipoib_setup_rn(struct ib_device *device,
        priv->port_num = port_num;
        priv->netdev_ops = netdev->netdev_ops;
 
-       netdev->netdev_ops = &hfi1_ipoib_netdev_ops;
-
        ib_query_pkey(device, port_num, priv->pkey_index, &priv->pkey);
 
        rc = hfi1_ipoib_txreq_init(priv);
        if (rc) {
                dd_dev_err(dd, "IPoIB netdev TX init - failed(%d)\n", rc);
-               hfi1_ipoib_free_rdma_netdev(netdev);
                return rc;
        }
 
        rc = hfi1_ipoib_rxq_init(netdev);
        if (rc) {
                dd_dev_err(dd, "IPoIB netdev RX init - failed(%d)\n", rc);
-               hfi1_ipoib_free_rdma_netdev(netdev);
+               hfi1_ipoib_txreq_deinit(priv);
                return rc;
        }
 
+       netdev->netdev_ops = &hfi1_ipoib_netdev_ops;
+
        netdev->priv_destructor = hfi1_ipoib_netdev_dtor;
        netdev->needs_free_netdev = true;
 
index f401089..d6bbdb8 100644 (file)
@@ -122,7 +122,7 @@ static void hfi1_ipoib_free_tx(struct ipoib_txreq *tx, int budget)
                dd_dev_warn(priv->dd,
                            "%s: Status = 0x%x pbc 0x%llx txq = %d sde = %d\n",
                            __func__, tx->sdma_status,
-                           le64_to_cpu(tx->sdma_hdr.pbc), tx->txq->q_idx,
+                           le64_to_cpu(tx->sdma_hdr->pbc), tx->txq->q_idx,
                            tx->txq->sde->this_idx);
        }
 
@@ -231,7 +231,7 @@ static int hfi1_ipoib_build_tx_desc(struct ipoib_txreq *tx,
 {
        struct hfi1_devdata *dd = txp->dd;
        struct sdma_txreq *txreq = &tx->txreq;
-       struct hfi1_sdma_header *sdma_hdr = &tx->sdma_hdr;
+       struct hfi1_sdma_header *sdma_hdr = tx->sdma_hdr;
        u16 pkt_bytes =
                sizeof(sdma_hdr->pbc) + (txp->hdr_dwords << 2) + tx->skb->len;
        int ret;
@@ -256,7 +256,7 @@ static void hfi1_ipoib_build_ib_tx_headers(struct ipoib_txreq *tx,
                                           struct ipoib_txparms *txp)
 {
        struct hfi1_ipoib_dev_priv *priv = tx->txq->priv;
-       struct hfi1_sdma_header *sdma_hdr = &tx->sdma_hdr;
+       struct hfi1_sdma_header *sdma_hdr = tx->sdma_hdr;
        struct sk_buff *skb = tx->skb;
        struct hfi1_pportdata *ppd = ppd_from_ibp(txp->ibp);
        struct rdma_ah_attr *ah_attr = txp->ah_attr;
@@ -483,7 +483,7 @@ static int hfi1_ipoib_send_dma_single(struct net_device *dev,
        if (likely(!ret)) {
 tx_ok:
                trace_sdma_output_ibhdr(txq->priv->dd,
-                                       &tx->sdma_hdr.hdr,
+                                       &tx->sdma_hdr->hdr,
                                        ib_is_sc5(txp->flow.sc5));
                hfi1_ipoib_check_queue_depth(txq);
                return NETDEV_TX_OK;
@@ -547,7 +547,7 @@ static int hfi1_ipoib_send_dma_list(struct net_device *dev,
        hfi1_ipoib_check_queue_depth(txq);
 
        trace_sdma_output_ibhdr(txq->priv->dd,
-                               &tx->sdma_hdr.hdr,
+                               &tx->sdma_hdr->hdr,
                                ib_is_sc5(txp->flow.sc5));
 
        if (!netdev_xmit_more())
@@ -683,7 +683,8 @@ int hfi1_ipoib_txreq_init(struct hfi1_ipoib_dev_priv *priv)
 {
        struct net_device *dev = priv->netdev;
        u32 tx_ring_size, tx_item_size;
-       int i;
+       struct hfi1_ipoib_circ_buf *tx_ring;
+       int i, j;
 
        /*
         * Ring holds 1 less than tx_ring_size
@@ -701,7 +702,9 @@ int hfi1_ipoib_txreq_init(struct hfi1_ipoib_dev_priv *priv)
 
        for (i = 0; i < dev->num_tx_queues; i++) {
                struct hfi1_ipoib_txq *txq = &priv->txqs[i];
+               struct ipoib_txreq *tx;
 
+               tx_ring = &txq->tx_ring;
                iowait_init(&txq->wait,
                            0,
                            hfi1_ipoib_flush_txq,
@@ -725,14 +728,19 @@ int hfi1_ipoib_txreq_init(struct hfi1_ipoib_dev_priv *priv)
                                             priv->dd->node);
 
                txq->tx_ring.items =
-                       kcalloc_node(tx_ring_size, tx_item_size,
-                                    GFP_KERNEL, priv->dd->node);
+                       kvzalloc_node(array_size(tx_ring_size, tx_item_size),
+                                     GFP_KERNEL, priv->dd->node);
                if (!txq->tx_ring.items)
                        goto free_txqs;
 
                txq->tx_ring.max_items = tx_ring_size;
-               txq->tx_ring.shift = ilog2(tx_ring_size);
+               txq->tx_ring.shift = ilog2(tx_item_size);
                txq->tx_ring.avail = hfi1_ipoib_ring_hwat(txq);
+               tx_ring = &txq->tx_ring;
+               for (j = 0; j < tx_ring_size; j++)
+                       hfi1_txreq_from_idx(tx_ring, j)->sdma_hdr =
+                               kzalloc_node(sizeof(*tx->sdma_hdr),
+                                            GFP_KERNEL, priv->dd->node);
 
                netif_tx_napi_add(dev, &txq->napi,
                                  hfi1_ipoib_poll_tx_ring,
@@ -746,7 +754,10 @@ free_txqs:
                struct hfi1_ipoib_txq *txq = &priv->txqs[i];
 
                netif_napi_del(&txq->napi);
-               kfree(txq->tx_ring.items);
+               tx_ring = &txq->tx_ring;
+               for (j = 0; j < tx_ring_size; j++)
+                       kfree(hfi1_txreq_from_idx(tx_ring, j)->sdma_hdr);
+               kvfree(tx_ring->items);
        }
 
        kfree(priv->txqs);
@@ -780,17 +791,20 @@ static void hfi1_ipoib_drain_tx_list(struct hfi1_ipoib_txq *txq)
 
 void hfi1_ipoib_txreq_deinit(struct hfi1_ipoib_dev_priv *priv)
 {
-       int i;
+       int i, j;
 
        for (i = 0; i < priv->netdev->num_tx_queues; i++) {
                struct hfi1_ipoib_txq *txq = &priv->txqs[i];
+               struct hfi1_ipoib_circ_buf *tx_ring = &txq->tx_ring;
 
                iowait_cancel_work(&txq->wait);
                iowait_sdma_drain(&txq->wait);
                hfi1_ipoib_drain_tx_list(txq);
                netif_napi_del(&txq->napi);
                hfi1_ipoib_drain_tx_ring(txq);
-               kfree(txq->tx_ring.items);
+               for (j = 0; j < tx_ring->max_items; j++)
+                       kfree(hfi1_txreq_from_idx(tx_ring, j)->sdma_hdr);
+               kvfree(tx_ring->items);
        }
 
        kfree(priv->txqs);
index 1c3d972..93b1650 100644 (file)
@@ -3237,7 +3237,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
        case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
                ew = kmalloc(sizeof *ew, GFP_ATOMIC);
                if (!ew)
-                       break;
+                       return;
 
                INIT_WORK(&ew->work, handle_port_mgmt_change_event);
                memcpy(&ew->ib_eqe, eqe, sizeof *eqe);
index 0a3b281..41c2729 100644 (file)
@@ -541,7 +541,7 @@ static struct attribute *port_diagc_attributes[] = {
 };
 
 static const struct attribute_group port_diagc_group = {
-       .name = "linkcontrol",
+       .name = "diag_counters",
        .attrs = port_diagc_attributes,
 };
 
index 3305f27..ae50b56 100644 (file)
@@ -3073,6 +3073,8 @@ do_write:
        case IB_WR_ATOMIC_FETCH_AND_ADD:
                if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC)))
                        goto inv_err;
+               if (unlikely(wqe->atomic_wr.remote_addr & (sizeof(u64) - 1)))
+                       goto inv_err;
                if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64),
                                          wqe->atomic_wr.remote_addr,
                                          wqe->atomic_wr.rkey,
index 368959a..df03d84 100644 (file)
@@ -644,14 +644,9 @@ static inline struct siw_sqe *orq_get_current(struct siw_qp *qp)
        return &qp->orq[qp->orq_get % qp->attrs.orq_size];
 }
 
-static inline struct siw_sqe *orq_get_tail(struct siw_qp *qp)
-{
-       return &qp->orq[qp->orq_put % qp->attrs.orq_size];
-}
-
 static inline struct siw_sqe *orq_get_free(struct siw_qp *qp)
 {
-       struct siw_sqe *orq_e = orq_get_tail(qp);
+       struct siw_sqe *orq_e = &qp->orq[qp->orq_put % qp->attrs.orq_size];
 
        if (READ_ONCE(orq_e->flags) == 0)
                return orq_e;
index 60116f2..875ea6f 100644 (file)
@@ -1153,11 +1153,12 @@ static int siw_check_tx_fence(struct siw_qp *qp)
 
        spin_lock_irqsave(&qp->orq_lock, flags);
 
-       rreq = orq_get_current(qp);
-
        /* free current orq entry */
+       rreq = orq_get_current(qp);
        WRITE_ONCE(rreq->flags, 0);
 
+       qp->orq_get++;
+
        if (qp->tx_ctx.orq_fence) {
                if (unlikely(tx_waiting->wr_status != SIW_WR_QUEUED)) {
                        pr_warn("siw: [QP %u]: fence resume: bad status %d\n",
@@ -1165,10 +1166,12 @@ static int siw_check_tx_fence(struct siw_qp *qp)
                        rv = -EPROTO;
                        goto out;
                }
-               /* resume SQ processing */
+               /* resume SQ processing, if possible */
                if (tx_waiting->sqe.opcode == SIW_OP_READ ||
                    tx_waiting->sqe.opcode == SIW_OP_READ_LOCAL_INV) {
-                       rreq = orq_get_tail(qp);
+
+                       /* SQ processing was stopped because of a full ORQ */
+                       rreq = orq_get_free(qp);
                        if (unlikely(!rreq)) {
                                pr_warn("siw: [QP %u]: no ORQE\n", qp_id(qp));
                                rv = -EPROTO;
@@ -1181,15 +1184,14 @@ static int siw_check_tx_fence(struct siw_qp *qp)
                        resume_tx = 1;
 
                } else if (siw_orq_empty(qp)) {
+                       /*
+                        * SQ processing was stopped by fenced work request.
+                        * Resume since all previous Read's are now completed.
+                        */
                        qp->tx_ctx.orq_fence = 0;
                        resume_tx = 1;
-               } else {
-                       pr_warn("siw: [QP %u]: fence resume: orq idx: %d:%d\n",
-                               qp_id(qp), qp->orq_get, qp->orq_put);
-                       rv = -EPROTO;
                }
        }
-       qp->orq_get++;
 out:
        spin_unlock_irqrestore(&qp->orq_lock, flags);
 
index a3dd2cb..54ef367 100644 (file)
@@ -313,7 +313,8 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
 
        if (atomic_inc_return(&sdev->num_qp) > SIW_MAX_QP) {
                siw_dbg(base_dev, "too many QP's\n");
-               return -ENOMEM;
+               rv = -ENOMEM;
+               goto err_atomic;
        }
        if (attrs->qp_type != IB_QPT_RC) {
                siw_dbg(base_dev, "only RC QP's supported\n");
index 7c3f98e..759b85f 100644 (file)
@@ -2682,6 +2682,8 @@ static void rtrs_clt_dev_release(struct device *dev)
        struct rtrs_clt_sess *clt = container_of(dev, struct rtrs_clt_sess,
                                                 dev);
 
+       mutex_destroy(&clt->paths_ev_mutex);
+       mutex_destroy(&clt->paths_mutex);
        kfree(clt);
 }
 
@@ -2711,6 +2713,8 @@ static struct rtrs_clt_sess *alloc_clt(const char *sessname, size_t paths_num,
                return ERR_PTR(-ENOMEM);
        }
 
+       clt->dev.class = rtrs_clt_dev_class;
+       clt->dev.release = rtrs_clt_dev_release;
        uuid_gen(&clt->paths_uuid);
        INIT_LIST_HEAD_RCU(&clt->paths_list);
        clt->paths_num = paths_num;
@@ -2727,53 +2731,51 @@ static struct rtrs_clt_sess *alloc_clt(const char *sessname, size_t paths_num,
        init_waitqueue_head(&clt->permits_wait);
        mutex_init(&clt->paths_ev_mutex);
        mutex_init(&clt->paths_mutex);
+       device_initialize(&clt->dev);
 
-       clt->dev.class = rtrs_clt_dev_class;
-       clt->dev.release = rtrs_clt_dev_release;
        err = dev_set_name(&clt->dev, "%s", sessname);
        if (err)
-               goto err;
+               goto err_put;
+
        /*
         * Suppress user space notification until
         * sysfs files are created
         */
        dev_set_uevent_suppress(&clt->dev, true);
-       err = device_register(&clt->dev);
-       if (err) {
-               put_device(&clt->dev);
-               goto err;
-       }
+       err = device_add(&clt->dev);
+       if (err)
+               goto err_put;
 
        clt->kobj_paths = kobject_create_and_add("paths", &clt->dev.kobj);
        if (!clt->kobj_paths) {
                err = -ENOMEM;
-               goto err_dev;
+               goto err_del;
        }
        err = rtrs_clt_create_sysfs_root_files(clt);
        if (err) {
                kobject_del(clt->kobj_paths);
                kobject_put(clt->kobj_paths);
-               goto err_dev;
+               goto err_del;
        }
        dev_set_uevent_suppress(&clt->dev, false);
        kobject_uevent(&clt->dev.kobj, KOBJ_ADD);
 
        return clt;
-err_dev:
-       device_unregister(&clt->dev);
-err:
+err_del:
+       device_del(&clt->dev);
+err_put:
        free_percpu(clt->pcpu_path);
-       kfree(clt);
+       put_device(&clt->dev);
        return ERR_PTR(err);
 }
 
 static void free_clt(struct rtrs_clt_sess *clt)
 {
-       free_permits(clt);
        free_percpu(clt->pcpu_path);
-       mutex_destroy(&clt->paths_ev_mutex);
-       mutex_destroy(&clt->paths_mutex);
-       /* release callback will free clt in last put */
+
+       /*
+        * release callback will free clt and destroy mutexes in last put
+        */
        device_unregister(&clt->dev);
 }
 
@@ -2890,6 +2892,7 @@ void rtrs_clt_close(struct rtrs_clt_sess *clt)
                rtrs_clt_destroy_path_files(clt_path, NULL);
                kobject_put(&clt_path->kobj);
        }
+       free_permits(clt);
        free_clt(clt);
 }
 EXPORT_SYMBOL(rtrs_clt_close);
index e174e85..285b766 100644 (file)
@@ -4047,9 +4047,11 @@ static void srp_remove_one(struct ib_device *device, void *client_data)
                spin_unlock(&host->target_lock);
 
                /*
-                * Wait for tl_err and target port removal tasks.
+                * srp_queue_remove_work() queues a call to
+                * srp_remove_target(). The latter function cancels
+                * target->tl_err_work so waiting for the remove works to
+                * finish is sufficient.
                 */
-               flush_workqueue(system_long_wq);
                flush_workqueue(srp_remove_wq);
 
                kfree(host);
index ccaeb24..c3139bc 100644 (file)
@@ -2285,6 +2285,12 @@ int input_register_device(struct input_dev *dev)
        /* KEY_RESERVED is not supposed to be transmitted to userspace. */
        __clear_bit(KEY_RESERVED, dev->keybit);
 
+       /* Buttonpads should not map BTN_RIGHT and/or BTN_MIDDLE. */
+       if (test_bit(INPUT_PROP_BUTTONPAD, dev->propbit)) {
+               __clear_bit(BTN_RIGHT, dev->keybit);
+               __clear_bit(BTN_MIDDLE, dev->keybit);
+       }
+
        /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
        input_cleanse_bitmasks(dev);
 
index a472489..164f6c7 100644 (file)
@@ -75,6 +75,8 @@ static void psmouse_smbus_detach_i2c_client(struct i2c_client *client)
                                    "Marking SMBus companion %s as gone\n",
                                    dev_name(&smbdev->client->dev));
                        smbdev->dead = true;
+                       device_link_remove(&smbdev->client->dev,
+                                          &smbdev->psmouse->ps2dev.serio->dev);
                        serio_rescan(smbdev->psmouse->ps2dev.serio);
                } else {
                        list_del(&smbdev->node);
@@ -174,6 +176,8 @@ static void psmouse_smbus_disconnect(struct psmouse *psmouse)
                kfree(smbdev);
        } else {
                smbdev->dead = true;
+               device_link_remove(&smbdev->client->dev,
+                                  &psmouse->ps2dev.serio->dev);
                psmouse_dbg(smbdev->psmouse,
                            "posting removal request for SMBus companion %s\n",
                            dev_name(&smbdev->client->dev));
@@ -270,6 +274,12 @@ int psmouse_smbus_init(struct psmouse *psmouse,
 
        if (smbdev->client) {
                /* We have our companion device */
+               if (!device_link_add(&smbdev->client->dev,
+                                    &psmouse->ps2dev.serio->dev,
+                                    DL_FLAG_STATELESS))
+                       psmouse_warn(psmouse,
+                                    "failed to set up link with iSMBus companion %s\n",
+                                    dev_name(&smbdev->client->dev));
                return 0;
        }
 
index 78d2ee9..1b58611 100644 (file)
@@ -615,10 +615,9 @@ static int wm97xx_register_touch(struct wm97xx *wm)
         * extensions)
         */
        wm->touch_dev = platform_device_alloc("wm97xx-touch", -1);
-       if (!wm->touch_dev) {
-               ret = -ENOMEM;
-               goto touch_err;
-       }
+       if (!wm->touch_dev)
+               return -ENOMEM;
+
        platform_set_drvdata(wm->touch_dev, wm);
        wm->touch_dev->dev.parent = wm->dev;
        wm->touch_dev->dev.platform_data = pdata;
@@ -629,9 +628,6 @@ static int wm97xx_register_touch(struct wm97xx *wm)
        return 0;
 touch_reg_err:
        platform_device_put(wm->touch_dev);
-touch_err:
-       input_unregister_device(wm->input_dev);
-       wm->input_dev = NULL;
 
        return ret;
 }
@@ -639,8 +635,6 @@ touch_err:
 static void wm97xx_unregister_touch(struct wm97xx *wm)
 {
        platform_device_unregister(wm->touch_dev);
-       input_unregister_device(wm->input_dev);
-       wm->input_dev = NULL;
 }
 
 static int _wm97xx_probe(struct wm97xx *wm)
index 7c82c4f..129ebc8 100644 (file)
@@ -571,8 +571,20 @@ static SIMPLE_DEV_PM_OPS(zinitix_pm_ops, zinitix_suspend, zinitix_resume);
 
 #ifdef CONFIG_OF
 static const struct of_device_id zinitix_of_match[] = {
+       { .compatible = "zinitix,bt402" },
+       { .compatible = "zinitix,bt403" },
+       { .compatible = "zinitix,bt404" },
+       { .compatible = "zinitix,bt412" },
+       { .compatible = "zinitix,bt413" },
+       { .compatible = "zinitix,bt431" },
+       { .compatible = "zinitix,bt432" },
+       { .compatible = "zinitix,bt531" },
        { .compatible = "zinitix,bt532" },
+       { .compatible = "zinitix,bt538" },
        { .compatible = "zinitix,bt541" },
+       { .compatible = "zinitix,bt548" },
+       { .compatible = "zinitix,bt554" },
+       { .compatible = "zinitix,at100" },
        { }
 };
 MODULE_DEVICE_TABLE(of, zinitix_of_match);
index dc338ac..b10fb52 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/export.h>
 #include <linux/kmemleak.h>
 #include <linux/cc_platform.h>
+#include <linux/iopoll.h>
 #include <asm/pci-direct.h>
 #include <asm/iommu.h>
 #include <asm/apic.h>
@@ -834,6 +835,7 @@ static int iommu_ga_log_enable(struct amd_iommu *iommu)
                status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
                if (status & (MMIO_STATUS_GALOG_RUN_MASK))
                        break;
+               udelay(10);
        }
 
        if (WARN_ON(i >= LOOP_TIMEOUT))
index f912fe4..a673195 100644 (file)
@@ -569,9 +569,8 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
                                            fn, &intel_ir_domain_ops,
                                            iommu);
        if (!iommu->ir_domain) {
-               irq_domain_free_fwnode(fn);
                pr_err("IR%d: failed to allocate irqdomain\n", iommu->seq_id);
-               goto out_free_bitmap;
+               goto out_free_fwnode;
        }
        iommu->ir_msi_domain =
                arch_create_remap_msi_irq_domain(iommu->ir_domain,
@@ -595,7 +594,7 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
 
                if (dmar_enable_qi(iommu)) {
                        pr_err("Failed to enable queued invalidation\n");
-                       goto out_free_bitmap;
+                       goto out_free_ir_domain;
                }
        }
 
@@ -619,6 +618,14 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
 
        return 0;
 
+out_free_ir_domain:
+       if (iommu->ir_msi_domain)
+               irq_domain_remove(iommu->ir_msi_domain);
+       iommu->ir_msi_domain = NULL;
+       irq_domain_remove(iommu->ir_domain);
+       iommu->ir_domain = NULL;
+out_free_fwnode:
+       irq_domain_free_fwnode(fn);
 out_free_bitmap:
        bitmap_free(bitmap);
 out_free_pages:
index 50ee27b..06fee74 100644 (file)
@@ -349,6 +349,7 @@ EXPORT_SYMBOL_GPL(ioasid_alloc);
 
 /**
  * ioasid_get - obtain a reference to the IOASID
+ * @ioasid: the ID to get
  */
 void ioasid_get(ioasid_t ioasid)
 {
index 8b86406..107dcf5 100644 (file)
@@ -207,9 +207,14 @@ static struct dev_iommu *dev_iommu_get(struct device *dev)
 
 static void dev_iommu_free(struct device *dev)
 {
-       iommu_fwspec_free(dev);
-       kfree(dev->iommu);
+       struct dev_iommu *param = dev->iommu;
+
        dev->iommu = NULL;
+       if (param->fwspec) {
+               fwnode_handle_put(param->fwspec->iommu_fwnode);
+               kfree(param->fwspec);
+       }
+       kfree(param);
 }
 
 static int __iommu_probe_device(struct device *dev, struct list_head *group_list)
@@ -980,17 +985,6 @@ static int iommu_group_device_count(struct iommu_group *group)
        return ret;
 }
 
-/**
- * iommu_group_for_each_dev - iterate over each device in the group
- * @group: the group
- * @data: caller opaque data to be passed to callback function
- * @fn: caller supplied callback function
- *
- * This function is called by group users to iterate over group devices.
- * Callers should hold a reference count to the group during callback.
- * The group->mutex is held across callbacks, which will block calls to
- * iommu_group_add/remove_device.
- */
 static int __iommu_group_for_each_dev(struct iommu_group *group, void *data,
                                      int (*fn)(struct device *, void *))
 {
@@ -1005,7 +999,17 @@ static int __iommu_group_for_each_dev(struct iommu_group *group, void *data,
        return ret;
 }
 
-
+/**
+ * iommu_group_for_each_dev - iterate over each device in the group
+ * @group: the group
+ * @data: caller opaque data to be passed to callback function
+ * @fn: caller supplied callback function
+ *
+ * This function is called by group users to iterate over group devices.
+ * Callers should hold a reference count to the group during callback.
+ * The group->mutex is held across callbacks, which will block calls to
+ * iommu_group_add/remove_device.
+ */
 int iommu_group_for_each_dev(struct iommu_group *group, void *data,
                             int (*fn)(struct device *, void *))
 {
@@ -3032,6 +3036,7 @@ EXPORT_SYMBOL_GPL(iommu_aux_get_pasid);
  * iommu_sva_bind_device() - Bind a process address space to a device
  * @dev: the device
  * @mm: the mm to bind, caller must hold a reference to it
+ * @drvdata: opaque data pointer to pass to bind callback
  *
  * Create a bond between device and address space, allowing the device to access
  * the mm using the returned PASID. If a bond already exists between @device and
index 9174965..980e4af 100644 (file)
@@ -1085,7 +1085,7 @@ static __maybe_unused int omap_iommu_runtime_resume(struct device *dev)
 }
 
 /**
- * omap_iommu_suspend_prepare - prepare() dev_pm_ops implementation
+ * omap_iommu_prepare - prepare() dev_pm_ops implementation
  * @dev:       iommu device
  *
  * This function performs the necessary checks to determine if the IOMMU
index 2543ef6..38091eb 100644 (file)
@@ -178,7 +178,6 @@ struct aic_irq_chip {
        struct irq_domain *hw_domain;
        struct irq_domain *ipi_domain;
        int nr_hw;
-       int ipi_hwirq;
 };
 
 static DEFINE_PER_CPU(uint32_t, aic_fiq_unmasked);
index d25b7a8..cd77297 100644 (file)
@@ -4856,6 +4856,38 @@ static struct syscore_ops its_syscore_ops = {
        .resume = its_restore_enable,
 };
 
+static void __init __iomem *its_map_one(struct resource *res, int *err)
+{
+       void __iomem *its_base;
+       u32 val;
+
+       its_base = ioremap(res->start, SZ_64K);
+       if (!its_base) {
+               pr_warn("ITS@%pa: Unable to map ITS registers\n", &res->start);
+               *err = -ENOMEM;
+               return NULL;
+       }
+
+       val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK;
+       if (val != 0x30 && val != 0x40) {
+               pr_warn("ITS@%pa: No ITS detected, giving up\n", &res->start);
+               *err = -ENODEV;
+               goto out_unmap;
+       }
+
+       *err = its_force_quiescent(its_base);
+       if (*err) {
+               pr_warn("ITS@%pa: Failed to quiesce, giving up\n", &res->start);
+               goto out_unmap;
+       }
+
+       return its_base;
+
+out_unmap:
+       iounmap(its_base);
+       return NULL;
+}
+
 static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)
 {
        struct irq_domain *inner_domain;
@@ -4963,29 +4995,14 @@ static int __init its_probe_one(struct resource *res,
 {
        struct its_node *its;
        void __iomem *its_base;
-       u32 val, ctlr;
        u64 baser, tmp, typer;
        struct page *page;
+       u32 ctlr;
        int err;
 
-       its_base = ioremap(res->start, SZ_64K);
-       if (!its_base) {
-               pr_warn("ITS@%pa: Unable to map ITS registers\n", &res->start);
-               return -ENOMEM;
-       }
-
-       val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK;
-       if (val != 0x30 && val != 0x40) {
-               pr_warn("ITS@%pa: No ITS detected, giving up\n", &res->start);
-               err = -ENODEV;
-               goto out_unmap;
-       }
-
-       err = its_force_quiescent(its_base);
-       if (err) {
-               pr_warn("ITS@%pa: Failed to quiesce, giving up\n", &res->start);
-               goto out_unmap;
-       }
+       its_base = its_map_one(res, &err);
+       if (!its_base)
+               return err;
 
        pr_info("ITS %pR\n", res);
 
@@ -5241,13 +5258,31 @@ static int its_cpu_memreserve_lpi(unsigned int cpu)
 
 out:
        /* Last CPU being brought up gets to issue the cleanup */
-       if (cpumask_equal(&cpus_booted_once_mask, cpu_possible_mask))
+       if (!IS_ENABLED(CONFIG_SMP) ||
+           cpumask_equal(&cpus_booted_once_mask, cpu_possible_mask))
                schedule_work(&rdist_memreserve_cpuhp_cleanup_work);
 
        gic_data_rdist()->flags |= RD_LOCAL_MEMRESERVE_DONE;
        return ret;
 }
 
+/* Mark all the BASER registers as invalid before they get reprogrammed */
+static int __init its_reset_one(struct resource *res)
+{
+       void __iomem *its_base;
+       int err, i;
+
+       its_base = its_map_one(res, &err);
+       if (!its_base)
+               return err;
+
+       for (i = 0; i < GITS_BASER_NR_REGS; i++)
+               gits_write_baser(0, its_base + GITS_BASER + (i << 3));
+
+       iounmap(its_base);
+       return 0;
+}
+
 static const struct of_device_id its_device_id[] = {
        {       .compatible     = "arm,gic-v3-its",     },
        {},
@@ -5258,6 +5293,26 @@ static int __init its_of_probe(struct device_node *node)
        struct device_node *np;
        struct resource res;
 
+       /*
+        * Make sure *all* the ITS are reset before we probe any, as
+        * they may be sharing memory. If any of the ITS fails to
+        * reset, don't even try to go any further, as this could
+        * result in something even worse.
+        */
+       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))
+                       continue;
+
+               err = its_reset_one(&res);
+               if (err)
+                       return err;
+       }
+
        for (np = of_find_matching_node(node, its_device_id); np;
             np = of_find_matching_node(np, its_device_id)) {
                if (!of_device_is_available(np))
@@ -5420,11 +5475,35 @@ dom_err:
        return err;
 }
 
+static int __init its_acpi_reset(union acpi_subtable_headers *header,
+                                const unsigned long end)
+{
+       struct acpi_madt_generic_translator *its_entry;
+       struct resource res;
+
+       its_entry = (struct acpi_madt_generic_translator *)header;
+       res = (struct resource) {
+               .start  = its_entry->base_address,
+               .end    = its_entry->base_address + ACPI_GICV3_ITS_MEM_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       };
+
+       return its_reset_one(&res);
+}
+
 static void __init its_acpi_probe(void)
 {
        acpi_table_parse_srat_its();
-       acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
-                             gic_acpi_parse_madt_its, 0);
+       /*
+        * Make sure *all* the ITS are reset before we probe any, as
+        * they may be sharing memory. If any of the ITS fails to
+        * reset, don't even try to go any further, as this could
+        * result in something even worse.
+        */
+       if (acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
+                                 its_acpi_reset, 0) > 0)
+               acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
+                                     gic_acpi_parse_madt_its, 0);
        acpi_its_srat_maps_free();
 }
 #else
@@ -5438,6 +5517,9 @@ int __init its_lpi_memreserve_init(void)
        if (!efi_enabled(EFI_CONFIG_TABLES))
                return 0;
 
+       if (list_empty(&its_nodes))
+               return 0;
+
        gic_rdists->cpuhp_memreserve_state = CPUHP_INVALID;
        state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
                                  "irqchip/arm/gicv3/memreserve:online",
index 32562b7..e3801c4 100644 (file)
@@ -241,7 +241,7 @@ static int pch_msi_init(struct device_node *node,
        return 0;
 
 err_map:
-       kfree(priv->msi_map);
+       bitmap_free(priv->msi_map);
 err_priv:
        kfree(priv);
        return ret;
index fd9f275..50a5682 100644 (file)
@@ -62,7 +62,7 @@ static struct irq_chip realtek_ictl_irq = {
 
 static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
 {
-       irq_set_chip_and_handler(hw, &realtek_ictl_irq, handle_level_irq);
+       irq_set_chip_and_handler(irq, &realtek_ictl_irq, handle_level_irq);
 
        return 0;
 }
@@ -76,16 +76,20 @@ static void realtek_irq_dispatch(struct irq_desc *desc)
 {
        struct irq_chip *chip = irq_desc_get_chip(desc);
        struct irq_domain *domain;
-       unsigned int pending;
+       unsigned long pending;
+       unsigned int soc_int;
 
        chained_irq_enter(chip, desc);
        pending = readl(REG(RTL_ICTL_GIMR)) & readl(REG(RTL_ICTL_GISR));
+
        if (unlikely(!pending)) {
                spurious_interrupt();
                goto out;
        }
+
        domain = irq_desc_get_handler_data(desc);
-       generic_handle_domain_irq(domain, __ffs(pending));
+       for_each_set_bit(soc_int, &pending, 32)
+               generic_handle_domain_irq(domain, soc_int);
 
 out:
        chained_irq_exit(chip, desc);
@@ -95,7 +99,8 @@ out:
  * SoC interrupts are cascaded to MIPS CPU interrupts according to the
  * interrupt-map in the device tree. Each SoC interrupt gets 4 bits for
  * the CPU interrupt in an Interrupt Routing Register. Max 32 SoC interrupts
- * thus go into 4 IRRs.
+ * thus go into 4 IRRs. A routing value of '0' means the interrupt is left
+ * disconnected. Routing values {1..15} connect to output lines {0..14}.
  */
 static int __init map_interrupts(struct device_node *node, struct irq_domain *domain)
 {
@@ -134,7 +139,7 @@ static int __init map_interrupts(struct device_node *node, struct irq_domain *do
                of_node_put(cpu_ictl);
 
                cpu_int = be32_to_cpup(imap + 2);
-               if (cpu_int > 7)
+               if (cpu_int > 7 || cpu_int < 2)
                        return -EINVAL;
 
                if (!(mips_irqs_set & BIT(cpu_int))) {
@@ -143,7 +148,8 @@ static int __init map_interrupts(struct device_node *node, struct irq_domain *do
                        mips_irqs_set |= BIT(cpu_int);
                }
 
-               regs[(soc_int * 4) / 32] |= cpu_int << (soc_int * 4) % 32;
+               /* Use routing values (1..6) for CPU interrupts (2..7) */
+               regs[(soc_int * 4) / 32] |= (cpu_int - 1) << (soc_int * 4) % 32;
                imap += 3;
        }
 
index 259065d..09cc982 100644 (file)
@@ -398,3 +398,4 @@ out_free_priv:
 
 IRQCHIP_DECLARE(sifive_plic, "sifive,plic-1.0.0", plic_init);
 IRQCHIP_DECLARE(riscv_plic0, "riscv,plic0", plic_init); /* for legacy systems */
+IRQCHIP_DECLARE(thead_c900_plic, "thead,c900-plic", plic_init); /* for firmware driver */
index c0ae808..997ace4 100644 (file)
@@ -489,7 +489,7 @@ static void start_io_acct(struct dm_io *io)
        struct mapped_device *md = io->md;
        struct bio *bio = io->orig_bio;
 
-       io->start_time = bio_start_io_acct(bio);
+       bio_start_io_acct_time(bio, io->start_time);
        if (unlikely(dm_stats_used(&md->stats)))
                dm_stats_account_io(&md->stats, bio_data_dir(bio),
                                    bio->bi_iter.bi_sector, bio_sectors(bio),
@@ -535,7 +535,7 @@ static struct dm_io *alloc_io(struct mapped_device *md, struct bio *bio)
        io->md = md;
        spin_lock_init(&io->endio_lock);
 
-       start_io_acct(io);
+       io->start_time = jiffies;
 
        return io;
 }
@@ -1442,9 +1442,6 @@ static void init_clone_info(struct clone_info *ci, struct mapped_device *md,
        ci->sector = bio->bi_iter.bi_sector;
 }
 
-#define __dm_part_stat_sub(part, field, subnd) \
-       (part_stat_get(part, field) -= (subnd))
-
 /*
  * Entry point to split a bio into clones and submit them to the targets.
  */
@@ -1480,23 +1477,12 @@ static void __split_and_process_bio(struct mapped_device *md,
                                                  GFP_NOIO, &md->queue->bio_split);
                        ci.io->orig_bio = b;
 
-                       /*
-                        * Adjust IO stats for each split, otherwise upon queue
-                        * reentry there will be redundant IO accounting.
-                        * NOTE: this is a stop-gap fix, a proper fix involves
-                        * significant refactoring of DM core's bio splitting
-                        * (by eliminating DM's splitting and just using bio_split)
-                        */
-                       part_stat_lock();
-                       __dm_part_stat_sub(dm_disk(md)->part0,
-                                          sectors[op_stat_group(bio_op(bio))], ci.sector_count);
-                       part_stat_unlock();
-
                        bio_chain(b, bio);
                        trace_block_split(b, bio->bi_iter.bi_sector);
                        submit_bio_noacct(bio);
                }
        }
+       start_io_acct(ci.io);
 
        /* drop the extra reference count */
        dm_io_dec_pending(ci.io, errno_to_blk_status(error));
@@ -2091,7 +2077,7 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
        set_bit(DMF_FREEING, &md->flags);
        spin_unlock(&_minor_lock);
 
-       blk_set_queue_dying(md->queue);
+       blk_mark_disk_dead(md->disk);
 
        /*
         * Take suspend_lock so that presuspend and postsuspend methods
index 5881d05..4d38bd7 100644 (file)
@@ -5869,10 +5869,6 @@ int md_run(struct mddev *mddev)
                nowait = nowait && blk_queue_nowait(bdev_get_queue(rdev->bdev));
        }
 
-       /* Set the NOWAIT flags if all underlying devices support it */
-       if (nowait)
-               blk_queue_flag_set(QUEUE_FLAG_NOWAIT, mddev->queue);
-
        if (!bioset_initialized(&mddev->bio_set)) {
                err = bioset_init(&mddev->bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
                if (err)
@@ -6010,6 +6006,10 @@ int md_run(struct mddev *mddev)
                else
                        blk_queue_flag_clear(QUEUE_FLAG_NONROT, mddev->queue);
                blk_queue_flag_set(QUEUE_FLAG_IO_STAT, mddev->queue);
+
+               /* Set the NOWAIT flags if all underlying devices support it */
+               if (nowait)
+                       blk_queue_flag_set(QUEUE_FLAG_NOWAIT, mddev->queue);
        }
        if (pers->sync_request) {
                if (mddev->kobj.sd &&
index 0f5a49f..a2b2642 100644 (file)
@@ -470,6 +470,18 @@ config HISI_HIKEY_USB
          switching between the dual-role USB-C port and the USB-A host ports
          using only one USB controller.
 
+config OPEN_DICE
+       tristate "Open Profile for DICE driver"
+       depends on OF_RESERVED_MEM
+       help
+         This driver exposes a DICE reserved memory region to userspace via
+         a character device. The memory region contains Compound Device
+         Identifiers (CDIs) generated by firmware as an output of DICE
+         measured boot flow. Userspace can use CDIs for remote attestation
+         and sealing.
+
+         If unsure, say N.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
index a086197..70e800e 100644 (file)
@@ -59,3 +59,4 @@ obj-$(CONFIG_UACCE)           += uacce/
 obj-$(CONFIG_XILINX_SDFEC)     += xilinx_sdfec.o
 obj-$(CONFIG_HISI_HIKEY_USB)   += hisi_hikey_usb.o
 obj-$(CONFIG_HI6421V600_IRQ)   += hi6421v600-irq.o
+obj-$(CONFIG_OPEN_DICE)                += open-dice.o
index de6d44a..3f514d7 100644 (file)
@@ -266,7 +266,7 @@ static int alcor_pci_probe(struct pci_dev *pdev,
        if (!priv)
                return -ENOMEM;
 
-       ret = ida_simple_get(&alcor_pci_idr, 0, 0, GFP_KERNEL);
+       ret = ida_alloc(&alcor_pci_idr, GFP_KERNEL);
        if (ret < 0)
                return ret;
        priv->id = ret;
@@ -280,7 +280,8 @@ static int alcor_pci_probe(struct pci_dev *pdev,
        ret = pci_request_regions(pdev, DRV_NAME_ALCOR_PCI);
        if (ret) {
                dev_err(&pdev->dev, "Cannot request region\n");
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto error_free_ida;
        }
 
        if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
@@ -324,6 +325,8 @@ static int alcor_pci_probe(struct pci_dev *pdev,
 
 error_release_regions:
        pci_release_regions(pdev);
+error_free_ida:
+       ida_free(&alcor_pci_idr, priv->id);
        return ret;
 }
 
@@ -337,7 +340,7 @@ static void alcor_pci_remove(struct pci_dev *pdev)
 
        mfd_remove_devices(&pdev->dev);
 
-       ida_simple_remove(&alcor_pci_idr, priv->id);
+       ida_free(&alcor_pci_idr, priv->id);
 
        pci_release_regions(pdev);
        pci_set_drvdata(pdev, NULL);
index 4c5621b..06457e8 100644 (file)
@@ -76,7 +76,7 @@ static void rtl8411b_fetch_vendor_settings(struct rtsx_pcr *pcr)
                map_sd_drive(rtl8411b_reg_to_sd30_drive_sel_3v3(reg));
 }
 
-static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
        rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);
 }
index 29f5414..52b0a47 100644 (file)
@@ -47,7 +47,7 @@ static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr)
        }
 }
 
-static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
        rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);
 }
index 4bcfbc9..d676cf6 100644 (file)
@@ -72,6 +72,8 @@ static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr)
 
        pci_read_config_dword(pdev, PCR_SETTING_REG2, &reg);
        pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
+       if (CHK_PCI_PID(pcr, 0x522A))
+               pcr->rtd3_en = rtsx_reg_to_rtd3(reg);
        if (rtsx_check_mmc_support(reg))
                pcr->extra_caps |= EXTRA_CAPS_NO_MMC;
        pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg);
@@ -171,6 +173,28 @@ static int rts5227_extra_init_hw(struct rtsx_pcr *pcr)
        else
                rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x30, 0x00);
 
+       if (CHK_PCI_PID(pcr, 0x522A))
+               rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RTS522A_AUTOLOAD_CFG1,
+                       CD_RESUME_EN_MASK, CD_RESUME_EN_MASK);
+
+       if (pcr->rtd3_en) {
+               if (CHK_PCI_PID(pcr, 0x522A)) {
+                       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RTS522A_PM_CTRL3, 0x01, 0x01);
+                       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RTS522A_PME_FORCE_CTL, 0x30, 0x30);
+               } else {
+                       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PM_CTRL3, 0x01, 0x01);
+                       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PME_FORCE_CTL, 0xFF, 0x33);
+               }
+       } else {
+               if (CHK_PCI_PID(pcr, 0x522A)) {
+                       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RTS522A_PM_CTRL3, 0x01, 0x00);
+                       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RTS522A_PME_FORCE_CTL, 0x30, 0x20);
+               } else {
+                       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PME_FORCE_CTL, 0xFF, 0x30);
+                       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PM_CTRL3, 0x01, 0x00);
+               }
+       }
+
        if (option->force_clkreq_0)
                rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG,
                                FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
@@ -438,6 +462,28 @@ static int rts522a_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
        return rtsx_pci_send_cmd(pcr, 100);
 }
 
+static void rts522a_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
+{
+       /* Set relink_time to 0 */
+       rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
+       rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, MASK_8_BIT_DEF, 0);
+       rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3,
+                               RELINK_TIME_MASK, 0);
+
+       rtsx_pci_write_register(pcr, RTS522A_PM_CTRL3,
+                       D3_DELINK_MODE_EN, D3_DELINK_MODE_EN);
+
+       if (!runtime) {
+               rtsx_pci_write_register(pcr, RTS522A_AUTOLOAD_CFG1,
+                               CD_RESUME_EN_MASK, 0);
+               rtsx_pci_write_register(pcr, RTS522A_PM_CTRL3, 0x01, 0x00);
+               rtsx_pci_write_register(pcr, RTS522A_PME_FORCE_CTL, 0x30, 0x20);
+       }
+
+       rtsx_pci_write_register(pcr, FPDCTL, ALL_POWER_DOWN, ALL_POWER_DOWN);
+}
+
+
 static void rts522a_set_l1off_cfg_sub_d0(struct rtsx_pcr *pcr, int active)
 {
        struct rtsx_cr_option *option = &pcr->option;
@@ -473,6 +519,7 @@ static const struct pcr_ops rts522a_pcr_ops = {
        .card_power_on = rts5227_card_power_on,
        .card_power_off = rts5227_card_power_off,
        .switch_output_voltage = rts522a_switch_output_voltage,
+       .force_power_down = rts522a_force_power_down,
        .cd_deglitch = NULL,
        .conv_clk_and_div_n = NULL,
        .set_l1off_cfg_sub_d0 = rts522a_set_l1off_cfg_sub_d0,
index ffc1282..af581f4 100644 (file)
@@ -91,7 +91,7 @@ static int rts5228_optimize_phy(struct rtsx_pcr *pcr)
        return rtsx_pci_write_phy_register(pcr, 0x07, 0x8F40);
 }
 
-static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
        /* Set relink_time to 0 */
        rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
@@ -102,6 +102,14 @@ static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
        rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3,
                        D3_DELINK_MODE_EN, D3_DELINK_MODE_EN);
 
+       if (!runtime) {
+               rtsx_pci_write_register(pcr, RTS5228_AUTOLOAD_CFG1,
+                               CD_RESUME_EN_MASK, 0);
+               rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x00);
+               rtsx_pci_write_register(pcr, RTS5228_REG_PME_FORCE_CTL,
+                               FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL);
+       }
+
        rtsx_pci_write_register(pcr, FPDCTL,
                SSC_POWER_DOWN, SSC_POWER_DOWN);
 }
@@ -480,9 +488,18 @@ static int rts5228_extra_init_hw(struct rtsx_pcr *pcr)
                                 FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
 
        rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFB);
-       rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x10, 0x00);
+
+       if (pcr->rtd3_en) {
+               rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x01);
        rtsx_pci_write_register(pcr, RTS5228_REG_PME_FORCE_CTL,
-                       FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL);
+                               FORCE_PM_CONTROL | FORCE_PM_VALUE,
+                               FORCE_PM_CONTROL | FORCE_PM_VALUE);
+       } else {
+               rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x00);
+               rtsx_pci_write_register(pcr, RTS5228_REG_PME_FORCE_CTL,
+                               FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL);
+       }
+       rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, D3_DELINK_MODE_EN, 0x00);
 
        return 0;
 }
index c748eaf..b0edd80 100644 (file)
@@ -44,7 +44,7 @@ static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr)
                map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg));
 }
 
-static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
        rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
 }
index 53f3a1f..91d240d 100644 (file)
@@ -74,7 +74,8 @@ static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr)
        pci_read_config_dword(pdev, PCR_SETTING_REG2, &reg);
        pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
 
-       pcr->rtd3_en = rtsx_reg_to_rtd3_uhsii(reg);
+       if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A))
+               pcr->rtd3_en = rtsx_reg_to_rtd3_uhsii(reg);
 
        if (rtsx_check_mmc_support(reg))
                pcr->extra_caps |= EXTRA_CAPS_NO_MMC;
@@ -143,6 +144,27 @@ static int rts5249_init_from_hw(struct rtsx_pcr *pcr)
        return 0;
 }
 
+static void rts52xa_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
+{
+       /* Set relink_time to 0 */
+       rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
+       rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, MASK_8_BIT_DEF, 0);
+       rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3,
+                               RELINK_TIME_MASK, 0);
+
+       rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3,
+                       D3_DELINK_MODE_EN, D3_DELINK_MODE_EN);
+
+       if (!runtime) {
+               rtsx_pci_write_register(pcr, RTS524A_AUTOLOAD_CFG1,
+                               CD_RESUME_EN_MASK, 0);
+               rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3, 0x01, 0x00);
+               rtsx_pci_write_register(pcr, RTS524A_PME_FORCE_CTL, 0x30, 0x20);
+       }
+
+       rtsx_pci_write_register(pcr, FPDCTL, ALL_POWER_DOWN, ALL_POWER_DOWN);
+}
+
 static void rts52xa_save_content_from_efuse(struct rtsx_pcr *pcr)
 {
        u8 cnt, sv;
@@ -281,8 +303,11 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
 
        rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
 
-       if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A))
+       if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A)) {
                rtsx_pci_write_register(pcr, REG_VREF, PWD_SUSPND_EN, PWD_SUSPND_EN);
+               rtsx_pci_write_register(pcr, RTS524A_AUTOLOAD_CFG1,
+                       CD_RESUME_EN_MASK, CD_RESUME_EN_MASK);
+       }
 
        if (pcr->rtd3_en) {
                if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A)) {
@@ -724,6 +749,7 @@ static const struct pcr_ops rts524a_pcr_ops = {
        .card_power_on = rtsx_base_card_power_on,
        .card_power_off = rtsx_base_card_power_off,
        .switch_output_voltage = rtsx_base_switch_output_voltage,
+       .force_power_down = rts52xa_force_power_down,
        .set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
 };
 
@@ -841,6 +867,7 @@ static const struct pcr_ops rts525a_pcr_ops = {
        .card_power_on = rts525a_card_power_on,
        .card_power_off = rtsx_base_card_power_off,
        .switch_output_voltage = rts525a_switch_output_voltage,
+       .force_power_down = rts52xa_force_power_down,
        .set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
 };
 
index 1fd4e0e..a77585a 100644 (file)
@@ -91,7 +91,7 @@ static void rtsx5261_fetch_vendor_settings(struct rtsx_pcr *pcr)
        pcr->sd30_drive_sel_3v3 = rts5261_reg_to_sd30_drive_sel_3v3(reg);
 }
 
-static void rts5261_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rts5261_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
        /* Set relink_time to 0 */
        rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
@@ -103,6 +103,24 @@ static void rts5261_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
                rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3,
                                        D3_DELINK_MODE_EN, D3_DELINK_MODE_EN);
 
+       if (!runtime) {
+               rtsx_pci_write_register(pcr, RTS5261_AUTOLOAD_CFG1,
+                               CD_RESUME_EN_MASK, 0);
+               rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x00);
+               rtsx_pci_write_register(pcr, RTS5261_REG_PME_FORCE_CTL,
+                               FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL);
+
+       } else {
+               rtsx_pci_write_register(pcr, RTS5261_REG_PME_FORCE_CTL,
+                               FORCE_PM_CONTROL | FORCE_PM_VALUE, 0);
+
+               rtsx_pci_write_register(pcr, RTS5261_FW_CTL,
+                               RTS5261_INFORM_RTD3_COLD, RTS5261_INFORM_RTD3_COLD);
+               rtsx_pci_write_register(pcr, RTS5261_AUTOLOAD_CFG4,
+                               RTS5261_FORCE_PRSNT_LOW, RTS5261_FORCE_PRSNT_LOW);
+
+       }
+
        rtsx_pci_write_register(pcr, RTS5261_REG_FPDCTL,
                SSC_POWER_DOWN, SSC_POWER_DOWN);
 }
@@ -536,9 +554,18 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
                                 FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
 
        rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFB);
-       rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x10, 0x00);
-       rtsx_pci_write_register(pcr, RTS5261_REG_PME_FORCE_CTL,
-                       FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL);
+
+       if (pcr->rtd3_en) {
+               rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x01);
+               rtsx_pci_write_register(pcr, RTS5261_REG_PME_FORCE_CTL,
+                               FORCE_PM_CONTROL | FORCE_PM_VALUE,
+                               FORCE_PM_CONTROL | FORCE_PM_VALUE);
+       } else {
+               rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x00);
+               rtsx_pci_write_register(pcr, RTS5261_REG_PME_FORCE_CTL,
+                               FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL);
+       }
+       rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, D3_DELINK_MODE_EN, 0x00);
 
        /* Clear Enter RTD3_cold Information*/
        rtsx_pci_write_register(pcr, RTS5261_FW_CTL,
index 6ac509c..2a2619e 100644 (file)
@@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
        if (pcr->remove_pci)
                return;
 
-       if (pcr->rtd3_en)
-               if (pcr->is_runtime_suspended) {
-                       pm_runtime_get(&(pcr->pci->dev));
-                       pcr->is_runtime_suspended = false;
-               }
-
        if (pcr->state != PDEV_STAT_RUN) {
                pcr->state = PDEV_STAT_RUN;
                if (pcr->ops->enable_auto_blink)
                        pcr->ops->enable_auto_blink(pcr);
                rtsx_pm_full_on(pcr);
        }
-
-       mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
 }
 EXPORT_SYMBOL_GPL(rtsx_pci_start_run);
 
@@ -1062,73 +1054,7 @@ static int rtsx_pci_acquire_irq(struct rtsx_pcr *pcr)
        return 0;
 }
 
-static void rtsx_enable_aspm(struct rtsx_pcr *pcr)
-{
-       if (pcr->ops->set_aspm)
-               pcr->ops->set_aspm(pcr, true);
-       else
-               rtsx_comm_set_aspm(pcr, true);
-}
-
-static void rtsx_comm_pm_power_saving(struct rtsx_pcr *pcr)
-{
-       struct rtsx_cr_option *option = &pcr->option;
-
-       if (option->ltr_enabled) {
-               u32 latency = option->ltr_l1off_latency;
-
-               if (rtsx_check_dev_flag(pcr, L1_SNOOZE_TEST_EN))
-                       mdelay(option->l1_snooze_delay);
-
-               rtsx_set_ltr_latency(pcr, latency);
-       }
-
-       if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN))
-               rtsx_set_l1off_sub_cfg_d0(pcr, 0);
-
-       rtsx_enable_aspm(pcr);
-}
-
-static void rtsx_pm_power_saving(struct rtsx_pcr *pcr)
-{
-       rtsx_comm_pm_power_saving(pcr);
-}
-
-static void rtsx_pci_rtd3_work(struct work_struct *work)
-{
-       struct delayed_work *dwork = to_delayed_work(work);
-       struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, rtd3_work);
-
-       pcr_dbg(pcr, "--> %s\n", __func__);
-       if (!pcr->is_runtime_suspended)
-               pm_runtime_put(&(pcr->pci->dev));
-}
-
-static void rtsx_pci_idle_work(struct work_struct *work)
-{
-       struct delayed_work *dwork = to_delayed_work(work);
-       struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work);
-
-       pcr_dbg(pcr, "--> %s\n", __func__);
-
-       mutex_lock(&pcr->pcr_mutex);
-
-       pcr->state = PDEV_STAT_IDLE;
-
-       if (pcr->ops->disable_auto_blink)
-               pcr->ops->disable_auto_blink(pcr);
-       if (pcr->ops->turn_off_led)
-               pcr->ops->turn_off_led(pcr);
-
-       rtsx_pm_power_saving(pcr);
-
-       mutex_unlock(&pcr->pcr_mutex);
-
-       if (pcr->rtd3_en)
-               mod_delayed_work(system_wq, &pcr->rtd3_work, msecs_to_jiffies(10000));
-}
-
-static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+static void rtsx_base_force_power_down(struct rtsx_pcr *pcr)
 {
        /* Set relink_time to 0 */
        rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
@@ -1142,7 +1068,7 @@ static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
        rtsx_pci_write_register(pcr, FPDCTL, ALL_POWER_DOWN, ALL_POWER_DOWN);
 }
 
-static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
+static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
 {
        if (pcr->ops->turn_off_led)
                pcr->ops->turn_off_led(pcr);
@@ -1154,9 +1080,9 @@ static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
        rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, pm_state);
 
        if (pcr->ops->force_power_down)
-               pcr->ops->force_power_down(pcr, pm_state);
+               pcr->ops->force_power_down(pcr, pm_state, runtime);
        else
-               rtsx_base_force_power_down(pcr, pm_state);
+               rtsx_base_force_power_down(pcr);
 }
 
 void rtsx_pci_enable_ocp(struct rtsx_pcr *pcr)
@@ -1598,7 +1524,6 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
        pcr->card_inserted = 0;
        pcr->card_removed = 0;
        INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect);
-       INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work);
 
        pcr->msi_en = msi_en;
        if (pcr->msi_en) {
@@ -1623,20 +1548,14 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
                rtsx_pcr_cells[i].pdata_size = sizeof(*handle);
        }
 
-       if (pcr->rtd3_en) {
-               INIT_DELAYED_WORK(&pcr->rtd3_work, rtsx_pci_rtd3_work);
-               pm_runtime_allow(&pcidev->dev);
-               pm_runtime_enable(&pcidev->dev);
-               pcr->is_runtime_suspended = false;
-       }
-
 
        ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells,
                        ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL);
        if (ret < 0)
                goto free_slots;
 
-       schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
+       pm_runtime_allow(&pcidev->dev);
+       pm_runtime_put(&pcidev->dev);
 
        return 0;
 
@@ -1668,11 +1587,11 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
        struct pcr_handle *handle = pci_get_drvdata(pcidev);
        struct rtsx_pcr *pcr = handle->pcr;
 
-       if (pcr->rtd3_en)
-               pm_runtime_get_noresume(&pcr->pci->dev);
-
        pcr->remove_pci = true;
 
+       pm_runtime_get_sync(&pcidev->dev);
+       pm_runtime_forbid(&pcidev->dev);
+
        /* Disable interrupts at the pcr level */
        spin_lock_irq(&pcr->lock);
        rtsx_pci_writel(pcr, RTSX_BIER, 0);
@@ -1680,9 +1599,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
        spin_unlock_irq(&pcr->lock);
 
        cancel_delayed_work_sync(&pcr->carddet_work);
-       cancel_delayed_work_sync(&pcr->idle_work);
-       if (pcr->rtd3_en)
-               cancel_delayed_work_sync(&pcr->rtd3_work);
 
        mfd_remove_devices(&pcidev->dev);
 
@@ -1700,11 +1616,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
        idr_remove(&rtsx_pci_idr, pcr->id);
        spin_unlock(&rtsx_pci_lock);
 
-       if (pcr->rtd3_en) {
-               pm_runtime_disable(&pcr->pci->dev);
-               pm_runtime_put_noidle(&pcr->pci->dev);
-       }
-
        kfree(pcr->slots);
        kfree(pcr);
        kfree(handle);
@@ -1717,22 +1628,16 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 {
        struct pci_dev *pcidev = to_pci_dev(dev_d);
-       struct pcr_handle *handle;
-       struct rtsx_pcr *pcr;
+       struct pcr_handle *handle = pci_get_drvdata(pcidev);
+       struct rtsx_pcr *pcr = handle->pcr;
 
        dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-       handle = pci_get_drvdata(pcidev);
-       pcr = handle->pcr;
-
-       cancel_delayed_work(&pcr->carddet_work);
-       cancel_delayed_work(&pcr->idle_work);
+       cancel_delayed_work_sync(&pcr->carddet_work);
 
        mutex_lock(&pcr->pcr_mutex);
 
-       rtsx_pci_power_off(pcr, HOST_ENTER_S3);
-
-       device_wakeup_disable(dev_d);
+       rtsx_pci_power_off(pcr, HOST_ENTER_S3, false);
 
        mutex_unlock(&pcr->pcr_mutex);
        return 0;
@@ -1741,15 +1646,12 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
 static int __maybe_unused rtsx_pci_resume(struct device *dev_d)
 {
        struct pci_dev *pcidev = to_pci_dev(dev_d);
-       struct pcr_handle *handle;
-       struct rtsx_pcr *pcr;
+       struct pcr_handle *handle = pci_get_drvdata(pcidev);
+       struct rtsx_pcr *pcr = handle->pcr;
        int ret = 0;
 
        dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-       handle = pci_get_drvdata(pcidev);
-       pcr = handle->pcr;
-
        mutex_lock(&pcr->pcr_mutex);
 
        ret = rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00);
@@ -1760,8 +1662,6 @@ static int __maybe_unused rtsx_pci_resume(struct device *dev_d)
        if (ret)
                goto out;
 
-       schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
-
 out:
        mutex_unlock(&pcr->pcr_mutex);
        return ret;
@@ -1769,16 +1669,46 @@ out:
 
 #ifdef CONFIG_PM
 
+static void rtsx_enable_aspm(struct rtsx_pcr *pcr)
+{
+       if (pcr->ops->set_aspm)
+               pcr->ops->set_aspm(pcr, true);
+       else
+               rtsx_comm_set_aspm(pcr, true);
+}
+
+static void rtsx_comm_pm_power_saving(struct rtsx_pcr *pcr)
+{
+       struct rtsx_cr_option *option = &pcr->option;
+
+       if (option->ltr_enabled) {
+               u32 latency = option->ltr_l1off_latency;
+
+               if (rtsx_check_dev_flag(pcr, L1_SNOOZE_TEST_EN))
+                       mdelay(option->l1_snooze_delay);
+
+               rtsx_set_ltr_latency(pcr, latency);
+       }
+
+       if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN))
+               rtsx_set_l1off_sub_cfg_d0(pcr, 0);
+
+       rtsx_enable_aspm(pcr);
+}
+
+static void rtsx_pm_power_saving(struct rtsx_pcr *pcr)
+{
+       rtsx_comm_pm_power_saving(pcr);
+}
+
 static void rtsx_pci_shutdown(struct pci_dev *pcidev)
 {
-       struct pcr_handle *handle;
-       struct rtsx_pcr *pcr;
+       struct pcr_handle *handle = pci_get_drvdata(pcidev);
+       struct rtsx_pcr *pcr = handle->pcr;
 
        dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
-       handle = pci_get_drvdata(pcidev);
-       pcr = handle->pcr;
-       rtsx_pci_power_off(pcr, HOST_ENTER_S1);
+       rtsx_pci_power_off(pcr, HOST_ENTER_S1, false);
 
        pci_disable_device(pcidev);
        free_irq(pcr->irq, (void *)pcr);
@@ -1786,47 +1716,63 @@ static void rtsx_pci_shutdown(struct pci_dev *pcidev)
                pci_disable_msi(pcr->pci);
 }
 
+static int rtsx_pci_runtime_idle(struct device *device)
+{
+       struct pci_dev *pcidev = to_pci_dev(device);
+       struct pcr_handle *handle = pci_get_drvdata(pcidev);
+       struct rtsx_pcr *pcr = handle->pcr;
+
+       dev_dbg(device, "--> %s\n", __func__);
+
+       mutex_lock(&pcr->pcr_mutex);
+
+       pcr->state = PDEV_STAT_IDLE;
+
+       if (pcr->ops->disable_auto_blink)
+               pcr->ops->disable_auto_blink(pcr);
+       if (pcr->ops->turn_off_led)
+               pcr->ops->turn_off_led(pcr);
+
+       rtsx_pm_power_saving(pcr);
+
+       mutex_unlock(&pcr->pcr_mutex);
+
+       if (pcr->rtd3_en)
+               pm_schedule_suspend(device, 10000);
+
+       return -EBUSY;
+}
+
 static int rtsx_pci_runtime_suspend(struct device *device)
 {
        struct pci_dev *pcidev = to_pci_dev(device);
-       struct pcr_handle *handle;
-       struct rtsx_pcr *pcr;
+       struct pcr_handle *handle = pci_get_drvdata(pcidev);
+       struct rtsx_pcr *pcr = handle->pcr;
 
-       handle = pci_get_drvdata(pcidev);
-       pcr = handle->pcr;
-       dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
+       dev_dbg(device, "--> %s\n", __func__);
 
-       cancel_delayed_work(&pcr->carddet_work);
-       cancel_delayed_work(&pcr->rtd3_work);
-       cancel_delayed_work(&pcr->idle_work);
+       cancel_delayed_work_sync(&pcr->carddet_work);
 
        mutex_lock(&pcr->pcr_mutex);
-       rtsx_pci_power_off(pcr, HOST_ENTER_S3);
+       rtsx_pci_power_off(pcr, HOST_ENTER_S3, true);
 
        mutex_unlock(&pcr->pcr_mutex);
 
-       pcr->is_runtime_suspended = true;
-
        return 0;
 }
 
 static int rtsx_pci_runtime_resume(struct device *device)
 {
        struct pci_dev *pcidev = to_pci_dev(device);
-       struct pcr_handle *handle;
-       struct rtsx_pcr *pcr;
+       struct pcr_handle *handle = pci_get_drvdata(pcidev);
+       struct rtsx_pcr *pcr = handle->pcr;
 
-       handle = pci_get_drvdata(pcidev);
-       pcr = handle->pcr;
-       dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
+       dev_dbg(device, "--> %s\n", __func__);
 
        mutex_lock(&pcr->pcr_mutex);
 
        rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00);
 
-       if (pcr->ops->fetch_vendor_settings)
-               pcr->ops->fetch_vendor_settings(pcr);
-
        rtsx_pci_init_hw(pcr);
 
        if (pcr->slots[RTSX_SD_CARD].p_dev != NULL) {
@@ -1834,8 +1780,6 @@ static int rtsx_pci_runtime_resume(struct device *device)
                                pcr->slots[RTSX_SD_CARD].p_dev);
        }
 
-       schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200));
-
        mutex_unlock(&pcr->pcr_mutex);
        return 0;
 }
@@ -1850,7 +1794,7 @@ static int rtsx_pci_runtime_resume(struct device *device)
 
 static const struct dev_pm_ops rtsx_pci_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend, rtsx_pci_resume)
-       SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend, rtsx_pci_runtime_resume, NULL)
+       SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend, rtsx_pci_runtime_resume, rtsx_pci_runtime_idle)
 };
 
 static struct pci_driver rtsx_pci_driver = {
index daf057c..37d1f31 100644 (file)
@@ -15,6 +15,8 @@
 #define MIN_DIV_N_PCR          80
 #define MAX_DIV_N_PCR          208
 
+#define RTS522A_PME_FORCE_CTL  0xFF78
+#define RTS522A_AUTOLOAD_CFG1  0xFF7C
 #define RTS522A_PM_CTRL3               0xFF7E
 
 #define RTS524A_PME_FORCE_CTL          0xFF78
@@ -25,6 +27,7 @@
 #define REG_EFUSE_POWEROFF             0x00
 #define RTS5250_CLK_CFG3               0xFF79
 #define RTS525A_CFG_MEM_PD             0xF0
+#define RTS524A_AUTOLOAD_CFG1          0xFF7C
 #define RTS524A_PM_CTRL3               0xFF7E
 #define RTS525A_BIOS_CFG               0xFF2D
 #define RTS525A_LOAD_BIOS_FLAG 0x01
index c3305bd..91f96ab 100644 (file)
@@ -309,7 +309,7 @@ static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
        u32 val;
        int err;
 
-       strncpy(chip->name, "at25", sizeof(chip->name));
+       strscpy(chip->name, "at25", sizeof(chip->name));
 
        err = device_property_read_u32(dev, "size", &val);
        if (err)
@@ -370,7 +370,7 @@ static int at25_fram_to_chip(struct device *dev, struct spi_eeprom *chip)
        u8 id[FM25_ID_LEN];
        int i;
 
-       strncpy(chip->name, "fm25", sizeof(chip->name));
+       strscpy(chip->name, "fm25", sizeof(chip->name));
 
        /* Get ID of chip */
        fm25_aux_read(at25, id, FM25_RDID, FM25_ID_LEN);
@@ -440,6 +440,10 @@ static int at25_probe(struct spi_device *spi)
                return -ENXIO;
        }
 
+       at25 = devm_kzalloc(&spi->dev, sizeof(*at25), GFP_KERNEL);
+       if (!at25)
+               return -ENOMEM;
+
        mutex_init(&at25->lock);
        at25->spi = spi;
        spi_set_drvdata(spi, at25);
index bb9c451..9fbfe78 100644 (file)
@@ -114,6 +114,9 @@ static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf,
        if (offset + count > EE1004_PAGE_SIZE)
                count = EE1004_PAGE_SIZE - offset;
 
+       if (count > I2C_SMBUS_BLOCK_MAX)
+               count = I2C_SMBUS_BLOCK_MAX;
+
        return i2c_smbus_read_i2c_block_data_or_emulated(client, offset, count, buf);
 }
 
index 4ccbf43..aa1682b 100644 (file)
@@ -1288,7 +1288,14 @@ static int fastrpc_dmabuf_alloc(struct fastrpc_user *fl, char __user *argp)
        }
 
        if (copy_to_user(argp, &bp, sizeof(bp))) {
-               dma_buf_put(buf->dmabuf);
+               /*
+                * The usercopy failed, but we can't do much about it, as
+                * dma_buf_fd() already called fd_install() and made the
+                * file descriptor accessible for the current process. It
+                * might already be closed and dmabuf no longer valid when
+                * we reach this point. Therefore "leak" the fd and rely on
+                * the process exit path to do any required cleanup.
+                */
                return -EFAULT;
        }
 
index 82c3824..6ebe3c7 100644 (file)
@@ -11,4 +11,4 @@ HL_COMMON_FILES := common/habanalabs_drv.o common/device.o common/context.o \
                common/command_buffer.o common/hw_queue.o common/irq.o \
                common/sysfs.o common/hwmon.o common/memory.o \
                common/command_submission.o common/firmware_if.o \
-               common/state_dump.o common/hwmgr.o
+               common/state_dump.o
index 3c0ae07..a507110 100644 (file)
@@ -424,8 +424,8 @@ int hl_cb_ioctl(struct hl_fpriv *hpriv, void *data)
 {
        union hl_cb_args *args = data;
        struct hl_device *hdev = hpriv->hdev;
+       u64 handle = 0, device_va = 0;
        enum hl_device_status status;
-       u64 handle = 0, device_va;
        u32 usage_cnt = 0;
        int rc;
 
@@ -464,6 +464,8 @@ int hl_cb_ioctl(struct hl_fpriv *hpriv, void *data)
                                args->in.flags,
                                &usage_cnt,
                                &device_va);
+               if (rc)
+                       break;
 
                memset(&args->out, 0, sizeof(args->out));
 
index 0a4ef13..d93ef9f 100644 (file)
@@ -14,6 +14,8 @@
 #define HL_CS_FLAGS_TYPE_MASK  (HL_CS_FLAGS_SIGNAL | HL_CS_FLAGS_WAIT | \
                                HL_CS_FLAGS_COLLECTIVE_WAIT)
 
+#define MAX_TS_ITER_NUM 10
+
 /**
  * enum hl_cs_wait_status - cs wait status
  * @CS_WAIT_STATUS_BUSY: cs was not completed yet
@@ -919,18 +921,21 @@ static void cs_rollback(struct hl_device *hdev, struct hl_cs *cs)
                complete_job(hdev, job);
 }
 
-void hl_cs_rollback_all(struct hl_device *hdev)
+void hl_cs_rollback_all(struct hl_device *hdev, bool skip_wq_flush)
 {
        int i;
        struct hl_cs *cs, *tmp;
 
-       flush_workqueue(hdev->sob_reset_wq);
+       if (!skip_wq_flush) {
+               flush_workqueue(hdev->ts_free_obj_wq);
 
-       /* flush all completions before iterating over the CS mirror list in
-        * order to avoid a race with the release functions
-        */
-       for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++)
-               flush_workqueue(hdev->cq_wq[i]);
+               /* flush all completions before iterating over the CS mirror list in
+                * order to avoid a race with the release functions
+                */
+               for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++)
+                       flush_workqueue(hdev->cq_wq[i]);
+
+       }
 
        /* Make sure we don't have leftovers in the CS mirror list */
        list_for_each_entry_safe(cs, tmp, &hdev->cs_mirror_list, mirror_node) {
@@ -948,13 +953,19 @@ void hl_cs_rollback_all(struct hl_device *hdev)
 static void
 wake_pending_user_interrupt_threads(struct hl_user_interrupt *interrupt)
 {
-       struct hl_user_pending_interrupt *pend;
+       struct hl_user_pending_interrupt *pend, *temp;
        unsigned long flags;
 
        spin_lock_irqsave(&interrupt->wait_list_lock, flags);
-       list_for_each_entry(pend, &interrupt->wait_list_head, wait_list_node) {
-               pend->fence.error = -EIO;
-               complete_all(&pend->fence.completion);
+       list_for_each_entry_safe(pend, temp, &interrupt->wait_list_head, wait_list_node) {
+               if (pend->ts_reg_info.ts_buff) {
+                       list_del(&pend->wait_list_node);
+                       hl_ts_put(pend->ts_reg_info.ts_buff);
+                       hl_cb_put(pend->ts_reg_info.cq_cb);
+               } else {
+                       pend->fence.error = -EIO;
+                       complete_all(&pend->fence.completion);
+               }
        }
        spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
 }
@@ -2063,13 +2074,16 @@ static int cs_ioctl_signal_wait(struct hl_fpriv *hpriv, enum hl_cs_type cs_type,
                        idp = &ctx->sig_mgr.handles;
                        idr_for_each_entry(idp, encaps_sig_hdl, id) {
                                if (encaps_sig_hdl->cs_seq == signal_seq) {
-                                       handle_found = true;
-                                       /* get refcount to protect removing
-                                        * this handle from idr, needed when
-                                        * multiple wait cs are used with offset
+                                       /* get refcount to protect removing this handle from idr,
+                                        * needed when multiple wait cs are used with offset
                                         * to wait on reserved encaps signals.
+                                        * Since kref_put of this handle is executed outside the
+                                        * current lock, it is possible that the handle refcount
+                                        * is 0 but it yet to be removed from the list. In this
+                                        * case need to consider the handle as not valid.
                                         */
-                                       kref_get(&encaps_sig_hdl->refcount);
+                                       if (kref_get_unless_zero(&encaps_sig_hdl->refcount))
+                                               handle_found = true;
                                        break;
                                }
                        }
@@ -2739,7 +2753,7 @@ static int hl_multi_cs_wait_ioctl(struct hl_fpriv *hpriv, void *data)
                mcs_data.update_ts = false;
                rc = hl_cs_poll_fences(&mcs_data, mcs_compl);
 
-               if (mcs_data.completion_bitmap)
+               if (rc || mcs_data.completion_bitmap)
                        break;
 
                /*
@@ -2854,64 +2868,174 @@ static int hl_cs_wait_ioctl(struct hl_fpriv *hpriv, void *data)
        return 0;
 }
 
+static int ts_buff_get_kernel_ts_record(struct hl_ts_buff *ts_buff,
+                                       struct hl_cb *cq_cb,
+                                       u64 ts_offset, u64 cq_offset, u64 target_value,
+                                       spinlock_t *wait_list_lock,
+                                       struct hl_user_pending_interrupt **pend)
+{
+       struct hl_user_pending_interrupt *requested_offset_record =
+                               (struct hl_user_pending_interrupt *)ts_buff->kernel_buff_address +
+                               ts_offset;
+       struct hl_user_pending_interrupt *cb_last =
+                       (struct hl_user_pending_interrupt *)ts_buff->kernel_buff_address +
+                       (ts_buff->kernel_buff_size / sizeof(struct hl_user_pending_interrupt));
+       unsigned long flags, iter_counter = 0;
+       u64 current_cq_counter;
+
+       /* Validate ts_offset not exceeding last max */
+       if (requested_offset_record > cb_last) {
+               dev_err(ts_buff->hdev->dev, "Ts offset exceeds max CB offset(0x%llx)\n",
+                                                               (u64)(uintptr_t)cb_last);
+               return -EINVAL;
+       }
+
+start_over:
+       spin_lock_irqsave(wait_list_lock, flags);
+
+       /* Unregister only if we didn't reach the target value
+        * since in this case there will be no handling in irq context
+        * and then it's safe to delete the node out of the interrupt list
+        * then re-use it on other interrupt
+        */
+       if (requested_offset_record->ts_reg_info.in_use) {
+               current_cq_counter = *requested_offset_record->cq_kernel_addr;
+               if (current_cq_counter < requested_offset_record->cq_target_value) {
+                       list_del(&requested_offset_record->wait_list_node);
+                       spin_unlock_irqrestore(wait_list_lock, flags);
+
+                       hl_ts_put(requested_offset_record->ts_reg_info.ts_buff);
+                       hl_cb_put(requested_offset_record->ts_reg_info.cq_cb);
+
+                       dev_dbg(ts_buff->hdev->dev, "ts node removed from interrupt list now can re-use\n");
+               } else {
+                       dev_dbg(ts_buff->hdev->dev, "ts node in middle of irq handling\n");
+
+                       /* irq handling in the middle give it time to finish */
+                       spin_unlock_irqrestore(wait_list_lock, flags);
+                       usleep_range(1, 10);
+                       if (++iter_counter == MAX_TS_ITER_NUM) {
+                               dev_err(ts_buff->hdev->dev, "handling registration interrupt took too long!!\n");
+                               return -EINVAL;
+                       }
+
+                       goto start_over;
+               }
+       } else {
+               spin_unlock_irqrestore(wait_list_lock, flags);
+       }
+
+       /* Fill up the new registration node info */
+       requested_offset_record->ts_reg_info.in_use = 1;
+       requested_offset_record->ts_reg_info.ts_buff = ts_buff;
+       requested_offset_record->ts_reg_info.cq_cb = cq_cb;
+       requested_offset_record->ts_reg_info.timestamp_kernel_addr =
+                       (u64 *) ts_buff->user_buff_address + ts_offset;
+       requested_offset_record->cq_kernel_addr =
+                       (u64 *) cq_cb->kernel_address + cq_offset;
+       requested_offset_record->cq_target_value = target_value;
+
+       *pend = requested_offset_record;
+
+       dev_dbg(ts_buff->hdev->dev, "Found available node in TS kernel CB(0x%llx)\n",
+                                               (u64)(uintptr_t)requested_offset_record);
+       return 0;
+}
+
 static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx,
-                               struct hl_cb_mgr *cb_mgr, u64 timeout_us,
-                               u64 cq_counters_handle, u64 cq_counters_offset,
+                               struct hl_cb_mgr *cb_mgr, struct hl_ts_mgr *ts_mgr,
+                               u64 timeout_us, u64 cq_counters_handle, u64 cq_counters_offset,
                                u64 target_value, struct hl_user_interrupt *interrupt,
-                               u32 *status,
-                               u64 *timestamp)
+                               bool register_ts_record, u64 ts_handle, u64 ts_offset,
+                               u32 *status, u64 *timestamp)
 {
+       u32 cq_patched_handle, ts_patched_handle;
        struct hl_user_pending_interrupt *pend;
+       struct hl_ts_buff *ts_buff;
+       struct hl_cb *cq_cb;
        unsigned long timeout, flags;
        long completion_rc;
-       struct hl_cb *cb;
        int rc = 0;
-       u32 handle;
 
        timeout = hl_usecs64_to_jiffies(timeout_us);
 
        hl_ctx_get(hdev, ctx);
 
-       cq_counters_handle >>= PAGE_SHIFT;
-       handle = (u32) cq_counters_handle;
-
-       cb = hl_cb_get(hdev, cb_mgr, handle);
-       if (!cb) {
-               hl_ctx_put(ctx);
-               return -EINVAL;
+       cq_patched_handle = lower_32_bits(cq_counters_handle >> PAGE_SHIFT);
+       cq_cb = hl_cb_get(hdev, cb_mgr, cq_patched_handle);
+       if (!cq_cb) {
+               rc = -EINVAL;
+               goto put_ctx;
        }
 
-       pend = kzalloc(sizeof(*pend), GFP_KERNEL);
-       if (!pend) {
-               hl_cb_put(cb);
-               hl_ctx_put(ctx);
-               return -ENOMEM;
-       }
+       if (register_ts_record) {
+               dev_dbg(hdev->dev, "Timestamp registration: interrupt id: %u, ts offset: %llu, cq_offset: %llu\n",
+                                       interrupt->interrupt_id, ts_offset, cq_counters_offset);
 
-       hl_fence_init(&pend->fence, ULONG_MAX);
+               ts_patched_handle = lower_32_bits(ts_handle >> PAGE_SHIFT);
+               ts_buff = hl_ts_get(hdev, ts_mgr, ts_patched_handle);
+               if (!ts_buff) {
+                       rc = -EINVAL;
+                       goto put_cq_cb;
+               }
 
-       pend->cq_kernel_addr = (u64 *) cb->kernel_address + cq_counters_offset;
-       pend->cq_target_value = target_value;
+               /* Find first available record */
+               rc = ts_buff_get_kernel_ts_record(ts_buff, cq_cb, ts_offset,
+                                               cq_counters_offset, target_value,
+                                               &interrupt->wait_list_lock, &pend);
+               if (rc)
+                       goto put_ts_buff;
+       } else {
+               pend = kzalloc(sizeof(*pend), GFP_KERNEL);
+               if (!pend) {
+                       rc = -ENOMEM;
+                       goto put_cq_cb;
+               }
+               hl_fence_init(&pend->fence, ULONG_MAX);
+               pend->cq_kernel_addr = (u64 *) cq_cb->kernel_address + cq_counters_offset;
+               pend->cq_target_value = target_value;
+       }
+
+       spin_lock_irqsave(&interrupt->wait_list_lock, flags);
 
        /* We check for completion value as interrupt could have been received
         * before we added the node to the wait list
         */
        if (*pend->cq_kernel_addr >= target_value) {
+               if (register_ts_record)
+                       pend->ts_reg_info.in_use = 0;
+               spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
+
                *status = HL_WAIT_CS_STATUS_COMPLETED;
-               /* There was no interrupt, we assume the completion is now. */
-               pend->fence.timestamp = ktime_get();
-       }
 
-       if (!timeout_us || (*status == HL_WAIT_CS_STATUS_COMPLETED))
+               if (register_ts_record) {
+                       *pend->ts_reg_info.timestamp_kernel_addr = ktime_get_ns();
+                       goto put_ts_buff;
+               } else {
+                       pend->fence.timestamp = ktime_get();
+                       goto set_timestamp;
+               }
+       } else if (!timeout_us) {
+               spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
+               *status = HL_WAIT_CS_STATUS_BUSY;
+               pend->fence.timestamp = ktime_get();
                goto set_timestamp;
+       }
 
        /* Add pending user interrupt to relevant list for the interrupt
-        * handler to monitor
+        * handler to monitor.
+        * Note that we cannot have sorted list by target value,
+        * in order to shorten the list pass loop, since
+        * same list could have nodes for different cq counter handle.
         */
-       spin_lock_irqsave(&interrupt->wait_list_lock, flags);
        list_add_tail(&pend->wait_list_node, &interrupt->wait_list_head);
        spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
 
+       if (register_ts_record) {
+               rc = *status = HL_WAIT_CS_STATUS_COMPLETED;
+               goto ts_registration_exit;
+       }
+
        /* Wait for interrupt handler to signal completion */
        completion_rc = wait_for_completion_interruptible_timeout(&pend->fence.completion,
                                                                timeout);
@@ -2932,23 +3056,41 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx,
                                rc = -EIO;
                                *status = HL_WAIT_CS_STATUS_ABORTED;
                        } else {
-                               dev_err_ratelimited(hdev->dev, "Waiting for interrupt ID %d timedout\n",
-                                               interrupt->interrupt_id);
-                               rc = -ETIMEDOUT;
+                               /* The wait has timed-out. We don't know anything beyond that
+                                * because the workload wasn't submitted through the driver.
+                                * Therefore, from driver's perspective, the workload is still
+                                * executing.
+                                */
+                               rc = 0;
+                               *status = HL_WAIT_CS_STATUS_BUSY;
                        }
-                       *status = HL_WAIT_CS_STATUS_BUSY;
                }
        }
 
+       /*
+        * We keep removing the node from list here, and not at the irq handler
+        * for completion timeout case. and if it's a registration
+        * for ts record, the node will be deleted in the irq handler after
+        * we reach the target value.
+        */
        spin_lock_irqsave(&interrupt->wait_list_lock, flags);
        list_del(&pend->wait_list_node);
        spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
 
 set_timestamp:
        *timestamp = ktime_to_ns(pend->fence.timestamp);
-
        kfree(pend);
-       hl_cb_put(cb);
+       hl_cb_put(cq_cb);
+ts_registration_exit:
+       hl_ctx_put(ctx);
+
+       return rc;
+
+put_ts_buff:
+       hl_ts_put(ts_buff);
+put_cq_cb:
+       hl_cb_put(cq_cb);
+put_ctx:
        hl_ctx_put(ctx);
 
        return rc;
@@ -3049,6 +3191,12 @@ wait_again:
                        interrupt->interrupt_id);
                rc = -EINTR;
        } else {
+               /* The wait has timed-out. We don't know anything beyond that
+                * because the workload wasn't submitted through the driver.
+                * Therefore, from driver's perspective, the workload is still
+                * executing.
+                */
+               rc = 0;
                *status = HL_WAIT_CS_STATUS_BUSY;
        }
 
@@ -3101,23 +3249,20 @@ static int hl_interrupt_wait_ioctl(struct hl_fpriv *hpriv, void *data)
                interrupt = &hdev->user_interrupt[interrupt_id - first_interrupt];
 
        if (args->in.flags & HL_WAIT_CS_FLAGS_INTERRUPT_KERNEL_CQ)
-               rc = _hl_interrupt_wait_ioctl(hdev, hpriv->ctx, &hpriv->cb_mgr,
+               rc = _hl_interrupt_wait_ioctl(hdev, hpriv->ctx, &hpriv->cb_mgr, &hpriv->ts_mem_mgr,
                                args->in.interrupt_timeout_us, args->in.cq_counters_handle,
                                args->in.cq_counters_offset,
-                               args->in.target, interrupt, &status,
-                               &timestamp);
+                               args->in.target, interrupt,
+                               !!(args->in.flags & HL_WAIT_CS_FLAGS_REGISTER_INTERRUPT),
+                               args->in.timestamp_handle, args->in.timestamp_offset,
+                               &status, &timestamp);
        else
                rc = _hl_interrupt_wait_ioctl_user_addr(hdev, hpriv->ctx,
                                args->in.interrupt_timeout_us, args->in.addr,
                                args->in.target, interrupt, &status,
                                &timestamp);
-       if (rc) {
-               if (rc != -EINTR)
-                       dev_err_ratelimited(hdev->dev,
-                               "interrupt_wait_ioctl failed (%d)\n", rc);
-
+       if (rc)
                return rc;
-       }
 
        memset(args, 0, sizeof(*args));
        args->out.status = status;
index fc084ee..f184955 100644 (file)
@@ -890,6 +890,8 @@ static ssize_t hl_set_power_state(struct file *f, const char __user *buf,
                pci_set_power_state(hdev->pdev, PCI_D0);
                pci_restore_state(hdev->pdev);
                rc = pci_enable_device(hdev->pdev);
+               if (rc < 0)
+                       return rc;
        } else if (value == 2) {
                pci_save_state(hdev->pdev);
                pci_disable_device(hdev->pdev);
@@ -1054,42 +1056,12 @@ static ssize_t hl_device_write(struct file *f, const char __user *buf,
 static ssize_t hl_clk_gate_read(struct file *f, char __user *buf,
                                        size_t count, loff_t *ppos)
 {
-       struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
-       struct hl_device *hdev = entry->hdev;
-       char tmp_buf[200];
-       ssize_t rc;
-
-       if (*ppos)
-               return 0;
-
-       sprintf(tmp_buf, "0x%llx\n", hdev->clock_gating_mask);
-       rc = simple_read_from_buffer(buf, count, ppos, tmp_buf,
-                       strlen(tmp_buf) + 1);
-
-       return rc;
+       return 0;
 }
 
 static ssize_t hl_clk_gate_write(struct file *f, const char __user *buf,
                                     size_t count, loff_t *ppos)
 {
-       struct hl_dbg_device_entry *entry = file_inode(f)->i_private;
-       struct hl_device *hdev = entry->hdev;
-       u64 value;
-       ssize_t rc;
-
-       if (hdev->reset_info.in_reset) {
-               dev_warn_ratelimited(hdev->dev,
-                               "Can't change clock gating during reset\n");
-               return 0;
-       }
-
-       rc = kstrtoull_from_user(buf, count, 16, &value);
-       if (rc)
-               return rc;
-
-       hdev->clock_gating_mask = value;
-       hdev->asic_funcs->set_clock_gating(hdev);
-
        return count;
 }
 
@@ -1101,6 +1073,9 @@ static ssize_t hl_stop_on_err_read(struct file *f, char __user *buf,
        char tmp_buf[200];
        ssize_t rc;
 
+       if (!hdev->asic_prop.configurable_stop_on_err)
+               return -EOPNOTSUPP;
+
        if (*ppos)
                return 0;
 
@@ -1119,6 +1094,9 @@ static ssize_t hl_stop_on_err_write(struct file *f, const char __user *buf,
        u32 value;
        ssize_t rc;
 
+       if (!hdev->asic_prop.configurable_stop_on_err)
+               return -EOPNOTSUPP;
+
        if (hdev->reset_info.in_reset) {
                dev_warn_ratelimited(hdev->dev,
                                "Can't change stop on error during reset\n");
index 733338a..dc9341a 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 
 /*
- * Copyright 2016-2021 HabanaLabs, Ltd.
+ * Copyright 2016-2022 HabanaLabs, Ltd.
  * All Rights Reserved.
  */
 
@@ -13,6 +13,8 @@
 #include <linux/pci.h>
 #include <linux/hwmon.h>
 
+#define HL_RESET_DELAY_USEC            10000   /* 10ms */
+
 enum hl_device_status hl_device_status(struct hl_device *hdev)
 {
        enum hl_device_status status;
@@ -145,6 +147,7 @@ static int hl_device_release(struct inode *inode, struct file *filp)
        hl_release_pending_user_interrupts(hpriv->hdev);
 
        hl_cb_mgr_fini(hdev, &hpriv->cb_mgr);
+       hl_ts_mgr_fini(hpriv->hdev, &hpriv->ts_mem_mgr);
        hl_ctx_mgr_fini(hdev, &hpriv->ctx_mgr);
 
        if (!hl_hpriv_put(hpriv))
@@ -209,6 +212,9 @@ static int hl_mmap(struct file *filp, struct vm_area_struct *vma)
 
        case HL_MMAP_TYPE_BLOCK:
                return hl_hw_block_mmap(hpriv, vma);
+
+       case HL_MMAP_TYPE_TS_BUFF:
+               return hl_ts_mmap(hpriv, vma);
        }
 
        return -EINVAL;
@@ -410,10 +416,10 @@ static int device_early_init(struct hl_device *hdev)
                goto free_cq_wq;
        }
 
-       hdev->sob_reset_wq = alloc_workqueue("hl-sob-reset", WQ_UNBOUND, 0);
-       if (!hdev->sob_reset_wq) {
+       hdev->ts_free_obj_wq = alloc_workqueue("hl-ts-free-obj", WQ_UNBOUND, 0);
+       if (!hdev->ts_free_obj_wq) {
                dev_err(hdev->dev,
-                       "Failed to allocate SOB reset workqueue\n");
+                       "Failed to allocate Timestamp registration free workqueue\n");
                rc = -ENOMEM;
                goto free_eq_wq;
        }
@@ -422,7 +428,7 @@ static int device_early_init(struct hl_device *hdev)
                                        GFP_KERNEL);
        if (!hdev->hl_chip_info) {
                rc = -ENOMEM;
-               goto free_sob_reset_wq;
+               goto free_ts_free_wq;
        }
 
        rc = hl_mmu_if_set_funcs(hdev);
@@ -461,8 +467,8 @@ free_cb_mgr:
        hl_cb_mgr_fini(hdev, &hdev->kernel_cb_mgr);
 free_chip_info:
        kfree(hdev->hl_chip_info);
-free_sob_reset_wq:
-       destroy_workqueue(hdev->sob_reset_wq);
+free_ts_free_wq:
+       destroy_workqueue(hdev->ts_free_obj_wq);
 free_eq_wq:
        destroy_workqueue(hdev->eq_wq);
 free_cq_wq:
@@ -501,7 +507,7 @@ static void device_early_fini(struct hl_device *hdev)
 
        kfree(hdev->hl_chip_info);
 
-       destroy_workqueue(hdev->sob_reset_wq);
+       destroy_workqueue(hdev->ts_free_obj_wq);
        destroy_workqueue(hdev->eq_wq);
        destroy_workqueue(hdev->device_reset_work.wq);
 
@@ -610,7 +616,7 @@ int hl_device_utilization(struct hl_device *hdev, u32 *utilization)
        u64 max_power, curr_power, dc_power, dividend;
        int rc;
 
-       max_power = hdev->asic_prop.max_power_default;
+       max_power = hdev->max_power;
        dc_power = hdev->asic_prop.dc_power_default;
        rc = hl_fw_cpucp_power_get(hdev, &curr_power);
 
@@ -644,9 +650,6 @@ int hl_device_set_debug_mode(struct hl_device *hdev, struct hl_ctx *ctx, bool en
 
                hdev->in_debug = 0;
 
-               if (!hdev->reset_info.hard_reset_pending)
-                       hdev->asic_funcs->set_clock_gating(hdev);
-
                goto out;
        }
 
@@ -657,7 +660,6 @@ int hl_device_set_debug_mode(struct hl_device *hdev, struct hl_ctx *ctx, bool en
                goto out;
        }
 
-       hdev->asic_funcs->disable_clock_gating(hdev);
        hdev->in_debug = 1;
 
 out:
@@ -685,7 +687,8 @@ static void take_release_locks(struct hl_device *hdev)
        mutex_unlock(&hdev->fpriv_ctrl_list_lock);
 }
 
-static void cleanup_resources(struct hl_device *hdev, bool hard_reset, bool fw_reset)
+static void cleanup_resources(struct hl_device *hdev, bool hard_reset, bool fw_reset,
+                               bool skip_wq_flush)
 {
        if (hard_reset)
                device_late_fini(hdev);
@@ -698,7 +701,7 @@ static void cleanup_resources(struct hl_device *hdev, bool hard_reset, bool fw_r
        hdev->asic_funcs->halt_engines(hdev, hard_reset, fw_reset);
 
        /* Go over all the queues, release all CS and their jobs */
-       hl_cs_rollback_all(hdev);
+       hl_cs_rollback_all(hdev, skip_wq_flush);
 
        /* Release all pending user interrupts, each pending user interrupt
         * holds a reference to user context
@@ -978,7 +981,8 @@ static void handle_reset_trigger(struct hl_device *hdev, u32 flags)
 int hl_device_reset(struct hl_device *hdev, u32 flags)
 {
        bool hard_reset, from_hard_reset_thread, fw_reset, hard_instead_soft = false,
-                       reset_upon_device_release = false, schedule_hard_reset = false;
+                       reset_upon_device_release = false, schedule_hard_reset = false,
+                       skip_wq_flush, delay_reset;
        u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0};
        struct hl_ctx *ctx;
        int i, rc;
@@ -991,6 +995,8 @@ int hl_device_reset(struct hl_device *hdev, u32 flags)
        hard_reset = !!(flags & HL_DRV_RESET_HARD);
        from_hard_reset_thread = !!(flags & HL_DRV_RESET_FROM_RESET_THR);
        fw_reset = !!(flags & HL_DRV_RESET_BYPASS_REQ_TO_FW);
+       skip_wq_flush = !!(flags & HL_DRV_RESET_DEV_RELEASE);
+       delay_reset = !!(flags & HL_DRV_RESET_DELAY);
 
        if (!hard_reset && !hdev->asic_prop.supports_soft_reset) {
                hard_instead_soft = true;
@@ -1040,6 +1046,9 @@ do_reset:
                hdev->reset_info.in_reset = 1;
                spin_unlock(&hdev->reset_info.lock);
 
+               if (delay_reset)
+                       usleep_range(HL_RESET_DELAY_USEC, HL_RESET_DELAY_USEC << 1);
+
                handle_reset_trigger(hdev, flags);
 
                /* This still allows the completion of some KDMA ops */
@@ -1076,7 +1085,7 @@ again:
                return 0;
        }
 
-       cleanup_resources(hdev, hard_reset, fw_reset);
+       cleanup_resources(hdev, hard_reset, fw_reset, skip_wq_flush);
 
 kill_processes:
        if (hard_reset) {
@@ -1232,7 +1241,7 @@ kill_processes:
                        goto out_err;
                }
 
-               hl_set_max_power(hdev);
+               hl_fw_set_max_power(hdev);
        } else {
                rc = hdev->asic_funcs->non_hard_reset_late_init(hdev);
                if (rc) {
@@ -1297,11 +1306,14 @@ out_err:
                hdev->reset_info.hard_reset_cnt++;
        } else if (reset_upon_device_release) {
                dev_err(hdev->dev, "Failed to reset device after user release\n");
+               flags |= HL_DRV_RESET_HARD;
+               flags &= ~HL_DRV_RESET_DEV_RELEASE;
                hard_reset = true;
                goto again;
        } else {
                dev_err(hdev->dev, "Failed to do soft-reset\n");
                hdev->reset_info.soft_reset_cnt++;
+               flags |= HL_DRV_RESET_HARD;
                hard_reset = true;
                goto again;
        }
@@ -1538,7 +1550,8 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
        /* Need to call this again because the max power might change,
         * depending on card type for certain ASICs
         */
-       hl_set_max_power(hdev);
+       if (hdev->asic_prop.set_max_power_on_device_init)
+               hl_fw_set_max_power(hdev);
 
        /*
         * hl_hwmon_init() must be called after device_late_init(), because only
@@ -1682,7 +1695,7 @@ void hl_device_fini(struct hl_device *hdev)
 
        hl_hwmon_fini(hdev);
 
-       cleanup_resources(hdev, true, false);
+       cleanup_resources(hdev, true, false, false);
 
        /* Kill processes here after CS rollback. This is because the process
         * can't really exit until all its CSs are done, which is what we
index 6775c5c..3262126 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 
 /*
- * Copyright 2016-2021 HabanaLabs, Ltd.
+ * Copyright 2016-2022 HabanaLabs, Ltd.
  * All Rights Reserved.
  */
 
@@ -214,7 +214,7 @@ int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg,
        dma_addr_t pkt_dma_addr;
        struct hl_bd *sent_bd;
        u32 tmp, expected_ack_val, pi;
-       int rc = 0;
+       int rc;
 
        pkt = hdev->asic_funcs->cpu_accessible_dma_pool_alloc(hdev, len,
                                                                &pkt_dma_addr);
@@ -228,8 +228,11 @@ int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg,
 
        mutex_lock(&hdev->send_cpu_message_lock);
 
-       if (hdev->disabled)
+       /* CPU-CP messages can be sent during soft-reset */
+       if (hdev->disabled && !hdev->reset_info.is_in_soft_reset) {
+               rc = 0;
                goto out;
+       }
 
        if (hdev->device_cpu_disabled) {
                rc = -EIO;
@@ -958,15 +961,17 @@ int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, u32 pll_index,
 
        rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),
                        HL_CPUCP_INFO_TIMEOUT_USEC, &result);
-       if (rc)
+       if (rc) {
                dev_err(hdev->dev, "Failed to read PLL info, error %d\n", rc);
+               return rc;
+       }
 
        pll_freq_arr[0] = FIELD_GET(CPUCP_PKT_RES_PLL_OUT0_MASK, result);
        pll_freq_arr[1] = FIELD_GET(CPUCP_PKT_RES_PLL_OUT1_MASK, result);
        pll_freq_arr[2] = FIELD_GET(CPUCP_PKT_RES_PLL_OUT2_MASK, result);
        pll_freq_arr[3] = FIELD_GET(CPUCP_PKT_RES_PLL_OUT3_MASK, result);
 
-       return rc;
+       return 0;
 }
 
 int hl_fw_cpucp_power_get(struct hl_device *hdev, u64 *power)
@@ -1202,8 +1207,6 @@ static int hl_fw_read_preboot_caps(struct hl_device *hdev,
                hdev,
                cpu_boot_status_reg,
                status,
-               (status == CPU_BOOT_STATUS_IN_UBOOT) ||
-               (status == CPU_BOOT_STATUS_DRAM_RDY) ||
                (status == CPU_BOOT_STATUS_NIC_FW_RDY) ||
                (status == CPU_BOOT_STATUS_READY_TO_BOOT) ||
                (status == CPU_BOOT_STATUS_WAITING_FOR_BOOT_FIT),
@@ -2682,3 +2685,138 @@ int hl_fw_init_cpu(struct hl_device *hdev)
                        hl_fw_dynamic_init_cpu(hdev, fw_loader) :
                        hl_fw_static_init_cpu(hdev, fw_loader);
 }
+
+void hl_fw_set_pll_profile(struct hl_device *hdev)
+{
+       hl_fw_set_frequency(hdev, hdev->asic_prop.clk_pll_index,
+                               hdev->asic_prop.max_freq_value);
+}
+
+int hl_fw_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk)
+{
+       long value;
+
+       if (!hl_device_operational(hdev, NULL))
+               return -ENODEV;
+
+       if (!hdev->pdev) {
+               *cur_clk = 0;
+               *max_clk = 0;
+               return 0;
+       }
+
+       value = hl_fw_get_frequency(hdev, hdev->asic_prop.clk_pll_index, false);
+
+       if (value < 0) {
+               dev_err(hdev->dev, "Failed to retrieve device max clock %ld\n", value);
+               return value;
+       }
+
+       *max_clk = (value / 1000 / 1000);
+
+       value = hl_fw_get_frequency(hdev, hdev->asic_prop.clk_pll_index, true);
+
+       if (value < 0) {
+               dev_err(hdev->dev, "Failed to retrieve device current clock %ld\n", value);
+               return value;
+       }
+
+       *cur_clk = (value / 1000 / 1000);
+
+       return 0;
+}
+
+long hl_fw_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr)
+{
+       struct cpucp_packet pkt;
+       u32 used_pll_idx;
+       u64 result;
+       int rc;
+
+       rc = get_used_pll_index(hdev, pll_index, &used_pll_idx);
+       if (rc)
+               return rc;
+
+       memset(&pkt, 0, sizeof(pkt));
+
+       if (curr)
+               pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_CURR_GET <<
+                                               CPUCP_PKT_CTL_OPCODE_SHIFT);
+       else
+               pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_GET << CPUCP_PKT_CTL_OPCODE_SHIFT);
+
+       pkt.pll_index = cpu_to_le32((u32)used_pll_idx);
+
+       rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, &result);
+
+       if (rc) {
+               dev_err(hdev->dev, "Failed to get frequency of PLL %d, error %d\n",
+                       used_pll_idx, rc);
+               return rc;
+       }
+
+       return (long) result;
+}
+
+void hl_fw_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq)
+{
+       struct cpucp_packet pkt;
+       u32 used_pll_idx;
+       int rc;
+
+       rc = get_used_pll_index(hdev, pll_index, &used_pll_idx);
+       if (rc)
+               return;
+
+       memset(&pkt, 0, sizeof(pkt));
+
+       pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_SET << CPUCP_PKT_CTL_OPCODE_SHIFT);
+       pkt.pll_index = cpu_to_le32((u32)used_pll_idx);
+       pkt.value = cpu_to_le64(freq);
+
+       rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, NULL);
+
+       if (rc)
+               dev_err(hdev->dev, "Failed to set frequency to PLL %d, error %d\n",
+                       used_pll_idx, rc);
+}
+
+long hl_fw_get_max_power(struct hl_device *hdev)
+{
+       struct cpucp_packet pkt;
+       u64 result;
+       int rc;
+
+       memset(&pkt, 0, sizeof(pkt));
+
+       pkt.ctl = cpu_to_le32(CPUCP_PACKET_MAX_POWER_GET << CPUCP_PKT_CTL_OPCODE_SHIFT);
+
+       rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, &result);
+
+       if (rc) {
+               dev_err(hdev->dev, "Failed to get max power, error %d\n", rc);
+               return rc;
+       }
+
+       return result;
+}
+
+void hl_fw_set_max_power(struct hl_device *hdev)
+{
+       struct cpucp_packet pkt;
+       int rc;
+
+       /* TODO: remove this after simulator supports this packet */
+       if (!hdev->pdev)
+               return;
+
+       memset(&pkt, 0, sizeof(pkt));
+
+       pkt.ctl = cpu_to_le32(CPUCP_PACKET_MAX_POWER_SET << CPUCP_PKT_CTL_OPCODE_SHIFT);
+       pkt.value = cpu_to_le64(hdev->max_power);
+
+       rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, NULL);
+
+       if (rc)
+               dev_err(hdev->dev, "Failed to set max power, error %d\n", rc);
+}
index cb710fd..1edaf6a 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0
  *
- * Copyright 2016-2021 HabanaLabs, Ltd.
+ * Copyright 2016-2022 HabanaLabs, Ltd.
  * All Rights Reserved.
  *
  */
 #define HL_NAME                                "habanalabs"
 
 /* Use upper bits of mmap offset to store habana driver specific information.
- * bits[63:61] - Encode mmap type
+ * bits[63:59] - Encode mmap type
  * bits[45:0]  - mmap offset value
  *
  * NOTE: struct vm_area_struct.vm_pgoff uses offset in pages. Hence, these
  *  defines are w.r.t to PAGE_SIZE
  */
-#define HL_MMAP_TYPE_SHIFT             (61 - PAGE_SHIFT)
-#define HL_MMAP_TYPE_MASK              (0x7ull << HL_MMAP_TYPE_SHIFT)
+#define HL_MMAP_TYPE_SHIFT             (59 - PAGE_SHIFT)
+#define HL_MMAP_TYPE_MASK              (0x1full << HL_MMAP_TYPE_SHIFT)
+#define HL_MMAP_TYPE_TS_BUFF           (0x10ull << HL_MMAP_TYPE_SHIFT)
 #define HL_MMAP_TYPE_BLOCK             (0x4ull << HL_MMAP_TYPE_SHIFT)
 #define HL_MMAP_TYPE_CB                        (0x2ull << HL_MMAP_TYPE_SHIFT)
 
@@ -141,6 +142,9 @@ enum hl_mmu_page_table_location {
  *
  * - HL_DRV_RESET_FW_FATAL_ERR
  *       Set if reset is due to a fatal error from FW
+ *
+ * - HL_DRV_RESET_DELAY
+ *       Set if a delay should be added before the reset
  */
 
 #define HL_DRV_RESET_HARD              (1 << 0)
@@ -150,6 +154,7 @@ enum hl_mmu_page_table_location {
 #define HL_DRV_RESET_DEV_RELEASE       (1 << 4)
 #define HL_DRV_RESET_BYPASS_REQ_TO_FW  (1 << 5)
 #define HL_DRV_RESET_FW_FATAL_ERR      (1 << 6)
+#define HL_DRV_RESET_DELAY             (1 << 7)
 
 #define HL_MAX_SOBS_PER_MONITOR        8
 
@@ -402,8 +407,11 @@ enum hl_device_hw_state {
  * @hop4_mask: mask to get the PTE address in hop 4.
  * @hop5_mask: mask to get the PTE address in hop 5.
  * @last_mask: mask to get the bit indicating this is the last hop.
+ * @pgt_size: size for page tables.
  * @page_size: default page size used to allocate memory.
  * @num_hops: The amount of hops supported by the translation table.
+ * @hop_table_size: HOP table size.
+ * @hop0_tables_total_size: total size for all HOP0 tables.
  * @host_resident: Should the MMU page table reside in host memory or in the
  *                 device DRAM.
  */
@@ -423,8 +431,11 @@ struct hl_mmu_properties {
        u64     hop4_mask;
        u64     hop5_mask;
        u64     last_mask;
+       u64     pgt_size;
        u32     page_size;
        u32     num_hops;
+       u32     hop_table_size;
+       u32     hop0_tables_total_size;
        u8      host_resident;
 };
 
@@ -554,6 +565,9 @@ struct hl_hints_range {
  *                              use-case of doing soft-reset in training (due
  *                              to the fact that training runs on multiple
  *                              devices)
+ * @configurable_stop_on_err: is stop-on-error option configurable via debugfs.
+ * @set_max_power_on_device_init: true if need to set max power in F/W on device init.
+ * @supports_user_set_page_size: true if user can set the allocation page size.
  */
 struct asic_fixed_properties {
        struct hw_queue_properties      *hw_queues_props;
@@ -637,6 +651,9 @@ struct asic_fixed_properties {
        u8                              use_get_power_for_reset_history;
        u8                              supports_soft_reset;
        u8                              allow_inference_soft_reset;
+       u8                              configurable_stop_on_err;
+       u8                              set_max_power_on_device_init;
+       u8                              supports_user_set_page_size;
 };
 
 /**
@@ -703,6 +720,40 @@ struct hl_cb_mgr {
        struct idr              cb_handles; /* protected by cb_lock */
 };
 
+/**
+ * struct hl_ts_mgr - describes the timestamp registration memory manager.
+ * @ts_lock: protects ts_handles.
+ * @ts_handles: an idr to hold all ts bufferes handles.
+ */
+struct hl_ts_mgr {
+       spinlock_t              ts_lock;
+       struct idr              ts_handles;
+};
+
+/**
+ * struct hl_ts_buff - describes a timestamp buffer.
+ * @refcount: reference counter for usage of the buffer.
+ * @hdev: pointer to device this buffer belongs to.
+ * @mmap: true if the buff is currently mapped to user.
+ * @kernel_buff_address: Holds the internal buffer's kernel virtual address.
+ * @user_buff_address: Holds the user buffer's kernel virtual address.
+ * @id: the buffer ID.
+ * @mmap_size: Holds the buffer size that was mmaped.
+ * @kernel_buff_size: Holds the internal kernel buffer size.
+ * @user_buff_size: Holds the user buffer size.
+ */
+struct hl_ts_buff {
+       struct kref             refcount;
+       struct hl_device        *hdev;
+       atomic_t                mmap;
+       void                    *kernel_buff_address;
+       void                    *user_buff_address;
+       u32                     id;
+       u32                     mmap_size;
+       u32                     kernel_buff_size;
+       u32                     user_buff_size;
+};
+
 /**
  * struct hl_cb - describes a Command Buffer.
  * @refcount: reference counter for usage of the CB.
@@ -880,9 +931,54 @@ struct hl_user_interrupt {
        u32                     interrupt_id;
 };
 
+/**
+ * struct timestamp_reg_free_node - holds the timestamp registration free objects node
+ * @free_objects_node: node in the list free_obj_jobs
+ * @cq_cb: pointer to cq command buffer to be freed
+ * @ts_buff: pointer to timestamp buffer to be freed
+ */
+struct timestamp_reg_free_node {
+       struct list_head        free_objects_node;
+       struct hl_cb            *cq_cb;
+       struct hl_ts_buff       *ts_buff;
+};
+
+/* struct timestamp_reg_work_obj - holds the timestamp registration free objects job
+ * the job will be to pass over the free_obj_jobs list and put refcount to objects
+ * in each node of the list
+ * @free_obj: workqueue object to free timestamp registration node objects
+ * @hdev: pointer to the device structure
+ * @free_obj_head: list of free jobs nodes (node type timestamp_reg_free_node)
+ */
+struct timestamp_reg_work_obj {
+       struct work_struct      free_obj;
+       struct hl_device        *hdev;
+       struct list_head        *free_obj_head;
+};
+
+/* struct timestamp_reg_info - holds the timestamp registration related data.
+ * @ts_buff: pointer to the timestamp buffer which include both user/kernel buffers.
+ *           relevant only when doing timestamps records registration.
+ * @cq_cb: pointer to CQ counter CB.
+ * @timestamp_kernel_addr: timestamp handle address, where to set timestamp
+ *                         relevant only when doing timestamps records
+ *                         registration.
+ * @in_use: indicates if the node already in use. relevant only when doing
+ *          timestamps records registration, since in this case the driver
+ *          will have it's own buffer which serve as a records pool instead of
+ *          allocating records dynamically.
+ */
+struct timestamp_reg_info {
+       struct hl_ts_buff       *ts_buff;
+       struct hl_cb            *cq_cb;
+       u64                     *timestamp_kernel_addr;
+       u8                      in_use;
+};
+
 /**
  * struct hl_user_pending_interrupt - holds a context to a user thread
  *                                    pending on an interrupt
+ * @ts_reg_info: holds the timestamps registration nodes info
  * @wait_list_node: node in the list of user threads pending on an interrupt
  * @fence: hl fence object for interrupt completion
  * @cq_target_value: CQ target value
@@ -890,10 +986,11 @@ struct hl_user_interrupt {
  *                  handler for taget value comparison
  */
 struct hl_user_pending_interrupt {
-       struct list_head        wait_list_node;
-       struct hl_fence         fence;
-       u64                     cq_target_value;
-       u64                     *cq_kernel_addr;
+       struct timestamp_reg_info       ts_reg_info;
+       struct list_head                wait_list_node;
+       struct hl_fence                 fence;
+       u64                             cq_target_value;
+       u64                             *cq_kernel_addr;
 };
 
 /**
@@ -1155,7 +1252,6 @@ struct fw_load_mgr {
  *                    internal memory via DMA engine.
  * @add_device_attr: add ASIC specific device attributes.
  * @handle_eqe: handle event queue entry (IRQ) from CPU-CP.
- * @set_pll_profile: change PLL profile (manual/automatic).
  * @get_events_stat: retrieve event queue entries histogram.
  * @read_pte: read MMU page table entry from DRAM.
  * @write_pte: write MMU page table entry to DRAM.
@@ -1164,9 +1260,6 @@ struct fw_load_mgr {
  * @mmu_invalidate_cache_range: flush specific MMU STLB cache lines with
  *                              ASID-VA-size mask.
  * @send_heartbeat: send is-alive packet to CPU-CP and verify response.
- * @set_clock_gating: enable/disable clock gating per engine according to
- *                    clock gating mask in hdev
- * @disable_clock_gating: disable clock gating completely
  * @debug_coresight: perform certain actions on Coresight for debugging.
  * @is_device_idle: return true if device is idle, false otherwise.
  * @non_hard_reset_late_init: perform certain actions needed after a reset which is not hard-reset
@@ -1187,7 +1280,6 @@ struct fw_load_mgr {
  * @halt_coresight: stop the ETF and ETR traces.
  * @ctx_init: context dependent initialization.
  * @ctx_fini: context dependent cleanup.
- * @get_clk_rate: Retrieve the ASIC current and maximum clock rate in MHz
  * @get_queue_id_for_cq: Get the H/W queue id related to the given CQ index.
  * @load_firmware_to_device: load the firmware to the device's memory
  * @load_boot_fit_to_device: load boot fit to device's memory
@@ -1225,6 +1317,8 @@ struct fw_load_mgr {
  * @get_sob_addr: get SOB base address offset.
  * @set_pci_memory_regions: setting properties of PCI memory regions
  * @get_stream_master_qid_arr: get pointer to stream masters QID array
+ * @is_valid_dram_page_size: return true if page size is supported in device
+ *                           memory allocation, otherwise false.
  */
 struct hl_asic_funcs {
        int (*early_init)(struct hl_device *hdev);
@@ -1285,12 +1379,10 @@ struct hl_asic_funcs {
                                bool user_address, u64 val);
        int (*debugfs_read_dma)(struct hl_device *hdev, u64 addr, u32 size,
                                void *blob_addr);
-       void (*add_device_attr)(struct hl_device *hdev,
-                               struct attribute_group *dev_attr_grp);
+       void (*add_device_attr)(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp,
+                               struct attribute_group *dev_vrm_attr_grp);
        void (*handle_eqe)(struct hl_device *hdev,
                                struct hl_eq_entry *eq_entry);
-       void (*set_pll_profile)(struct hl_device *hdev,
-                       enum hl_pll_frequency freq);
        void* (*get_events_stat)(struct hl_device *hdev, bool aggregate,
                                u32 *size);
        u64 (*read_pte)(struct hl_device *hdev, u64 addr);
@@ -1300,8 +1392,6 @@ struct hl_asic_funcs {
        int (*mmu_invalidate_cache_range)(struct hl_device *hdev, bool is_hard,
                                u32 flags, u32 asid, u64 va, u64 size);
        int (*send_heartbeat)(struct hl_device *hdev);
-       void (*set_clock_gating)(struct hl_device *hdev);
-       void (*disable_clock_gating)(struct hl_device *hdev);
        int (*debug_coresight)(struct hl_device *hdev, struct hl_ctx *ctx, void *data);
        bool (*is_device_idle)(struct hl_device *hdev, u64 *mask_arr,
                                        u8 mask_len, struct seq_file *s);
@@ -1320,7 +1410,6 @@ struct hl_asic_funcs {
        void (*halt_coresight)(struct hl_device *hdev, struct hl_ctx *ctx);
        int (*ctx_init)(struct hl_ctx *ctx);
        void (*ctx_fini)(struct hl_ctx *ctx);
-       int (*get_clk_rate)(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk);
        u32 (*get_queue_id_for_cq)(struct hl_device *hdev, u32 cq_idx);
        int (*load_firmware_to_device)(struct hl_device *hdev);
        int (*load_boot_fit_to_device)(struct hl_device *hdev);
@@ -1355,6 +1444,7 @@ struct hl_asic_funcs {
        u32 (*get_sob_addr)(struct hl_device *hdev, u32 sob_id);
        void (*set_pci_memory_regions)(struct hl_device *hdev);
        u32* (*get_stream_master_qid_arr)(void);
+       bool (*is_valid_dram_page_size)(u32 page_size);
 };
 
 
@@ -1742,6 +1832,8 @@ struct hl_vm_hw_block_list_node {
  * @pages: the physical page array.
  * @npages: num physical pages in the pack.
  * @total_size: total size of all the pages in this list.
+ * @node: used to attach to deletion list that is used when all the allocations are cleared
+ *        at the teardown of the context.
  * @mapping_cnt: number of shared mappings.
  * @exporting_cnt: number of dma-buf exporting.
  * @asid: the context related to this list.
@@ -1757,6 +1849,7 @@ struct hl_vm_phys_pg_pack {
        u64                     *pages;
        u64                     npages;
        u64                     total_size;
+       struct list_head        node;
        atomic_t                mapping_cnt;
        u32                     exporting_cnt;
        u32                     asid;
@@ -1834,6 +1927,7 @@ struct hl_debug_params {
  * @ctx: current executing context. TODO: remove for multiple ctx per process
  * @ctx_mgr: context manager to handle multiple context for this FD.
  * @cb_mgr: command buffer manager to handle multiple buffers for this FD.
+ * @ts_mem_mgr: timestamp registration manager for alloc/free/map timestamp buffers.
  * @debugfs_list: list of relevant ASIC debugfs.
  * @dev_node: node in the device list of file private data
  * @refcount: number of related contexts.
@@ -1846,6 +1940,7 @@ struct hl_fpriv {
        struct hl_ctx           *ctx;
        struct hl_ctx_mgr       ctx_mgr;
        struct hl_cb_mgr        cb_mgr;
+       struct hl_ts_mgr        ts_mem_mgr;
        struct list_head        debugfs_list;
        struct list_head        dev_node;
        struct kref             refcount;
@@ -2518,7 +2613,7 @@ struct hl_reset_info {
  * @cq_wq: work queues of completion queues for executing work in process
  *         context.
  * @eq_wq: work queue of event queue for executing work in process context.
- * @sob_reset_wq: work queue for sob reset executions.
+ * @ts_free_obj_wq: work queue for timestamp registration objects release.
  * @kernel_ctx: Kernel driver context structure.
  * @kernel_queues: array of hl_hw_queue.
  * @cs_mirror_list: CS mirror list for TDR.
@@ -2569,9 +2664,6 @@ struct hl_reset_info {
  * @max_power: the max power of the device, as configured by the sysadmin. This
  *             value is saved so in case of hard-reset, the driver will restore
  *             this value and update the F/W after the re-initialization
- * @clock_gating_mask: is clock gating enabled. bitmask that represents the
- *                     different engines. See debugfs-driver-habanalabs for
- *                     details.
  * @boot_error_status_mask: contains a mask of the device boot error status.
  *                          Each bit represents a different error, according to
  *                          the defines in hl_boot_if.h. If the bit is cleared,
@@ -2611,8 +2703,6 @@ struct hl_reset_info {
  * @in_debug: whether the device is in a state where the profiling/tracing infrastructure
  *            can be used. This indication is needed because in some ASICs we need to do
  *            specific operations to enable that infrastructure.
- * @power9_64bit_dma_enable: true to enable 64-bit DMA mask support. Relevant
- *                           only to POWER9 machines.
  * @cdev_sysfs_created: were char devices and sysfs nodes created.
  * @stop_on_err: true if engines should stop on error.
  * @supports_sync_stream: is sync stream supported.
@@ -2651,7 +2741,7 @@ struct hl_device {
        struct hl_user_interrupt        common_user_interrupt;
        struct workqueue_struct         **cq_wq;
        struct workqueue_struct         *eq_wq;
-       struct workqueue_struct         *sob_reset_wq;
+       struct workqueue_struct         *ts_free_obj_wq;
        struct hl_ctx                   *kernel_ctx;
        struct hl_hw_queue              *kernel_queues;
        struct list_head                cs_mirror_list;
@@ -2710,7 +2800,6 @@ struct hl_device {
        atomic64_t                      dram_used_mem;
        u64                             timeout_jiffies;
        u64                             max_power;
-       u64                             clock_gating_mask;
        u64                             boot_error_status_mask;
        u64                             dram_pci_bar_start;
        u64                             last_successful_open_jif;
@@ -2736,7 +2825,6 @@ struct hl_device {
        u8                              device_cpu_disabled;
        u8                              dma_mask;
        u8                              in_debug;
-       u8                              power9_64bit_dma_enable;
        u8                              cdev_sysfs_created;
        u8                              stop_on_err;
        u8                              supports_sync_stream;
@@ -2970,7 +3058,7 @@ int hl_cb_pool_fini(struct hl_device *hdev);
 int hl_cb_va_pool_init(struct hl_ctx *ctx);
 void hl_cb_va_pool_fini(struct hl_ctx *ctx);
 
-void hl_cs_rollback_all(struct hl_device *hdev);
+void hl_cs_rollback_all(struct hl_device *hdev, bool skip_wq_flush);
 struct hl_cs_job *hl_cs_allocate_job(struct hl_device *hdev,
                enum hl_queue_type queue_type, bool is_kernel_allocated_cb);
 void hl_sob_reset_error(struct kref *ref);
@@ -3024,6 +3112,9 @@ int hl_mmu_unmap_contiguous(struct hl_ctx *ctx, u64 virt_addr, u32 size);
 int hl_mmu_invalidate_cache(struct hl_device *hdev, bool is_hard, u32 flags);
 int hl_mmu_invalidate_cache_range(struct hl_device *hdev, bool is_hard,
                                        u32 flags, u32 asid, u64 va, u64 size);
+u64 hl_mmu_get_next_hop_addr(struct hl_ctx *ctx, u64 curr_pte);
+u64 hl_mmu_get_hop_pte_phys_addr(struct hl_ctx *ctx, struct hl_mmu_properties *mmu_prop,
+                                       u8 hop_idx, u64 hop_addr, u64 virt_addr);
 void hl_mmu_swap_out(struct hl_ctx *ctx);
 void hl_mmu_swap_in(struct hl_ctx *ctx);
 int hl_mmu_if_set_funcs(struct hl_device *hdev);
@@ -3094,39 +3185,26 @@ enum pci_region hl_get_pci_memory_region(struct hl_device *hdev, u64 addr);
 int hl_pci_init(struct hl_device *hdev);
 void hl_pci_fini(struct hl_device *hdev);
 
-long hl_get_frequency(struct hl_device *hdev, u32 pll_index,
-                                                               bool curr);
-void hl_set_frequency(struct hl_device *hdev, u32 pll_index,
-                                                               u64 freq);
-int hl_get_temperature(struct hl_device *hdev,
-                      int sensor_index, u32 attr, long *value);
-int hl_set_temperature(struct hl_device *hdev,
-                      int sensor_index, u32 attr, long value);
-int hl_get_voltage(struct hl_device *hdev,
-                  int sensor_index, u32 attr, long *value);
-int hl_get_current(struct hl_device *hdev,
-                  int sensor_index, u32 attr, long *value);
-int hl_get_fan_speed(struct hl_device *hdev,
-                    int sensor_index, u32 attr, long *value);
-int hl_get_pwm_info(struct hl_device *hdev,
-                   int sensor_index, u32 attr, long *value);
-void hl_set_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr,
-                       long value);
-u64 hl_get_max_power(struct hl_device *hdev);
-void hl_set_max_power(struct hl_device *hdev);
-int hl_set_voltage(struct hl_device *hdev,
-                       int sensor_index, u32 attr, long value);
-int hl_set_current(struct hl_device *hdev,
-                       int sensor_index, u32 attr, long value);
-int hl_set_power(struct hl_device *hdev,
-                       int sensor_index, u32 attr, long value);
-int hl_get_power(struct hl_device *hdev,
-                       int sensor_index, u32 attr, long *value);
-int hl_get_clk_rate(struct hl_device *hdev,
-                       u32 *cur_clk, u32 *max_clk);
-void hl_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq);
-void hl_add_device_attr(struct hl_device *hdev,
-                       struct attribute_group *dev_attr_grp);
+long hl_fw_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr);
+void hl_fw_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq);
+int hl_get_temperature(struct hl_device *hdev, int sensor_index, u32 attr, long *value);
+int hl_set_temperature(struct hl_device *hdev, int sensor_index, u32 attr, long value);
+int hl_get_voltage(struct hl_device *hdev, int sensor_index, u32 attr, long *value);
+int hl_get_current(struct hl_device *hdev, int sensor_index, u32 attr, long *value);
+int hl_get_fan_speed(struct hl_device *hdev, int sensor_index, u32 attr, long *value);
+int hl_get_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr, long *value);
+void hl_set_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr, long value);
+long hl_fw_get_max_power(struct hl_device *hdev);
+void hl_fw_set_max_power(struct hl_device *hdev);
+int hl_set_voltage(struct hl_device *hdev, int sensor_index, u32 attr, long value);
+int hl_set_current(struct hl_device *hdev, int sensor_index, u32 attr, long value);
+int hl_set_power(struct hl_device *hdev, int sensor_index, u32 attr, long value);
+int hl_get_power(struct hl_device *hdev, int sensor_index, u32 attr, long *value);
+int hl_fw_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk);
+void hl_fw_set_pll_profile(struct hl_device *hdev);
+void hl_sysfs_add_dev_clk_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp);
+void hl_sysfs_add_dev_vrm_attr(struct hl_device *hdev, struct attribute_group *dev_vrm_attr_grp);
+
 void hw_sob_get(struct hl_hw_sob *hw_sob);
 void hw_sob_put(struct hl_hw_sob *hw_sob);
 void hl_encaps_handle_do_release(struct kref *ref);
@@ -3146,6 +3224,11 @@ __printf(4, 5) int hl_snprintf_resize(char **buf, size_t *size, size_t *offset,
                                        const char *format, ...);
 char *hl_format_as_binary(char *buf, size_t buf_len, u32 n);
 const char *hl_sync_engine_to_string(enum hl_sync_engine_type engine_type);
+void hl_ts_mgr_init(struct hl_ts_mgr *mgr);
+void hl_ts_mgr_fini(struct hl_device *hdev, struct hl_ts_mgr *mgr);
+int hl_ts_mmap(struct hl_fpriv *hpriv, struct vm_area_struct *vma);
+struct hl_ts_buff *hl_ts_get(struct hl_device *hdev, struct hl_ts_mgr *mgr, u32 handle);
+void hl_ts_put(struct hl_ts_buff *buff);
 
 #ifdef CONFIG_DEBUG_FS
 
index 690b763..ca404ed 100644 (file)
@@ -140,6 +140,7 @@ int hl_device_open(struct inode *inode, struct file *filp)
 
        hl_cb_mgr_init(&hpriv->cb_mgr);
        hl_ctx_mgr_init(&hpriv->ctx_mgr);
+       hl_ts_mgr_init(&hpriv->ts_mem_mgr);
 
        hpriv->taskpid = get_task_pid(current, PIDTYPE_PID);
 
@@ -184,6 +185,7 @@ int hl_device_open(struct inode *inode, struct file *filp)
 out_err:
        mutex_unlock(&hdev->fpriv_list_lock);
        hl_cb_mgr_fini(hpriv->hdev, &hpriv->cb_mgr);
+       hl_ts_mgr_fini(hpriv->hdev, &hpriv->ts_mem_mgr);
        hl_ctx_mgr_fini(hpriv->hdev, &hpriv->ctx_mgr);
        filp->private_data = NULL;
        mutex_destroy(&hpriv->restore_phase_mutex);
@@ -256,7 +258,6 @@ static void set_driver_behavior_per_device(struct hl_device *hdev)
        hdev->cpu_queues_enable = 1;
        hdev->heartbeat = 1;
        hdev->mmu_enable = 1;
-       hdev->clock_gating_mask = ULONG_MAX;
        hdev->sram_scrambler_enable = 1;
        hdev->dram_scrambler_enable = 1;
        hdev->bmc_enable = 1;
index 3ba3a8f..c13a3c2 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 
 /*
- * Copyright 2016-2019 HabanaLabs, Ltd.
+ * Copyright 2016-2022 HabanaLabs, Ltd.
  * All Rights Reserved.
  */
 
@@ -92,8 +92,8 @@ static int hw_ip_info(struct hl_device *hdev, struct hl_info_args *args)
        hw_ip.psoc_pci_pll_od = prop->psoc_pci_pll_od;
        hw_ip.psoc_pci_pll_div_factor = prop->psoc_pci_pll_div_factor;
 
-       hw_ip.first_available_interrupt_id =
-                       prop->first_available_user_msix_interrupt;
+       hw_ip.first_available_interrupt_id = prop->first_available_user_msix_interrupt;
+       hw_ip.number_of_user_interrupts = prop->user_interrupt_count;
        hw_ip.server_type = prop->server_type;
 
        return copy_to_user(out, &hw_ip,
@@ -251,13 +251,12 @@ static int get_clk_rate(struct hl_device *hdev, struct hl_info_args *args)
        if ((!max_size) || (!out))
                return -EINVAL;
 
-       rc = hdev->asic_funcs->get_clk_rate(hdev, &clk_rate.cur_clk_rate_mhz,
-                                               &clk_rate.max_clk_rate_mhz);
+       rc = hl_fw_get_clk_rate(hdev, &clk_rate.cur_clk_rate_mhz, &clk_rate.max_clk_rate_mhz);
        if (rc)
                return rc;
 
-       return copy_to_user(out, &clk_rate,
-               min((size_t) max_size, sizeof(clk_rate))) ? -EFAULT : 0;
+       return copy_to_user(out, &clk_rate, min_t(size_t, max_size, sizeof(clk_rate)))
+                                                                               ? -EFAULT : 0;
 }
 
 static int get_reset_count(struct hl_device *hdev, struct hl_info_args *args)
diff --git a/drivers/misc/habanalabs/common/hwmgr.c b/drivers/misc/habanalabs/common/hwmgr.c
deleted file mode 100644 (file)
index 5451019..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-/*
- * Copyright 2019-2021 HabanaLabs, Ltd.
- * All Rights Reserved.
- */
-
-#include "habanalabs.h"
-
-void hl_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq)
-{
-       hl_set_frequency(hdev, hdev->asic_prop.clk_pll_index,
-                       hdev->asic_prop.max_freq_value);
-}
-
-int hl_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk)
-{
-       long value;
-
-       if (!hl_device_operational(hdev, NULL))
-               return -ENODEV;
-
-       value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, false);
-
-       if (value < 0) {
-               dev_err(hdev->dev, "Failed to retrieve device max clock %ld\n",
-                       value);
-               return value;
-       }
-
-       *max_clk = (value / 1000 / 1000);
-
-       value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, true);
-
-       if (value < 0) {
-               dev_err(hdev->dev,
-                       "Failed to retrieve device current clock %ld\n",
-                       value);
-               return value;
-       }
-
-       *cur_clk = (value / 1000 / 1000);
-
-       return 0;
-}
-
-static ssize_t clk_max_freq_mhz_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct hl_device *hdev = dev_get_drvdata(dev);
-       long value;
-
-       if (!hl_device_operational(hdev, NULL))
-               return -ENODEV;
-
-       value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, false);
-
-       hdev->asic_prop.max_freq_value = value;
-
-       return sprintf(buf, "%lu\n", (value / 1000 / 1000));
-}
-
-static ssize_t clk_max_freq_mhz_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct hl_device *hdev = dev_get_drvdata(dev);
-       int rc;
-       u64 value;
-
-       if (!hl_device_operational(hdev, NULL)) {
-               count = -ENODEV;
-               goto fail;
-       }
-
-       rc = kstrtoull(buf, 0, &value);
-       if (rc) {
-               count = -EINVAL;
-               goto fail;
-       }
-
-       hdev->asic_prop.max_freq_value = value * 1000 * 1000;
-
-       hl_set_frequency(hdev, hdev->asic_prop.clk_pll_index,
-                       hdev->asic_prop.max_freq_value);
-
-fail:
-       return count;
-}
-
-static ssize_t clk_cur_freq_mhz_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct hl_device *hdev = dev_get_drvdata(dev);
-       long value;
-
-       if (!hl_device_operational(hdev, NULL))
-               return -ENODEV;
-
-       value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, true);
-
-       return sprintf(buf, "%lu\n", (value / 1000 / 1000));
-}
-
-static DEVICE_ATTR_RW(clk_max_freq_mhz);
-static DEVICE_ATTR_RO(clk_cur_freq_mhz);
-
-static struct attribute *hl_dev_attrs[] = {
-       &dev_attr_clk_max_freq_mhz.attr,
-       &dev_attr_clk_cur_freq_mhz.attr,
-       NULL,
-};
-
-void hl_add_device_attr(struct hl_device *hdev,
-                       struct attribute_group *dev_attr_grp)
-{
-       dev_attr_grp->attrs = hl_dev_attrs;
-}
index 1b6bdc9..e2bc128 100644 (file)
@@ -137,22 +137,137 @@ irqreturn_t hl_irq_handler_cq(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
+/*
+ * hl_ts_free_objects - handler of the free objects workqueue.
+ * This function should put refcount to objects that the registration node
+ * took refcount to them.
+ * @work: workqueue object pointer
+ */
+static void hl_ts_free_objects(struct work_struct *work)
+{
+       struct timestamp_reg_work_obj *job =
+                       container_of(work, struct timestamp_reg_work_obj, free_obj);
+       struct timestamp_reg_free_node *free_obj, *temp_free_obj;
+       struct list_head *free_list_head = job->free_obj_head;
+       struct hl_device *hdev = job->hdev;
+
+       list_for_each_entry_safe(free_obj, temp_free_obj, free_list_head, free_objects_node) {
+               dev_dbg(hdev->dev, "About to put refcount to ts_buff (%p) cq_cb(%p)\n",
+                                       free_obj->ts_buff,
+                                       free_obj->cq_cb);
+
+               hl_ts_put(free_obj->ts_buff);
+               hl_cb_put(free_obj->cq_cb);
+               kfree(free_obj);
+       }
+
+       kfree(free_list_head);
+       kfree(job);
+}
+
+/*
+ * This function called with spin_lock of wait_list_lock taken
+ * This function will set timestamp and delete the registration node from the
+ * wait_list_lock.
+ * and since we're protected with spin_lock here, so we cannot just put the refcount
+ * for the objects here, since the release function may be called and it's also a long
+ * logic (which might sleep also) that cannot be handled in irq context.
+ * so here we'll be filling a list with nodes of "put" jobs and then will send this
+ * list to a dedicated workqueue to do the actual put.
+ */
+static int handle_registration_node(struct hl_device *hdev, struct hl_user_pending_interrupt *pend,
+                                               struct list_head **free_list)
+{
+       struct timestamp_reg_free_node *free_node;
+       u64 timestamp;
+
+       if (!(*free_list)) {
+               /* Alloc/Init the timestamp registration free objects list */
+               *free_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC);
+               if (!(*free_list))
+                       return -ENOMEM;
+
+               INIT_LIST_HEAD(*free_list);
+       }
+
+       free_node = kmalloc(sizeof(*free_node), GFP_ATOMIC);
+       if (!free_node)
+               return -ENOMEM;
+
+       timestamp = ktime_get_ns();
+
+       *pend->ts_reg_info.timestamp_kernel_addr = timestamp;
+
+       dev_dbg(hdev->dev, "Timestamp is set to ts cb address (%p), ts: 0x%llx\n",
+                       pend->ts_reg_info.timestamp_kernel_addr,
+                       *(u64 *)pend->ts_reg_info.timestamp_kernel_addr);
+
+       list_del(&pend->wait_list_node);
+
+       /* Mark kernel CB node as free */
+       pend->ts_reg_info.in_use = 0;
+
+       /* Putting the refcount for ts_buff and cq_cb objects will be handled
+        * in workqueue context, just add job to free_list.
+        */
+       free_node->ts_buff = pend->ts_reg_info.ts_buff;
+       free_node->cq_cb = pend->ts_reg_info.cq_cb;
+       list_add(&free_node->free_objects_node, *free_list);
+
+       return 0;
+}
+
 static void handle_user_cq(struct hl_device *hdev,
                        struct hl_user_interrupt *user_cq)
 {
-       struct hl_user_pending_interrupt *pend;
+       struct hl_user_pending_interrupt *pend, *temp_pend;
+       struct list_head *ts_reg_free_list_head = NULL;
+       struct timestamp_reg_work_obj *job;
+       bool reg_node_handle_fail = false;
        ktime_t now = ktime_get();
+       int rc;
+
+       /* For registration nodes:
+        * As part of handling the registration nodes, we should put refcount to
+        * some objects. the problem is that we cannot do that under spinlock
+        * or in irq handler context at all (since release functions are long and
+        * might sleep), so we will need to handle that part in workqueue context.
+        * To avoid handling kmalloc failure which compels us rolling back actions
+        * and move nodes hanged on the free list back to the interrupt wait list
+        * we always alloc the job of the WQ at the beginning.
+        */
+       job = kmalloc(sizeof(*job), GFP_ATOMIC);
+       if (!job)
+               return;
 
        spin_lock(&user_cq->wait_list_lock);
-       list_for_each_entry(pend, &user_cq->wait_list_head, wait_list_node) {
-               if ((pend->cq_kernel_addr &&
-                               *(pend->cq_kernel_addr) >= pend->cq_target_value) ||
+       list_for_each_entry_safe(pend, temp_pend, &user_cq->wait_list_head, wait_list_node) {
+               if ((pend->cq_kernel_addr && *(pend->cq_kernel_addr) >= pend->cq_target_value) ||
                                !pend->cq_kernel_addr) {
-                       pend->fence.timestamp = now;
-                       complete_all(&pend->fence.completion);
+                       if (pend->ts_reg_info.ts_buff) {
+                               if (!reg_node_handle_fail) {
+                                       rc = handle_registration_node(hdev, pend,
+                                                                       &ts_reg_free_list_head);
+                                       if (rc)
+                                               reg_node_handle_fail = true;
+                               }
+                       } else {
+                               /* Handle wait target value node */
+                               pend->fence.timestamp = now;
+                               complete_all(&pend->fence.completion);
+                       }
                }
        }
        spin_unlock(&user_cq->wait_list_lock);
+
+       if (ts_reg_free_list_head) {
+               INIT_WORK(&job->free_obj, hl_ts_free_objects);
+               job->free_obj_head = ts_reg_free_list_head;
+               job->hdev = hdev;
+               queue_work(hdev->ts_free_obj_wq, &job->free_obj);
+       } else {
+               kfree(job);
+       }
 }
 
 /**
index c1eefae..e008d82 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/uaccess.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <linux/pci-p2pdma.h>
 
 MODULE_IMPORT_NS(DMA_BUF);
@@ -20,6 +21,34 @@ MODULE_IMPORT_NS(DMA_BUF);
 /* use small pages for supporting non-pow2 (32M/40M/48M) DRAM phys page sizes */
 #define DRAM_POOL_PAGE_SIZE SZ_8M
 
+static int allocate_timestamps_buffers(struct hl_fpriv *hpriv,
+                       struct hl_mem_in *args, u64 *handle);
+
+static int set_alloc_page_size(struct hl_device *hdev, struct hl_mem_in *args, u32 *page_size)
+{
+       struct asic_fixed_properties *prop = &hdev->asic_prop;
+       u32 psize;
+
+       /*
+        * for ASIC that supports setting the allocation page size by user we will address
+        * user's choice only if it is not 0 (as 0 means taking the default page size)
+        */
+       if (prop->supports_user_set_page_size && args->alloc.page_size) {
+               psize = args->alloc.page_size;
+
+               if (!hdev->asic_funcs->is_valid_dram_page_size(psize)) {
+                       dev_err(hdev->dev, "user page size (%#x) is not valid\n", psize);
+                       return -EINVAL;
+               }
+       } else {
+               psize = hdev->asic_prop.dram_page_size;
+       }
+
+       *page_size = psize;
+
+       return 0;
+}
+
 /*
  * The va ranges in context object contain a list with the available chunks of
  * device virtual memory.
@@ -61,11 +90,15 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args,
        struct hl_vm_phys_pg_pack *phys_pg_pack;
        u64 paddr = 0, total_size, num_pgs, i;
        u32 num_curr_pgs, page_size;
-       int handle, rc;
        bool contiguous;
+       int handle, rc;
 
        num_curr_pgs = 0;
-       page_size = hdev->asic_prop.dram_page_size;
+
+       rc = set_alloc_page_size(hdev, args, &page_size);
+       if (rc)
+               return rc;
+
        num_pgs = DIV_ROUND_UP_ULL(args->alloc.mem_size, page_size);
        total_size = num_pgs * page_size;
 
@@ -77,7 +110,11 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args,
        contiguous = args->flags & HL_MEM_CONTIGUOUS;
 
        if (contiguous) {
-               paddr = (u64) gen_pool_alloc(vm->dram_pg_pool, total_size);
+               if (is_power_of_2(page_size))
+                       paddr = (u64) (uintptr_t) gen_pool_dma_alloc_align(vm->dram_pg_pool,
+                                                               total_size, NULL, page_size);
+               else
+                       paddr = (u64) (uintptr_t) gen_pool_alloc(vm->dram_pg_pool, total_size);
                if (!paddr) {
                        dev_err(hdev->dev,
                                "failed to allocate %llu contiguous pages with total size of %llu\n",
@@ -111,9 +148,14 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args,
                        phys_pg_pack->pages[i] = paddr + i * page_size;
        } else {
                for (i = 0 ; i < num_pgs ; i++) {
-                       phys_pg_pack->pages[i] = (u64) gen_pool_alloc(
-                                                       vm->dram_pg_pool,
-                                                       page_size);
+                       if (is_power_of_2(page_size))
+                               phys_pg_pack->pages[i] =
+                                               (u64) gen_pool_dma_alloc_align(vm->dram_pg_pool,
+                                                                               page_size, NULL,
+                                                                               page_size);
+                       else
+                               phys_pg_pack->pages[i] = (u64) gen_pool_alloc(vm->dram_pg_pool,
+                                                                               page_size);
                        if (!phys_pg_pack->pages[i]) {
                                dev_err(hdev->dev,
                                        "Failed to allocate device memory (out of memory)\n");
@@ -652,7 +694,7 @@ static u64 get_va_block(struct hl_device *hdev,
                        continue;
 
                /*
-                * In case hint address is 0, and arc_hints_range_reservation
+                * In case hint address is 0, and hints_range_reservation
                 * property enabled, then avoid allocating va blocks from the
                 * range reserved for hint addresses
                 */
@@ -1967,16 +2009,15 @@ err_dec_exporting_cnt:
 static int mem_ioctl_no_mmu(struct hl_fpriv *hpriv, union hl_mem_args *args)
 {
        struct hl_device *hdev = hpriv->hdev;
-       struct hl_ctx *ctx = hpriv->ctx;
        u64 block_handle, device_addr = 0;
+       struct hl_ctx *ctx = hpriv->ctx;
        u32 handle = 0, block_size;
-       int rc, dmabuf_fd = -EBADF;
+       int rc;
 
        switch (args->in.op) {
        case HL_MEM_OP_ALLOC:
                if (args->in.alloc.mem_size == 0) {
-                       dev_err(hdev->dev,
-                               "alloc size must be larger than 0\n");
+                       dev_err(hdev->dev, "alloc size must be larger than 0\n");
                        rc = -EINVAL;
                        goto out;
                }
@@ -1997,15 +2038,14 @@ static int mem_ioctl_no_mmu(struct hl_fpriv *hpriv, union hl_mem_args *args)
 
        case HL_MEM_OP_MAP:
                if (args->in.flags & HL_MEM_USERPTR) {
-                       device_addr = args->in.map_host.host_virt_addr;
-                       rc = 0;
+                       dev_err(hdev->dev, "Failed to map host memory when MMU is disabled\n");
+                       rc = -EPERM;
                } else {
-                       rc = get_paddr_from_handle(ctx, &args->in,
-                                                       &device_addr);
+                       rc = get_paddr_from_handle(ctx, &args->in, &device_addr);
+                       memset(args, 0, sizeof(*args));
+                       args->out.device_virt_addr = device_addr;
                }
 
-               memset(args, 0, sizeof(*args));
-               args->out.device_virt_addr = device_addr;
                break;
 
        case HL_MEM_OP_UNMAP:
@@ -2013,22 +2053,19 @@ static int mem_ioctl_no_mmu(struct hl_fpriv *hpriv, union hl_mem_args *args)
                break;
 
        case HL_MEM_OP_MAP_BLOCK:
-               rc = map_block(hdev, args->in.map_block.block_addr,
-                               &block_handle, &block_size);
+               rc = map_block(hdev, args->in.map_block.block_addr, &block_handle, &block_size);
                args->out.block_handle = block_handle;
                args->out.block_size = block_size;
                break;
 
        case HL_MEM_OP_EXPORT_DMABUF_FD:
-               rc = export_dmabuf_from_addr(ctx,
-                               args->in.export_dmabuf_fd.handle,
-                               args->in.export_dmabuf_fd.mem_size,
-                               args->in.flags,
-                               &dmabuf_fd);
-               memset(args, 0, sizeof(*args));
-               args->out.fd = dmabuf_fd;
+               dev_err(hdev->dev, "Failed to export dma-buf object when MMU is disabled\n");
+               rc = -EPERM;
                break;
 
+       case HL_MEM_OP_TS_ALLOC:
+               rc = allocate_timestamps_buffers(hpriv, &args->in, &args->out.handle);
+               break;
        default:
                dev_err(hdev->dev, "Unknown opcode for memory IOCTL\n");
                rc = -EINVAL;
@@ -2039,6 +2076,258 @@ out:
        return rc;
 }
 
+static void ts_buff_release(struct kref *ref)
+{
+       struct hl_ts_buff *buff;
+
+       buff = container_of(ref, struct hl_ts_buff, refcount);
+
+       vfree(buff->kernel_buff_address);
+       vfree(buff->user_buff_address);
+       kfree(buff);
+}
+
+struct hl_ts_buff *hl_ts_get(struct hl_device *hdev, struct hl_ts_mgr *mgr,
+                                       u32 handle)
+{
+       struct hl_ts_buff *buff;
+
+       spin_lock(&mgr->ts_lock);
+       buff = idr_find(&mgr->ts_handles, handle);
+       if (!buff) {
+               spin_unlock(&mgr->ts_lock);
+               dev_warn(hdev->dev,
+                       "TS buff get failed, no match to handle 0x%x\n", handle);
+               return NULL;
+       }
+       kref_get(&buff->refcount);
+       spin_unlock(&mgr->ts_lock);
+
+       return buff;
+}
+
+void hl_ts_put(struct hl_ts_buff *buff)
+{
+       kref_put(&buff->refcount, ts_buff_release);
+}
+
+static void buff_vm_close(struct vm_area_struct *vma)
+{
+       struct hl_ts_buff *buff = (struct hl_ts_buff *) vma->vm_private_data;
+       long new_mmap_size;
+
+       new_mmap_size = buff->mmap_size - (vma->vm_end - vma->vm_start);
+
+       if (new_mmap_size > 0) {
+               buff->mmap_size = new_mmap_size;
+               return;
+       }
+
+       atomic_set(&buff->mmap, 0);
+       hl_ts_put(buff);
+       vma->vm_private_data = NULL;
+}
+
+static const struct vm_operations_struct ts_buff_vm_ops = {
+       .close = buff_vm_close
+};
+
+int hl_ts_mmap(struct hl_fpriv *hpriv, struct vm_area_struct *vma)
+{
+       struct hl_device *hdev = hpriv->hdev;
+       struct hl_ts_buff *buff;
+       u32 handle, user_buff_size;
+       int rc;
+
+       /* We use the page offset to hold the idr and thus we need to clear
+        * it before doing the mmap itself
+        */
+       handle = vma->vm_pgoff;
+       vma->vm_pgoff = 0;
+
+       buff = hl_ts_get(hdev, &hpriv->ts_mem_mgr, handle);
+       if (!buff) {
+               dev_err(hdev->dev,
+                       "TS buff mmap failed, no match to handle 0x%x\n", handle);
+               return -EINVAL;
+       }
+
+       /* Validation check */
+       user_buff_size = vma->vm_end - vma->vm_start;
+       if (user_buff_size != ALIGN(buff->user_buff_size, PAGE_SIZE)) {
+               dev_err(hdev->dev,
+                       "TS buff mmap failed, mmap size 0x%x != 0x%x buff size\n",
+                       user_buff_size, ALIGN(buff->user_buff_size, PAGE_SIZE));
+               rc = -EINVAL;
+               goto put_buff;
+       }
+
+#ifdef _HAS_TYPE_ARG_IN_ACCESS_OK
+       if (!access_ok(VERIFY_WRITE,
+               (void __user *) (uintptr_t) vma->vm_start, user_buff_size)) {
+#else
+       if (!access_ok((void __user *) (uintptr_t) vma->vm_start,
+                                               user_buff_size)) {
+#endif
+               dev_err(hdev->dev,
+                       "user pointer is invalid - 0x%lx\n",
+                       vma->vm_start);
+
+               rc = -EINVAL;
+               goto put_buff;
+       }
+
+       if (atomic_cmpxchg(&buff->mmap, 0, 1)) {
+               dev_err(hdev->dev, "TS buff memory mmap failed, already mmaped to user\n");
+               rc = -EINVAL;
+               goto put_buff;
+       }
+
+       vma->vm_ops = &ts_buff_vm_ops;
+       vma->vm_private_data = buff;
+       vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_DONTCOPY | VM_NORESERVE;
+       rc = remap_vmalloc_range(vma, buff->user_buff_address, 0);
+       if (rc) {
+               atomic_set(&buff->mmap, 0);
+               goto put_buff;
+       }
+
+       buff->mmap_size = buff->user_buff_size;
+       vma->vm_pgoff = handle;
+
+       return 0;
+
+put_buff:
+       hl_ts_put(buff);
+       return rc;
+}
+
+void hl_ts_mgr_init(struct hl_ts_mgr *mgr)
+{
+       spin_lock_init(&mgr->ts_lock);
+       idr_init(&mgr->ts_handles);
+}
+
+void hl_ts_mgr_fini(struct hl_device *hdev, struct hl_ts_mgr *mgr)
+{
+       struct hl_ts_buff *buff;
+       struct idr *idp;
+       u32 id;
+
+       idp = &mgr->ts_handles;
+
+       idr_for_each_entry(idp, buff, id) {
+               if (kref_put(&buff->refcount, ts_buff_release) != 1)
+                       dev_err(hdev->dev, "TS buff handle %d for CTX is still alive\n",
+                                                       id);
+       }
+
+       idr_destroy(&mgr->ts_handles);
+}
+
+static struct hl_ts_buff *hl_ts_alloc_buff(struct hl_device *hdev, u32 num_elements)
+{
+       struct hl_ts_buff *ts_buff = NULL;
+       u32 size;
+       void *p;
+
+       ts_buff = kzalloc(sizeof(*ts_buff), GFP_KERNEL);
+       if (!ts_buff)
+               return NULL;
+
+       /* Allocate the user buffer */
+       size = num_elements * sizeof(u64);
+       p = vmalloc_user(size);
+       if (!p)
+               goto free_mem;
+
+       ts_buff->user_buff_address = p;
+       ts_buff->user_buff_size = size;
+
+       /* Allocate the internal kernel buffer */
+       size = num_elements * sizeof(struct hl_user_pending_interrupt);
+       p = vmalloc(size);
+       if (!p)
+               goto free_user_buff;
+
+       ts_buff->kernel_buff_address = p;
+       ts_buff->kernel_buff_size = size;
+
+       return ts_buff;
+
+free_user_buff:
+       vfree(ts_buff->user_buff_address);
+free_mem:
+       kfree(ts_buff);
+       return NULL;
+}
+
+/**
+ * allocate_timestamps_buffers() - allocate timestamps buffers
+ * This function will allocate ts buffer that will later on be mapped to the user
+ * in order to be able to read the timestamp.
+ * in additon it'll allocate an extra buffer for registration management.
+ * since we cannot fail during registration for out-of-memory situation, so
+ * we'll prepare a pool which will be used as user interrupt nodes and instead
+ * of dynamically allocating nodes while registration we'll pick the node from
+ * this pool. in addtion it'll add node to the mapping hash which will be used
+ * to map user ts buffer to the internal kernel ts buffer.
+ * @hpriv: pointer to the private data of the fd
+ * @args: ioctl input
+ * @handle: user timestamp buffer handle as an output
+ */
+static int allocate_timestamps_buffers(struct hl_fpriv *hpriv, struct hl_mem_in *args, u64 *handle)
+{
+       struct hl_ts_mgr *ts_mgr = &hpriv->ts_mem_mgr;
+       struct hl_device *hdev = hpriv->hdev;
+       struct hl_ts_buff *ts_buff;
+       int rc = 0;
+
+       if (args->num_of_elements > TS_MAX_ELEMENTS_NUM) {
+               dev_err(hdev->dev, "Num of elements exceeds Max allowed number (0x%x > 0x%x)\n",
+                               args->num_of_elements, TS_MAX_ELEMENTS_NUM);
+               return -EINVAL;
+       }
+
+       /* Allocate ts buffer object
+        * This object will contain two buffers one that will be mapped to the user
+        * and another internal buffer for the driver use only, which won't be mapped
+        * to the user.
+        */
+       ts_buff = hl_ts_alloc_buff(hdev, args->num_of_elements);
+       if (!ts_buff) {
+               rc = -ENOMEM;
+               goto out_err;
+       }
+
+       spin_lock(&ts_mgr->ts_lock);
+       rc = idr_alloc(&ts_mgr->ts_handles, ts_buff, 1, 0, GFP_ATOMIC);
+       spin_unlock(&ts_mgr->ts_lock);
+       if (rc < 0) {
+               dev_err(hdev->dev, "Failed to allocate IDR for a new ts buffer\n");
+               goto release_ts_buff;
+       }
+
+       ts_buff->id = rc;
+       ts_buff->hdev = hdev;
+
+       kref_init(&ts_buff->refcount);
+
+       /* idr is 32-bit so we can safely OR it with a mask that is above 32 bit */
+       *handle = (u64) ts_buff->id | HL_MMAP_TYPE_TS_BUFF;
+       *handle <<= PAGE_SHIFT;
+
+       dev_dbg(hdev->dev, "Created ts buff object handle(%u)\n", ts_buff->id);
+
+       return 0;
+
+release_ts_buff:
+       kref_put(&ts_buff->refcount, ts_buff_release);
+out_err:
+       *handle = 0;
+       return rc;
+}
+
 int hl_mem_ioctl(struct hl_fpriv *hpriv, void *data)
 {
        enum hl_device_status status;
@@ -2154,6 +2443,9 @@ int hl_mem_ioctl(struct hl_fpriv *hpriv, void *data)
                args->out.fd = dmabuf_fd;
                break;
 
+       case HL_MEM_OP_TS_ALLOC:
+               rc = allocate_timestamps_buffers(hpriv, &args->in, &args->out.handle);
+               break;
        default:
                dev_err(hdev->dev, "Unknown opcode for memory IOCTL\n");
                rc = -EINVAL;
@@ -2607,11 +2899,12 @@ int hl_vm_ctx_init(struct hl_ctx *ctx)
  */
 void hl_vm_ctx_fini(struct hl_ctx *ctx)
 {
+       struct hl_vm_phys_pg_pack *phys_pg_list, *tmp_phys_node;
        struct hl_device *hdev = ctx->hdev;
-       struct hl_vm *vm = &hdev->vm;
-       struct hl_vm_phys_pg_pack *phys_pg_list;
        struct hl_vm_hash_node *hnode;
+       struct hl_vm *vm = &hdev->vm;
        struct hlist_node *tmp_node;
+       struct list_head free_list;
        struct hl_mem_in args;
        int i;
 
@@ -2644,19 +2937,24 @@ void hl_vm_ctx_fini(struct hl_ctx *ctx)
 
        mutex_unlock(&ctx->mmu_lock);
 
+       INIT_LIST_HEAD(&free_list);
+
        spin_lock(&vm->idr_lock);
        idr_for_each_entry(&vm->phys_pg_pack_handles, phys_pg_list, i)
                if (phys_pg_list->asid == ctx->asid) {
                        dev_dbg(hdev->dev,
                                "page list 0x%px of asid %d is still alive\n",
                                phys_pg_list, ctx->asid);
-                       atomic64_sub(phys_pg_list->total_size,
-                                       &hdev->dram_used_mem);
-                       free_phys_pg_pack(hdev, phys_pg_list);
+
+                       atomic64_sub(phys_pg_list->total_size, &hdev->dram_used_mem);
                        idr_remove(&vm->phys_pg_pack_handles, i);
+                       list_add(&phys_pg_list->node, &free_list);
                }
        spin_unlock(&vm->idr_lock);
 
+       list_for_each_entry_safe(phys_pg_list, tmp_phys_node, &free_list, node)
+               free_phys_pg_pack(hdev, phys_pg_list);
+
        va_range_fini(hdev, ctx->va_range[HL_VA_RANGE_TYPE_DRAM]);
        va_range_fini(hdev, ctx->va_range[HL_VA_RANGE_TYPE_HOST]);
 
index 9153a1f..810b734 100644 (file)
@@ -662,3 +662,58 @@ int hl_mmu_invalidate_cache_range(struct hl_device *hdev, bool is_hard,
        return rc;
 }
 
+u64 hl_mmu_get_next_hop_addr(struct hl_ctx *ctx, u64 curr_pte)
+{
+       return (curr_pte & PAGE_PRESENT_MASK) ? (curr_pte & HOP_PHYS_ADDR_MASK) : ULLONG_MAX;
+}
+
+/**
+ * hl_mmu_get_hop_pte_phys_addr() - extract PTE address from HOP
+ * @ctx: pointer to the context structure to initialize.
+ * @hop_idx: HOP index.
+ * @hop_addr: HOP address.
+ * @virt_addr: virtual address fro the translation.
+ *
+ * @return the matching PTE value on success, otherwise U64_MAX.
+ */
+u64 hl_mmu_get_hop_pte_phys_addr(struct hl_ctx *ctx, struct hl_mmu_properties *mmu_prop,
+                                       u8 hop_idx, u64 hop_addr, u64 virt_addr)
+{
+       u64 mask, shift;
+
+       if (hop_idx >= mmu_prop->num_hops) {
+               dev_err_ratelimited(ctx->hdev->dev, "Invalid hop index %d\n", hop_idx);
+               return U64_MAX;
+       }
+
+       /* currently max number of HOPs is 6 */
+       switch (hop_idx) {
+       case 0:
+               mask = mmu_prop->hop0_mask;
+               shift = mmu_prop->hop0_shift;
+               break;
+       case 1:
+               mask = mmu_prop->hop1_mask;
+               shift = mmu_prop->hop1_shift;
+               break;
+       case 2:
+               mask = mmu_prop->hop2_mask;
+               shift = mmu_prop->hop2_shift;
+               break;
+       case 3:
+               mask = mmu_prop->hop3_mask;
+               shift = mmu_prop->hop3_shift;
+               break;
+       case 4:
+               mask = mmu_prop->hop4_mask;
+               shift = mmu_prop->hop4_shift;
+               break;
+       default:
+               mask = mmu_prop->hop5_mask;
+               shift = mmu_prop->hop5_shift;
+               break;
+       }
+
+       return hop_addr + ctx->hdev->asic_prop.mmu_pte_size * ((virt_addr & mask) >> shift);
+}
+
index 6134b6a..d03786d 100644 (file)
@@ -217,18 +217,10 @@ static inline u64 get_hop4_pte_addr(struct hl_ctx *ctx,
                                        mmu_prop->hop4_shift);
 }
 
-static inline u64 get_next_hop_addr(struct hl_ctx *ctx, u64 curr_pte)
-{
-       if (curr_pte & PAGE_PRESENT_MASK)
-               return curr_pte & HOP_PHYS_ADDR_MASK;
-       else
-               return ULLONG_MAX;
-}
-
 static inline u64 get_alloc_next_hop_addr(struct hl_ctx *ctx, u64 curr_pte,
                                                bool *is_new_hop)
 {
-       u64 hop_addr = get_next_hop_addr(ctx, curr_pte);
+       u64 hop_addr = hl_mmu_get_next_hop_addr(ctx, curr_pte);
 
        if (hop_addr == ULLONG_MAX) {
                hop_addr = alloc_hop(ctx);
@@ -467,7 +459,7 @@ static void hl_mmu_v1_fini(struct hl_device *hdev)
 {
        /* MMU H/W fini was already done in device hw_fini() */
 
-       if (!ZERO_OR_NULL_PTR(hdev->mmu_priv.hr.mmu_shadow_hop0)) {
+       if (!ZERO_OR_NULL_PTR(hdev->mmu_priv.dr.mmu_shadow_hop0)) {
                kvfree(hdev->mmu_priv.dr.mmu_shadow_hop0);
                gen_pool_destroy(hdev->mmu_priv.dr.mmu_pgt_pool);
 
@@ -546,7 +538,7 @@ static int _hl_mmu_v1_unmap(struct hl_ctx *ctx,
 
        curr_pte = *(u64 *) (uintptr_t) hop0_pte_addr;
 
-       hop1_addr = get_next_hop_addr(ctx, curr_pte);
+       hop1_addr = hl_mmu_get_next_hop_addr(ctx, curr_pte);
 
        if (hop1_addr == ULLONG_MAX)
                goto not_mapped;
@@ -555,7 +547,7 @@ static int _hl_mmu_v1_unmap(struct hl_ctx *ctx,
 
        curr_pte = *(u64 *) (uintptr_t) hop1_pte_addr;
 
-       hop2_addr = get_next_hop_addr(ctx, curr_pte);
+       hop2_addr = hl_mmu_get_next_hop_addr(ctx, curr_pte);
 
        if (hop2_addr == ULLONG_MAX)
                goto not_mapped;
@@ -564,7 +556,7 @@ static int _hl_mmu_v1_unmap(struct hl_ctx *ctx,
 
        curr_pte = *(u64 *) (uintptr_t) hop2_pte_addr;
 
-       hop3_addr = get_next_hop_addr(ctx, curr_pte);
+       hop3_addr = hl_mmu_get_next_hop_addr(ctx, curr_pte);
 
        if (hop3_addr == ULLONG_MAX)
                goto not_mapped;
@@ -582,7 +574,7 @@ static int _hl_mmu_v1_unmap(struct hl_ctx *ctx,
        }
 
        if (!is_huge) {
-               hop4_addr = get_next_hop_addr(ctx, curr_pte);
+               hop4_addr = hl_mmu_get_next_hop_addr(ctx, curr_pte);
 
                if (hop4_addr == ULLONG_MAX)
                        goto not_mapped;
@@ -845,27 +837,6 @@ static void hl_mmu_v1_swap_in(struct hl_ctx *ctx)
 
 }
 
-static inline u64 get_hop_pte_addr(struct hl_ctx *ctx,
-                               struct hl_mmu_properties *mmu_prop,
-                               int hop_num, u64 hop_addr, u64 virt_addr)
-{
-       switch (hop_num) {
-       case 0:
-               return get_hop0_pte_addr(ctx, mmu_prop, hop_addr, virt_addr);
-       case 1:
-               return get_hop1_pte_addr(ctx, mmu_prop, hop_addr, virt_addr);
-       case 2:
-               return get_hop2_pte_addr(ctx, mmu_prop, hop_addr, virt_addr);
-       case 3:
-               return get_hop3_pte_addr(ctx, mmu_prop, hop_addr, virt_addr);
-       case 4:
-               return get_hop4_pte_addr(ctx, mmu_prop, hop_addr, virt_addr);
-       default:
-               break;
-       }
-       return U64_MAX;
-}
-
 static int hl_mmu_v1_get_tlb_info(struct hl_ctx *ctx, u64 virt_addr,
                                struct hl_mmu_hop_info *hops)
 {
@@ -906,7 +877,7 @@ static int hl_mmu_v1_get_tlb_info(struct hl_ctx *ctx, u64 virt_addr,
 
        hops->hop_info[0].hop_addr = get_phys_hop0_addr(ctx);
        hops->hop_info[0].hop_pte_addr =
-                       get_hop_pte_addr(ctx, mmu_prop, 0,
+                       hl_mmu_get_hop_pte_phys_addr(ctx, mmu_prop, 0,
                                        hops->hop_info[0].hop_addr, virt_addr);
        hops->hop_info[0].hop_pte_val =
                        hdev->asic_funcs->read_pte(hdev,
@@ -914,13 +885,13 @@ static int hl_mmu_v1_get_tlb_info(struct hl_ctx *ctx, u64 virt_addr,
 
        for (i = 1 ; i < used_hops ; i++) {
                hops->hop_info[i].hop_addr =
-                       get_next_hop_addr(ctx,
+                       hl_mmu_get_next_hop_addr(ctx,
                                        hops->hop_info[i - 1].hop_pte_val);
                if (hops->hop_info[i].hop_addr == ULLONG_MAX)
                        return -EFAULT;
 
                hops->hop_info[i].hop_pte_addr =
-                               get_hop_pte_addr(ctx, mmu_prop, i,
+                               hl_mmu_get_hop_pte_phys_addr(ctx, mmu_prop, i,
                                                hops->hop_info[i].hop_addr,
                                                virt_addr);
                hops->hop_info[i].hop_pte_val =
index 0b5366c..bb9ce22 100644 (file)
@@ -338,10 +338,7 @@ int hl_pci_set_outbound_region(struct hl_device *hdev,
                                lower_32_bits(outbound_region_end_address));
        rc |= hl_pci_iatu_write(hdev, 0x014, 0);
 
-       if ((hdev->power9_64bit_dma_enable) && (hdev->dma_mask == 64))
-               rc |= hl_pci_iatu_write(hdev, 0x018, 0x08000000);
-       else
-               rc |= hl_pci_iatu_write(hdev, 0x018, 0);
+       rc |= hl_pci_iatu_write(hdev, 0x018, 0);
 
        rc |= hl_pci_iatu_write(hdev, 0x020,
                                upper_32_bits(outbound_region_end_address));
@@ -411,13 +408,13 @@ int hl_pci_init(struct hl_device *hdev)
 
        rc = hdev->asic_funcs->pci_bars_map(hdev);
        if (rc) {
-               dev_err(hdev->dev, "Failed to initialize PCI BARs\n");
+               dev_err(hdev->dev, "Failed to map PCI BAR addresses\n");
                goto disable_device;
        }
 
        rc = hdev->asic_funcs->init_iatu(hdev);
        if (rc) {
-               dev_err(hdev->dev, "Failed to initialize iATU\n");
+               dev_err(hdev->dev, "PCI controller was not initialized successfully\n");
                goto unmap_pci_bars;
        }
 
index 45c7153..9ebeb18 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 
 /*
- * Copyright 2016-2019 HabanaLabs, Ltd.
+ * Copyright 2016-2022 HabanaLabs, Ltd.
  * All Rights Reserved.
  */
 
 
 #include <linux/pci.h>
 
-long hl_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr)
+static ssize_t clk_max_freq_mhz_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct cpucp_packet pkt;
-       u32 used_pll_idx;
-       u64 result;
-       int rc;
-
-       rc = get_used_pll_index(hdev, pll_index, &used_pll_idx);
-       if (rc)
-               return rc;
-
-       memset(&pkt, 0, sizeof(pkt));
+       struct hl_device *hdev = dev_get_drvdata(dev);
+       long value;
 
-       if (curr)
-               pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_CURR_GET <<
-                                               CPUCP_PKT_CTL_OPCODE_SHIFT);
-       else
-               pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_GET <<
-                                               CPUCP_PKT_CTL_OPCODE_SHIFT);
-       pkt.pll_index = cpu_to_le32((u32)used_pll_idx);
+       if (!hl_device_operational(hdev, NULL))
+               return -ENODEV;
 
-       rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),
-                                               0, &result);
+       value = hl_fw_get_frequency(hdev, hdev->asic_prop.clk_pll_index, false);
+       if (value < 0)
+               return value;
 
-       if (rc) {
-               dev_err(hdev->dev,
-                       "Failed to get frequency of PLL %d, error %d\n",
-                       used_pll_idx, rc);
-               return rc;
-       }
+       hdev->asic_prop.max_freq_value = value;
 
-       return (long) result;
+       return sprintf(buf, "%lu\n", (value / 1000 / 1000));
 }
 
-void hl_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq)
+static ssize_t clk_max_freq_mhz_store(struct device *dev, struct device_attribute *attr,
+                                       const char *buf, size_t count)
 {
-       struct cpucp_packet pkt;
-       u32 used_pll_idx;
+       struct hl_device *hdev = dev_get_drvdata(dev);
        int rc;
+       u64 value;
 
-       rc = get_used_pll_index(hdev, pll_index, &used_pll_idx);
-       if (rc)
-               return;
+       if (!hl_device_operational(hdev, NULL)) {
+               count = -ENODEV;
+               goto fail;
+       }
 
-       memset(&pkt, 0, sizeof(pkt));
+       rc = kstrtoull(buf, 0, &value);
+       if (rc) {
+               count = -EINVAL;
+               goto fail;
+       }
 
-       pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_SET <<
-                                       CPUCP_PKT_CTL_OPCODE_SHIFT);
-       pkt.pll_index = cpu_to_le32((u32)used_pll_idx);
-       pkt.value = cpu_to_le64(freq);
+       hdev->asic_prop.max_freq_value = value * 1000 * 1000;
 
-       rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),
-                                               0, NULL);
+       hl_fw_set_frequency(hdev, hdev->asic_prop.clk_pll_index, hdev->asic_prop.max_freq_value);
 
-       if (rc)
-               dev_err(hdev->dev,
-                       "Failed to set frequency to PLL %d, error %d\n",
-                       used_pll_idx, rc);
+fail:
+       return count;
 }
 
-u64 hl_get_max_power(struct hl_device *hdev)
+static ssize_t clk_cur_freq_mhz_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct cpucp_packet pkt;
-       u64 result;
-       int rc;
+       struct hl_device *hdev = dev_get_drvdata(dev);
+       long value;
 
-       memset(&pkt, 0, sizeof(pkt));
+       if (!hl_device_operational(hdev, NULL))
+               return -ENODEV;
 
-       pkt.ctl = cpu_to_le32(CPUCP_PACKET_MAX_POWER_GET <<
-                               CPUCP_PKT_CTL_OPCODE_SHIFT);
+       value = hl_fw_get_frequency(hdev, hdev->asic_prop.clk_pll_index, true);
+       if (value < 0)
+               return value;
 
-       rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),
-                                               0, &result);
+       return sprintf(buf, "%lu\n", (value / 1000 / 1000));
+}
 
-       if (rc) {
-               dev_err(hdev->dev, "Failed to get max power, error %d\n", rc);
-               return (u64) rc;
-       }
+static DEVICE_ATTR_RW(clk_max_freq_mhz);
+static DEVICE_ATTR_RO(clk_cur_freq_mhz);
 
-       return result;
-}
+static struct attribute *hl_dev_clk_attrs[] = {
+       &dev_attr_clk_max_freq_mhz.attr,
+       &dev_attr_clk_cur_freq_mhz.attr,
+};
 
-void hl_set_max_power(struct hl_device *hdev)
+static ssize_t vrm_ver_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct cpucp_packet pkt;
-       int rc;
+       struct hl_device *hdev = dev_get_drvdata(dev);
+       struct cpucp_info *cpucp_info;
 
-       memset(&pkt, 0, sizeof(pkt));
+       cpucp_info = &hdev->asic_prop.cpucp_info;
 
-       pkt.ctl = cpu_to_le32(CPUCP_PACKET_MAX_POWER_SET <<
-                               CPUCP_PKT_CTL_OPCODE_SHIFT);
-       pkt.value = cpu_to_le64(hdev->max_power);
+       if (cpucp_info->infineon_second_stage_version)
+               return sprintf(buf, "%#04x %#04x\n", le32_to_cpu(cpucp_info->infineon_version),
+                               le32_to_cpu(cpucp_info->infineon_second_stage_version));
+       else
+               return sprintf(buf, "%#04x\n", le32_to_cpu(cpucp_info->infineon_version));
+}
 
-       rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),
-                                               0, NULL);
+static DEVICE_ATTR_RO(vrm_ver);
 
-       if (rc)
-               dev_err(hdev->dev, "Failed to set max power, error %d\n", rc);
-}
+static struct attribute *hl_dev_vrm_attrs[] = {
+       &dev_attr_vrm_ver.attr,
+};
 
 static ssize_t uboot_ver_show(struct device *dev, struct device_attribute *attr,
                                char *buf)
@@ -158,20 +144,6 @@ static ssize_t cpucp_ver_show(struct device *dev, struct device_attribute *attr,
        return sprintf(buf, "%s\n", hdev->asic_prop.cpucp_info.cpucp_version);
 }
 
-static ssize_t infineon_ver_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct hl_device *hdev = dev_get_drvdata(dev);
-
-       if (hdev->asic_prop.cpucp_info.infineon_second_stage_version)
-               return sprintf(buf, "%#04x %#04x\n",
-                       le32_to_cpu(hdev->asic_prop.cpucp_info.infineon_version),
-                       le32_to_cpu(hdev->asic_prop.cpucp_info.infineon_second_stage_version));
-       else
-               return sprintf(buf, "%#04x\n",
-                       le32_to_cpu(hdev->asic_prop.cpucp_info.infineon_version));
-}
-
 static ssize_t fuse_ver_show(struct device *dev, struct device_attribute *attr,
                                char *buf)
 {
@@ -188,6 +160,14 @@ static ssize_t thermal_ver_show(struct device *dev,
        return sprintf(buf, "%s", hdev->asic_prop.cpucp_info.thermal_version);
 }
 
+static ssize_t fw_os_ver_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct hl_device *hdev = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s", hdev->asic_prop.cpucp_info.fw_os_version);
+}
+
 static ssize_t preboot_btl_ver_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
@@ -323,7 +303,9 @@ static ssize_t max_power_show(struct device *dev, struct device_attribute *attr,
        if (!hl_device_operational(hdev, NULL))
                return -ENODEV;
 
-       val = hl_get_max_power(hdev);
+       val = hl_fw_get_max_power(hdev);
+       if (val < 0)
+               return val;
 
        return sprintf(buf, "%lu\n", val);
 }
@@ -348,7 +330,7 @@ static ssize_t max_power_store(struct device *dev,
        }
 
        hdev->max_power = value;
-       hl_set_max_power(hdev);
+       hl_fw_set_max_power(hdev);
 
 out:
        return count;
@@ -394,7 +376,6 @@ static DEVICE_ATTR_RO(device_type);
 static DEVICE_ATTR_RO(fuse_ver);
 static DEVICE_ATTR_WO(hard_reset);
 static DEVICE_ATTR_RO(hard_reset_cnt);
-static DEVICE_ATTR_RO(infineon_ver);
 static DEVICE_ATTR_RW(max_power);
 static DEVICE_ATTR_RO(pci_addr);
 static DEVICE_ATTR_RO(preboot_btl_ver);
@@ -403,6 +384,7 @@ static DEVICE_ATTR_RO(soft_reset_cnt);
 static DEVICE_ATTR_RO(status);
 static DEVICE_ATTR_RO(thermal_ver);
 static DEVICE_ATTR_RO(uboot_ver);
+static DEVICE_ATTR_RO(fw_os_ver);
 
 static struct bin_attribute bin_attr_eeprom = {
        .attr = {.name = "eeprom", .mode = (0444)},
@@ -420,13 +402,13 @@ static struct attribute *hl_dev_attrs[] = {
        &dev_attr_fuse_ver.attr,
        &dev_attr_hard_reset.attr,
        &dev_attr_hard_reset_cnt.attr,
-       &dev_attr_infineon_ver.attr,
        &dev_attr_max_power.attr,
        &dev_attr_pci_addr.attr,
        &dev_attr_preboot_btl_ver.attr,
        &dev_attr_status.attr,
        &dev_attr_thermal_ver.attr,
        &dev_attr_uboot_ver.attr,
+       &dev_attr_fw_os_ver.attr,
        NULL,
 };
 
@@ -441,10 +423,12 @@ static struct attribute_group hl_dev_attr_group = {
 };
 
 static struct attribute_group hl_dev_clks_attr_group;
+static struct attribute_group hl_dev_vrm_attr_group;
 
 static const struct attribute_group *hl_dev_attr_groups[] = {
        &hl_dev_attr_group,
        &hl_dev_clks_attr_group,
+       &hl_dev_vrm_attr_group,
        NULL,
 };
 
@@ -463,13 +447,23 @@ static const struct attribute_group *hl_dev_inference_attr_groups[] = {
        NULL,
 };
 
+void hl_sysfs_add_dev_clk_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp)
+{
+       dev_clk_attr_grp->attrs = hl_dev_clk_attrs;
+}
+
+void hl_sysfs_add_dev_vrm_attr(struct hl_device *hdev, struct attribute_group *dev_vrm_attr_grp)
+{
+       dev_vrm_attr_grp->attrs = hl_dev_vrm_attrs;
+}
+
 int hl_sysfs_init(struct hl_device *hdev)
 {
        int rc;
 
        hdev->max_power = hdev->asic_prop.max_power_default;
 
-       hdev->asic_funcs->add_device_attr(hdev, &hl_dev_clks_attr_group);
+       hdev->asic_funcs->add_device_attr(hdev, &hl_dev_clks_attr_group, &hl_dev_vrm_attr_group);
 
        rc = device_add_groups(hdev->dev, hl_dev_attr_groups);
        if (rc) {
index 013c6da..21c2b67 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 
 /*
- * Copyright 2016-2021 HabanaLabs, Ltd.
+ * Copyright 2016-2022 HabanaLabs, Ltd.
  * All Rights Reserved.
  */
 
@@ -458,7 +458,6 @@ struct ecc_info_extract_params {
        u64 block_address;
        u32 num_memories;
        bool derr;
-       bool disable_clock_gating;
 };
 
 static int gaudi_mmu_update_asid_hop0_addr(struct hl_device *hdev, u32 asid,
@@ -614,6 +613,9 @@ static int gaudi_set_fixed_properties(struct hl_device *hdev)
        prop->pmmu.page_size = PAGE_SIZE_4KB;
        prop->pmmu.num_hops = MMU_ARCH_5_HOPS;
        prop->pmmu.last_mask = LAST_MASK;
+       /* TODO: will be duplicated until implementing per-MMU props */
+       prop->pmmu.hop_table_size = prop->mmu_hop_table_size;
+       prop->pmmu.hop0_tables_total_size = prop->mmu_hop0_tables_total_size;
 
        /* PMMU and HPMMU are the same except of page size */
        memcpy(&prop->pmmu_huge, &prop->pmmu, sizeof(prop->pmmu));
@@ -667,6 +669,10 @@ static int gaudi_set_fixed_properties(struct hl_device *hdev)
 
        prop->use_get_power_for_reset_history = true;
 
+       prop->configurable_stop_on_err = true;
+
+       prop->set_max_power_on_device_init = true;
+
        return 0;
 }
 
@@ -1636,7 +1642,7 @@ static int gaudi_late_init(struct hl_device *hdev)
         */
        gaudi_mmu_prepare(hdev, 1);
 
-       hdev->asic_funcs->set_pll_profile(hdev, PLL_LAST);
+       hl_fw_set_pll_profile(hdev);
 
        return 0;
 
@@ -1896,7 +1902,6 @@ static int gaudi_sw_init(struct hl_device *hdev)
                goto free_cpu_accessible_dma_pool;
 
        spin_lock_init(&gaudi->hw_queues_lock);
-       mutex_init(&gaudi->clk_gate_mutex);
 
        hdev->supports_sync_stream = true;
        hdev->supports_coresight = true;
@@ -1946,8 +1951,6 @@ static int gaudi_sw_fini(struct hl_device *hdev)
 
        dma_pool_destroy(hdev->dma_pool);
 
-       mutex_destroy(&gaudi->clk_gate_mutex);
-
        kfree(gaudi);
 
        return 0;
@@ -3738,76 +3741,8 @@ static void gaudi_tpc_stall(struct hl_device *hdev)
        WREG32(mmTPC7_CFG_TPC_STALL, 1 << TPC0_CFG_TPC_STALL_V_SHIFT);
 }
 
-static void gaudi_set_clock_gating(struct hl_device *hdev)
-{
-       struct gaudi_device *gaudi = hdev->asic_specific;
-       u32 qman_offset;
-       bool enable;
-       int i;
-
-       /* In case we are during debug session, don't enable the clock gate
-        * as it may interfere
-        */
-       if (hdev->in_debug)
-               return;
-
-       if (hdev->asic_prop.fw_security_enabled)
-               return;
-
-       for (i = GAUDI_PCI_DMA_1, qman_offset = 0 ; i < GAUDI_HBM_DMA_1 ; i++) {
-               enable = !!(hdev->clock_gating_mask &
-                               (BIT_ULL(gaudi_dma_assignment[i])));
-
-               qman_offset = gaudi_dma_assignment[i] * DMA_QMAN_OFFSET;
-               WREG32(mmDMA0_QM_CGM_CFG1 + qman_offset,
-                               enable ? QMAN_CGM1_PWR_GATE_EN : 0);
-               WREG32(mmDMA0_QM_CGM_CFG + qman_offset,
-                               enable ? QMAN_UPPER_CP_CGM_PWR_GATE_EN : 0);
-       }
-
-       for (i = GAUDI_HBM_DMA_1 ; i < GAUDI_DMA_MAX ; i++) {
-               enable = !!(hdev->clock_gating_mask &
-                               (BIT_ULL(gaudi_dma_assignment[i])));
-
-               /* GC sends work to DMA engine through Upper CP in DMA5 so
-                * we need to not enable clock gating in that DMA
-                */
-               if (i == GAUDI_HBM_DMA_4)
-                       enable = 0;
-
-               qman_offset = gaudi_dma_assignment[i] * DMA_QMAN_OFFSET;
-               WREG32(mmDMA0_QM_CGM_CFG1 + qman_offset,
-                               enable ? QMAN_CGM1_PWR_GATE_EN : 0);
-               WREG32(mmDMA0_QM_CGM_CFG + qman_offset,
-                               enable ? QMAN_COMMON_CP_CGM_PWR_GATE_EN : 0);
-       }
-
-       enable = !!(hdev->clock_gating_mask & (BIT_ULL(GAUDI_ENGINE_ID_MME_0)));
-       WREG32(mmMME0_QM_CGM_CFG1, enable ? QMAN_CGM1_PWR_GATE_EN : 0);
-       WREG32(mmMME0_QM_CGM_CFG, enable ? QMAN_COMMON_CP_CGM_PWR_GATE_EN : 0);
-
-       enable = !!(hdev->clock_gating_mask & (BIT_ULL(GAUDI_ENGINE_ID_MME_2)));
-       WREG32(mmMME2_QM_CGM_CFG1, enable ? QMAN_CGM1_PWR_GATE_EN : 0);
-       WREG32(mmMME2_QM_CGM_CFG, enable ? QMAN_COMMON_CP_CGM_PWR_GATE_EN : 0);
-
-       for (i = 0, qman_offset = 0 ; i < TPC_NUMBER_OF_ENGINES ; i++) {
-               enable = !!(hdev->clock_gating_mask &
-                               (BIT_ULL(GAUDI_ENGINE_ID_TPC_0 + i)));
-
-               WREG32(mmTPC0_QM_CGM_CFG1 + qman_offset,
-                               enable ? QMAN_CGM1_PWR_GATE_EN : 0);
-               WREG32(mmTPC0_QM_CGM_CFG + qman_offset,
-                               enable ? QMAN_COMMON_CP_CGM_PWR_GATE_EN : 0);
-
-               qman_offset += TPC_QMAN_OFFSET;
-       }
-
-       gaudi->hw_cap_initialized |= HW_CAP_CLK_GATE;
-}
-
 static void gaudi_disable_clock_gating(struct hl_device *hdev)
 {
-       struct gaudi_device *gaudi = hdev->asic_specific;
        u32 qman_offset;
        int i;
 
@@ -3832,8 +3767,6 @@ static void gaudi_disable_clock_gating(struct hl_device *hdev)
 
                qman_offset += (mmTPC1_QM_CGM_CFG - mmTPC0_QM_CGM_CFG);
        }
-
-       gaudi->hw_cap_initialized &= ~(HW_CAP_CLK_GATE);
 }
 
 static void gaudi_enable_timestamp(struct hl_device *hdev)
@@ -3876,8 +3809,6 @@ static void gaudi_halt_engines(struct hl_device *hdev, bool hard_reset, bool fw_
        gaudi_stop_hbm_dma_qmans(hdev);
        gaudi_stop_pci_dma_qmans(hdev);
 
-       hdev->asic_funcs->disable_clock_gating(hdev);
-
        msleep(wait_timeout_ms);
 
        gaudi_pci_dma_stall(hdev);
@@ -3931,7 +3862,7 @@ static int gaudi_mmu_init(struct hl_device *hdev)
        /* mem cache invalidation */
        WREG32(mmSTLB_MEM_CACHE_INVALIDATION, 1);
 
-       hdev->asic_funcs->mmu_invalidate_cache(hdev, true, 0);
+       hl_mmu_invalidate_cache(hdev, true, 0);
 
        WREG32(mmMMU_UP_MMU_ENABLE, 1);
        WREG32(mmMMU_UP_SPI_MASK, 0xF);
@@ -4203,10 +4134,8 @@ static int gaudi_hw_init(struct hl_device *hdev)
 
        /* In case the clock gating was enabled in preboot we need to disable
         * it here before touching the MME/TPC registers.
-        * There is no need to take clk gating mutex because when this function
-        * runs, no other relevant code can run
         */
-       hdev->asic_funcs->disable_clock_gating(hdev);
+       gaudi_disable_clock_gating(hdev);
 
        /* SRAM scrambler must be initialized after CPU is running from HBM */
        gaudi_init_scrambler_sram(hdev);
@@ -4232,8 +4161,6 @@ static int gaudi_hw_init(struct hl_device *hdev)
 
        gaudi_init_nic_qmans(hdev);
 
-       hdev->asic_funcs->set_clock_gating(hdev);
-
        gaudi_enable_timestamp(hdev);
 
        /* MSI must be enabled before CPU queues and NIC are initialized */
@@ -4400,14 +4327,11 @@ skip_reset:
                        status);
 
        if (gaudi) {
-               gaudi->hw_cap_initialized &= ~(HW_CAP_CPU | HW_CAP_CPU_Q |
-                               HW_CAP_HBM | HW_CAP_PCI_DMA |
-                               HW_CAP_MME | HW_CAP_TPC_MASK |
-                               HW_CAP_HBM_DMA | HW_CAP_PLL |
-                               HW_CAP_NIC_MASK | HW_CAP_MMU |
-                               HW_CAP_SRAM_SCRAMBLER |
-                               HW_CAP_HBM_SCRAMBLER |
-                               HW_CAP_CLK_GATE);
+               gaudi->hw_cap_initialized &= ~(HW_CAP_CPU | HW_CAP_CPU_Q | HW_CAP_HBM |
+                                               HW_CAP_PCI_DMA | HW_CAP_MME | HW_CAP_TPC_MASK |
+                                               HW_CAP_HBM_DMA | HW_CAP_PLL | HW_CAP_NIC_MASK |
+                                               HW_CAP_MMU | HW_CAP_SRAM_SCRAMBLER |
+                                               HW_CAP_HBM_SCRAMBLER);
 
                memset(gaudi->events_stat, 0, sizeof(gaudi->events_stat));
 
@@ -4884,7 +4808,6 @@ static int gaudi_hbm_scrubbing(struct hl_device *hdev)
 static int gaudi_scrub_device_mem(struct hl_device *hdev, u64 addr, u64 size)
 {
        struct asic_fixed_properties *prop = &hdev->asic_prop;
-       struct gaudi_device *gaudi = hdev->asic_specific;
        int rc = 0;
        u64 val = 0;
 
@@ -4919,17 +4842,11 @@ static int gaudi_scrub_device_mem(struct hl_device *hdev, u64 addr, u64 size)
                        return rc;
                }
 
-               mutex_lock(&gaudi->clk_gate_mutex);
-               hdev->asic_funcs->disable_clock_gating(hdev);
-
                /* Scrub HBM using all DMA channels in parallel */
                rc = gaudi_hbm_scrubbing(hdev);
                if (rc)
                        dev_err(hdev->dev,
                                "Failed to clear HBM in mem scrub all\n");
-
-               hdev->asic_funcs->set_clock_gating(hdev);
-               mutex_unlock(&gaudi->clk_gate_mutex);
        }
 
        return rc;
@@ -6188,7 +6105,6 @@ static int gaudi_debugfs_read32(struct hl_device *hdev, u64 addr,
                        bool user_address, u32 *val)
 {
        struct asic_fixed_properties *prop = &hdev->asic_prop;
-       struct gaudi_device *gaudi = hdev->asic_specific;
        u64 hbm_bar_addr, host_phys_end;
        int rc = 0;
 
@@ -6196,38 +6112,31 @@ static int gaudi_debugfs_read32(struct hl_device *hdev, u64 addr,
 
        if ((addr >= CFG_BASE) && (addr < CFG_BASE + CFG_SIZE)) {
 
-               if ((gaudi->hw_cap_initialized & HW_CAP_CLK_GATE) &&
-                               (hdev->clock_gating_mask &
-                                               GAUDI_CLK_GATE_DEBUGFS_MASK)) {
+               *val = RREG32(addr - CFG_BASE);
 
-                       dev_err_ratelimited(hdev->dev,
-                               "Can't read register - clock gating is enabled!\n");
-                       rc = -EFAULT;
-               } else {
-                       *val = RREG32(addr - CFG_BASE);
-               }
+       } else if ((addr >= SRAM_BASE_ADDR) && (addr < SRAM_BASE_ADDR + SRAM_BAR_SIZE)) {
+
+               *val = readl(hdev->pcie_bar[SRAM_BAR_ID] + (addr - SRAM_BASE_ADDR));
 
-       } else if ((addr >= SRAM_BASE_ADDR) &&
-                       (addr < SRAM_BASE_ADDR + SRAM_BAR_SIZE)) {
-               *val = readl(hdev->pcie_bar[SRAM_BAR_ID] +
-                               (addr - SRAM_BASE_ADDR));
        } else if (addr < DRAM_PHYS_BASE + hdev->asic_prop.dram_size) {
-               u64 bar_base_addr = DRAM_PHYS_BASE +
-                               (addr & ~(prop->dram_pci_bar_size - 0x1ull));
+
+               u64 bar_base_addr = DRAM_PHYS_BASE + (addr & ~(prop->dram_pci_bar_size - 0x1ull));
 
                hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, bar_base_addr);
-               if (hbm_bar_addr != U64_MAX) {
-                       *val = readl(hdev->pcie_bar[HBM_BAR_ID] +
-                                               (addr - bar_base_addr));
 
-                       hbm_bar_addr = gaudi_set_hbm_bar_base(hdev,
-                                               hbm_bar_addr);
+               if (hbm_bar_addr != U64_MAX) {
+                       *val = readl(hdev->pcie_bar[HBM_BAR_ID] + (addr - bar_base_addr));
+                       hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, hbm_bar_addr);
                }
+
                if (hbm_bar_addr == U64_MAX)
                        rc = -EIO;
+
        } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end &&
                        user_address && !iommu_present(&pci_bus_type)) {
+
                *val = *(u32 *) phys_to_virt(addr - HOST_PHYS_BASE);
+
        } else {
                rc = -EFAULT;
        }
@@ -6239,7 +6148,6 @@ static int gaudi_debugfs_write32(struct hl_device *hdev, u64 addr,
                        bool user_address, u32 val)
 {
        struct asic_fixed_properties *prop = &hdev->asic_prop;
-       struct gaudi_device *gaudi = hdev->asic_specific;
        u64 hbm_bar_addr, host_phys_end;
        int rc = 0;
 
@@ -6247,38 +6155,31 @@ static int gaudi_debugfs_write32(struct hl_device *hdev, u64 addr,
 
        if ((addr >= CFG_BASE) && (addr < CFG_BASE + CFG_SIZE)) {
 
-               if ((gaudi->hw_cap_initialized & HW_CAP_CLK_GATE) &&
-                               (hdev->clock_gating_mask &
-                                               GAUDI_CLK_GATE_DEBUGFS_MASK)) {
+               WREG32(addr - CFG_BASE, val);
 
-                       dev_err_ratelimited(hdev->dev,
-                               "Can't write register - clock gating is enabled!\n");
-                       rc = -EFAULT;
-               } else {
-                       WREG32(addr - CFG_BASE, val);
-               }
+       } else if ((addr >= SRAM_BASE_ADDR) && (addr < SRAM_BASE_ADDR + SRAM_BAR_SIZE)) {
+
+               writel(val, hdev->pcie_bar[SRAM_BAR_ID] + (addr - SRAM_BASE_ADDR));
 
-       } else if ((addr >= SRAM_BASE_ADDR) &&
-                       (addr < SRAM_BASE_ADDR + SRAM_BAR_SIZE)) {
-               writel(val, hdev->pcie_bar[SRAM_BAR_ID] +
-                                       (addr - SRAM_BASE_ADDR));
        } else if (addr < DRAM_PHYS_BASE + hdev->asic_prop.dram_size) {
-               u64 bar_base_addr = DRAM_PHYS_BASE +
-                               (addr & ~(prop->dram_pci_bar_size - 0x1ull));
+
+               u64 bar_base_addr = DRAM_PHYS_BASE + (addr & ~(prop->dram_pci_bar_size - 0x1ull));
 
                hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, bar_base_addr);
-               if (hbm_bar_addr != U64_MAX) {
-                       writel(val, hdev->pcie_bar[HBM_BAR_ID] +
-                                               (addr - bar_base_addr));
 
-                       hbm_bar_addr = gaudi_set_hbm_bar_base(hdev,
-                                               hbm_bar_addr);
+               if (hbm_bar_addr != U64_MAX) {
+                       writel(val, hdev->pcie_bar[HBM_BAR_ID] + (addr - bar_base_addr));
+                       hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, hbm_bar_addr);
                }
+
                if (hbm_bar_addr == U64_MAX)
                        rc = -EIO;
+
        } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end &&
                        user_address && !iommu_present(&pci_bus_type)) {
+
                *(u32 *) phys_to_virt(addr - HOST_PHYS_BASE) = val;
+
        } else {
                rc = -EFAULT;
        }
@@ -6290,7 +6191,6 @@ static int gaudi_debugfs_read64(struct hl_device *hdev, u64 addr,
                                bool user_address, u64 *val)
 {
        struct asic_fixed_properties *prop = &hdev->asic_prop;
-       struct gaudi_device *gaudi = hdev->asic_specific;
        u64 hbm_bar_addr, host_phys_end;
        int rc = 0;
 
@@ -6298,42 +6198,35 @@ static int gaudi_debugfs_read64(struct hl_device *hdev, u64 addr,
 
        if ((addr >= CFG_BASE) && (addr <= CFG_BASE + CFG_SIZE - sizeof(u64))) {
 
-               if ((gaudi->hw_cap_initialized & HW_CAP_CLK_GATE) &&
-                               (hdev->clock_gating_mask &
-                                               GAUDI_CLK_GATE_DEBUGFS_MASK)) {
-
-                       dev_err_ratelimited(hdev->dev,
-                               "Can't read register - clock gating is enabled!\n");
-                       rc = -EFAULT;
-               } else {
-                       u32 val_l = RREG32(addr - CFG_BASE);
-                       u32 val_h = RREG32(addr + sizeof(u32) - CFG_BASE);
+               u32 val_l = RREG32(addr - CFG_BASE);
+               u32 val_h = RREG32(addr + sizeof(u32) - CFG_BASE);
 
-                       *val = (((u64) val_h) << 32) | val_l;
-               }
+               *val = (((u64) val_h) << 32) | val_l;
 
        } else if ((addr >= SRAM_BASE_ADDR) &&
-                  (addr <= SRAM_BASE_ADDR + SRAM_BAR_SIZE - sizeof(u64))) {
-               *val = readq(hdev->pcie_bar[SRAM_BAR_ID] +
-                               (addr - SRAM_BASE_ADDR));
-       } else if (addr <=
-                   DRAM_PHYS_BASE + hdev->asic_prop.dram_size - sizeof(u64)) {
-               u64 bar_base_addr = DRAM_PHYS_BASE +
-                               (addr & ~(prop->dram_pci_bar_size - 0x1ull));
+                       (addr <= SRAM_BASE_ADDR + SRAM_BAR_SIZE - sizeof(u64))) {
+
+               *val = readq(hdev->pcie_bar[SRAM_BAR_ID] + (addr - SRAM_BASE_ADDR));
+
+       } else if (addr <= DRAM_PHYS_BASE + hdev->asic_prop.dram_size - sizeof(u64)) {
+
+               u64 bar_base_addr = DRAM_PHYS_BASE + (addr & ~(prop->dram_pci_bar_size - 0x1ull));
 
                hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, bar_base_addr);
-               if (hbm_bar_addr != U64_MAX) {
-                       *val = readq(hdev->pcie_bar[HBM_BAR_ID] +
-                                               (addr - bar_base_addr));
 
-                       hbm_bar_addr = gaudi_set_hbm_bar_base(hdev,
-                                               hbm_bar_addr);
+               if (hbm_bar_addr != U64_MAX) {
+                       *val = readq(hdev->pcie_bar[HBM_BAR_ID] + (addr - bar_base_addr));
+                       hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, hbm_bar_addr);
                }
+
                if (hbm_bar_addr == U64_MAX)
                        rc = -EIO;
+
        } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end &&
                        user_address && !iommu_present(&pci_bus_type)) {
+
                *val = *(u64 *) phys_to_virt(addr - HOST_PHYS_BASE);
+
        } else {
                rc = -EFAULT;
        }
@@ -6345,7 +6238,6 @@ static int gaudi_debugfs_write64(struct hl_device *hdev, u64 addr,
                                bool user_address, u64 val)
 {
        struct asic_fixed_properties *prop = &hdev->asic_prop;
-       struct gaudi_device *gaudi = hdev->asic_specific;
        u64 hbm_bar_addr, host_phys_end;
        int rc = 0;
 
@@ -6353,41 +6245,33 @@ static int gaudi_debugfs_write64(struct hl_device *hdev, u64 addr,
 
        if ((addr >= CFG_BASE) && (addr <= CFG_BASE + CFG_SIZE - sizeof(u64))) {
 
-               if ((gaudi->hw_cap_initialized & HW_CAP_CLK_GATE) &&
-                               (hdev->clock_gating_mask &
-                                               GAUDI_CLK_GATE_DEBUGFS_MASK)) {
-
-                       dev_err_ratelimited(hdev->dev,
-                               "Can't write register - clock gating is enabled!\n");
-                       rc = -EFAULT;
-               } else {
-                       WREG32(addr - CFG_BASE, lower_32_bits(val));
-                       WREG32(addr + sizeof(u32) - CFG_BASE,
-                               upper_32_bits(val));
-               }
+               WREG32(addr - CFG_BASE, lower_32_bits(val));
+               WREG32(addr + sizeof(u32) - CFG_BASE, upper_32_bits(val));
 
        } else if ((addr >= SRAM_BASE_ADDR) &&
-                  (addr <= SRAM_BASE_ADDR + SRAM_BAR_SIZE - sizeof(u64))) {
-               writeq(val, hdev->pcie_bar[SRAM_BAR_ID] +
-                                       (addr - SRAM_BASE_ADDR));
-       } else if (addr <=
-                   DRAM_PHYS_BASE + hdev->asic_prop.dram_size - sizeof(u64)) {
-               u64 bar_base_addr = DRAM_PHYS_BASE +
-                               (addr & ~(prop->dram_pci_bar_size - 0x1ull));
+                       (addr <= SRAM_BASE_ADDR + SRAM_BAR_SIZE - sizeof(u64))) {
+
+               writeq(val, hdev->pcie_bar[SRAM_BAR_ID] + (addr - SRAM_BASE_ADDR));
+
+       } else if (addr <= DRAM_PHYS_BASE + hdev->asic_prop.dram_size - sizeof(u64)) {
+
+               u64 bar_base_addr = DRAM_PHYS_BASE + (addr & ~(prop->dram_pci_bar_size - 0x1ull));
 
                hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, bar_base_addr);
-               if (hbm_bar_addr != U64_MAX) {
-                       writeq(val, hdev->pcie_bar[HBM_BAR_ID] +
-                                               (addr - bar_base_addr));
 
-                       hbm_bar_addr = gaudi_set_hbm_bar_base(hdev,
-                                               hbm_bar_addr);
+               if (hbm_bar_addr != U64_MAX) {
+                       writeq(val, hdev->pcie_bar[HBM_BAR_ID] + (addr - bar_base_addr));
+                       hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, hbm_bar_addr);
                }
+
                if (hbm_bar_addr == U64_MAX)
                        rc = -EIO;
+
        } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end &&
                        user_address && !iommu_present(&pci_bus_type)) {
+
                *(u64 *) phys_to_virt(addr - HOST_PHYS_BASE) = val;
+
        } else {
                rc = -EFAULT;
        }
@@ -6446,7 +6330,6 @@ static int gaudi_debugfs_read_dma(struct hl_device *hdev, u64 addr, u32 size,
                                void *blob_addr)
 {
        u32 dma_core_sts0, err_cause, cfg1, size_left, pos, size_to_dma;
-       struct gaudi_device *gaudi = hdev->asic_specific;
        u32 qm_glbl_sts0, qm_cgm_sts;
        u64 dma_offset, qm_offset;
        dma_addr_t dma_addr;
@@ -6462,10 +6345,6 @@ static int gaudi_debugfs_read_dma(struct hl_device *hdev, u64 addr, u32 size,
        if (!kernel_addr)
                return -ENOMEM;
 
-       mutex_lock(&gaudi->clk_gate_mutex);
-
-       hdev->asic_funcs->disable_clock_gating(hdev);
-
        hdev->asic_funcs->hw_queues_lock(hdev);
 
        dma_id = gaudi_dma_assignment[GAUDI_PCI_DMA_1];
@@ -6550,10 +6429,6 @@ static int gaudi_debugfs_read_dma(struct hl_device *hdev, u64 addr, u32 size,
 out:
        hdev->asic_funcs->hw_queues_unlock(hdev);
 
-       hdev->asic_funcs->set_clock_gating(hdev);
-
-       mutex_unlock(&gaudi->clk_gate_mutex);
-
        hdev->asic_funcs->asic_dma_free_coherent(hdev, SZ_2M, kernel_addr,
                                                dma_addr);
 
@@ -6601,10 +6476,6 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid)
                return;
        }
 
-       mutex_lock(&gaudi->clk_gate_mutex);
-
-       hdev->asic_funcs->disable_clock_gating(hdev);
-
        gaudi_mmu_prepare_reg(hdev, mmDMA0_QM_GLBL_NON_SECURE_PROPS_0, asid);
        gaudi_mmu_prepare_reg(hdev, mmDMA0_QM_GLBL_NON_SECURE_PROPS_1, asid);
        gaudi_mmu_prepare_reg(hdev, mmDMA0_QM_GLBL_NON_SECURE_PROPS_2, asid);
@@ -6882,10 +6753,6 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid)
 
        gaudi_mmu_prepare_reg(hdev, mmPSOC_GLOBAL_CONF_TRACE_ARUSER, asid);
        gaudi_mmu_prepare_reg(hdev, mmPSOC_GLOBAL_CONF_TRACE_AWUSER, asid);
-
-       hdev->asic_funcs->set_clock_gating(hdev);
-
-       mutex_unlock(&gaudi->clk_gate_mutex);
 }
 
 static int gaudi_send_job_on_qman0(struct hl_device *hdev,
@@ -7266,10 +7133,8 @@ static int gaudi_extract_ecc_info(struct hl_device *hdev,
                struct ecc_info_extract_params *params, u64 *ecc_address,
                u64 *ecc_syndrom, u8 *memory_wrapper_idx)
 {
-       struct gaudi_device *gaudi = hdev->asic_specific;
        u32 i, num_mem_regs, reg, err_bit;
        u64 err_addr, err_word = 0;
-       int rc = 0;
 
        num_mem_regs = params->num_memories / 32 +
                        ((params->num_memories % 32) ? 1 : 0);
@@ -7282,11 +7147,6 @@ static int gaudi_extract_ecc_info(struct hl_device *hdev,
        else
                err_addr = params->block_address + GAUDI_ECC_SERR0_OFFSET;
 
-       if (params->disable_clock_gating) {
-               mutex_lock(&gaudi->clk_gate_mutex);
-               hdev->asic_funcs->disable_clock_gating(hdev);
-       }
-
        /* Set invalid wrapper index */
        *memory_wrapper_idx = 0xFF;
 
@@ -7303,8 +7163,7 @@ static int gaudi_extract_ecc_info(struct hl_device *hdev,
 
        if (*memory_wrapper_idx == 0xFF) {
                dev_err(hdev->dev, "ECC error information cannot be found\n");
-               rc = -EINVAL;
-               goto enable_clk_gate;
+               return -EINVAL;
        }
 
        WREG32(params->block_address + GAUDI_ECC_MEM_SEL_OFFSET,
@@ -7324,14 +7183,7 @@ static int gaudi_extract_ecc_info(struct hl_device *hdev,
 
        WREG32(params->block_address + GAUDI_ECC_MEM_INFO_CLR_OFFSET, reg);
 
-enable_clk_gate:
-       if (params->disable_clock_gating) {
-               hdev->asic_funcs->set_clock_gating(hdev);
-
-               mutex_unlock(&gaudi->clk_gate_mutex);
-       }
-
-       return rc;
+       return 0;
 }
 
 /*
@@ -7589,7 +7441,6 @@ static void gaudi_handle_ecc_event(struct hl_device *hdev, u16 event_type,
                params.block_address = mmTPC0_CFG_BASE + index * TPC_CFG_OFFSET;
                params.num_memories = 90;
                params.derr = false;
-               params.disable_clock_gating = true;
                extract_info_from_fw = false;
                break;
        case GAUDI_EVENT_TPC0_DERR ... GAUDI_EVENT_TPC7_DERR:
@@ -7598,7 +7449,6 @@ static void gaudi_handle_ecc_event(struct hl_device *hdev, u16 event_type,
                        mmTPC0_CFG_BASE + index * TPC_CFG_OFFSET;
                params.num_memories = 90;
                params.derr = true;
-               params.disable_clock_gating = true;
                extract_info_from_fw = false;
                break;
        case GAUDI_EVENT_MME0_ACC_SERR:
@@ -7609,7 +7459,6 @@ static void gaudi_handle_ecc_event(struct hl_device *hdev, u16 event_type,
                params.block_address = mmMME0_ACC_BASE + index * MME_ACC_OFFSET;
                params.num_memories = 128;
                params.derr = false;
-               params.disable_clock_gating = true;
                extract_info_from_fw = false;
                break;
        case GAUDI_EVENT_MME0_ACC_DERR:
@@ -7620,7 +7469,6 @@ static void gaudi_handle_ecc_event(struct hl_device *hdev, u16 event_type,
                params.block_address = mmMME0_ACC_BASE + index * MME_ACC_OFFSET;
                params.num_memories = 128;
                params.derr = true;
-               params.disable_clock_gating = true;
                extract_info_from_fw = false;
                break;
        case GAUDI_EVENT_MME0_SBAB_SERR:
@@ -7632,7 +7480,6 @@ static void gaudi_handle_ecc_event(struct hl_device *hdev, u16 event_type,
                        mmMME0_SBAB_BASE + index * MME_ACC_OFFSET;
                params.num_memories = 33;
                params.derr = false;
-               params.disable_clock_gating = true;
                extract_info_from_fw = false;
                break;
        case GAUDI_EVENT_MME0_SBAB_DERR:
@@ -7644,7 +7491,6 @@ static void gaudi_handle_ecc_event(struct hl_device *hdev, u16 event_type,
                        mmMME0_SBAB_BASE + index * MME_ACC_OFFSET;
                params.num_memories = 33;
                params.derr = true;
-               params.disable_clock_gating = true;
                extract_info_from_fw = false;
                break;
        default:
@@ -7819,6 +7665,48 @@ static void gaudi_print_fw_alive_info(struct hl_device *hdev,
                fw_alive->thread_id, fw_alive->uptime_seconds);
 }
 
+static void gaudi_print_nic_axi_irq_info(struct hl_device *hdev, u16 event_type,
+                                               void *data)
+{
+       char desc[64] = "", *type;
+       struct eq_nic_sei_event *eq_nic_sei = data;
+       u16 nic_id = event_type - GAUDI_EVENT_NIC_SEI_0;
+
+       switch (eq_nic_sei->axi_error_cause) {
+       case RXB:
+               type = "RXB";
+               break;
+       case RXE:
+               type = "RXE";
+               break;
+       case TXS:
+               type = "TXS";
+               break;
+       case TXE:
+               type = "TXE";
+               break;
+       case QPC_RESP:
+               type = "QPC_RESP";
+               break;
+       case NON_AXI_ERR:
+               type = "NON_AXI_ERR";
+               break;
+       case TMR:
+               type = "TMR";
+               break;
+       default:
+               dev_err(hdev->dev, "unknown NIC AXI cause %d\n",
+                       eq_nic_sei->axi_error_cause);
+               type = "N/A";
+               break;
+       }
+
+       snprintf(desc, sizeof(desc), "NIC%d_%s%d", nic_id, type,
+                       eq_nic_sei->id);
+       dev_err_ratelimited(hdev->dev, "Received H/W interrupt %d [\"%s\"]\n",
+               event_type, desc);
+}
+
 static int gaudi_non_hard_reset_late_init(struct hl_device *hdev)
 {
        /* GAUDI doesn't support any reset except hard-reset */
@@ -7966,19 +7854,9 @@ static int gaudi_hbm_event_to_dev(u16 hbm_event_type)
 static bool gaudi_tpc_read_interrupts(struct hl_device *hdev, u8 tpc_id,
                                        char *interrupt_name)
 {
-       struct gaudi_device *gaudi = hdev->asic_specific;
        u32 tpc_offset = tpc_id * TPC_CFG_OFFSET, tpc_interrupts_cause, i;
        bool soft_reset_required = false;
 
-       /* Accessing the TPC_INTR_CAUSE registers requires disabling the clock
-        * gating, and thus cannot be done in CPU-CP and should be done instead
-        * by the driver.
-        */
-
-       mutex_lock(&gaudi->clk_gate_mutex);
-
-       hdev->asic_funcs->disable_clock_gating(hdev);
-
        tpc_interrupts_cause = RREG32(mmTPC0_CFG_TPC_INTR_CAUSE + tpc_offset) &
                                TPC0_CFG_TPC_INTR_CAUSE_CAUSE_MASK;
 
@@ -7996,10 +7874,6 @@ static bool gaudi_tpc_read_interrupts(struct hl_device *hdev, u8 tpc_id,
        /* Clear interrupts */
        WREG32(mmTPC0_CFG_TPC_INTR_CAUSE + tpc_offset, 0);
 
-       hdev->asic_funcs->set_clock_gating(hdev);
-
-       mutex_unlock(&gaudi->clk_gate_mutex);
-
        return soft_reset_required;
 }
 
@@ -8066,6 +7940,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev,
                                struct hl_eq_entry *eq_entry)
 {
        struct gaudi_device *gaudi = hdev->asic_specific;
+       u64 data = le64_to_cpu(eq_entry->data[0]);
        u32 ctl = le32_to_cpu(eq_entry->hdr.ctl);
        u32 fw_fatal_err_flag = 0;
        u16 event_type = ((ctl & EQ_CTL_EVENT_TYPE_MASK)
@@ -8102,6 +7977,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev,
        case GAUDI_EVENT_PSOC_MEM_DERR:
        case GAUDI_EVENT_PSOC_CORESIGHT_DERR:
        case GAUDI_EVENT_SRAM0_DERR ... GAUDI_EVENT_SRAM28_DERR:
+       case GAUDI_EVENT_NIC0_DERR ... GAUDI_EVENT_NIC4_DERR:
        case GAUDI_EVENT_DMA_IF0_DERR ... GAUDI_EVENT_DMA_IF3_DERR:
        case GAUDI_EVENT_HBM_0_DERR ... GAUDI_EVENT_HBM_3_DERR:
        case GAUDI_EVENT_MMU_DERR:
@@ -8202,6 +8078,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev,
        case GAUDI_EVENT_PSOC_MEM_SERR:
        case GAUDI_EVENT_PSOC_CORESIGHT_SERR:
        case GAUDI_EVENT_SRAM0_SERR ... GAUDI_EVENT_SRAM28_SERR:
+       case GAUDI_EVENT_NIC0_SERR ... GAUDI_EVENT_NIC4_SERR:
        case GAUDI_EVENT_DMA_IF0_SERR ... GAUDI_EVENT_DMA_IF3_SERR:
        case GAUDI_EVENT_HBM_0_SERR ... GAUDI_EVENT_HBM_3_SERR:
                fallthrough;
@@ -8263,6 +8140,11 @@ static void gaudi_handle_eqe(struct hl_device *hdev,
                hl_fw_unmask_irq(hdev, event_type);
                break;
 
+       case GAUDI_EVENT_NIC_SEI_0 ... GAUDI_EVENT_NIC_SEI_4:
+               gaudi_print_nic_axi_irq_info(hdev, event_type, &data);
+               hl_fw_unmask_irq(hdev, event_type);
+               break;
+
        case GAUDI_EVENT_DMA_IF_SEI_0 ... GAUDI_EVENT_DMA_IF_SEI_3:
                gaudi_print_irq_info(hdev, event_type, false);
                gaudi_print_sm_sei_info(hdev, event_type,
@@ -8274,6 +8156,9 @@ static void gaudi_handle_eqe(struct hl_device *hdev,
                hl_fw_unmask_irq(hdev, event_type);
                break;
 
+       case GAUDI_EVENT_STATUS_NIC0_ENG0 ... GAUDI_EVENT_STATUS_NIC4_ENG1:
+               break;
+
        case GAUDI_EVENT_FIX_POWER_ENV_S ... GAUDI_EVENT_FIX_THERMAL_ENV_E:
                gaudi_print_clk_change_info(hdev, event_type);
                hl_fw_unmask_irq(hdev, event_type);
@@ -8314,7 +8199,7 @@ reset_device:
                                        | HL_DRV_RESET_BYPASS_REQ_TO_FW
                                        | fw_fatal_err_flag);
        else if (hdev->hard_reset_on_fw_events)
-               hl_device_reset(hdev, HL_DRV_RESET_HARD | fw_fatal_err_flag);
+               hl_device_reset(hdev, HL_DRV_RESET_HARD | HL_DRV_RESET_DELAY | fw_fatal_err_flag);
        else
                hl_fw_unmask_irq(hdev, event_type);
 }
@@ -8461,10 +8346,6 @@ static bool gaudi_is_device_idle(struct hl_device *hdev, u64 *mask_arr,
        u64 offset;
        int i, dma_id, port;
 
-       mutex_lock(&gaudi->clk_gate_mutex);
-
-       hdev->asic_funcs->disable_clock_gating(hdev);
-
        if (s)
                seq_puts(s,
                        "\nDMA  is_idle  QM_GLBL_STS0  QM_CGM_STS  DMA_CORE_STS0\n"
@@ -8585,10 +8466,6 @@ static bool gaudi_is_device_idle(struct hl_device *hdev, u64 *mask_arr,
        if (s)
                seq_puts(s, "\n");
 
-       hdev->asic_funcs->set_clock_gating(hdev);
-
-       mutex_unlock(&gaudi->clk_gate_mutex);
-
        return is_idle;
 }
 
@@ -8628,10 +8505,8 @@ static int gaudi_get_eeprom_data(struct hl_device *hdev, void *data,
  * this function should be used only during initialization and/or after reset,
  * when there are no active users.
  */
-static int gaudi_run_tpc_kernel(struct hl_device *hdev, u64 tpc_kernel,
-                               u32 tpc_id)
+static int gaudi_run_tpc_kernel(struct hl_device *hdev, u64 tpc_kernel,        u32 tpc_id)
 {
-       struct gaudi_device *gaudi = hdev->asic_specific;
        u64 kernel_timeout;
        u32 status, offset;
        int rc;
@@ -8643,10 +8518,6 @@ static int gaudi_run_tpc_kernel(struct hl_device *hdev, u64 tpc_kernel,
        else
                kernel_timeout = HL_DEVICE_TIMEOUT_USEC;
 
-       mutex_lock(&gaudi->clk_gate_mutex);
-
-       hdev->asic_funcs->disable_clock_gating(hdev);
-
        WREG32(mmTPC0_CFG_QM_KERNEL_BASE_ADDRESS_LOW + offset,
                        lower_32_bits(tpc_kernel));
        WREG32(mmTPC0_CFG_QM_KERNEL_BASE_ADDRESS_HIGH + offset,
@@ -8686,8 +8557,6 @@ static int gaudi_run_tpc_kernel(struct hl_device *hdev, u64 tpc_kernel,
                dev_err(hdev->dev,
                        "Timeout while waiting for TPC%d icache prefetch\n",
                        tpc_id);
-               hdev->asic_funcs->set_clock_gating(hdev);
-               mutex_unlock(&gaudi->clk_gate_mutex);
                return -EIO;
        }
 
@@ -8711,8 +8580,6 @@ static int gaudi_run_tpc_kernel(struct hl_device *hdev, u64 tpc_kernel,
                dev_err(hdev->dev,
                        "Timeout while waiting for TPC%d vector pipe\n",
                        tpc_id);
-               hdev->asic_funcs->set_clock_gating(hdev);
-               mutex_unlock(&gaudi->clk_gate_mutex);
                return -EIO;
        }
 
@@ -8724,9 +8591,6 @@ static int gaudi_run_tpc_kernel(struct hl_device *hdev, u64 tpc_kernel,
                1000,
                kernel_timeout);
 
-       hdev->asic_funcs->set_clock_gating(hdev);
-       mutex_unlock(&gaudi->clk_gate_mutex);
-
        if (rc) {
                dev_err(hdev->dev,
                        "Timeout while waiting for TPC%d kernel to execute\n",
@@ -8791,7 +8655,7 @@ static int gaudi_internal_cb_pool_init(struct hl_device *hdev,
                        hdev->internal_cb_pool_dma_addr,
                        HOST_SPACE_INTERNAL_CB_SZ);
 
-       hdev->asic_funcs->mmu_invalidate_cache(hdev, false, MMU_OP_USERPTR);
+       hl_mmu_invalidate_cache(hdev, false, MMU_OP_USERPTR);
        mutex_unlock(&ctx->mmu_lock);
 
        if (rc)
@@ -8826,7 +8690,7 @@ static void gaudi_internal_cb_pool_fini(struct hl_device *hdev,
                        HOST_SPACE_INTERNAL_CB_SZ);
        hl_unreserve_va_block(hdev, ctx, hdev->internal_cb_va_base,
                        HOST_SPACE_INTERNAL_CB_SZ);
-       hdev->asic_funcs->mmu_invalidate_cache(hdev, true, MMU_OP_USERPTR);
+       hl_mmu_invalidate_cache(hdev, true, MMU_OP_USERPTR);
        mutex_unlock(&ctx->mmu_lock);
 
        gen_pool_destroy(hdev->internal_cb_pool);
@@ -9204,14 +9068,7 @@ static void gaudi_reset_sob(struct hl_device *hdev, void *data)
 
 static void gaudi_set_dma_mask_from_fw(struct hl_device *hdev)
 {
-       if (RREG32(mmPSOC_GLOBAL_CONF_NON_RST_FLOPS_0) ==
-                                                       HL_POWER9_HOST_MAGIC) {
-               hdev->power9_64bit_dma_enable = 1;
-               hdev->dma_mask = 64;
-       } else {
-               hdev->power9_64bit_dma_enable = 0;
-               hdev->dma_mask = 48;
-       }
+       hdev->dma_mask = 48;
 }
 
 static u64 gaudi_get_device_time(struct hl_device *hdev)
@@ -9293,23 +9150,15 @@ static int gaudi_gen_sync_to_engine_map(struct hl_device *hdev,
                                struct hl_sync_to_engine_map *map)
 {
        struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
-       struct gaudi_device *gaudi = hdev->asic_specific;
        int i, j, rc;
        u32 reg_value;
 
        /* Iterate over TPC engines */
        for (i = 0; i < sds->props[SP_NUM_OF_TPC_ENGINES]; ++i) {
-               /* TPC registered must be accessed with clock gating disabled */
-               mutex_lock(&gaudi->clk_gate_mutex);
-               hdev->asic_funcs->disable_clock_gating(hdev);
 
                reg_value = RREG32(sds->props[SP_TPC0_CFG_SO] +
                                        sds->props[SP_NEXT_TPC] * i);
 
-               /* We can reenable clock_gating */
-               hdev->asic_funcs->set_clock_gating(hdev);
-               mutex_unlock(&gaudi->clk_gate_mutex);
-
                rc = gaudi_add_sync_to_engine_map_entry(map, reg_value,
                                                        ENGINE_TPC, i);
                if (rc)
@@ -9319,20 +9168,11 @@ static int gaudi_gen_sync_to_engine_map(struct hl_device *hdev,
        /* Iterate over MME engines */
        for (i = 0; i < sds->props[SP_NUM_OF_MME_ENGINES]; ++i) {
                for (j = 0; j < sds->props[SP_SUB_MME_ENG_NUM]; ++j) {
-                       /* MME registered must be accessed with clock gating
-                        * disabled
-                        */
-                       mutex_lock(&gaudi->clk_gate_mutex);
-                       hdev->asic_funcs->disable_clock_gating(hdev);
 
                        reg_value = RREG32(sds->props[SP_MME_CFG_SO] +
                                                sds->props[SP_NEXT_MME] * i +
                                                j * sizeof(u32));
 
-                       /* We can reenable clock_gating */
-                       hdev->asic_funcs->set_clock_gating(hdev);
-                       mutex_unlock(&gaudi->clk_gate_mutex);
-
                        rc = gaudi_add_sync_to_engine_map_entry(
                                map, reg_value, ENGINE_MME,
                                i * sds->props[SP_SUB_MME_ENG_NUM] + j);
@@ -9537,6 +9377,29 @@ static u32 *gaudi_get_stream_master_qid_arr(void)
        return gaudi_stream_master;
 }
 
+static ssize_t infineon_ver_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct hl_device *hdev = dev_get_drvdata(dev);
+       struct cpucp_info *cpucp_info;
+
+       cpucp_info = &hdev->asic_prop.cpucp_info;
+
+       return sprintf(buf, "%#04x\n", le32_to_cpu(cpucp_info->infineon_version));
+}
+
+static DEVICE_ATTR_RO(infineon_ver);
+
+static struct attribute *gaudi_vrm_dev_attrs[] = {
+       &dev_attr_infineon_ver.attr,
+};
+
+static void gaudi_add_device_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp,
+                                       struct attribute_group *dev_vrm_attr_grp)
+{
+       hl_sysfs_add_dev_clk_attr(hdev, dev_clk_attr_grp);
+       dev_vrm_attr_grp->attrs = gaudi_vrm_dev_attrs;
+}
+
 static const struct hl_asic_funcs gaudi_funcs = {
        .early_init = gaudi_early_init,
        .early_fini = gaudi_early_fini,
@@ -9574,17 +9437,14 @@ static const struct hl_asic_funcs gaudi_funcs = {
        .debugfs_read64 = gaudi_debugfs_read64,
        .debugfs_write64 = gaudi_debugfs_write64,
        .debugfs_read_dma = gaudi_debugfs_read_dma,
-       .add_device_attr = hl_add_device_attr,
+       .add_device_attr = gaudi_add_device_attr,
        .handle_eqe = gaudi_handle_eqe,
-       .set_pll_profile = hl_set_pll_profile,
        .get_events_stat = gaudi_get_events_stat,
        .read_pte = gaudi_read_pte,
        .write_pte = gaudi_write_pte,
        .mmu_invalidate_cache = gaudi_mmu_invalidate_cache,
        .mmu_invalidate_cache_range = gaudi_mmu_invalidate_cache_range,
        .send_heartbeat = gaudi_send_heartbeat,
-       .set_clock_gating = gaudi_set_clock_gating,
-       .disable_clock_gating = gaudi_disable_clock_gating,
        .debug_coresight = gaudi_debug_coresight,
        .is_device_idle = gaudi_is_device_idle,
        .non_hard_reset_late_init = gaudi_non_hard_reset_late_init,
@@ -9600,7 +9460,6 @@ static const struct hl_asic_funcs gaudi_funcs = {
        .halt_coresight = gaudi_halt_coresight,
        .ctx_init = gaudi_ctx_init,
        .ctx_fini = gaudi_ctx_fini,
-       .get_clk_rate = hl_get_clk_rate,
        .get_queue_id_for_cq = gaudi_get_queue_id_for_cq,
        .load_firmware_to_device = gaudi_load_firmware_to_device,
        .load_boot_fit_to_device = gaudi_load_boot_fit_to_device,
@@ -9626,7 +9485,8 @@ static const struct hl_asic_funcs gaudi_funcs = {
        .state_dump_init = gaudi_state_dump_init,
        .get_sob_addr = gaudi_get_sob_addr,
        .set_pci_memory_regions = gaudi_set_pci_memory_regions,
-       .get_stream_master_qid_arr = gaudi_get_stream_master_qid_arr
+       .get_stream_master_qid_arr = gaudi_get_stream_master_qid_arr,
+       .is_valid_dram_page_size = NULL
 };
 
 /**
index 8ac16a9..54de7c5 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0
  *
- * Copyright 2019-2020 HabanaLabs, Ltd.
+ * Copyright 2019-2022 HabanaLabs, Ltd.
  * All Rights Reserved.
  *
  */
 #define HW_CAP_MSI             BIT(6)
 #define HW_CAP_CPU_Q           BIT(7)
 #define HW_CAP_HBM_DMA         BIT(8)
-#define HW_CAP_CLK_GATE                BIT(9)
 #define HW_CAP_SRAM_SCRAMBLER  BIT(10)
 #define HW_CAP_HBM_SCRAMBLER   BIT(11)
 
@@ -313,8 +312,6 @@ struct gaudi_internal_qman_info {
  * struct gaudi_device - ASIC specific manage structure.
  * @cpucp_info_get: get information on device from CPU-CP
  * @hw_queues_lock: protects the H/W queues from concurrent access.
- * @clk_gate_mutex: protects code areas that require clock gating to be disabled
- *                  temporarily
  * @internal_qmans: Internal QMANs information. The array size is larger than
  *                  the actual number of internal queues because they are not in
  *                  consecutive order.
@@ -337,7 +334,6 @@ struct gaudi_device {
 
        /* TODO: remove hw_queues_lock after moving to scheduler code */
        spinlock_t                      hw_queues_lock;
-       struct mutex                    clk_gate_mutex;
 
        struct gaudi_internal_qman_info internal_qmans[GAUDI_QUEUE_ID_SIZE];
 
@@ -355,8 +351,6 @@ struct gaudi_device {
 
 void gaudi_init_security(struct hl_device *hdev);
 void gaudi_ack_protection_bits_errors(struct hl_device *hdev);
-void gaudi_add_device_attr(struct hl_device *hdev,
-                       struct attribute_group *dev_attr_grp);
 int gaudi_debug_coresight(struct hl_device *hdev, struct hl_ctx *ctx, void *data);
 void gaudi_halt_coresight(struct hl_device *hdev, struct hl_ctx *ctx);
 void gaudi_mmu_prepare_reg(struct hl_device *hdev, u64 reg, u32 asid);
index fbcc7bb..ec9358b 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 
 /*
- * Copyright 2016-2021 HabanaLabs, Ltd.
+ * Copyright 2016-2022 HabanaLabs, Ltd.
  * All Rights Reserved.
  */
 
@@ -430,6 +430,9 @@ int goya_set_fixed_properties(struct hl_device *hdev)
        prop->dmmu.page_size = PAGE_SIZE_2MB;
        prop->dmmu.num_hops = MMU_ARCH_5_HOPS;
        prop->dmmu.last_mask = LAST_MASK;
+       /* TODO: will be duplicated until implementing per-MMU props */
+       prop->dmmu.hop_table_size = prop->mmu_hop_table_size;
+       prop->dmmu.hop0_tables_total_size = prop->mmu_hop0_tables_total_size;
 
        /* shifts and masks are the same in PMMU and DMMU */
        memcpy(&prop->pmmu, &prop->dmmu, sizeof(prop->dmmu));
@@ -438,6 +441,9 @@ int goya_set_fixed_properties(struct hl_device *hdev)
        prop->pmmu.page_size = PAGE_SIZE_4KB;
        prop->pmmu.num_hops = MMU_ARCH_5_HOPS;
        prop->pmmu.last_mask = LAST_MASK;
+       /* TODO: will be duplicated until implementing per-MMU props */
+       prop->pmmu.hop_table_size = prop->mmu_hop_table_size;
+       prop->pmmu.hop0_tables_total_size = prop->mmu_hop0_tables_total_size;
 
        /* PMMU and HPMMU are the same except of page size */
        memcpy(&prop->pmmu_huge, &prop->pmmu, sizeof(prop->pmmu));
@@ -477,6 +483,10 @@ int goya_set_fixed_properties(struct hl_device *hdev)
 
        prop->use_get_power_for_reset_history = true;
 
+       prop->configurable_stop_on_err = true;
+
+       prop->set_max_power_on_device_init = true;
+
        return 0;
 }
 
@@ -893,7 +903,7 @@ int goya_late_init(struct hl_device *hdev)
 
        goya->pm_mng_profile = PM_AUTO;
 
-       hdev->asic_funcs->set_pll_profile(hdev, PLL_LOW);
+       goya_set_pll_profile(hdev, PLL_LOW);
 
        schedule_delayed_work(&goya->goya_work->work_freq,
                usecs_to_jiffies(HL_PLL_LOW_JOB_FREQ_USEC));
@@ -2700,8 +2710,7 @@ int goya_mmu_init(struct hl_device *hdev)
        WREG32_AND(mmSTLB_STLB_FEATURE_EN,
                        (~STLB_STLB_FEATURE_EN_FOLLOWER_EN_MASK));
 
-       hdev->asic_funcs->mmu_invalidate_cache(hdev, true,
-                                       MMU_OP_USERPTR | MMU_OP_PHYS_PACK);
+       hl_mmu_invalidate_cache(hdev, true, MMU_OP_USERPTR | MMU_OP_PHYS_PACK);
 
        WREG32(mmMMU_MMU_ENABLE, 1);
        WREG32(mmMMU_SPI_MASK, 0xF);
@@ -5341,7 +5350,7 @@ static int goya_mmu_invalidate_cache_range(struct hl_device *hdev,
        /* Treat as invalidate all because there is no range invalidation
         * in Goya
         */
-       return hdev->asic_funcs->mmu_invalidate_cache(hdev, is_hard, flags);
+       return hl_mmu_invalidate_cache(hdev, is_hard, flags);
 }
 
 int goya_send_heartbeat(struct hl_device *hdev)
@@ -5391,16 +5400,6 @@ int goya_cpucp_info_get(struct hl_device *hdev)
        return 0;
 }
 
-static void goya_set_clock_gating(struct hl_device *hdev)
-{
-       /* clock gating not supported in Goya */
-}
-
-static void goya_disable_clock_gating(struct hl_device *hdev)
-{
-       /* clock gating not supported in Goya */
-}
-
 static bool goya_is_device_idle(struct hl_device *hdev, u64 *mask_arr,
                                        u8 mask_len, struct seq_file *s)
 {
@@ -5564,16 +5563,7 @@ static void goya_reset_sob_group(struct hl_device *hdev, u16 sob_group)
 
 static void goya_set_dma_mask_from_fw(struct hl_device *hdev)
 {
-       if (RREG32(mmPSOC_GLOBAL_CONF_NON_RST_FLOPS_0) ==
-                                                       HL_POWER9_HOST_MAGIC) {
-               dev_dbg(hdev->dev, "Working in 64-bit DMA mode\n");
-               hdev->power9_64bit_dma_enable = 1;
-               hdev->dma_mask = 64;
-       } else {
-               dev_dbg(hdev->dev, "Working in 48-bit DMA mode\n");
-               hdev->power9_64bit_dma_enable = 0;
-               hdev->dma_mask = 48;
-       }
+       hdev->dma_mask = 48;
 }
 
 u64 goya_get_device_time(struct hl_device *hdev)
@@ -5727,15 +5717,12 @@ static const struct hl_asic_funcs goya_funcs = {
        .debugfs_read_dma = goya_debugfs_read_dma,
        .add_device_attr = goya_add_device_attr,
        .handle_eqe = goya_handle_eqe,
-       .set_pll_profile = goya_set_pll_profile,
        .get_events_stat = goya_get_events_stat,
        .read_pte = goya_read_pte,
        .write_pte = goya_write_pte,
        .mmu_invalidate_cache = goya_mmu_invalidate_cache,
        .mmu_invalidate_cache_range = goya_mmu_invalidate_cache_range,
        .send_heartbeat = goya_send_heartbeat,
-       .set_clock_gating = goya_set_clock_gating,
-       .disable_clock_gating = goya_disable_clock_gating,
        .debug_coresight = goya_debug_coresight,
        .is_device_idle = goya_is_device_idle,
        .non_hard_reset_late_init = goya_non_hard_reset_late_init,
@@ -5751,7 +5738,6 @@ static const struct hl_asic_funcs goya_funcs = {
        .halt_coresight = goya_halt_coresight,
        .ctx_init = goya_ctx_init,
        .ctx_fini = goya_ctx_fini,
-       .get_clk_rate = hl_get_clk_rate,
        .get_queue_id_for_cq = goya_get_queue_id_for_cq,
        .load_firmware_to_device = goya_load_firmware_to_device,
        .load_boot_fit_to_device = goya_load_boot_fit_to_device,
@@ -5778,6 +5764,7 @@ static const struct hl_asic_funcs goya_funcs = {
        .get_sob_addr = &goya_get_sob_addr,
        .set_pci_memory_regions = goya_set_pci_memory_regions,
        .get_stream_master_qid_arr = goya_get_stream_master_qid_arr,
+       .is_valid_dram_page_size = NULL
 };
 
 /*
index 3740fd2..647f574 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0
  *
- * Copyright 2016-2019 HabanaLabs, Ltd.
+ * Copyright 2016-2022 HabanaLabs, Ltd.
  * All Rights Reserved.
  *
  */
@@ -217,8 +217,8 @@ u64 goya_get_max_power(struct hl_device *hdev);
 void goya_set_max_power(struct hl_device *hdev, u64 value);
 
 void goya_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq);
-void goya_add_device_attr(struct hl_device *hdev,
-                       struct attribute_group *dev_attr_grp);
+void goya_add_device_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp,
+                               struct attribute_group *dev_vrm_attr_grp);
 int goya_cpucp_info_get(struct hl_device *hdev);
 int goya_debug_coresight(struct hl_device *hdev, struct hl_ctx *ctx, void *data);
 void goya_halt_coresight(struct hl_device *hdev, struct hl_ctx *ctx);
index 76b4774..6580fc6 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 
 /*
- * Copyright 2016-2021 HabanaLabs, Ltd.
+ * Copyright 2016-2022 HabanaLabs, Ltd.
  * All Rights Reserved.
  */
 
@@ -11,21 +11,24 @@ void goya_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq)
 {
        struct goya_device *goya = hdev->asic_specific;
 
+       if (!hdev->pdev)
+               return;
+
        switch (freq) {
        case PLL_HIGH:
-               hl_set_frequency(hdev, HL_GOYA_MME_PLL, hdev->high_pll);
-               hl_set_frequency(hdev, HL_GOYA_TPC_PLL, hdev->high_pll);
-               hl_set_frequency(hdev, HL_GOYA_IC_PLL, hdev->high_pll);
+               hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, hdev->high_pll);
+               hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, hdev->high_pll);
+               hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, hdev->high_pll);
                break;
        case PLL_LOW:
-               hl_set_frequency(hdev, HL_GOYA_MME_PLL, GOYA_PLL_FREQ_LOW);
-               hl_set_frequency(hdev, HL_GOYA_TPC_PLL, GOYA_PLL_FREQ_LOW);
-               hl_set_frequency(hdev, HL_GOYA_IC_PLL, GOYA_PLL_FREQ_LOW);
+               hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, GOYA_PLL_FREQ_LOW);
+               hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, GOYA_PLL_FREQ_LOW);
+               hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, GOYA_PLL_FREQ_LOW);
                break;
        case PLL_LAST:
-               hl_set_frequency(hdev, HL_GOYA_MME_PLL, goya->mme_clk);
-               hl_set_frequency(hdev, HL_GOYA_TPC_PLL, goya->tpc_clk);
-               hl_set_frequency(hdev, HL_GOYA_IC_PLL, goya->ic_clk);
+               hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, goya->mme_clk);
+               hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, goya->tpc_clk);
+               hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, goya->ic_clk);
                break;
        default:
                dev_err(hdev->dev, "unknown frequency setting\n");
@@ -41,7 +44,7 @@ static ssize_t mme_clk_show(struct device *dev, struct device_attribute *attr,
        if (!hl_device_operational(hdev, NULL))
                return -ENODEV;
 
-       value = hl_get_frequency(hdev, HL_GOYA_MME_PLL, false);
+       value = hl_fw_get_frequency(hdev, HL_GOYA_MME_PLL, false);
 
        if (value < 0)
                return value;
@@ -74,7 +77,7 @@ static ssize_t mme_clk_store(struct device *dev, struct device_attribute *attr,
                goto fail;
        }
 
-       hl_set_frequency(hdev, HL_GOYA_MME_PLL, value);
+       hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, value);
        goya->mme_clk = value;
 
 fail:
@@ -90,7 +93,7 @@ static ssize_t tpc_clk_show(struct device *dev, struct device_attribute *attr,
        if (!hl_device_operational(hdev, NULL))
                return -ENODEV;
 
-       value = hl_get_frequency(hdev, HL_GOYA_TPC_PLL, false);
+       value = hl_fw_get_frequency(hdev, HL_GOYA_TPC_PLL, false);
 
        if (value < 0)
                return value;
@@ -123,7 +126,7 @@ static ssize_t tpc_clk_store(struct device *dev, struct device_attribute *attr,
                goto fail;
        }
 
-       hl_set_frequency(hdev, HL_GOYA_TPC_PLL, value);
+       hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, value);
        goya->tpc_clk = value;
 
 fail:
@@ -139,7 +142,7 @@ static ssize_t ic_clk_show(struct device *dev, struct device_attribute *attr,
        if (!hl_device_operational(hdev, NULL))
                return -ENODEV;
 
-       value = hl_get_frequency(hdev, HL_GOYA_IC_PLL, false);
+       value = hl_fw_get_frequency(hdev, HL_GOYA_IC_PLL, false);
 
        if (value < 0)
                return value;
@@ -172,7 +175,7 @@ static ssize_t ic_clk_store(struct device *dev, struct device_attribute *attr,
                goto fail;
        }
 
-       hl_set_frequency(hdev, HL_GOYA_IC_PLL, value);
+       hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, value);
        goya->ic_clk = value;
 
 fail:
@@ -188,7 +191,7 @@ static ssize_t mme_clk_curr_show(struct device *dev,
        if (!hl_device_operational(hdev, NULL))
                return -ENODEV;
 
-       value = hl_get_frequency(hdev, HL_GOYA_MME_PLL, true);
+       value = hl_fw_get_frequency(hdev, HL_GOYA_MME_PLL, true);
 
        if (value < 0)
                return value;
@@ -205,7 +208,7 @@ static ssize_t tpc_clk_curr_show(struct device *dev,
        if (!hl_device_operational(hdev, NULL))
                return -ENODEV;
 
-       value = hl_get_frequency(hdev, HL_GOYA_TPC_PLL, true);
+       value = hl_fw_get_frequency(hdev, HL_GOYA_TPC_PLL, true);
 
        if (value < 0)
                return value;
@@ -222,7 +225,7 @@ static ssize_t ic_clk_curr_show(struct device *dev,
        if (!hl_device_operational(hdev, NULL))
                return -ENODEV;
 
-       value = hl_get_frequency(hdev, HL_GOYA_IC_PLL, true);
+       value = hl_fw_get_frequency(hdev, HL_GOYA_IC_PLL, true);
 
        if (value < 0)
                return value;
@@ -347,7 +350,7 @@ static DEVICE_ATTR_RW(pm_mng_profile);
 static DEVICE_ATTR_RW(tpc_clk);
 static DEVICE_ATTR_RO(tpc_clk_curr);
 
-static struct attribute *goya_dev_attrs[] = {
+static struct attribute *goya_clk_dev_attrs[] = {
        &dev_attr_high_pll.attr,
        &dev_attr_ic_clk.attr,
        &dev_attr_ic_clk_curr.attr,
@@ -356,11 +359,27 @@ static struct attribute *goya_dev_attrs[] = {
        &dev_attr_pm_mng_profile.attr,
        &dev_attr_tpc_clk.attr,
        &dev_attr_tpc_clk_curr.attr,
-       NULL,
 };
 
-void goya_add_device_attr(struct hl_device *hdev,
-                       struct attribute_group *dev_attr_grp)
+static ssize_t infineon_ver_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct hl_device *hdev = dev_get_drvdata(dev);
+       struct cpucp_info *cpucp_info;
+
+       cpucp_info = &hdev->asic_prop.cpucp_info;
+
+       return sprintf(buf, "%#04x\n", le32_to_cpu(cpucp_info->infineon_version));
+}
+
+static DEVICE_ATTR_RO(infineon_ver);
+
+static struct attribute *goya_vrm_dev_attrs[] = {
+       &dev_attr_infineon_ver.attr,
+};
+
+void goya_add_device_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp,
+                               struct attribute_group *dev_vrm_attr_grp)
 {
-       dev_attr_grp->attrs = goya_dev_attrs;
+       dev_clk_attr_grp->attrs = goya_clk_dev_attrs;
+       dev_vrm_attr_grp->attrs = goya_vrm_dev_attrs;
 }
index 737c39f..f00db22 100644 (file)
@@ -780,6 +780,7 @@ struct cpucp_security_info {
  *                     (0 = functional 1 = binned)
  * @xbar_binning_mask: Xbar binning mask, 1 bit per Xbar instance
  *                     (0 = functional 1 = binned)
+ * @fw_os_version: Firmware OS Version
  */
 struct cpucp_info {
        struct cpucp_sensor sensors[CPUCP_MAX_SENSORS];
@@ -807,6 +808,7 @@ struct cpucp_info {
        __le32 reserved6;
        __u8 pll_map[PLL_MAP_LEN];
        __le64 mme_binning_mask;
+       __u8 fw_os_version[VERSION_MAX_LEN];
 };
 
 struct cpucp_mac_addr {
index 135e21d..15f91ae 100644 (file)
@@ -33,6 +33,7 @@ enum cpu_boot_err {
        CPU_BOOT_ERR_BOOT_FW_CRIT_ERR = 18,
        CPU_BOOT_ERR_BINNING_FAIL = 19,
        CPU_BOOT_ERR_TPM_FAIL = 20,
+       CPU_BOOT_ERR_TMP_THRESH_INIT_FAIL = 21,
        CPU_BOOT_ERR_ENABLED = 31,
        CPU_BOOT_ERR_SCND_EN = 63,
        CPU_BOOT_ERR_LAST = 64 /* we have 2 registers of 32 bits */
@@ -111,6 +112,9 @@ enum cpu_boot_err {
  *
  * CPU_BOOT_ERR0_TPM_FAIL              TPM verification flow failed.
  *
+ * CPU_BOOT_ERR0_TMP_THRESH_INIT_FAIL  Failed to set threshold for tmperature
+ *                                     sensor.
+ *
  * CPU_BOOT_ERR0_ENABLED               Error registers enabled.
  *                                     This is a main indication that the
  *                                     running FW populates the error
@@ -134,6 +138,7 @@ enum cpu_boot_err {
 #define CPU_BOOT_ERR0_BOOT_FW_CRIT_ERR         (1 << CPU_BOOT_ERR_BOOT_FW_CRIT_ERR)
 #define CPU_BOOT_ERR0_BINNING_FAIL             (1 << CPU_BOOT_ERR_BINNING_FAIL)
 #define CPU_BOOT_ERR0_TPM_FAIL                 (1 << CPU_BOOT_ERR_TPM_FAIL)
+#define CPU_BOOT_ERR0_TMP_THRESH_INIT_FAIL     (1 << CPU_BOOT_ERR_TMP_THRESH_INIT_FAIL)
 #define CPU_BOOT_ERR0_ENABLED                  (1 << CPU_BOOT_ERR_ENABLED)
 #define CPU_BOOT_ERR1_ENABLED                  (1 << CPU_BOOT_ERR_ENABLED)
 
index d966bd4..c07ed4e 100644 (file)
@@ -311,6 +311,16 @@ enum gaudi_async_event_id {
        GAUDI_EVENT_FW_ALIVE_S = 645,
        GAUDI_EVENT_DEV_RESET_REQ = 646,
        GAUDI_EVENT_PKT_QUEUE_OUT_SYNC = 647,
+       GAUDI_EVENT_STATUS_NIC0_ENG0 = 648,
+       GAUDI_EVENT_STATUS_NIC0_ENG1 = 649,
+       GAUDI_EVENT_STATUS_NIC1_ENG0 = 650,
+       GAUDI_EVENT_STATUS_NIC1_ENG1 = 651,
+       GAUDI_EVENT_STATUS_NIC2_ENG0 = 652,
+       GAUDI_EVENT_STATUS_NIC2_ENG1 = 653,
+       GAUDI_EVENT_STATUS_NIC3_ENG0 = 654,
+       GAUDI_EVENT_STATUS_NIC3_ENG1 = 655,
+       GAUDI_EVENT_STATUS_NIC4_ENG0 = 656,
+       GAUDI_EVENT_STATUS_NIC4_ENG1 = 657,
        GAUDI_EVENT_FIX_POWER_ENV_S = 658,
        GAUDI_EVENT_FIX_POWER_ENV_E = 659,
        GAUDI_EVENT_FIX_THERMAL_ENV_S = 660,
index d06458a..ab33bb5 100644 (file)
@@ -44,14 +44,14 @@ void lkdtm_FORTIFIED_SUBOBJECT(void)
        strscpy(src, "over ten bytes", size);
        size = strlen(src) + 1;
 
-       pr_info("trying to strcpy past the end of a member of a struct\n");
+       pr_info("trying to strncpy past the end of a member of a struct\n");
 
        /*
-        * memcpy(target.a, src, 20); will hit a compile error because the
+        * strncpy(target.a, src, 20); will hit a compile error because the
         * compiler knows at build time that target.a < 20 bytes. Use a
         * volatile to force a runtime error.
         */
-       memcpy(target.a, src, size);
+       strncpy(target.a, src, size);
 
        /* Store result to global to prevent the code from being eliminated */
        fortify_scratch_space = target.a[3];
index 0673467..31264ab 100644 (file)
@@ -2148,6 +2148,7 @@ void mei_cl_all_disconnect(struct mei_device *dev)
        list_for_each_entry(cl, &dev->file_list, link)
                mei_cl_set_disconnected(cl);
 }
+EXPORT_SYMBOL_GPL(mei_cl_all_disconnect);
 
 static struct mei_cl *mei_cl_dma_map_find(struct mei_device *dev, u8 buffer_id)
 {
index 67bb6a2..888c27b 100644 (file)
 #define PCI_CFG_HFS_2         0x48
 #define PCI_CFG_HFS_3         0x60
 #  define PCI_CFG_HFS_3_FW_SKU_MSK   0x00000070
+#  define PCI_CFG_HFS_3_FW_SKU_IGN   0x00000000
 #  define PCI_CFG_HFS_3_FW_SKU_SPS   0x00000060
 #define PCI_CFG_HFS_4         0x64
 #define PCI_CFG_HFS_5         0x68
index d3a6c07..719fee9 100644 (file)
@@ -1257,7 +1257,11 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
        /* check if ME wants a reset */
        if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) {
                dev_warn(dev->dev, "FW not ready: resetting.\n");
-               schedule_work(&dev->reset_work);
+               if (dev->dev_state == MEI_DEV_POWERING_DOWN ||
+                   dev->dev_state == MEI_DEV_POWER_DOWN)
+                       mei_cl_all_disconnect(dev);
+               else if (dev->dev_state != MEI_DEV_DISABLED)
+                       schedule_work(&dev->reset_work);
                goto end;
        }
 
@@ -1289,12 +1293,14 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
                if (rets == -ENODATA)
                        break;
 
-               if (rets &&
-                   (dev->dev_state != MEI_DEV_RESETTING &&
-                    dev->dev_state != MEI_DEV_POWER_DOWN)) {
-                       dev_err(dev->dev, "mei_irq_read_handler ret = %d.\n",
-                                               rets);
-                       schedule_work(&dev->reset_work);
+               if (rets) {
+                       dev_err(dev->dev, "mei_irq_read_handler ret = %d, state = %d.\n",
+                               rets, dev->dev_state);
+                       if (dev->dev_state != MEI_DEV_RESETTING &&
+                           dev->dev_state != MEI_DEV_DISABLED &&
+                           dev->dev_state != MEI_DEV_POWERING_DOWN &&
+                           dev->dev_state != MEI_DEV_POWER_DOWN)
+                               schedule_work(&dev->reset_work);
                        goto end;
                }
        }
@@ -1405,16 +1411,16 @@ static bool mei_me_fw_type_sps_4(const struct pci_dev *pdev)
        .quirk_probe = mei_me_fw_type_sps_4
 
 /**
- * mei_me_fw_type_sps() - check for sps sku
+ * mei_me_fw_type_sps_ign() - check for sps or ign sku
  *
- * Read ME FW Status register to check for SPS Firmware.
- * The SPS FW is only signaled in pci function 0
+ * Read ME FW Status register to check for SPS or IGN Firmware.
+ * The SPS/IGN FW is only signaled in pci function 0
  *
  * @pdev: pci device
  *
- * Return: true in case of SPS firmware
+ * Return: true in case of SPS/IGN firmware
  */
-static bool mei_me_fw_type_sps(const struct pci_dev *pdev)
+static bool mei_me_fw_type_sps_ign(const struct pci_dev *pdev)
 {
        u32 reg;
        u32 fw_type;
@@ -1427,14 +1433,15 @@ static bool mei_me_fw_type_sps(const struct pci_dev *pdev)
 
        dev_dbg(&pdev->dev, "fw type is %d\n", fw_type);
 
-       return fw_type == PCI_CFG_HFS_3_FW_SKU_SPS;
+       return fw_type == PCI_CFG_HFS_3_FW_SKU_IGN ||
+              fw_type == PCI_CFG_HFS_3_FW_SKU_SPS;
 }
 
 #define MEI_CFG_KIND_ITOUCH                     \
        .kind = "itouch"
 
-#define MEI_CFG_FW_SPS                          \
-       .quirk_probe = mei_me_fw_type_sps
+#define MEI_CFG_FW_SPS_IGN                      \
+       .quirk_probe = mei_me_fw_type_sps_ign
 
 #define MEI_CFG_FW_VER_SUPP                     \
        .fw_ver_supported = 1
@@ -1535,7 +1542,7 @@ static const struct mei_cfg mei_me_pch12_sps_cfg = {
        MEI_CFG_PCH8_HFS,
        MEI_CFG_FW_VER_SUPP,
        MEI_CFG_DMA_128,
-       MEI_CFG_FW_SPS,
+       MEI_CFG_FW_SPS_IGN,
 };
 
 /* Cannon Lake itouch with quirk for SPS 5.0 and newer Firmware exclusion
@@ -1545,7 +1552,7 @@ static const struct mei_cfg mei_me_pch12_itouch_sps_cfg = {
        MEI_CFG_KIND_ITOUCH,
        MEI_CFG_PCH8_HFS,
        MEI_CFG_FW_VER_SUPP,
-       MEI_CFG_FW_SPS,
+       MEI_CFG_FW_SPS_IGN,
 };
 
 /* Tiger Lake and newer devices */
@@ -1562,7 +1569,7 @@ static const struct mei_cfg mei_me_pch15_sps_cfg = {
        MEI_CFG_FW_VER_SUPP,
        MEI_CFG_DMA_128,
        MEI_CFG_TRC,
-       MEI_CFG_FW_SPS,
+       MEI_CFG_FW_SPS_IGN,
 };
 
 /*
index f79076c..eb05200 100644 (file)
@@ -161,6 +161,11 @@ int mei_reset(struct mei_device *dev)
                return ret;
        }
 
+       if (dev->dev_state != MEI_DEV_RESETTING) {
+               dev_dbg(dev->dev, "wrong state = %d on link start\n", dev->dev_state);
+               return 0;
+       }
+
        dev_dbg(dev->dev, "link is established start sending messages.\n");
 
        mei_set_devstate(dev, MEI_DEV_INIT_CLIENTS);
index 3a45aaf..a05cdb2 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 
@@ -192,14 +193,7 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto end;
        }
 
-       if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) ||
-           dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) {
-
-               err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
-               if (err)
-                       err = dma_set_coherent_mask(&pdev->dev,
-                                                   DMA_BIT_MASK(32));
-       }
+       err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
        if (err) {
                dev_err(&pdev->dev, "No usable DMA configuration, aborting\n");
                goto end;
index ab039c1..9670d02 100644 (file)
@@ -94,7 +94,7 @@ struct ocxl_link {
        struct spa *spa;
        void *platform_data;
 };
-static struct list_head links_list = LIST_HEAD_INIT(links_list);
+static LIST_HEAD(links_list);
 static DEFINE_MUTEX(links_list_lock);
 
 enum xsl_response {
diff --git a/drivers/misc/open-dice.c b/drivers/misc/open-dice.c
new file mode 100644 (file)
index 0000000..c61be34
--- /dev/null
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021 - Google LLC
+ * Author: David Brazdil <dbrazdil@google.com>
+ *
+ * Driver for Open Profile for DICE.
+ *
+ * This driver takes ownership of a reserved memory region containing data
+ * generated by the Open Profile for DICE measured boot protocol. The memory
+ * contents are not interpreted by the kernel but can be mapped into a userspace
+ * process via a misc device. Userspace can also request a wipe of the memory.
+ *
+ * Userspace can access the data with (w/o error handling):
+ *
+ *     fd = open("/dev/open-dice0", O_RDWR);
+ *     read(fd, &size, sizeof(unsigned long));
+ *     data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+ *     write(fd, NULL, 0); // wipe
+ *     close(fd);
+ */
+
+#include <linux/io.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+
+#define DRIVER_NAME "open-dice"
+
+struct open_dice_drvdata {
+       struct mutex lock;
+       char name[16];
+       struct reserved_mem *rmem;
+       struct miscdevice misc;
+};
+
+static inline struct open_dice_drvdata *to_open_dice_drvdata(struct file *filp)
+{
+       return container_of(filp->private_data, struct open_dice_drvdata, misc);
+}
+
+static int open_dice_wipe(struct open_dice_drvdata *drvdata)
+{
+       void *kaddr;
+
+       mutex_lock(&drvdata->lock);
+       kaddr = devm_memremap(drvdata->misc.this_device, drvdata->rmem->base,
+                             drvdata->rmem->size, MEMREMAP_WC);
+       if (IS_ERR(kaddr)) {
+               mutex_unlock(&drvdata->lock);
+               return PTR_ERR(kaddr);
+       }
+
+       memset(kaddr, 0, drvdata->rmem->size);
+       devm_memunmap(drvdata->misc.this_device, kaddr);
+       mutex_unlock(&drvdata->lock);
+       return 0;
+}
+
+/*
+ * Copies the size of the reserved memory region to the user-provided buffer.
+ */
+static ssize_t open_dice_read(struct file *filp, char __user *ptr, size_t len,
+                             loff_t *off)
+{
+       unsigned long val = to_open_dice_drvdata(filp)->rmem->size;
+
+       return simple_read_from_buffer(ptr, len, off, &val, sizeof(val));
+}
+
+/*
+ * Triggers a wipe of the reserved memory region. The user-provided pointer
+ * is never dereferenced.
+ */
+static ssize_t open_dice_write(struct file *filp, const char __user *ptr,
+                              size_t len, loff_t *off)
+{
+       if (open_dice_wipe(to_open_dice_drvdata(filp)))
+               return -EIO;
+
+       /* Consume the input buffer. */
+       return len;
+}
+
+/*
+ * Creates a mapping of the reserved memory region in user address space.
+ */
+static int open_dice_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct open_dice_drvdata *drvdata = to_open_dice_drvdata(filp);
+
+       /* Do not allow userspace to modify the underlying data. */
+       if ((vma->vm_flags & VM_WRITE) && (vma->vm_flags & VM_SHARED))
+               return -EPERM;
+
+       /* Ensure userspace cannot acquire VM_WRITE + VM_SHARED later. */
+       if (vma->vm_flags & VM_WRITE)
+               vma->vm_flags &= ~VM_MAYSHARE;
+       else if (vma->vm_flags & VM_SHARED)
+               vma->vm_flags &= ~VM_MAYWRITE;
+
+       /* Create write-combine mapping so all clients observe a wipe. */
+       vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+       vma->vm_flags |= VM_DONTCOPY | VM_DONTDUMP;
+       return vm_iomap_memory(vma, drvdata->rmem->base, drvdata->rmem->size);
+}
+
+static const struct file_operations open_dice_fops = {
+       .owner = THIS_MODULE,
+       .read = open_dice_read,
+       .write = open_dice_write,
+       .mmap = open_dice_mmap,
+};
+
+static int __init open_dice_probe(struct platform_device *pdev)
+{
+       static unsigned int dev_idx;
+       struct device *dev = &pdev->dev;
+       struct reserved_mem *rmem;
+       struct open_dice_drvdata *drvdata;
+       int ret;
+
+       rmem = of_reserved_mem_lookup(dev->of_node);
+       if (!rmem) {
+               dev_err(dev, "failed to lookup reserved memory\n");
+               return -EINVAL;
+       }
+
+       if (!rmem->size || (rmem->size > ULONG_MAX)) {
+               dev_err(dev, "invalid memory region size\n");
+               return -EINVAL;
+       }
+
+       if (!PAGE_ALIGNED(rmem->base) || !PAGE_ALIGNED(rmem->size)) {
+               dev_err(dev, "memory region must be page-aligned\n");
+               return -EINVAL;
+       }
+
+       drvdata = devm_kmalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+       if (!drvdata)
+               return -ENOMEM;
+
+       *drvdata = (struct open_dice_drvdata){
+               .lock = __MUTEX_INITIALIZER(drvdata->lock),
+               .rmem = rmem,
+               .misc = (struct miscdevice){
+                       .parent = dev,
+                       .name   = drvdata->name,
+                       .minor  = MISC_DYNAMIC_MINOR,
+                       .fops   = &open_dice_fops,
+                       .mode   = 0600,
+               },
+       };
+
+       /* Index overflow check not needed, misc_register() will fail. */
+       snprintf(drvdata->name, sizeof(drvdata->name), DRIVER_NAME"%u", dev_idx++);
+
+       ret = misc_register(&drvdata->misc);
+       if (ret) {
+               dev_err(dev, "failed to register misc device '%s': %d\n",
+                       drvdata->name, ret);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, drvdata);
+       return 0;
+}
+
+static int open_dice_remove(struct platform_device *pdev)
+{
+       struct open_dice_drvdata *drvdata = platform_get_drvdata(pdev);
+
+       misc_deregister(&drvdata->misc);
+       return 0;
+}
+
+static const struct of_device_id open_dice_of_match[] = {
+       { .compatible = "google,open-dice" },
+       {},
+};
+
+static struct platform_driver open_dice_driver = {
+       .remove = open_dice_remove,
+       .driver = {
+               .name = DRIVER_NAME,
+               .of_match_table = open_dice_of_match,
+       },
+};
+
+static int __init open_dice_init(void)
+{
+       int ret = platform_driver_probe(&open_dice_driver, open_dice_probe);
+
+       /* DICE regions are optional. Succeed even with zero instances. */
+       return (ret == -ENODEV) ? 0 : ret;
+}
+
+static void __exit open_dice_exit(void)
+{
+       platform_driver_unregister(&open_dice_driver);
+}
+
+module_init(open_dice_init);
+module_exit(open_dice_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("David Brazdil <dbrazdil@google.com>");
index e4c067c..5efc869 100644 (file)
@@ -530,12 +530,6 @@ struct gru_blade_state {
                for ((i) = (k)*GRU_CBR_AU_SIZE;                         \
                                (i) < ((k) + 1) * GRU_CBR_AU_SIZE; (i)++)
 
-/* Scan each DSR in a DSR bitmap. Note: multiple DSRs in an allocation unit */
-#define for_each_dsr_in_allocation_map(i, map, k)                      \
-       for_each_set_bit((k), (const unsigned long *)(map), GRU_DSR_AU) \
-               for ((i) = (k) * GRU_DSR_AU_CL;                         \
-                               (i) < ((k) + 1) * GRU_DSR_AU_CL; (i)++)
-
 #define gseg_physical_address(gru, ctxnum)                             \
                ((gru)->gs_gru_base_paddr + ctxnum * GRU_GSEG_STRIDE)
 #define gseg_virtual_address(gru, ctxnum)                              \
index 1018dc7..981b193 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/module.h>
+#include <linux/processor.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 
 #define VMCI_UTIL_NUM_RESOURCES 1
 
+/*
+ * Datagram buffers for DMA send/receive must accommodate at least
+ * a maximum sized datagram and the header.
+ */
+#define VMCI_DMA_DG_BUFFER_SIZE (VMCI_MAX_DG_SIZE + PAGE_SIZE)
+
 static bool vmci_disable_msi;
 module_param_named(disable_msi, vmci_disable_msi, bool, 0);
 MODULE_PARM_DESC(disable_msi, "Disable MSI use in driver - (default=0)");
@@ -45,13 +52,18 @@ static u32 vm_context_id = VMCI_INVALID_ID;
 struct vmci_guest_device {
        struct device *dev;     /* PCI device we are attached to */
        void __iomem *iobase;
+       void __iomem *mmio_base;
 
        bool exclusive_vectors;
 
        struct tasklet_struct datagram_tasklet;
        struct tasklet_struct bm_tasklet;
+       struct wait_queue_head inout_wq;
 
        void *data_buffer;
+       dma_addr_t data_buffer_base;
+       void *tx_buffer;
+       dma_addr_t tx_buffer_base;
        void *notification_bitmap;
        dma_addr_t notification_base;
 };
@@ -89,6 +101,92 @@ u32 vmci_get_vm_context_id(void)
        return vm_context_id;
 }
 
+static unsigned int vmci_read_reg(struct vmci_guest_device *dev, u32 reg)
+{
+       if (dev->mmio_base != NULL)
+               return readl(dev->mmio_base + reg);
+       return ioread32(dev->iobase + reg);
+}
+
+static void vmci_write_reg(struct vmci_guest_device *dev, u32 val, u32 reg)
+{
+       if (dev->mmio_base != NULL)
+               writel(val, dev->mmio_base + reg);
+       else
+               iowrite32(val, dev->iobase + reg);
+}
+
+static void vmci_read_data(struct vmci_guest_device *vmci_dev,
+                          void *dest, size_t size)
+{
+       if (vmci_dev->mmio_base == NULL)
+               ioread8_rep(vmci_dev->iobase + VMCI_DATA_IN_ADDR,
+                           dest, size);
+       else {
+               /*
+                * For DMA datagrams, the data_buffer will contain the header on the
+                * first page, followed by the incoming datagram(s) on the following
+                * pages. The header uses an S/G element immediately following the
+                * header on the first page to point to the data area.
+                */
+               struct vmci_data_in_out_header *buffer_header = vmci_dev->data_buffer;
+               struct vmci_sg_elem *sg_array = (struct vmci_sg_elem *)(buffer_header + 1);
+               size_t buffer_offset = dest - vmci_dev->data_buffer;
+
+               buffer_header->opcode = 1;
+               buffer_header->size = 1;
+               buffer_header->busy = 0;
+               sg_array[0].addr = vmci_dev->data_buffer_base + buffer_offset;
+               sg_array[0].size = size;
+
+               vmci_write_reg(vmci_dev, lower_32_bits(vmci_dev->data_buffer_base),
+                              VMCI_DATA_IN_LOW_ADDR);
+
+               wait_event(vmci_dev->inout_wq, buffer_header->busy == 1);
+       }
+}
+
+static int vmci_write_data(struct vmci_guest_device *dev,
+                          struct vmci_datagram *dg)
+{
+       int result;
+
+       if (dev->mmio_base != NULL) {
+               struct vmci_data_in_out_header *buffer_header = dev->tx_buffer;
+               u8 *dg_out_buffer = (u8 *)(buffer_header + 1);
+
+               if (VMCI_DG_SIZE(dg) > VMCI_MAX_DG_SIZE)
+                       return VMCI_ERROR_INVALID_ARGS;
+
+               /*
+                * Initialize send buffer with outgoing datagram
+                * and set up header for inline data. Device will
+                * not access buffer asynchronously - only after
+                * the write to VMCI_DATA_OUT_LOW_ADDR.
+                */
+               memcpy(dg_out_buffer, dg, VMCI_DG_SIZE(dg));
+               buffer_header->opcode = 0;
+               buffer_header->size = VMCI_DG_SIZE(dg);
+               buffer_header->busy = 1;
+
+               vmci_write_reg(dev, lower_32_bits(dev->tx_buffer_base),
+                              VMCI_DATA_OUT_LOW_ADDR);
+
+               /* Caller holds a spinlock, so cannot block. */
+               spin_until_cond(buffer_header->busy == 0);
+
+               result = vmci_read_reg(vmci_dev_g, VMCI_RESULT_LOW_ADDR);
+               if (result == VMCI_SUCCESS)
+                       result = (int)buffer_header->result;
+       } else {
+               iowrite8_rep(dev->iobase + VMCI_DATA_OUT_ADDR,
+                            dg, VMCI_DG_SIZE(dg));
+               result = vmci_read_reg(vmci_dev_g, VMCI_RESULT_LOW_ADDR);
+       }
+
+       return result;
+}
+
 /*
  * VM to hypervisor call mechanism. We use the standard VMware naming
  * convention since shared code is calling this function as well.
@@ -114,9 +212,8 @@ int vmci_send_datagram(struct vmci_datagram *dg)
        spin_lock_irqsave(&vmci_dev_spinlock, flags);
 
        if (vmci_dev_g) {
-               iowrite8_rep(vmci_dev_g->iobase + VMCI_DATA_OUT_ADDR,
-                            dg, VMCI_DG_SIZE(dg));
-               result = ioread32(vmci_dev_g->iobase + VMCI_RESULT_LOW_ADDR);
+               vmci_write_data(vmci_dev_g, dg);
+               result = vmci_read_reg(vmci_dev_g, VMCI_RESULT_LOW_ADDR);
        } else {
                result = VMCI_ERROR_UNAVAILABLE;
        }
@@ -156,9 +253,9 @@ static void vmci_guest_cid_update(u32 sub_id,
 
 /*
  * Verify that the host supports the hypercalls we need. If it does not,
- * try to find fallback hypercalls and use those instead.  Returns
- * true if required hypercalls (or fallback hypercalls) are
- * supported by the host, false otherwise.
+ * try to find fallback hypercalls and use those instead.  Returns 0 if
+ * required hypercalls (or fallback hypercalls) are supported by the host,
+ * an error code otherwise.
  */
 static int vmci_check_host_caps(struct pci_dev *pdev)
 {
@@ -195,15 +292,17 @@ static int vmci_check_host_caps(struct pci_dev *pdev)
 }
 
 /*
- * Reads datagrams from the data in port and dispatches them. We
- * always start reading datagrams into only the first page of the
- * datagram buffer. If the datagrams don't fit into one page, we
- * use the maximum datagram buffer size for the remainder of the
- * invocation. This is a simple heuristic for not penalizing
- * small datagrams.
+ * Reads datagrams from the device and dispatches them. For IO port
+ * based access to the device, we always start reading datagrams into
+ * only the first page of the datagram buffer. If the datagrams don't
+ * fit into one page, we use the maximum datagram buffer size for the
+ * remainder of the invocation. This is a simple heuristic for not
+ * penalizing small datagrams. For DMA-based datagrams, we always
+ * use the maximum datagram buffer size, since there is no performance
+ * penalty for doing so.
  *
  * This function assumes that it has exclusive access to the data
- * in port for the duration of the call.
+ * in register(s) for the duration of the call.
  */
 static void vmci_dispatch_dgs(unsigned long data)
 {
@@ -211,23 +310,41 @@ static void vmci_dispatch_dgs(unsigned long data)
        u8 *dg_in_buffer = vmci_dev->data_buffer;
        struct vmci_datagram *dg;
        size_t dg_in_buffer_size = VMCI_MAX_DG_SIZE;
-       size_t current_dg_in_buffer_size = PAGE_SIZE;
+       size_t current_dg_in_buffer_size;
        size_t remaining_bytes;
+       bool is_io_port = vmci_dev->mmio_base == NULL;
 
        BUILD_BUG_ON(VMCI_MAX_DG_SIZE < PAGE_SIZE);
 
-       ioread8_rep(vmci_dev->iobase + VMCI_DATA_IN_ADDR,
-                   vmci_dev->data_buffer, current_dg_in_buffer_size);
+       if (!is_io_port) {
+               /* For mmio, the first page is used for the header. */
+               dg_in_buffer += PAGE_SIZE;
+
+               /*
+                * For DMA-based datagram operations, there is no performance
+                * penalty for reading the maximum buffer size.
+                */
+               current_dg_in_buffer_size = VMCI_MAX_DG_SIZE;
+       } else {
+               current_dg_in_buffer_size = PAGE_SIZE;
+       }
+       vmci_read_data(vmci_dev, dg_in_buffer, current_dg_in_buffer_size);
        dg = (struct vmci_datagram *)dg_in_buffer;
        remaining_bytes = current_dg_in_buffer_size;
 
+       /*
+        * Read through the buffer until an invalid datagram header is
+        * encountered. The exit condition for datagrams read through
+        * VMCI_DATA_IN_ADDR is a bit more complicated, since a datagram
+        * can start on any page boundary in the buffer.
+        */
        while (dg->dst.resource != VMCI_INVALID_ID ||
-              remaining_bytes > PAGE_SIZE) {
+              (is_io_port && remaining_bytes > PAGE_SIZE)) {
                unsigned dg_in_size;
 
                /*
-                * When the input buffer spans multiple pages, a datagram can
-                * start on any page boundary in the buffer.
+                * If using VMCI_DATA_IN_ADDR, skip to the next page
+                * as a datagram can start on any page boundary.
                 */
                if (dg->dst.resource == VMCI_INVALID_ID) {
                        dg = (struct vmci_datagram *)roundup(
@@ -277,11 +394,10 @@ static void vmci_dispatch_dgs(unsigned long data)
                                        current_dg_in_buffer_size =
                                            dg_in_buffer_size;
 
-                               ioread8_rep(vmci_dev->iobase +
-                                               VMCI_DATA_IN_ADDR,
-                                       vmci_dev->data_buffer +
+                               vmci_read_data(vmci_dev,
+                                              dg_in_buffer +
                                                remaining_bytes,
-                                       current_dg_in_buffer_size -
+                                              current_dg_in_buffer_size -
                                                remaining_bytes);
                        }
 
@@ -319,10 +435,8 @@ static void vmci_dispatch_dgs(unsigned long data)
                                current_dg_in_buffer_size = dg_in_buffer_size;
 
                        for (;;) {
-                               ioread8_rep(vmci_dev->iobase +
-                                               VMCI_DATA_IN_ADDR,
-                                       vmci_dev->data_buffer,
-                                       current_dg_in_buffer_size);
+                               vmci_read_data(vmci_dev, dg_in_buffer,
+                                              current_dg_in_buffer_size);
                                if (bytes_to_skip <= current_dg_in_buffer_size)
                                        break;
 
@@ -339,8 +453,7 @@ static void vmci_dispatch_dgs(unsigned long data)
                if (remaining_bytes < VMCI_DG_HEADERSIZE) {
                        /* Get the next batch of datagrams. */
 
-                       ioread8_rep(vmci_dev->iobase + VMCI_DATA_IN_ADDR,
-                                   vmci_dev->data_buffer,
+                       vmci_read_data(vmci_dev, dg_in_buffer,
                                    current_dg_in_buffer_size);
                        dg = (struct vmci_datagram *)dg_in_buffer;
                        remaining_bytes = current_dg_in_buffer_size;
@@ -384,7 +497,7 @@ static irqreturn_t vmci_interrupt(int irq, void *_dev)
                unsigned int icr;
 
                /* Acknowledge interrupt and determine what needs doing. */
-               icr = ioread32(dev->iobase + VMCI_ICR_ADDR);
+               icr = vmci_read_reg(dev, VMCI_ICR_ADDR);
                if (icr == 0 || icr == ~0)
                        return IRQ_NONE;
 
@@ -398,6 +511,12 @@ static irqreturn_t vmci_interrupt(int irq, void *_dev)
                        icr &= ~VMCI_ICR_NOTIFICATION;
                }
 
+
+               if (icr & VMCI_ICR_DMA_DATAGRAM) {
+                       wake_up_all(&dev->inout_wq);
+                       icr &= ~VMCI_ICR_DMA_DATAGRAM;
+               }
+
                if (icr != 0)
                        dev_warn(dev->dev,
                                 "Ignoring unknown interrupt cause (%d)\n",
@@ -422,6 +541,38 @@ static irqreturn_t vmci_interrupt_bm(int irq, void *_dev)
        return IRQ_HANDLED;
 }
 
+/*
+ * Interrupt handler for MSI-X interrupt vector VMCI_INTR_DMA_DATAGRAM,
+ * which is for the completion of a DMA datagram send or receive operation.
+ * Will only get called if we are using MSI-X with exclusive vectors.
+ */
+static irqreturn_t vmci_interrupt_dma_datagram(int irq, void *_dev)
+{
+       struct vmci_guest_device *dev = _dev;
+
+       wake_up_all(&dev->inout_wq);
+
+       return IRQ_HANDLED;
+}
+
+static void vmci_free_dg_buffers(struct vmci_guest_device *vmci_dev)
+{
+       if (vmci_dev->mmio_base != NULL) {
+               if (vmci_dev->tx_buffer != NULL)
+                       dma_free_coherent(vmci_dev->dev,
+                                         VMCI_DMA_DG_BUFFER_SIZE,
+                                         vmci_dev->tx_buffer,
+                                         vmci_dev->tx_buffer_base);
+               if (vmci_dev->data_buffer != NULL)
+                       dma_free_coherent(vmci_dev->dev,
+                                         VMCI_DMA_DG_BUFFER_SIZE,
+                                         vmci_dev->data_buffer,
+                                         vmci_dev->data_buffer_base);
+       } else {
+               vfree(vmci_dev->data_buffer);
+       }
+}
+
 /*
  * Most of the initialization at module load time is done here.
  */
@@ -429,7 +580,9 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
                                   const struct pci_device_id *id)
 {
        struct vmci_guest_device *vmci_dev;
-       void __iomem *iobase;
+       void __iomem *iobase = NULL;
+       void __iomem *mmio_base = NULL;
+       unsigned int num_irq_vectors;
        unsigned int capabilities;
        unsigned int caps_in_use;
        unsigned long cmd;
@@ -445,16 +598,29 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
                return error;
        }
 
-       error = pcim_iomap_regions(pdev, 1 << 0, KBUILD_MODNAME);
-       if (error) {
-               dev_err(&pdev->dev, "Failed to reserve/map IO regions\n");
-               return error;
-       }
+       /*
+        * The VMCI device with mmio access to registers requests 256KB
+        * for BAR1. If present, driver will use new VMCI device
+        * functionality for register access and datagram send/recv.
+        */
 
-       iobase = pcim_iomap_table(pdev)[0];
+       if (pci_resource_len(pdev, 1) == VMCI_WITH_MMIO_ACCESS_BAR_SIZE) {
+               dev_info(&pdev->dev, "MMIO register access is available\n");
+               mmio_base = pci_iomap_range(pdev, 1, VMCI_MMIO_ACCESS_OFFSET,
+                                           VMCI_MMIO_ACCESS_SIZE);
+               /* If the map fails, we fall back to IOIO access. */
+               if (!mmio_base)
+                       dev_warn(&pdev->dev, "Failed to map MMIO register access\n");
+       }
 
-       dev_info(&pdev->dev, "Found VMCI PCI device at %#lx, irq %u\n",
-                (unsigned long)iobase, pdev->irq);
+       if (!mmio_base) {
+               error = pcim_iomap_regions(pdev, BIT(0), KBUILD_MODNAME);
+               if (error) {
+                       dev_err(&pdev->dev, "Failed to reserve/map IO regions\n");
+                       return error;
+               }
+               iobase = pcim_iomap_table(pdev)[0];
+       }
 
        vmci_dev = devm_kzalloc(&pdev->dev, sizeof(*vmci_dev), GFP_KERNEL);
        if (!vmci_dev) {
@@ -466,17 +632,35 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
        vmci_dev->dev = &pdev->dev;
        vmci_dev->exclusive_vectors = false;
        vmci_dev->iobase = iobase;
+       vmci_dev->mmio_base = mmio_base;
 
        tasklet_init(&vmci_dev->datagram_tasklet,
                     vmci_dispatch_dgs, (unsigned long)vmci_dev);
        tasklet_init(&vmci_dev->bm_tasklet,
                     vmci_process_bitmap, (unsigned long)vmci_dev);
+       init_waitqueue_head(&vmci_dev->inout_wq);
 
-       vmci_dev->data_buffer = vmalloc(VMCI_MAX_DG_SIZE);
+       if (mmio_base != NULL) {
+               vmci_dev->tx_buffer = dma_alloc_coherent(&pdev->dev, VMCI_DMA_DG_BUFFER_SIZE,
+                                                        &vmci_dev->tx_buffer_base,
+                                                        GFP_KERNEL);
+               if (!vmci_dev->tx_buffer) {
+                       dev_err(&pdev->dev,
+                               "Can't allocate memory for datagram tx buffer\n");
+                       return -ENOMEM;
+               }
+
+               vmci_dev->data_buffer = dma_alloc_coherent(&pdev->dev, VMCI_DMA_DG_BUFFER_SIZE,
+                                                          &vmci_dev->data_buffer_base,
+                                                          GFP_KERNEL);
+       } else {
+               vmci_dev->data_buffer = vmalloc(VMCI_MAX_DG_SIZE);
+       }
        if (!vmci_dev->data_buffer) {
                dev_err(&pdev->dev,
                        "Can't allocate memory for datagram buffer\n");
-               return -ENOMEM;
+               error = -ENOMEM;
+               goto err_free_data_buffers;
        }
 
        pci_set_master(pdev);   /* To enable queue_pair functionality. */
@@ -490,11 +674,11 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
         *
         * Right now, we need datagrams. There are no fallbacks.
         */
-       capabilities = ioread32(vmci_dev->iobase + VMCI_CAPS_ADDR);
+       capabilities = vmci_read_reg(vmci_dev, VMCI_CAPS_ADDR);
        if (!(capabilities & VMCI_CAPS_DATAGRAM)) {
                dev_err(&pdev->dev, "Device does not support datagrams\n");
                error = -ENXIO;
-               goto err_free_data_buffer;
+               goto err_free_data_buffers;
        }
        caps_in_use = VMCI_CAPS_DATAGRAM;
 
@@ -522,19 +706,39 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
                vmci_dev->notification_bitmap = dma_alloc_coherent(
                        &pdev->dev, PAGE_SIZE, &vmci_dev->notification_base,
                        GFP_KERNEL);
-               if (!vmci_dev->notification_bitmap) {
+               if (!vmci_dev->notification_bitmap)
                        dev_warn(&pdev->dev,
                                 "Unable to allocate notification bitmap\n");
-               } else {
-                       memset(vmci_dev->notification_bitmap, 0, PAGE_SIZE);
+               else
                        caps_in_use |= VMCI_CAPS_NOTIFICATIONS;
+       }
+
+       if (mmio_base != NULL) {
+               if (capabilities & VMCI_CAPS_DMA_DATAGRAM) {
+                       caps_in_use |= VMCI_CAPS_DMA_DATAGRAM;
+               } else {
+                       dev_err(&pdev->dev,
+                               "Missing capability: VMCI_CAPS_DMA_DATAGRAM\n");
+                       error = -ENXIO;
+                       goto err_free_data_buffers;
                }
        }
 
        dev_info(&pdev->dev, "Using capabilities 0x%x\n", caps_in_use);
 
        /* Let the host know which capabilities we intend to use. */
-       iowrite32(caps_in_use, vmci_dev->iobase + VMCI_CAPS_ADDR);
+       vmci_write_reg(vmci_dev, caps_in_use, VMCI_CAPS_ADDR);
+
+       if (caps_in_use & VMCI_CAPS_DMA_DATAGRAM) {
+               /* Let the device know the size for pages passed down. */
+               vmci_write_reg(vmci_dev, PAGE_SHIFT, VMCI_GUEST_PAGE_SHIFT);
+
+               /* Configure the high order parts of the data in/out buffers. */
+               vmci_write_reg(vmci_dev, upper_32_bits(vmci_dev->data_buffer_base),
+                              VMCI_DATA_IN_HIGH_ADDR);
+               vmci_write_reg(vmci_dev, upper_32_bits(vmci_dev->tx_buffer_base),
+                              VMCI_DATA_OUT_HIGH_ADDR);
+       }
 
        /* Set up global device so that we can start sending datagrams */
        spin_lock_irq(&vmci_dev_spinlock);
@@ -561,7 +765,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
        /* Check host capabilities. */
        error = vmci_check_host_caps(pdev);
        if (error)
-               goto err_remove_bitmap;
+               goto err_remove_vmci_dev_g;
 
        /* Enable device. */
 
@@ -581,13 +785,17 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
         * Enable interrupts.  Try MSI-X first, then MSI, and then fallback on
         * legacy interrupts.
         */
-       error = pci_alloc_irq_vectors(pdev, VMCI_MAX_INTRS, VMCI_MAX_INTRS,
-                       PCI_IRQ_MSIX);
+       if (vmci_dev->mmio_base != NULL)
+               num_irq_vectors = VMCI_MAX_INTRS;
+       else
+               num_irq_vectors = VMCI_MAX_INTRS_NOTIFICATION;
+       error = pci_alloc_irq_vectors(pdev, num_irq_vectors, num_irq_vectors,
+                                     PCI_IRQ_MSIX);
        if (error < 0) {
                error = pci_alloc_irq_vectors(pdev, 1, 1,
                                PCI_IRQ_MSIX | PCI_IRQ_MSI | PCI_IRQ_LEGACY);
                if (error < 0)
-                       goto err_remove_bitmap;
+                       goto err_unsubscribe_event;
        } else {
                vmci_dev->exclusive_vectors = true;
        }
@@ -620,6 +828,17 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
                                pci_irq_vector(pdev, 1), error);
                        goto err_free_irq;
                }
+               if (caps_in_use & VMCI_CAPS_DMA_DATAGRAM) {
+                       error = request_irq(pci_irq_vector(pdev, 2),
+                                           vmci_interrupt_dma_datagram,
+                                           0, KBUILD_MODNAME, vmci_dev);
+                       if (error) {
+                               dev_err(&pdev->dev,
+                                       "Failed to allocate irq %u: %d\n",
+                                       pci_irq_vector(pdev, 2), error);
+                               goto err_free_bm_irq;
+                       }
+               }
        }
 
        dev_dbg(&pdev->dev, "Registered device\n");
@@ -630,17 +849,20 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
        cmd = VMCI_IMR_DATAGRAM;
        if (caps_in_use & VMCI_CAPS_NOTIFICATIONS)
                cmd |= VMCI_IMR_NOTIFICATION;
-       iowrite32(cmd, vmci_dev->iobase + VMCI_IMR_ADDR);
+       if (caps_in_use & VMCI_CAPS_DMA_DATAGRAM)
+               cmd |= VMCI_IMR_DMA_DATAGRAM;
+       vmci_write_reg(vmci_dev, cmd, VMCI_IMR_ADDR);
 
        /* Enable interrupts. */
-       iowrite32(VMCI_CONTROL_INT_ENABLE,
-                 vmci_dev->iobase + VMCI_CONTROL_ADDR);
+       vmci_write_reg(vmci_dev, VMCI_CONTROL_INT_ENABLE, VMCI_CONTROL_ADDR);
 
        pci_set_drvdata(pdev, vmci_dev);
 
        vmci_call_vsock_callback(false);
        return 0;
 
+err_free_bm_irq:
+       free_irq(pci_irq_vector(pdev, 1), vmci_dev);
 err_free_irq:
        free_irq(pci_irq_vector(pdev, 0), vmci_dev);
        tasklet_kill(&vmci_dev->datagram_tasklet);
@@ -649,29 +871,28 @@ err_free_irq:
 err_disable_msi:
        pci_free_irq_vectors(pdev);
 
+err_unsubscribe_event:
        vmci_err = vmci_event_unsubscribe(ctx_update_sub_id);
        if (vmci_err < VMCI_SUCCESS)
                dev_warn(&pdev->dev,
                         "Failed to unsubscribe from event (type=%d) with subscriber (ID=0x%x): %d\n",
                         VMCI_EVENT_CTX_ID_UPDATE, ctx_update_sub_id, vmci_err);
 
-err_remove_bitmap:
-       if (vmci_dev->notification_bitmap) {
-               iowrite32(VMCI_CONTROL_RESET,
-                         vmci_dev->iobase + VMCI_CONTROL_ADDR);
-               dma_free_coherent(&pdev->dev, PAGE_SIZE,
-                                 vmci_dev->notification_bitmap,
-                                 vmci_dev->notification_base);
-       }
-
 err_remove_vmci_dev_g:
        spin_lock_irq(&vmci_dev_spinlock);
        vmci_pdev = NULL;
        vmci_dev_g = NULL;
        spin_unlock_irq(&vmci_dev_spinlock);
 
-err_free_data_buffer:
-       vfree(vmci_dev->data_buffer);
+       if (vmci_dev->notification_bitmap) {
+               vmci_write_reg(vmci_dev, VMCI_CONTROL_RESET, VMCI_CONTROL_ADDR);
+               dma_free_coherent(&pdev->dev, PAGE_SIZE,
+                                 vmci_dev->notification_bitmap,
+                                 vmci_dev->notification_base);
+       }
+
+err_free_data_buffers:
+       vmci_free_dg_buffers(vmci_dev);
 
        /* The rest are managed resources and will be freed by PCI core */
        return error;
@@ -700,15 +921,18 @@ static void vmci_guest_remove_device(struct pci_dev *pdev)
        spin_unlock_irq(&vmci_dev_spinlock);
 
        dev_dbg(&pdev->dev, "Resetting vmci device\n");
-       iowrite32(VMCI_CONTROL_RESET, vmci_dev->iobase + VMCI_CONTROL_ADDR);
+       vmci_write_reg(vmci_dev, VMCI_CONTROL_RESET, VMCI_CONTROL_ADDR);
 
        /*
         * Free IRQ and then disable MSI/MSI-X as appropriate.  For
         * MSI-X, we might have multiple vectors, each with their own
         * IRQ, which we must free too.
         */
-       if (vmci_dev->exclusive_vectors)
+       if (vmci_dev->exclusive_vectors) {
                free_irq(pci_irq_vector(pdev, 1), vmci_dev);
+               if (vmci_dev->mmio_base != NULL)
+                       free_irq(pci_irq_vector(pdev, 2), vmci_dev);
+       }
        free_irq(pci_irq_vector(pdev, 0), vmci_dev);
        pci_free_irq_vectors(pdev);
 
@@ -726,7 +950,10 @@ static void vmci_guest_remove_device(struct pci_dev *pdev)
                                  vmci_dev->notification_base);
        }
 
-       vfree(vmci_dev->data_buffer);
+       vmci_free_dg_buffers(vmci_dev);
+
+       if (vmci_dev->mmio_base != NULL)
+               pci_iounmap(pdev, vmci_dev->mmio_base);
 
        /* The rest are managed resources and will be freed by PCI core */
 }
index 4e61b28..8d718aa 100644 (file)
@@ -1682,31 +1682,31 @@ static void mmc_blk_read_single(struct mmc_queue *mq, struct request *req)
        struct mmc_card *card = mq->card;
        struct mmc_host *host = card->host;
        blk_status_t error = BLK_STS_OK;
-       int retries = 0;
 
        do {
                u32 status;
                int err;
+               int retries = 0;
 
-               mmc_blk_rw_rq_prep(mqrq, card, 1, mq);
+               while (retries++ <= MMC_READ_SINGLE_RETRIES) {
+                       mmc_blk_rw_rq_prep(mqrq, card, 1, mq);
 
-               mmc_wait_for_req(host, mrq);
+                       mmc_wait_for_req(host, mrq);
 
-               err = mmc_send_status(card, &status);
-               if (err)
-                       goto error_exit;
-
-               if (!mmc_host_is_spi(host) &&
-                   !mmc_ready_for_data(status)) {
-                       err = mmc_blk_fix_state(card, req);
+                       err = mmc_send_status(card, &status);
                        if (err)
                                goto error_exit;
-               }
 
-               if (mrq->cmd->error && retries++ < MMC_READ_SINGLE_RETRIES)
-                       continue;
+                       if (!mmc_host_is_spi(host) &&
+                           !mmc_ready_for_data(status)) {
+                               err = mmc_blk_fix_state(card, req);
+                               if (err)
+                                       goto error_exit;
+                       }
 
-               retries = 0;
+                       if (!mrq->cmd->error)
+                               break;
+               }
 
                if (mrq->cmd->error ||
                    mrq->data->error ||
index 45f5787..bd87012 100644 (file)
@@ -67,7 +67,7 @@ static const unsigned int sd_au_size[] = {
                __res & __mask;                                         \
        })
 
-#define SD_POWEROFF_NOTIFY_TIMEOUT_MS 2000
+#define SD_POWEROFF_NOTIFY_TIMEOUT_MS 1000
 #define SD_WRITE_EXTR_SINGLE_TIMEOUT_MS 1000
 
 struct sd_busy_data {
@@ -1664,6 +1664,12 @@ static int sd_poweroff_notify(struct mmc_card *card)
                goto out;
        }
 
+       /* Find out when the command is completed. */
+       err = mmc_poll_for_busy(card, SD_WRITE_EXTR_SINGLE_TIMEOUT_MS, false,
+                               MMC_BUSY_EXTR_SINGLE);
+       if (err)
+               goto out;
+
        cb_data.card = card;
        cb_data.reg_buf = reg_buf;
        err = __mmc_poll_for_busy(card->host, SD_POWEROFF_NOTIFY_TIMEOUT_MS,
index 16d1c7a..b6eb75f 100644 (file)
@@ -705,12 +705,12 @@ static int moxart_remove(struct platform_device *pdev)
        if (!IS_ERR_OR_NULL(host->dma_chan_rx))
                dma_release_channel(host->dma_chan_rx);
        mmc_remove_host(mmc);
-       mmc_free_host(mmc);
 
        writel(0, host->base + REG_INTERRUPT_MASK);
        writel(0, host->base + REG_POWER_CONTROL);
        writel(readl(host->base + REG_CLOCK_CONTROL) | CLK_OFF,
               host->base + REG_CLOCK_CONTROL);
+       mmc_free_host(mmc);
 
        return 0;
 }
index 58cfaff..f7c384d 100644 (file)
@@ -1495,12 +1495,12 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
 
        realtek_init_host(host);
 
-       if (pcr->rtd3_en) {
-               pm_runtime_set_autosuspend_delay(&pdev->dev, 5000);
-               pm_runtime_use_autosuspend(&pdev->dev);
-               pm_runtime_enable(&pdev->dev);
-       }
-
+       pm_runtime_no_callbacks(&pdev->dev);
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_set_autosuspend_delay(&pdev->dev, 200);
+       pm_runtime_mark_last_busy(&pdev->dev);
+       pm_runtime_use_autosuspend(&pdev->dev);
 
        mmc_add_host(mmc);
 
@@ -1521,11 +1521,6 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
        pcr->slots[RTSX_SD_CARD].card_event = NULL;
        mmc = host->mmc;
 
-       if (pcr->rtd3_en) {
-               pm_runtime_dont_use_autosuspend(&pdev->dev);
-               pm_runtime_disable(&pdev->dev);
-       }
-
        cancel_work_sync(&host->work);
 
        mutex_lock(&host->host_mutex);
@@ -1548,6 +1543,9 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
 
        flush_work(&host->work);
 
+       pm_runtime_dont_use_autosuspend(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+
        mmc_free_host(mmc);
 
        dev_dbg(&(pdev->dev),
index a593b1f..0f3658b 100644 (file)
@@ -524,12 +524,16 @@ static void esdhc_of_adma_workaround(struct sdhci_host *host, u32 intmask)
 
 static int esdhc_of_enable_dma(struct sdhci_host *host)
 {
+       int ret;
        u32 value;
        struct device *dev = mmc_dev(host->mmc);
 
        if (of_device_is_compatible(dev->of_node, "fsl,ls1043a-esdhc") ||
-           of_device_is_compatible(dev->of_node, "fsl,ls1046a-esdhc"))
-               dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+           of_device_is_compatible(dev->of_node, "fsl,ls1046a-esdhc")) {
+               ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+               if (ret)
+                       return ret;
+       }
 
        value = sdhci_readl(host, ESDHC_DMA_SYSCTL);
 
index bcc595c..104dcd7 100644 (file)
@@ -405,6 +405,9 @@ static int sh_mmcif_dma_slave_config(struct sh_mmcif_host *host,
        struct dma_slave_config cfg = { 0, };
 
        res = platform_get_resource(host->pd, IORESOURCE_MEM, 0);
+       if (!res)
+               return -EINVAL;
+
        cfg.direction = direction;
 
        if (direction == DMA_DEV_TO_MEM) {
index 6ed6c51..d503821 100644 (file)
@@ -264,16 +264,20 @@ static int phram_setup(const char *val)
                }
        }
 
-       if (erasesize)
-               div_u64_rem(len, (uint32_t)erasesize, &rem);
-
        if (len == 0 || erasesize == 0 || erasesize > len
-           || erasesize > UINT_MAX || rem) {
+           || erasesize > UINT_MAX) {
                parse_err("illegal erasesize or len\n");
                ret = -EINVAL;
                goto error;
        }
 
+       div_u64_rem(len, (uint32_t)erasesize, &rem);
+       if (rem) {
+               parse_err("len is not multiple of erasesize\n");
+               ret = -EINVAL;
+               goto error;
+       }
+
        ret = register_device(name, start, len, (uint32_t)erasesize);
        if (ret)
                goto error;
index 70f492d..fc60903 100644 (file)
@@ -546,6 +546,7 @@ static int mtd_nvmem_add(struct mtd_info *mtd)
        config.stride = 1;
        config.read_only = true;
        config.root_only = true;
+       config.ignore_wp = true;
        config.no_of_node = !of_device_is_compatible(node, "nvmem-cells");
        config.priv = mtd;
 
@@ -742,8 +743,7 @@ int del_mtd_device(struct mtd_info *mtd)
                debugfs_remove_recursive(mtd->dbg.dfs_dir);
 
                /* Try to remove the NVMEM provider */
-               if (mtd->nvmem)
-                       nvmem_unregister(mtd->nvmem);
+               nvmem_unregister(mtd->nvmem);
 
                device_unregister(&mtd->dev);
 
@@ -833,6 +833,7 @@ static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd,
        config.owner = THIS_MODULE;
        config.type = NVMEM_TYPE_OTP;
        config.root_only = true;
+       config.ignore_wp = true;
        config.reg_read = reg_read;
        config.size = size;
        config.of_node = np;
@@ -921,8 +922,7 @@ static int mtd_otp_nvmem_add(struct mtd_info *mtd)
        return 0;
 
 err:
-       if (mtd->otp_user_nvmem)
-               nvmem_unregister(mtd->otp_user_nvmem);
+       nvmem_unregister(mtd->otp_user_nvmem);
        return err;
 }
 
@@ -1026,11 +1026,8 @@ int mtd_device_unregister(struct mtd_info *master)
                memset(&master->reboot_notifier, 0, sizeof(master->reboot_notifier));
        }
 
-       if (master->otp_user_nvmem)
-               nvmem_unregister(master->otp_user_nvmem);
-
-       if (master->otp_factory_nvmem)
-               nvmem_unregister(master->otp_factory_nvmem);
+       nvmem_unregister(master->otp_user_nvmem);
+       nvmem_unregister(master->otp_factory_nvmem);
 
        err = del_mtd_partitions(master);
        if (err)
index 20408b7..d986ab4 100644 (file)
@@ -42,7 +42,8 @@ config MTD_NAND_OMAP2
        tristate "OMAP2, OMAP3, OMAP4 and Keystone NAND controller"
        depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
        depends on HAS_IOMEM
-       select OMAP_GPMC if ARCH_K3
+       select MEMORY
+       select OMAP_GPMC
        help
          Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
          and Keystone platforms.
index f759297..aee78f5 100644 (file)
@@ -2106,7 +2106,7 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
                                        mtd->oobsize / trans,
                                        host->hwcfg.sector_size_1k);
 
-               if (!ret) {
+               if (ret != -EBADMSG) {
                        *err_addr = brcmnand_get_uncorrecc_addr(ctrl);
 
                        if (*err_addr)
index 1b64c5a..ded4df4 100644 (file)
@@ -2285,7 +2285,7 @@ static int gpmi_nfc_exec_op(struct nand_chip *chip,
                this->hw.must_apply_timings = false;
                ret = gpmi_nfc_apply_timings(this);
                if (ret)
-                       return ret;
+                       goto out_pm;
        }
 
        dev_dbg(this->dev, "%s: %d instructions\n", __func__, op->ninstrs);
@@ -2414,6 +2414,7 @@ unmap:
 
        this->bch = false;
 
+out_pm:
        pm_runtime_mark_last_busy(this->dev);
        pm_runtime_put_autosuspend(this->dev);
 
index efe0ffe..9054559 100644 (file)
@@ -68,9 +68,14 @@ static struct ingenic_ecc *ingenic_ecc_get(struct device_node *np)
        struct ingenic_ecc *ecc;
 
        pdev = of_find_device_by_node(np);
-       if (!pdev || !platform_get_drvdata(pdev))
+       if (!pdev)
                return ERR_PTR(-EPROBE_DEFER);
 
+       if (!platform_get_drvdata(pdev)) {
+               put_device(&pdev->dev);
+               return ERR_PTR(-EPROBE_DEFER);
+       }
+
        ecc = platform_get_drvdata(pdev);
        clk_prepare_enable(ecc->clk);
 
index 7c6efa3..1a77542 100644 (file)
@@ -2,7 +2,6 @@
 /*
  * Copyright (c) 2016, The Linux Foundation. All rights reserved.
  */
-
 #include <linux/clk.h>
 #include <linux/slab.h>
 #include <linux/bitops.h>
@@ -3073,10 +3072,6 @@ static int qcom_nandc_probe(struct platform_device *pdev)
        if (dma_mapping_error(dev, nandc->base_dma))
                return -ENXIO;
 
-       ret = qcom_nandc_alloc(nandc);
-       if (ret)
-               goto err_nandc_alloc;
-
        ret = clk_prepare_enable(nandc->core_clk);
        if (ret)
                goto err_core_clk;
@@ -3085,6 +3080,10 @@ static int qcom_nandc_probe(struct platform_device *pdev)
        if (ret)
                goto err_aon_clk;
 
+       ret = qcom_nandc_alloc(nandc);
+       if (ret)
+               goto err_nandc_alloc;
+
        ret = qcom_nandc_setup(nandc);
        if (ret)
                goto err_setup;
@@ -3096,15 +3095,14 @@ static int qcom_nandc_probe(struct platform_device *pdev)
        return 0;
 
 err_setup:
+       qcom_nandc_unalloc(nandc);
+err_nandc_alloc:
        clk_disable_unprepare(nandc->aon_clk);
 err_aon_clk:
        clk_disable_unprepare(nandc->core_clk);
 err_core_clk:
-       qcom_nandc_unalloc(nandc);
-err_nandc_alloc:
        dma_unmap_resource(dev, res->start, resource_size(res),
                           DMA_BIDIRECTIONAL, 0);
-
        return ret;
 }
 
index 06a818c..4311b89 100644 (file)
@@ -58,11 +58,11 @@ static int parse_qcomsmem_part(struct mtd_info *mtd,
                               const struct mtd_partition **pparts,
                               struct mtd_part_parser_data *data)
 {
+       size_t len = SMEM_FLASH_PTABLE_HDR_LEN;
+       int ret, i, j, tmpparts, numparts = 0;
        struct smem_flash_pentry *pentry;
        struct smem_flash_ptable *ptable;
-       size_t len = SMEM_FLASH_PTABLE_HDR_LEN;
        struct mtd_partition *parts;
-       int ret, i, numparts;
        char *name, *c;
 
        if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_4K_SECTORS)
@@ -75,7 +75,8 @@ static int parse_qcomsmem_part(struct mtd_info *mtd,
        pr_debug("Parsing partition table info from SMEM\n");
        ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len);
        if (IS_ERR(ptable)) {
-               pr_err("Error reading partition table header\n");
+               if (PTR_ERR(ptable) != -EPROBE_DEFER)
+                       pr_err("Error reading partition table header\n");
                return PTR_ERR(ptable);
        }
 
@@ -87,8 +88,8 @@ static int parse_qcomsmem_part(struct mtd_info *mtd,
        }
 
        /* Ensure that # of partitions is less than the max we have allocated */
-       numparts = le32_to_cpu(ptable->numparts);
-       if (numparts > SMEM_FLASH_PTABLE_MAX_PARTS_V4) {
+       tmpparts = le32_to_cpu(ptable->numparts);
+       if (tmpparts > SMEM_FLASH_PTABLE_MAX_PARTS_V4) {
                pr_err("Partition numbers exceed the max limit\n");
                return -EINVAL;
        }
@@ -116,11 +117,17 @@ static int parse_qcomsmem_part(struct mtd_info *mtd,
                return PTR_ERR(ptable);
        }
 
+       for (i = 0; i < tmpparts; i++) {
+               pentry = &ptable->pentry[i];
+               if (pentry->name[0] != '\0')
+                       numparts++;
+       }
+
        parts = kcalloc(numparts, sizeof(*parts), GFP_KERNEL);
        if (!parts)
                return -ENOMEM;
 
-       for (i = 0; i < numparts; i++) {
+       for (i = 0, j = 0; i < tmpparts; i++) {
                pentry = &ptable->pentry[i];
                if (pentry->name[0] == '\0')
                        continue;
@@ -135,24 +142,25 @@ static int parse_qcomsmem_part(struct mtd_info *mtd,
                for (c = name; *c != '\0'; c++)
                        *c = tolower(*c);
 
-               parts[i].name = name;
-               parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize;
-               parts[i].mask_flags = pentry->attr;
-               parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize;
+               parts[j].name = name;
+               parts[j].offset = le32_to_cpu(pentry->offset) * mtd->erasesize;
+               parts[j].mask_flags = pentry->attr;
+               parts[j].size = le32_to_cpu(pentry->length) * mtd->erasesize;
                pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n",
                         i, pentry->name, le32_to_cpu(pentry->offset),
                         le32_to_cpu(pentry->length), pentry->attr);
+               j++;
        }
 
        pr_debug("SMEM partition table found: ver: %d len: %d\n",
-                le32_to_cpu(ptable->version), numparts);
+                le32_to_cpu(ptable->version), tmpparts);
        *pparts = parts;
 
        return numparts;
 
 out_free_parts:
-       while (--i >= 0)
-               kfree(parts[i].name);
+       while (--j >= 0)
+               kfree(parts[j].name);
        kfree(parts);
        *pparts = NULL;
 
@@ -166,6 +174,8 @@ static void parse_qcomsmem_cleanup(const struct mtd_partition *pparts,
 
        for (i = 0; i < nr_parts; i++)
                kfree(pparts[i].name);
+
+       kfree(pparts);
 }
 
 static const struct of_device_id qcomsmem_of_match_table[] = {
index 22f4709..49bedbe 100644 (file)
  */
 #define MUX_CACHE_UNKNOWN MUX_IDLE_AS_IS
 
+/**
+ * struct mux_state -  Represents a mux controller state specific to a given
+ *                     consumer.
+ * @mux:               Pointer to a mux controller.
+ * @state:             State of the mux to be selected.
+ *
+ * This structure is specific to the consumer that acquires it and has
+ * information specific to that consumer.
+ */
+struct mux_state {
+       struct mux_control *mux;
+       unsigned int state;
+};
+
 static struct class mux_class = {
        .name = "mux",
        .owner = THIS_MODULE,
@@ -341,7 +355,8 @@ static void mux_control_delay(struct mux_control *mux, unsigned int delay_us)
  * On successfully selecting the mux-control state, it will be locked until
  * there is a call to mux_control_deselect(). If the mux-control is already
  * selected when mux_control_select() is called, the caller will be blocked
- * until mux_control_deselect() is called (by someone else).
+ * until mux_control_deselect() or mux_state_deselect() is called (by someone
+ * else).
  *
  * Therefore, make sure to call mux_control_deselect() when the operation is
  * complete and the mux-control is free for others to use, but do not call
@@ -370,6 +385,30 @@ int mux_control_select_delay(struct mux_control *mux, unsigned int state,
 }
 EXPORT_SYMBOL_GPL(mux_control_select_delay);
 
+/**
+ * mux_state_select_delay() - Select the given multiplexer state.
+ * @mstate: The mux-state to select.
+ * @delay_us: The time to delay (in microseconds) if the mux state is changed.
+ *
+ * On successfully selecting the mux-state, its mux-control will be locked
+ * until there is a call to mux_state_deselect(). If the mux-control is already
+ * selected when mux_state_select() is called, the caller will be blocked
+ * until mux_state_deselect() or mux_control_deselect() is called (by someone
+ * else).
+ *
+ * Therefore, make sure to call mux_state_deselect() when the operation is
+ * complete and the mux-control is free for others to use, but do not call
+ * mux_state_deselect() if mux_state_select() fails.
+ *
+ * Return: 0 when the mux-state has been selected or a negative
+ * errno on error.
+ */
+int mux_state_select_delay(struct mux_state *mstate, unsigned int delay_us)
+{
+       return mux_control_select_delay(mstate->mux, mstate->state, delay_us);
+}
+EXPORT_SYMBOL_GPL(mux_state_select_delay);
+
 /**
  * mux_control_try_select_delay() - Try to select the given multiplexer state.
  * @mux: The mux-control to request a change of state from.
@@ -377,7 +416,7 @@ EXPORT_SYMBOL_GPL(mux_control_select_delay);
  * @delay_us: The time to delay (in microseconds) if the mux state is changed.
  *
  * On successfully selecting the mux-control state, it will be locked until
- * mux_control_deselect() called.
+ * mux_control_deselect() is called.
  *
  * Therefore, make sure to call mux_control_deselect() when the operation is
  * complete and the mux-control is free for others to use, but do not call
@@ -405,6 +444,27 @@ int mux_control_try_select_delay(struct mux_control *mux, unsigned int state,
 }
 EXPORT_SYMBOL_GPL(mux_control_try_select_delay);
 
+/**
+ * mux_state_try_select_delay() - Try to select the given multiplexer state.
+ * @mstate: The mux-state to select.
+ * @delay_us: The time to delay (in microseconds) if the mux state is changed.
+ *
+ * On successfully selecting the mux-state, its mux-control will be locked
+ * until mux_state_deselect() is called.
+ *
+ * Therefore, make sure to call mux_state_deselect() when the operation is
+ * complete and the mux-control is free for others to use, but do not call
+ * mux_state_deselect() if mux_state_try_select() fails.
+ *
+ * Return: 0 when the mux-state has been selected or a negative errno on
+ * error. Specifically -EBUSY if the mux-control is contended.
+ */
+int mux_state_try_select_delay(struct mux_state *mstate, unsigned int delay_us)
+{
+       return mux_control_try_select_delay(mstate->mux, mstate->state, delay_us);
+}
+EXPORT_SYMBOL_GPL(mux_state_try_select_delay);
+
 /**
  * mux_control_deselect() - Deselect the previously selected multiplexer state.
  * @mux: The mux-control to deselect.
@@ -431,6 +491,24 @@ int mux_control_deselect(struct mux_control *mux)
 }
 EXPORT_SYMBOL_GPL(mux_control_deselect);
 
+/**
+ * mux_state_deselect() - Deselect the previously selected multiplexer state.
+ * @mstate: The mux-state to deselect.
+ *
+ * It is required that a single call is made to mux_state_deselect() for
+ * each and every successful call made to either of mux_state_select() or
+ * mux_state_try_select().
+ *
+ * Return: 0 on success and a negative errno on error. An error can only
+ * occur if the mux has an idle state. Note that even if an error occurs, the
+ * mux-control is unlocked and is thus free for the next access.
+ */
+int mux_state_deselect(struct mux_state *mstate)
+{
+       return mux_control_deselect(mstate->mux);
+}
+EXPORT_SYMBOL_GPL(mux_state_deselect);
+
 /* Note this function returns a reference to the mux_chip dev. */
 static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
 {
@@ -441,14 +519,17 @@ static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
        return dev ? to_mux_chip(dev) : NULL;
 }
 
-/**
- * mux_control_get() - Get the mux-control for a device.
+/*
+ * mux_get() - Get the mux-control for a device.
  * @dev: The device that needs a mux-control.
  * @mux_name: The name identifying the mux-control.
+ * @state: Pointer to where the requested state is returned, or NULL when
+ *         the required multiplexer states are handled by other means.
  *
  * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
  */
-struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
+static struct mux_control *mux_get(struct device *dev, const char *mux_name,
+                                  unsigned int *state)
 {
        struct device_node *np = dev->of_node;
        struct of_phandle_args args;
@@ -458,8 +539,12 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
        int ret;
 
        if (mux_name) {
-               index = of_property_match_string(np, "mux-control-names",
-                                                mux_name);
+               if (state)
+                       index = of_property_match_string(np, "mux-state-names",
+                                                        mux_name);
+               else
+                       index = of_property_match_string(np, "mux-control-names",
+                                                        mux_name);
                if (index < 0) {
                        dev_err(dev, "mux controller '%s' not found\n",
                                mux_name);
@@ -467,12 +552,17 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
                }
        }
 
-       ret = of_parse_phandle_with_args(np,
-                                        "mux-controls", "#mux-control-cells",
-                                        index, &args);
+       if (state)
+               ret = of_parse_phandle_with_args(np,
+                                                "mux-states", "#mux-state-cells",
+                                                index, &args);
+       else
+               ret = of_parse_phandle_with_args(np,
+                                                "mux-controls", "#mux-control-cells",
+                                                index, &args);
        if (ret) {
-               dev_err(dev, "%pOF: failed to get mux-control %s(%i)\n",
-                       np, mux_name ?: "", index);
+               dev_err(dev, "%pOF: failed to get mux-%s %s(%i)\n",
+                       np, state ? "state" : "control", mux_name ?: "", index);
                return ERR_PTR(ret);
        }
 
@@ -481,17 +571,35 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
        if (!mux_chip)
                return ERR_PTR(-EPROBE_DEFER);
 
-       if (args.args_count > 1 ||
-           (!args.args_count && (mux_chip->controllers > 1))) {
-               dev_err(dev, "%pOF: wrong #mux-control-cells for %pOF\n",
-                       np, args.np);
-               put_device(&mux_chip->dev);
-               return ERR_PTR(-EINVAL);
-       }
-
        controller = 0;
-       if (args.args_count)
-               controller = args.args[0];
+       if (state) {
+               if (args.args_count > 2 || args.args_count == 0 ||
+                   (args.args_count < 2 && mux_chip->controllers > 1)) {
+                       dev_err(dev, "%pOF: wrong #mux-state-cells for %pOF\n",
+                               np, args.np);
+                       put_device(&mux_chip->dev);
+                       return ERR_PTR(-EINVAL);
+               }
+
+               if (args.args_count == 2) {
+                       controller = args.args[0];
+                       *state = args.args[1];
+               } else {
+                       *state = args.args[0];
+               }
+
+       } else {
+               if (args.args_count > 1 ||
+                   (!args.args_count && mux_chip->controllers > 1)) {
+                       dev_err(dev, "%pOF: wrong #mux-control-cells for %pOF\n",
+                               np, args.np);
+                       put_device(&mux_chip->dev);
+                       return ERR_PTR(-EINVAL);
+               }
+
+               if (args.args_count)
+                       controller = args.args[0];
+       }
 
        if (controller >= mux_chip->controllers) {
                dev_err(dev, "%pOF: bad mux controller %u specified in %pOF\n",
@@ -502,6 +610,18 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
 
        return &mux_chip->mux[controller];
 }
+
+/**
+ * mux_control_get() - Get the mux-control for a device.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
+{
+       return mux_get(dev, mux_name, NULL);
+}
 EXPORT_SYMBOL_GPL(mux_control_get);
 
 /**
@@ -553,6 +673,81 @@ struct mux_control *devm_mux_control_get(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(devm_mux_control_get);
 
+/*
+ * mux_state_get() - Get the mux-state for a device.
+ * @dev: The device that needs a mux-state.
+ * @mux_name: The name identifying the mux-state.
+ *
+ * Return: A pointer to the mux-state, or an ERR_PTR with a negative errno.
+ */
+static struct mux_state *mux_state_get(struct device *dev, const char *mux_name)
+{
+       struct mux_state *mstate;
+
+       mstate = kzalloc(sizeof(*mstate), GFP_KERNEL);
+       if (!mstate)
+               return ERR_PTR(-ENOMEM);
+
+       mstate->mux = mux_get(dev, mux_name, &mstate->state);
+       if (IS_ERR(mstate->mux)) {
+               int err = PTR_ERR(mstate->mux);
+
+               kfree(mstate);
+               return ERR_PTR(err);
+       }
+
+       return mstate;
+}
+
+/*
+ * mux_state_put() - Put away the mux-state for good.
+ * @mstate: The mux-state to put away.
+ *
+ * mux_state_put() reverses the effects of mux_state_get().
+ */
+static void mux_state_put(struct mux_state *mstate)
+{
+       mux_control_put(mstate->mux);
+       kfree(mstate);
+}
+
+static void devm_mux_state_release(struct device *dev, void *res)
+{
+       struct mux_state *mstate = *(struct mux_state **)res;
+
+       mux_state_put(mstate);
+}
+
+/**
+ * devm_mux_state_get() - Get the mux-state for a device, with resource
+ *                       management.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: Pointer to the mux-state, or an ERR_PTR with a negative errno.
+ */
+struct mux_state *devm_mux_state_get(struct device *dev,
+                                    const char *mux_name)
+{
+       struct mux_state **ptr, *mstate;
+
+       ptr = devres_alloc(devm_mux_state_release, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr)
+               return ERR_PTR(-ENOMEM);
+
+       mstate = mux_state_get(dev, mux_name);
+       if (IS_ERR(mstate)) {
+               devres_free(ptr);
+               return mstate;
+       }
+
+       *ptr = mstate;
+       devres_add(dev, ptr);
+
+       return mstate;
+}
+EXPORT_SYMBOL_GPL(devm_mux_state_get);
+
 /*
  * Using subsys_initcall instead of module_init here to try to ensure - for
  * the non-modular case - that the subsystem is initialized when mux consumers
index 6006c2e..a86b1f7 100644 (file)
@@ -225,7 +225,7 @@ static inline int __check_agg_selection_timer(struct port *port)
        if (bond == NULL)
                return 0;
 
-       return BOND_AD_INFO(bond).agg_select_timer ? 1 : 0;
+       return atomic_read(&BOND_AD_INFO(bond).agg_select_timer) ? 1 : 0;
 }
 
 /**
@@ -1021,8 +1021,8 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
                                if (port->aggregator &&
                                    port->aggregator->is_active &&
                                    !__port_is_enabled(port)) {
-
                                        __enable_port(port);
+                                       *update_slave_arr = true;
                                }
                        }
                        break;
@@ -1779,6 +1779,7 @@ static void ad_agg_selection_logic(struct aggregator *agg,
                             port = port->next_port_in_aggregator) {
                                __enable_port(port);
                        }
+                       *update_slave_arr = true;
                }
        }
 
@@ -1994,7 +1995,7 @@ static void ad_marker_response_received(struct bond_marker *marker,
  */
 void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout)
 {
-       BOND_AD_INFO(bond).agg_select_timer = timeout;
+       atomic_set(&BOND_AD_INFO(bond).agg_select_timer, timeout);
 }
 
 /**
@@ -2277,6 +2278,28 @@ void bond_3ad_update_ad_actor_settings(struct bonding *bond)
        spin_unlock_bh(&bond->mode_lock);
 }
 
+/**
+ * bond_agg_timer_advance - advance agg_select_timer
+ * @bond:  bonding structure
+ *
+ * Return true when agg_select_timer reaches 0.
+ */
+static bool bond_agg_timer_advance(struct bonding *bond)
+{
+       int val, nval;
+
+       while (1) {
+               val = atomic_read(&BOND_AD_INFO(bond).agg_select_timer);
+               if (!val)
+                       return false;
+               nval = val - 1;
+               if (atomic_cmpxchg(&BOND_AD_INFO(bond).agg_select_timer,
+                                  val, nval) == val)
+                       break;
+       }
+       return nval == 0;
+}
+
 /**
  * bond_3ad_state_machine_handler - handle state machines timeout
  * @work: work context to fetch bonding struct to work on from
@@ -2312,9 +2335,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
        if (!bond_has_slaves(bond))
                goto re_arm;
 
-       /* check if agg_select_timer timer after initialize is timed out */
-       if (BOND_AD_INFO(bond).agg_select_timer &&
-           !(--BOND_AD_INFO(bond).agg_select_timer)) {
+       if (bond_agg_timer_advance(bond)) {
                slave = bond_first_slave_rcu(bond);
                port = slave ? &(SLAVE_AD_INFO(slave)->port) : NULL;
 
index ec498ce..aebeb46 100644 (file)
@@ -2379,10 +2379,9 @@ static int __bond_release_one(struct net_device *bond_dev,
                bond_select_active_slave(bond);
        }
 
-       if (!bond_has_slaves(bond)) {
-               bond_set_carrier(bond);
+       bond_set_carrier(bond);
+       if (!bond_has_slaves(bond))
                eth_hw_addr_random(bond_dev);
-       }
 
        unblock_netpoll_tx();
        synchronize_rcu();
@@ -4133,9 +4132,7 @@ static int bond_eth_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cm
 
                fallthrough;
        case SIOCGHWTSTAMP:
-               rcu_read_lock();
                real_dev = bond_option_active_slave_get_rcu(bond);
-               rcu_read_unlock();
                if (!real_dev)
                        return -EOPNOTSUPP;
 
@@ -5382,9 +5379,7 @@ static int bond_ethtool_get_ts_info(struct net_device *bond_dev,
        struct net_device *real_dev;
        struct phy_device *phydev;
 
-       rcu_read_lock();
        real_dev = bond_option_active_slave_get_rcu(bond);
-       rcu_read_unlock();
        if (real_dev) {
                ops = real_dev->ethtool_ops;
                phydev = real_dev->phydev;
index 0bff188..74d7fcb 100644 (file)
@@ -296,6 +296,7 @@ static_assert(sizeof(struct flexcan_regs) ==  0x4 * 18 + 0xfb8);
 static const struct flexcan_devtype_data fsl_mcf5441x_devtype_data = {
        .quirks = FLEXCAN_QUIRK_BROKEN_PERR_STATE |
                FLEXCAN_QUIRK_NR_IRQ_3 | FLEXCAN_QUIRK_NR_MB_16 |
+               FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX |
                FLEXCAN_QUIRK_SUPPPORT_RX_FIFO,
 };
 
index fccdff8..23fc09a 100644 (file)
@@ -21,7 +21,7 @@
  * Below is some version info we got:
  *    SOC   Version   IP-Version  Glitch- [TR]WRN_INT IRQ Err Memory err RTR rece-   FD Mode     MB
  *                                Filter? connected?  Passive detection  ption in MB Supported?
- * MCF5441X FlexCAN2  ?               no       yes        no       no       yes           no     16
+ * MCF5441X FlexCAN2  ?               no       yes        no       no        no           no     16
  *    MX25  FlexCAN2  03.00.00.00     no        no        no       no        no           no     64
  *    MX28  FlexCAN2  03.00.04.00    yes       yes        no       no        no           no     64
  *    MX35  FlexCAN2  03.00.00.00     no        no        no       no        no           no     64
index 5b47cd8..1a4b56f 100644 (file)
@@ -336,6 +336,9 @@ m_can_fifo_read(struct m_can_classdev *cdev,
        u32 addr_offset = cdev->mcfg[MRAM_RXF0].off + fgi * RXF0_ELEMENT_SIZE +
                offset;
 
+       if (val_count == 0)
+               return 0;
+
        return cdev->ops->read_fifo(cdev, addr_offset, val, val_count);
 }
 
@@ -346,6 +349,9 @@ m_can_fifo_write(struct m_can_classdev *cdev,
        u32 addr_offset = cdev->mcfg[MRAM_TXB].off + fpi * TXB_ELEMENT_SIZE +
                offset;
 
+       if (val_count == 0)
+               return 0;
+
        return cdev->ops->write_fifo(cdev, addr_offset, val, val_count);
 }
 
index ca80dba..26e212b 100644 (file)
@@ -12,7 +12,7 @@
 #define TCAN4X5X_SPI_INSTRUCTION_WRITE (0x61 << 24)
 #define TCAN4X5X_SPI_INSTRUCTION_READ (0x41 << 24)
 
-#define TCAN4X5X_MAX_REGISTER 0x8ffc
+#define TCAN4X5X_MAX_REGISTER 0x87fc
 
 static int tcan4x5x_regmap_gather_write(void *context,
                                        const void *reg, size_t reg_len,
index 7b1457a..0029d27 100644 (file)
@@ -36,6 +36,7 @@ config NET_DSA_LANTIQ_GSWIP
 config NET_DSA_MT7530
        tristate "MediaTek MT753x and MT7621 Ethernet switch support"
        select NET_DSA_TAG_MTK
+       select MEDIATEK_GE_PHY
        help
          This enables support for the MediaTek MT7530, MT7531, and MT7621
          Ethernet switch chips.
@@ -81,6 +82,7 @@ config NET_DSA_REALTEK_SMI
 
 config NET_DSA_SMSC_LAN9303
        tristate
+       depends on VLAN_8021Q || VLAN_8021Q=n
        select NET_DSA_TAG_LAN9303
        select REGMAP
        help
index 33499fc..6afb5db 100644 (file)
@@ -621,7 +621,7 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds)
        get_device(&priv->master_mii_bus->dev);
        priv->master_mii_dn = dn;
 
-       priv->slave_mii_bus = devm_mdiobus_alloc(ds->dev);
+       priv->slave_mii_bus = mdiobus_alloc();
        if (!priv->slave_mii_bus) {
                of_node_put(dn);
                return -ENOMEM;
@@ -681,8 +681,10 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds)
        }
 
        err = mdiobus_register(priv->slave_mii_bus);
-       if (err && dn)
+       if (err && dn) {
+               mdiobus_free(priv->slave_mii_bus);
                of_node_put(dn);
+       }
 
        return err;
 }
@@ -690,6 +692,7 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds)
 static void bcm_sf2_mdio_unregister(struct bcm_sf2_priv *priv)
 {
        mdiobus_unregister(priv->slave_mii_bus);
+       mdiobus_free(priv->slave_mii_bus);
        of_node_put(priv->master_mii_dn);
 }
 
index d55784d..3969d89 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/mii.h>
 #include <linux/phy.h>
 #include <linux/if_bridge.h>
+#include <linux/if_vlan.h>
 #include <linux/etherdevice.h>
 
 #include "lan9303.h"
@@ -1083,21 +1084,27 @@ static void lan9303_adjust_link(struct dsa_switch *ds, int port,
 static int lan9303_port_enable(struct dsa_switch *ds, int port,
                               struct phy_device *phy)
 {
+       struct dsa_port *dp = dsa_to_port(ds, port);
        struct lan9303 *chip = ds->priv;
 
-       if (!dsa_is_user_port(ds, port))
+       if (!dsa_port_is_user(dp))
                return 0;
 
+       vlan_vid_add(dp->cpu_dp->master, htons(ETH_P_8021Q), port);
+
        return lan9303_enable_processing_port(chip, port);
 }
 
 static void lan9303_port_disable(struct dsa_switch *ds, int port)
 {
+       struct dsa_port *dp = dsa_to_port(ds, port);
        struct lan9303 *chip = ds->priv;
 
-       if (!dsa_is_user_port(ds, port))
+       if (!dsa_port_is_user(dp))
                return;
 
+       vlan_vid_del(dp->cpu_dp->master, htons(ETH_P_8021Q), port);
+
        lan9303_disable_processing_port(chip, port);
        lan9303_phy_write(ds, chip->phy_addr_base + port, MII_BMCR, BMCR_PDOWN);
 }
@@ -1310,7 +1317,7 @@ static int lan9303_probe_reset_gpio(struct lan9303 *chip,
                                     struct device_node *np)
 {
        chip->reset_gpio = devm_gpiod_get_optional(chip->dev, "reset",
-                                                  GPIOD_OUT_LOW);
+                                                  GPIOD_OUT_HIGH);
        if (IS_ERR(chip->reset_gpio))
                return PTR_ERR(chip->reset_gpio);
 
index 46ed953..8a7a809 100644 (file)
@@ -498,8 +498,9 @@ static int gswip_mdio_rd(struct mii_bus *bus, int addr, int reg)
 static int gswip_mdio(struct gswip_priv *priv, struct device_node *mdio_np)
 {
        struct dsa_switch *ds = priv->ds;
+       int err;
 
-       ds->slave_mii_bus = devm_mdiobus_alloc(priv->dev);
+       ds->slave_mii_bus = mdiobus_alloc();
        if (!ds->slave_mii_bus)
                return -ENOMEM;
 
@@ -512,7 +513,11 @@ static int gswip_mdio(struct gswip_priv *priv, struct device_node *mdio_np)
        ds->slave_mii_bus->parent = priv->dev;
        ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask;
 
-       return of_mdiobus_register(ds->slave_mii_bus, mdio_np);
+       err = of_mdiobus_register(ds->slave_mii_bus, mdio_np);
+       if (err)
+               mdiobus_free(ds->slave_mii_bus);
+
+       return err;
 }
 
 static int gswip_pce_table_entry_read(struct gswip_priv *priv,
@@ -2145,8 +2150,10 @@ disable_switch:
        gswip_mdio_mask(priv, GSWIP_MDIO_GLOB_ENABLE, 0, GSWIP_MDIO_GLOB);
        dsa_unregister_switch(priv->ds);
 mdio_bus:
-       if (mdio_np)
+       if (mdio_np) {
                mdiobus_unregister(priv->ds->slave_mii_bus);
+               mdiobus_free(priv->ds->slave_mii_bus);
+       }
 put_mdio_node:
        of_node_put(mdio_np);
        for (i = 0; i < priv->num_gphy_fw; i++)
@@ -2170,6 +2177,7 @@ static int gswip_remove(struct platform_device *pdev)
        if (priv->ds->slave_mii_bus) {
                mdiobus_unregister(priv->ds->slave_mii_bus);
                of_node_put(priv->ds->slave_mii_bus->dev.of_node);
+               mdiobus_free(priv->ds->slave_mii_bus);
        }
 
        for (i = 0; i < priv->num_gphy_fw; i++)
index 55dbda0..243f8ad 100644 (file)
@@ -26,7 +26,7 @@ void ksz_update_port_member(struct ksz_device *dev, int port)
        struct dsa_switch *ds = dev->ds;
        u8 port_member = 0, cpu_port;
        const struct dsa_port *dp;
-       int i;
+       int i, j;
 
        if (!dsa_is_user_port(ds, port))
                return;
@@ -45,13 +45,33 @@ void ksz_update_port_member(struct ksz_device *dev, int port)
                        continue;
                if (!dsa_port_bridge_same(dp, other_dp))
                        continue;
+               if (other_p->stp_state != BR_STATE_FORWARDING)
+                       continue;
 
-               if (other_p->stp_state == BR_STATE_FORWARDING &&
-                   p->stp_state == BR_STATE_FORWARDING) {
+               if (p->stp_state == BR_STATE_FORWARDING) {
                        val |= BIT(port);
                        port_member |= BIT(i);
                }
 
+               /* Retain port [i]'s relationship to other ports than [port] */
+               for (j = 0; j < ds->num_ports; j++) {
+                       const struct dsa_port *third_dp;
+                       struct ksz_port *third_p;
+
+                       if (j == i)
+                               continue;
+                       if (j == port)
+                               continue;
+                       if (!dsa_is_user_port(ds, j))
+                               continue;
+                       third_p = &dev->ports[j];
+                       if (third_p->stp_state != BR_STATE_FORWARDING)
+                               continue;
+                       third_dp = dsa_to_port(ds, j);
+                       if (dsa_port_bridge_same(other_dp, third_dp))
+                               val |= BIT(j);
+               }
+
                dev->dev_ops->cfg_port_member(dev, i, val | cpu_port);
        }
 
index b82512e..ff3c267 100644 (file)
@@ -2074,7 +2074,7 @@ mt7530_setup_mdio(struct mt7530_priv *priv)
        if (priv->irq)
                mt7530_setup_mdio_irq(priv);
 
-       ret = mdiobus_register(bus);
+       ret = devm_mdiobus_register(dev, bus);
        if (ret) {
                dev_err(dev, "failed to register MDIO bus: %d\n", ret);
                if (priv->irq)
index 58ca684..ab16765 100644 (file)
@@ -2284,6 +2284,13 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
        if (!mv88e6xxx_max_vid(chip))
                return -EOPNOTSUPP;
 
+       /* The ATU removal procedure needs the FID to be mapped in the VTU,
+        * but FDB deletion runs concurrently with VLAN deletion. Flush the DSA
+        * switchdev workqueue to ensure that all FDB entries are deleted
+        * before we remove the VLAN.
+        */
+       dsa_flush_workqueue();
+
        mv88e6xxx_reg_lock(chip);
 
        err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
@@ -3399,7 +3406,7 @@ static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
                        return err;
        }
 
-       bus = devm_mdiobus_alloc_size(chip->dev, sizeof(*mdio_bus));
+       bus = mdiobus_alloc_size(sizeof(*mdio_bus));
        if (!bus)
                return -ENOMEM;
 
@@ -3424,14 +3431,14 @@ static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
        if (!external) {
                err = mv88e6xxx_g2_irq_mdio_setup(chip, bus);
                if (err)
-                       return err;
+                       goto out;
        }
 
        err = of_mdiobus_register(bus, np);
        if (err) {
                dev_err(chip->dev, "Cannot register MDIO bus (%d)\n", err);
                mv88e6xxx_g2_irq_mdio_free(chip, bus);
-               return err;
+               goto out;
        }
 
        if (external)
@@ -3440,21 +3447,26 @@ static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
                list_add(&mdio_bus->list, &chip->mdios);
 
        return 0;
+
+out:
+       mdiobus_free(bus);
+       return err;
 }
 
 static void mv88e6xxx_mdios_unregister(struct mv88e6xxx_chip *chip)
 
 {
-       struct mv88e6xxx_mdio_bus *mdio_bus;
+       struct mv88e6xxx_mdio_bus *mdio_bus, *p;
        struct mii_bus *bus;
 
-       list_for_each_entry(mdio_bus, &chip->mdios, list) {
+       list_for_each_entry_safe(mdio_bus, p, &chip->mdios, list) {
                bus = mdio_bus->bus;
 
                if (!mdio_bus->external)
                        mv88e6xxx_g2_irq_mdio_free(chip, bus);
 
                mdiobus_unregister(bus);
+               mdiobus_free(bus);
        }
 }
 
index bf8d382..33f0cea 100644 (file)
@@ -1061,7 +1061,7 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
                return PTR_ERR(hw);
        }
 
-       bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
+       bus = mdiobus_alloc_size(sizeof(*mdio_priv));
        if (!bus)
                return -ENOMEM;
 
@@ -1081,6 +1081,7 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
        rc = mdiobus_register(bus);
        if (rc < 0) {
                dev_err(dev, "failed to register MDIO bus\n");
+               mdiobus_free(bus);
                return rc;
        }
 
@@ -1132,6 +1133,7 @@ static void vsc9959_mdio_bus_free(struct ocelot *ocelot)
                lynx_pcs_destroy(phylink_pcs);
        }
        mdiobus_unregister(felix->imdio);
+       mdiobus_free(felix->imdio);
 }
 
 static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port,
index 8c1c9da..f2f1608 100644 (file)
@@ -1029,7 +1029,7 @@ static int vsc9953_mdio_bus_alloc(struct ocelot *ocelot)
        }
 
        /* Needed in order to initialize the bus mutex lock */
-       rc = of_mdiobus_register(bus, NULL);
+       rc = devm_of_mdiobus_register(dev, bus, NULL);
        if (rc < 0) {
                dev_err(dev, "failed to register MDIO bus\n");
                return rc;
@@ -1083,7 +1083,8 @@ static void vsc9953_mdio_bus_free(struct ocelot *ocelot)
                mdio_device_free(mdio_device);
                lynx_pcs_destroy(phylink_pcs);
        }
-       mdiobus_unregister(felix->imdio);
+
+       /* mdiobus_unregister and mdiobus_free handled by devres */
 }
 
 static const struct felix_info seville_info_vsc9953 = {
index da0d7e6..c39de2a 100644 (file)
@@ -378,7 +378,7 @@ static int ar9331_sw_mbus_init(struct ar9331_sw_priv *priv)
        if (!mnp)
                return -ENODEV;
 
-       ret = of_mdiobus_register(mbus, mnp);
+       ret = devm_of_mdiobus_register(dev, mbus, mnp);
        of_node_put(mnp);
        if (ret)
                return ret;
@@ -1091,7 +1091,6 @@ static void ar9331_sw_remove(struct mdio_device *mdiodev)
        }
 
        irq_domain_remove(priv->irqdomain);
-       mdiobus_unregister(priv->mbus);
        dsa_unregister_switch(&priv->ds);
 
        reset_control_assert(priv->sw_reset);
index 481f1df..8aec5d9 100644 (file)
@@ -2278,6 +2278,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct net_device *dev;
        struct typhoon *tp;
        int card_id = (int) ent->driver_data;
+       u8 addr[ETH_ALEN] __aligned(4);
        void __iomem *ioaddr;
        void *shared;
        dma_addr_t shared_dma;
@@ -2409,8 +2410,9 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto error_out_reset;
        }
 
-       *(__be16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp[0].parm1));
-       *(__be32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2));
+       *(__be16 *)&addr[0] = htons(le16_to_cpu(xp_resp[0].parm1));
+       *(__be32 *)&addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2));
+       eth_hw_addr_set(dev, addr);
 
        if (!is_valid_ether_addr(dev->dev_addr)) {
                err_msg = "Could not obtain valid ethernet address, aborting";
index bd22a53..e7b8791 100644 (file)
@@ -655,6 +655,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
        struct ei_device *ei_local;
        struct net_device *dev;
        struct etherh_priv *eh;
+       u8 addr[ETH_ALEN];
        int ret;
 
        ret = ecard_request_resources(ec);
@@ -724,12 +725,13 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
        spin_lock_init(&ei_local->page_lock);
 
        if (ec->cid.product == PROD_ANT_ETHERM) {
-               etherm_addr(dev->dev_addr);
+               etherm_addr(addr);
                ei_local->reg_offset = etherm_regoffsets;
        } else {
-               etherh_addr(dev->dev_addr, ec);
+               etherh_addr(addr, ec);
                ei_local->reg_offset = etherh_regoffsets;
        }
+       eth_hw_addr_set(dev, addr);
 
        ei_local->name          = dev->name;
        ei_local->word16        = 1;
index 493b0ce..ec8df05 100644 (file)
@@ -1032,6 +1032,7 @@ static int dec_lance_probe(struct device *bdev, const int type)
        int i, ret;
        unsigned long esar_base;
        unsigned char *esar;
+       u8 addr[ETH_ALEN];
        const char *desc;
 
        if (dec_lance_debug && version_printed++ == 0)
@@ -1228,7 +1229,8 @@ static int dec_lance_probe(struct device *bdev, const int type)
                break;
        }
        for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = esar[i * 4];
+               addr[i] = esar[i * 4];
+       eth_hw_addr_set(dev, addr);
 
        printk("%s: %s, addr = %pM, irq = %d\n",
               name, desc, dev->dev_addr, dev->irq);
index 492ac38..a359329 100644 (file)
@@ -721,7 +721,9 @@ static void xgbe_stop_timers(struct xgbe_prv_data *pdata)
                if (!channel->tx_ring)
                        break;
 
+               /* Deactivate the Tx timer */
                del_timer_sync(&channel->tx_timer);
+               channel->tx_timer_active = 0;
        }
 }
 
@@ -2550,6 +2552,14 @@ read_again:
                        buf2_len = xgbe_rx_buf2_len(rdata, packet, len);
                        len += buf2_len;
 
+                       if (buf2_len > rdata->rx.buf.dma_len) {
+                               /* Hardware inconsistency within the descriptors
+                                * that has resulted in a length underflow.
+                                */
+                               error = 1;
+                               goto skip_data;
+                       }
+
                        if (!skb) {
                                skb = xgbe_create_skb(pdata, napi, rdata,
                                                      buf1_len);
@@ -2579,8 +2589,10 @@ skip_data:
                if (!last || context_next)
                        goto read_again;
 
-               if (!skb)
+               if (!skb || error) {
+                       dev_kfree_skb(skb);
                        goto next_packet;
+               }
 
                /* Be sure we don't exceed the configured MTU */
                max_len = netdev->mtu + ETH_HLEN;
index efdcf48..2af3da4 100644 (file)
@@ -425,6 +425,9 @@ static void xgbe_pci_remove(struct pci_dev *pdev)
 
        pci_free_irq_vectors(pdata->pcidev);
 
+       /* Disable all interrupts in the hardware */
+       XP_IOWRITE(pdata, XP_INT_EN, 0x0);
+
        xgbe_free_pdata(pdata);
 }
 
index 1bc4d33..30a573d 100644 (file)
@@ -826,7 +826,6 @@ int aq_filters_vlans_update(struct aq_nic_s *aq_nic)
        struct aq_hw_s *aq_hw = aq_nic->aq_hw;
        int hweight = 0;
        int err = 0;
-       int i;
 
        if (unlikely(!aq_hw_ops->hw_filter_vlan_set))
                return -EOPNOTSUPP;
@@ -837,8 +836,7 @@ int aq_filters_vlans_update(struct aq_nic_s *aq_nic)
                         aq_nic->aq_hw_rx_fltrs.fl2.aq_vlans);
 
        if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) {
-               for (i = 0; i < BITS_TO_LONGS(VLAN_N_VID); i++)
-                       hweight += hweight_long(aq_nic->active_vlans[i]);
+               hweight = bitmap_weight(aq_nic->active_vlans, VLAN_N_VID);
 
                err = aq_hw_ops->hw_filter_vlan_ctrl(aq_hw, false);
                if (err)
@@ -871,7 +869,7 @@ int aq_filters_vlan_offload_off(struct aq_nic_s *aq_nic)
        struct aq_hw_s *aq_hw = aq_nic->aq_hw;
        int err = 0;
 
-       memset(aq_nic->active_vlans, 0, sizeof(aq_nic->active_vlans));
+       bitmap_zero(aq_nic->active_vlans, VLAN_N_VID);
        aq_fvlan_rebuild(aq_nic, aq_nic->active_vlans,
                         aq_nic->aq_hw_rx_fltrs.fl2.aq_vlans);
 
index da59524..f50604f 100644 (file)
@@ -900,7 +900,7 @@ static void atl1c_clean_tx_ring(struct atl1c_adapter *adapter,
                atl1c_clean_buffer(pdev, buffer_info);
        }
 
-       netdev_reset_queue(adapter->netdev);
+       netdev_tx_reset_queue(netdev_get_tx_queue(adapter->netdev, queue));
 
        /* Zero out Tx-buffers */
        memset(tpd_ring->desc, 0, sizeof(struct atl1c_tpd_desc) *
index c6412c5..b4381cd 100644 (file)
@@ -172,6 +172,7 @@ static int bgmac_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct bgmac *bgmac;
+       struct resource *regs;
        int ret;
 
        bgmac = bgmac_alloc(&pdev->dev);
@@ -208,15 +209,23 @@ static int bgmac_probe(struct platform_device *pdev)
        if (IS_ERR(bgmac->plat.base))
                return PTR_ERR(bgmac->plat.base);
 
-       bgmac->plat.idm_base = devm_platform_ioremap_resource_byname(pdev, "idm_base");
-       if (IS_ERR(bgmac->plat.idm_base))
-               return PTR_ERR(bgmac->plat.idm_base);
-       else
+       /* The idm_base resource is optional for some platforms */
+       regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "idm_base");
+       if (regs) {
+               bgmac->plat.idm_base = devm_ioremap_resource(&pdev->dev, regs);
+               if (IS_ERR(bgmac->plat.idm_base))
+                       return PTR_ERR(bgmac->plat.idm_base);
                bgmac->feature_flags &= ~BGMAC_FEAT_IDM_MASK;
+       }
 
-       bgmac->plat.nicpm_base = devm_platform_ioremap_resource_byname(pdev, "nicpm_base");
-       if (IS_ERR(bgmac->plat.nicpm_base))
-               return PTR_ERR(bgmac->plat.nicpm_base);
+       /* The nicpm_base resource is optional for some platforms */
+       regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nicpm_base");
+       if (regs) {
+               bgmac->plat.nicpm_base = devm_ioremap_resource(&pdev->dev,
+                                                              regs);
+               if (IS_ERR(bgmac->plat.nicpm_base))
+                       return PTR_ERR(bgmac->plat.nicpm_base);
+       }
 
        bgmac->read = platform_bgmac_read;
        bgmac->write = platform_bgmac_write;
index 774c1f1..eedb48d 100644 (file)
@@ -100,6 +100,9 @@ MODULE_LICENSE("GPL");
 MODULE_FIRMWARE(FW_FILE_NAME_E1);
 MODULE_FIRMWARE(FW_FILE_NAME_E1H);
 MODULE_FIRMWARE(FW_FILE_NAME_E2);
+MODULE_FIRMWARE(FW_FILE_NAME_E1_V15);
+MODULE_FIRMWARE(FW_FILE_NAME_E1H_V15);
+MODULE_FIRMWARE(FW_FILE_NAME_E2_V15);
 
 int bnx2x_num_queues;
 module_param_named(num_queues, bnx2x_num_queues, int, 0444);
index 4f94136..b1c98d1 100644 (file)
@@ -4747,8 +4747,10 @@ static int bnxt_hwrm_cfa_l2_set_rx_mask(struct bnxt *bp, u16 vnic_id)
                return rc;
 
        req->vnic_id = cpu_to_le32(vnic->fw_vnic_id);
-       req->num_mc_entries = cpu_to_le32(vnic->mc_list_count);
-       req->mc_tbl_addr = cpu_to_le64(vnic->mc_list_mapping);
+       if (vnic->rx_mask & CFA_L2_SET_RX_MASK_REQ_MASK_MCAST) {
+               req->num_mc_entries = cpu_to_le32(vnic->mc_list_count);
+               req->mc_tbl_addr = cpu_to_le64(vnic->mc_list_mapping);
+       }
        req->mask = cpu_to_le32(vnic->rx_mask);
        return hwrm_req_send_silent(bp, req);
 }
@@ -7787,6 +7789,19 @@ static int bnxt_map_fw_health_regs(struct bnxt *bp)
        return 0;
 }
 
+static void bnxt_remap_fw_health_regs(struct bnxt *bp)
+{
+       if (!bp->fw_health)
+               return;
+
+       if (bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY) {
+               bp->fw_health->status_reliable = true;
+               bp->fw_health->resets_reliable = true;
+       } else {
+               bnxt_try_map_fw_health_reg(bp);
+       }
+}
+
 static int bnxt_hwrm_error_recovery_qcfg(struct bnxt *bp)
 {
        struct bnxt_fw_health *fw_health = bp->fw_health;
@@ -8639,6 +8654,9 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init)
        vnic->uc_filter_count = 1;
 
        vnic->rx_mask = 0;
+       if (test_bit(BNXT_STATE_HALF_OPEN, &bp->state))
+               goto skip_rx_mask;
+
        if (bp->dev->flags & IFF_BROADCAST)
                vnic->rx_mask |= CFA_L2_SET_RX_MASK_REQ_MASK_BCAST;
 
@@ -8648,7 +8666,7 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init)
        if (bp->dev->flags & IFF_ALLMULTI) {
                vnic->rx_mask |= CFA_L2_SET_RX_MASK_REQ_MASK_ALL_MCAST;
                vnic->mc_list_count = 0;
-       } else {
+       } else if (bp->dev->flags & IFF_MULTICAST) {
                u32 mask = 0;
 
                bnxt_mc_list_updated(bp, &mask);
@@ -8659,6 +8677,7 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init)
        if (rc)
                goto err_out;
 
+skip_rx_mask:
        rc = bnxt_hwrm_set_coal(bp);
        if (rc)
                netdev_warn(bp->dev, "HWRM set coalescing failure rc: %x\n",
@@ -9850,8 +9869,8 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up)
                resc_reinit = true;
        if (flags & FUNC_DRV_IF_CHANGE_RESP_FLAGS_HOT_FW_RESET_DONE)
                fw_reset = true;
-       else if (bp->fw_health && !bp->fw_health->status_reliable)
-               bnxt_try_map_fw_health_reg(bp);
+       else
+               bnxt_remap_fw_health_regs(bp);
 
        if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state) && !fw_reset) {
                netdev_err(bp->dev, "RESET_DONE not set during FW reset.\n");
@@ -10330,13 +10349,15 @@ int bnxt_half_open_nic(struct bnxt *bp)
                goto half_open_err;
        }
 
-       rc = bnxt_alloc_mem(bp, false);
+       rc = bnxt_alloc_mem(bp, true);
        if (rc) {
                netdev_err(bp->dev, "bnxt_alloc_mem err: %x\n", rc);
                goto half_open_err;
        }
-       rc = bnxt_init_nic(bp, false);
+       set_bit(BNXT_STATE_HALF_OPEN, &bp->state);
+       rc = bnxt_init_nic(bp, true);
        if (rc) {
+               clear_bit(BNXT_STATE_HALF_OPEN, &bp->state);
                netdev_err(bp->dev, "bnxt_init_nic err: %x\n", rc);
                goto half_open_err;
        }
@@ -10344,7 +10365,7 @@ int bnxt_half_open_nic(struct bnxt *bp)
 
 half_open_err:
        bnxt_free_skbs(bp);
-       bnxt_free_mem(bp, false);
+       bnxt_free_mem(bp, true);
        dev_close(bp->dev);
        return rc;
 }
@@ -10354,9 +10375,10 @@ half_open_err:
  */
 void bnxt_half_close_nic(struct bnxt *bp)
 {
-       bnxt_hwrm_resource_free(bp, false, false);
+       bnxt_hwrm_resource_free(bp, false, true);
        bnxt_free_skbs(bp);
-       bnxt_free_mem(bp, false);
+       bnxt_free_mem(bp, true);
+       clear_bit(BNXT_STATE_HALF_OPEN, &bp->state);
 }
 
 void bnxt_reenable_sriov(struct bnxt *bp)
@@ -10772,7 +10794,7 @@ static void bnxt_set_rx_mode(struct net_device *dev)
        if (dev->flags & IFF_ALLMULTI) {
                mask |= CFA_L2_SET_RX_MASK_REQ_MASK_ALL_MCAST;
                vnic->mc_list_count = 0;
-       } else {
+       } else if (dev->flags & IFF_MULTICAST) {
                mc_update = bnxt_mc_list_updated(bp, &mask);
        }
 
@@ -10849,9 +10871,10 @@ skip_uc:
            !bnxt_promisc_ok(bp))
                vnic->rx_mask &= ~CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS;
        rc = bnxt_hwrm_cfa_l2_set_rx_mask(bp, 0);
-       if (rc && vnic->mc_list_count) {
+       if (rc && (vnic->rx_mask & CFA_L2_SET_RX_MASK_REQ_MASK_MCAST)) {
                netdev_info(bp->dev, "Failed setting MC filters rc: %d, turning on ALL_MCAST mode\n",
                            rc);
+               vnic->rx_mask &= ~CFA_L2_SET_RX_MASK_REQ_MASK_MCAST;
                vnic->rx_mask |= CFA_L2_SET_RX_MASK_REQ_MASK_ALL_MCAST;
                vnic->mc_list_count = 0;
                rc = bnxt_hwrm_cfa_l2_set_rx_mask(bp, 0);
index 440dfeb..666fc1e 100644 (file)
@@ -1921,6 +1921,7 @@ struct bnxt {
 #define BNXT_STATE_RECOVER             12
 #define BNXT_STATE_FW_NON_FATAL_COND   13
 #define BNXT_STATE_FW_ACTIVATE_RESET   14
+#define BNXT_STATE_HALF_OPEN           15      /* For offline ethtool tests */
 
 #define BNXT_NO_FW_ACCESS(bp)                                  \
        (test_bit(BNXT_STATE_FW_FATAL_COND, &(bp)->state) ||    \
index 4da31b1..f6e21fa 100644 (file)
@@ -367,6 +367,16 @@ bnxt_dl_livepatch_report_err(struct bnxt *bp, struct netlink_ext_ack *extack,
        }
 }
 
+/* Live patch status in NVM */
+#define BNXT_LIVEPATCH_NOT_INSTALLED   0
+#define BNXT_LIVEPATCH_INSTALLED       FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_INSTALL
+#define BNXT_LIVEPATCH_REMOVED         FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_ACTIVE
+#define BNXT_LIVEPATCH_MASK            (FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_INSTALL | \
+                                        FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_ACTIVE)
+#define BNXT_LIVEPATCH_ACTIVATED       BNXT_LIVEPATCH_MASK
+
+#define BNXT_LIVEPATCH_STATE(flags)    ((flags) & BNXT_LIVEPATCH_MASK)
+
 static int
 bnxt_dl_livepatch_activate(struct bnxt *bp, struct netlink_ext_ack *extack)
 {
@@ -374,8 +384,9 @@ bnxt_dl_livepatch_activate(struct bnxt *bp, struct netlink_ext_ack *extack)
        struct hwrm_fw_livepatch_query_input *query_req;
        struct hwrm_fw_livepatch_output *patch_resp;
        struct hwrm_fw_livepatch_input *patch_req;
+       u16 flags, live_patch_state;
+       bool activated = false;
        u32 installed = 0;
-       u16 flags;
        u8 target;
        int rc;
 
@@ -394,7 +405,6 @@ bnxt_dl_livepatch_activate(struct bnxt *bp, struct netlink_ext_ack *extack)
                hwrm_req_drop(bp, query_req);
                return rc;
        }
-       patch_req->opcode = FW_LIVEPATCH_REQ_OPCODE_ACTIVATE;
        patch_req->loadtype = FW_LIVEPATCH_REQ_LOADTYPE_NVM_INSTALL;
        patch_resp = hwrm_req_hold(bp, patch_req);
 
@@ -407,12 +417,20 @@ bnxt_dl_livepatch_activate(struct bnxt *bp, struct netlink_ext_ack *extack)
                }
 
                flags = le16_to_cpu(query_resp->status_flags);
-               if (~flags & FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_INSTALL)
+               live_patch_state = BNXT_LIVEPATCH_STATE(flags);
+
+               if (live_patch_state == BNXT_LIVEPATCH_NOT_INSTALLED)
                        continue;
-               if ((flags & FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_ACTIVE) &&
-                   !strncmp(query_resp->active_ver, query_resp->install_ver,
-                            sizeof(query_resp->active_ver)))
+
+               if (live_patch_state == BNXT_LIVEPATCH_ACTIVATED) {
+                       activated = true;
                        continue;
+               }
+
+               if (live_patch_state == BNXT_LIVEPATCH_INSTALLED)
+                       patch_req->opcode = FW_LIVEPATCH_REQ_OPCODE_ACTIVATE;
+               else if (live_patch_state == BNXT_LIVEPATCH_REMOVED)
+                       patch_req->opcode = FW_LIVEPATCH_REQ_OPCODE_DEACTIVATE;
 
                patch_req->fw_target = target;
                rc = hwrm_req_send(bp, patch_req);
@@ -424,8 +442,13 @@ bnxt_dl_livepatch_activate(struct bnxt *bp, struct netlink_ext_ack *extack)
        }
 
        if (!rc && !installed) {
-               NL_SET_ERR_MSG_MOD(extack, "No live patches found");
-               rc = -ENOENT;
+               if (activated) {
+                       NL_SET_ERR_MSG_MOD(extack, "Live patch already activated");
+                       rc = -EEXIST;
+               } else {
+                       NL_SET_ERR_MSG_MOD(extack, "No live patches found");
+                       rc = -ENOENT;
+               }
        }
        hwrm_req_drop(bp, query_req);
        hwrm_req_drop(bp, patch_req);
index 003330e..8aaa233 100644 (file)
@@ -25,6 +25,7 @@
 #include "bnxt_hsi.h"
 #include "bnxt.h"
 #include "bnxt_hwrm.h"
+#include "bnxt_ulp.h"
 #include "bnxt_xdp.h"
 #include "bnxt_ptp.h"
 #include "bnxt_ethtool.h"
@@ -1969,6 +1970,9 @@ static int bnxt_get_fecparam(struct net_device *dev,
        case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_IEEE_ACTIVE:
                fec->active_fec |= ETHTOOL_FEC_LLRS;
                break;
+       case PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_NONE_ACTIVE:
+               fec->active_fec |= ETHTOOL_FEC_OFF;
+               break;
        }
        return 0;
 }
@@ -3454,7 +3458,7 @@ static int bnxt_run_loopback(struct bnxt *bp)
        if (!skb)
                return -ENOMEM;
        data = skb_put(skb, pkt_size);
-       eth_broadcast_addr(data);
+       ether_addr_copy(&data[i], bp->dev->dev_addr);
        i += ETH_ALEN;
        ether_addr_copy(&data[i], bp->dev->dev_addr);
        i += ETH_ALEN;
@@ -3548,9 +3552,12 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest,
        if (!offline) {
                bnxt_run_fw_tests(bp, test_mask, &test_results);
        } else {
-               rc = bnxt_close_nic(bp, false, false);
-               if (rc)
+               bnxt_ulp_stop(bp);
+               rc = bnxt_close_nic(bp, true, false);
+               if (rc) {
+                       bnxt_ulp_start(bp, rc);
                        return;
+               }
                bnxt_run_fw_tests(bp, test_mask, &test_results);
 
                buf[BNXT_MACLPBK_TEST_IDX] = 1;
@@ -3560,6 +3567,7 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest,
                if (rc) {
                        bnxt_hwrm_mac_loopback(bp, false);
                        etest->flags |= ETH_TEST_FL_FAILED;
+                       bnxt_ulp_start(bp, rc);
                        return;
                }
                if (bnxt_run_loopback(bp))
@@ -3585,7 +3593,8 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest,
                }
                bnxt_hwrm_phy_loopback(bp, false, false);
                bnxt_half_close_nic(bp);
-               rc = bnxt_open_nic(bp, false, true);
+               rc = bnxt_open_nic(bp, true, true);
+               bnxt_ulp_start(bp, rc);
        }
        if (rc || bnxt_test_irq(bp)) {
                buf[BNXT_IRQ_TEST_IDX] = 1;
index 566c948..b01d429 100644 (file)
@@ -644,17 +644,23 @@ static int __hwrm_send(struct bnxt *bp, struct bnxt_hwrm_ctx *ctx)
 
                /* Last byte of resp contains valid bit */
                valid = ((u8 *)ctx->resp) + len - 1;
-               for (j = 0; j < HWRM_VALID_BIT_DELAY_USEC; j++) {
+               for (j = 0; j < HWRM_VALID_BIT_DELAY_USEC; ) {
                        /* make sure we read from updated DMA memory */
                        dma_rmb();
                        if (*valid)
                                break;
-                       usleep_range(1, 5);
+                       if (j < 10) {
+                               udelay(1);
+                               j++;
+                       } else {
+                               usleep_range(20, 30);
+                               j += 20;
+                       }
                }
 
                if (j >= HWRM_VALID_BIT_DELAY_USEC) {
                        hwrm_err(bp, ctx, "Error (timeout: %u) msg {0x%x 0x%x} len:%d v:%d\n",
-                                hwrm_total_timeout(i), req_type,
+                                hwrm_total_timeout(i) + j, req_type,
                                 le16_to_cpu(ctx->req->seq_id), len, *valid);
                        goto exit;
                }
index d52bd2d..c98032e 100644 (file)
@@ -90,7 +90,7 @@ static inline unsigned int hwrm_total_timeout(unsigned int n)
 }
 
 
-#define HWRM_VALID_BIT_DELAY_USEC      150
+#define HWRM_VALID_BIT_DELAY_USEC      50000
 
 static inline bool bnxt_cfa_hwrm_message(u16 req_type)
 {
index f38f40e..a1a3845 100644 (file)
@@ -2183,9 +2183,7 @@ static int sbmac_init(struct platform_device *pldev, long long base)
                ea_reg >>= 8;
        }
 
-       for (i = 0; i < 6; i++) {
-               dev->dev_addr[i] = eaddr[i];
-       }
+       eth_hw_addr_set(dev, eaddr);
 
        /*
         * Initialize context (get pointers to registers and stuff), then
index a363da9..98498a7 100644 (file)
@@ -4712,7 +4712,7 @@ static int macb_probe(struct platform_device *pdev)
 
 #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
        if (GEM_BFEXT(DAW64, gem_readl(bp, DCFG6))) {
-               dma_set_mask(&pdev->dev, DMA_BIT_MASK(44));
+               dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44));
                bp->hw_dma_cap |= HW_DMA_CAP_64B;
        }
 #endif
index 691605c..d5356db 100644 (file)
@@ -989,117 +989,6 @@ static int ftgmac100_alloc_rx_buffers(struct ftgmac100 *priv)
        return 0;
 }
 
-static void ftgmac100_adjust_link(struct net_device *netdev)
-{
-       struct ftgmac100 *priv = netdev_priv(netdev);
-       struct phy_device *phydev = netdev->phydev;
-       bool tx_pause, rx_pause;
-       int new_speed;
-
-       /* We store "no link" as speed 0 */
-       if (!phydev->link)
-               new_speed = 0;
-       else
-               new_speed = phydev->speed;
-
-       /* Grab pause settings from PHY if configured to do so */
-       if (priv->aneg_pause) {
-               rx_pause = tx_pause = phydev->pause;
-               if (phydev->asym_pause)
-                       tx_pause = !rx_pause;
-       } else {
-               rx_pause = priv->rx_pause;
-               tx_pause = priv->tx_pause;
-       }
-
-       /* Link hasn't changed, do nothing */
-       if (phydev->speed == priv->cur_speed &&
-           phydev->duplex == priv->cur_duplex &&
-           rx_pause == priv->rx_pause &&
-           tx_pause == priv->tx_pause)
-               return;
-
-       /* Print status if we have a link or we had one and just lost it,
-        * don't print otherwise.
-        */
-       if (new_speed || priv->cur_speed)
-               phy_print_status(phydev);
-
-       priv->cur_speed = new_speed;
-       priv->cur_duplex = phydev->duplex;
-       priv->rx_pause = rx_pause;
-       priv->tx_pause = tx_pause;
-
-       /* Link is down, do nothing else */
-       if (!new_speed)
-               return;
-
-       /* Disable all interrupts */
-       iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
-
-       /* Reset the adapter asynchronously */
-       schedule_work(&priv->reset_task);
-}
-
-static int ftgmac100_mii_probe(struct net_device *netdev)
-{
-       struct ftgmac100 *priv = netdev_priv(netdev);
-       struct platform_device *pdev = to_platform_device(priv->dev);
-       struct device_node *np = pdev->dev.of_node;
-       struct phy_device *phydev;
-       phy_interface_t phy_intf;
-       int err;
-
-       /* Default to RGMII. It's a gigabit part after all */
-       err = of_get_phy_mode(np, &phy_intf);
-       if (err)
-               phy_intf = PHY_INTERFACE_MODE_RGMII;
-
-       /* Aspeed only supports these. I don't know about other IP
-        * block vendors so I'm going to just let them through for
-        * now. Note that this is only a warning if for some obscure
-        * reason the DT really means to lie about it or it's a newer
-        * part we don't know about.
-        *
-        * On the Aspeed SoC there are additionally straps and SCU
-        * control bits that could tell us what the interface is
-        * (or allow us to configure it while the IP block is held
-        * in reset). For now I chose to keep this driver away from
-        * those SoC specific bits and assume the device-tree is
-        * right and the SCU has been configured properly by pinmux
-        * or the firmware.
-        */
-       if (priv->is_aspeed && !(phy_interface_mode_is_rgmii(phy_intf))) {
-               netdev_warn(netdev,
-                           "Unsupported PHY mode %s !\n",
-                           phy_modes(phy_intf));
-       }
-
-       phydev = phy_find_first(priv->mii_bus);
-       if (!phydev) {
-               netdev_info(netdev, "%s: no PHY found\n", netdev->name);
-               return -ENODEV;
-       }
-
-       phydev = phy_connect(netdev, phydev_name(phydev),
-                            &ftgmac100_adjust_link, phy_intf);
-
-       if (IS_ERR(phydev)) {
-               netdev_err(netdev, "%s: Could not attach to PHY\n", netdev->name);
-               return PTR_ERR(phydev);
-       }
-
-       /* Indicate that we support PAUSE frames (see comment in
-        * Documentation/networking/phy.rst)
-        */
-       phy_support_asym_pause(phydev);
-
-       /* Display what we found */
-       phy_attached_info(phydev);
-
-       return 0;
-}
-
 static int ftgmac100_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
 {
        struct net_device *netdev = bus->priv;
@@ -1410,10 +1299,8 @@ static int ftgmac100_init_all(struct ftgmac100 *priv, bool ignore_alloc_err)
        return err;
 }
 
-static void ftgmac100_reset_task(struct work_struct *work)
+static void ftgmac100_reset(struct ftgmac100 *priv)
 {
-       struct ftgmac100 *priv = container_of(work, struct ftgmac100,
-                                             reset_task);
        struct net_device *netdev = priv->netdev;
        int err;
 
@@ -1459,6 +1346,134 @@ static void ftgmac100_reset_task(struct work_struct *work)
        rtnl_unlock();
 }
 
+static void ftgmac100_reset_task(struct work_struct *work)
+{
+       struct ftgmac100 *priv = container_of(work, struct ftgmac100,
+                                             reset_task);
+
+       ftgmac100_reset(priv);
+}
+
+static void ftgmac100_adjust_link(struct net_device *netdev)
+{
+       struct ftgmac100 *priv = netdev_priv(netdev);
+       struct phy_device *phydev = netdev->phydev;
+       bool tx_pause, rx_pause;
+       int new_speed;
+
+       /* We store "no link" as speed 0 */
+       if (!phydev->link)
+               new_speed = 0;
+       else
+               new_speed = phydev->speed;
+
+       /* Grab pause settings from PHY if configured to do so */
+       if (priv->aneg_pause) {
+               rx_pause = tx_pause = phydev->pause;
+               if (phydev->asym_pause)
+                       tx_pause = !rx_pause;
+       } else {
+               rx_pause = priv->rx_pause;
+               tx_pause = priv->tx_pause;
+       }
+
+       /* Link hasn't changed, do nothing */
+       if (phydev->speed == priv->cur_speed &&
+           phydev->duplex == priv->cur_duplex &&
+           rx_pause == priv->rx_pause &&
+           tx_pause == priv->tx_pause)
+               return;
+
+       /* Print status if we have a link or we had one and just lost it,
+        * don't print otherwise.
+        */
+       if (new_speed || priv->cur_speed)
+               phy_print_status(phydev);
+
+       priv->cur_speed = new_speed;
+       priv->cur_duplex = phydev->duplex;
+       priv->rx_pause = rx_pause;
+       priv->tx_pause = tx_pause;
+
+       /* Link is down, do nothing else */
+       if (!new_speed)
+               return;
+
+       /* Disable all interrupts */
+       iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
+
+       /* Release phy lock to allow ftgmac100_reset to aquire it, keeping lock
+        * order consistent to prevent dead lock.
+        */
+       if (netdev->phydev)
+               mutex_unlock(&netdev->phydev->lock);
+
+       ftgmac100_reset(priv);
+
+       if (netdev->phydev)
+               mutex_lock(&netdev->phydev->lock);
+
+}
+
+static int ftgmac100_mii_probe(struct net_device *netdev)
+{
+       struct ftgmac100 *priv = netdev_priv(netdev);
+       struct platform_device *pdev = to_platform_device(priv->dev);
+       struct device_node *np = pdev->dev.of_node;
+       struct phy_device *phydev;
+       phy_interface_t phy_intf;
+       int err;
+
+       /* Default to RGMII. It's a gigabit part after all */
+       err = of_get_phy_mode(np, &phy_intf);
+       if (err)
+               phy_intf = PHY_INTERFACE_MODE_RGMII;
+
+       /* Aspeed only supports these. I don't know about other IP
+        * block vendors so I'm going to just let them through for
+        * now. Note that this is only a warning if for some obscure
+        * reason the DT really means to lie about it or it's a newer
+        * part we don't know about.
+        *
+        * On the Aspeed SoC there are additionally straps and SCU
+        * control bits that could tell us what the interface is
+        * (or allow us to configure it while the IP block is held
+        * in reset). For now I chose to keep this driver away from
+        * those SoC specific bits and assume the device-tree is
+        * right and the SCU has been configured properly by pinmux
+        * or the firmware.
+        */
+       if (priv->is_aspeed && !(phy_interface_mode_is_rgmii(phy_intf))) {
+               netdev_warn(netdev,
+                           "Unsupported PHY mode %s !\n",
+                           phy_modes(phy_intf));
+       }
+
+       phydev = phy_find_first(priv->mii_bus);
+       if (!phydev) {
+               netdev_info(netdev, "%s: no PHY found\n", netdev->name);
+               return -ENODEV;
+       }
+
+       phydev = phy_connect(netdev, phydev_name(phydev),
+                            &ftgmac100_adjust_link, phy_intf);
+
+       if (IS_ERR(phydev)) {
+               netdev_err(netdev, "%s: Could not attach to PHY\n", netdev->name);
+               return PTR_ERR(phydev);
+       }
+
+       /* Indicate that we support PAUSE frames (see comment in
+        * Documentation/networking/phy.rst)
+        */
+       phy_support_asym_pause(phydev);
+
+       /* Display what we found */
+       phy_attached_info(phydev);
+
+       return 0;
+}
+
 static int ftgmac100_open(struct net_device *netdev)
 {
        struct ftgmac100 *priv = netdev_priv(netdev);
index e985ae0..0f90d2d 100644 (file)
@@ -4338,7 +4338,7 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
        }
 
        INIT_WORK(&priv->tx_onestep_tstamp, dpaa2_eth_tx_onestep_tstamp);
-
+       mutex_init(&priv->onestep_tstamp_lock);
        skb_queue_head_init(&priv->tx_skbs);
 
        priv->rx_copybreak = DPAA2_ETH_DEFAULT_COPYBREAK;
@@ -4523,12 +4523,12 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev)
 #ifdef CONFIG_DEBUG_FS
        dpaa2_dbg_remove(priv);
 #endif
+
+       unregister_netdev(net_dev);
        rtnl_lock();
        dpaa2_eth_disconnect_mac(priv);
        rtnl_unlock();
 
-       unregister_netdev(net_dev);
-
        dpaa2_eth_dl_port_del(priv);
        dpaa2_eth_dl_traps_unregister(priv);
        dpaa2_eth_dl_free(priv);
index d6eefbb..cacd454 100644 (file)
@@ -532,6 +532,7 @@ static int dpaa2_switch_flower_parse_mirror_key(struct flow_cls_offload *cls,
        struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
        struct flow_dissector *dissector = rule->match.dissector;
        struct netlink_ext_ack *extack = cls->common.extack;
+       int ret = -EOPNOTSUPP;
 
        if (dissector->used_keys &
            ~(BIT(FLOW_DISSECTOR_KEY_BASIC) |
@@ -561,9 +562,10 @@ static int dpaa2_switch_flower_parse_mirror_key(struct flow_cls_offload *cls,
                }
 
                *vlan = (u16)match.key->vlan_id;
+               ret = 0;
        }
 
-       return 0;
+       return ret;
 }
 
 static int
index bbbde9f..be0bd4b 100644 (file)
@@ -99,13 +99,13 @@ static void mpc52xx_fec_tx_timeout(struct net_device *dev, unsigned int txqueue)
        netif_wake_queue(dev);
 }
 
-static void mpc52xx_fec_set_paddr(struct net_device *dev, u8 *mac)
+static void mpc52xx_fec_set_paddr(struct net_device *dev, const u8 *mac)
 {
        struct mpc52xx_fec_priv *priv = netdev_priv(dev);
        struct mpc52xx_fec __iomem *fec = priv->fec;
 
-       out_be32(&fec->paddr1, *(u32 *)(&mac[0]));
-       out_be32(&fec->paddr2, (*(u16 *)(&mac[4]) << 16) | FEC_PADDR2_TYPE);
+       out_be32(&fec->paddr1, *(const u32 *)(&mac[0]));
+       out_be32(&fec->paddr2, (*(const u16 *)(&mac[4]) << 16) | FEC_PADDR2_TYPE);
 }
 
 static int mpc52xx_fec_set_mac_address(struct net_device *dev, void *addr)
@@ -893,13 +893,15 @@ static int mpc52xx_fec_probe(struct platform_device *op)
        rv = of_get_ethdev_address(np, ndev);
        if (rv) {
                struct mpc52xx_fec __iomem *fec = priv->fec;
+               u8 addr[ETH_ALEN] __aligned(4);
 
                /*
                 * If the MAC addresse is not provided via DT then read
                 * it back from the controller regs
                 */
-               *(u32 *)(&ndev->dev_addr[0]) = in_be32(&fec->paddr1);
-               *(u16 *)(&ndev->dev_addr[4]) = in_be32(&fec->paddr2) >> 16;
+               *(u32 *)(&addr[0]) = in_be32(&fec->paddr1);
+               *(u16 *)(&addr[4]) = in_be32(&fec->paddr2) >> 16;
+               eth_hw_addr_set(ndev, addr);
        }
 
        /*
index 5f5d4f7..1607354 100644 (file)
@@ -843,7 +843,7 @@ static inline bool gve_is_gqi(struct gve_priv *priv)
 /* buffers */
 int gve_alloc_page(struct gve_priv *priv, struct device *dev,
                   struct page **page, dma_addr_t *dma,
-                  enum dma_data_direction);
+                  enum dma_data_direction, gfp_t gfp_flags);
 void gve_free_page(struct device *dev, struct page *page, dma_addr_t dma,
                   enum dma_data_direction);
 /* tx handling */
index 2ad7f57..f7621ab 100644 (file)
@@ -301,7 +301,7 @@ static int gve_adminq_parse_err(struct gve_priv *priv, u32 status)
  */
 static int gve_adminq_kick_and_wait(struct gve_priv *priv)
 {
-       u32 tail, head;
+       int tail, head;
        int i;
 
        tail = ioread32be(&priv->reg_bar0->adminq_event_counter);
index f7f65c4..54e51c8 100644 (file)
@@ -766,9 +766,9 @@ static void gve_free_rings(struct gve_priv *priv)
 
 int gve_alloc_page(struct gve_priv *priv, struct device *dev,
                   struct page **page, dma_addr_t *dma,
-                  enum dma_data_direction dir)
+                  enum dma_data_direction dir, gfp_t gfp_flags)
 {
-       *page = alloc_page(GFP_KERNEL);
+       *page = alloc_page(gfp_flags);
        if (!*page) {
                priv->page_alloc_fail++;
                return -ENOMEM;
@@ -811,7 +811,7 @@ static int gve_alloc_queue_page_list(struct gve_priv *priv, u32 id,
        for (i = 0; i < pages; i++) {
                err = gve_alloc_page(priv, &priv->pdev->dev, &qpl->pages[i],
                                     &qpl->page_buses[i],
-                                    gve_qpl_dma_dir(priv, id));
+                                    gve_qpl_dma_dir(priv, id), GFP_KERNEL);
                /* caller handles clean up */
                if (err)
                        return -ENOMEM;
index 9ddcc49..e4e98aa 100644 (file)
@@ -86,7 +86,8 @@ static int gve_rx_alloc_buffer(struct gve_priv *priv, struct device *dev,
        dma_addr_t dma;
        int err;
 
-       err = gve_alloc_page(priv, dev, &page, &dma, DMA_FROM_DEVICE);
+       err = gve_alloc_page(priv, dev, &page, &dma, DMA_FROM_DEVICE,
+                            GFP_ATOMIC);
        if (err)
                return err;
 
@@ -608,6 +609,7 @@ static bool gve_rx(struct gve_rx_ring *rx, netdev_features_t feat,
 
        *packet_size_bytes = skb->len + (skb->protocol ? ETH_HLEN : 0);
        *work_done = work_cnt;
+       skb_record_rx_queue(skb, rx->q_num);
        if (skb_is_nonlinear(skb))
                napi_gro_frags(napi);
        else
index beb8bb0..8c93962 100644 (file)
@@ -157,7 +157,7 @@ static int gve_alloc_page_dqo(struct gve_priv *priv,
        int err;
 
        err = gve_alloc_page(priv, &priv->pdev->dev, &buf_state->page_info.page,
-                            &buf_state->addr, DMA_FROM_DEVICE);
+                            &buf_state->addr, DMA_FROM_DEVICE, GFP_KERNEL);
        if (err)
                return err;
 
index 7df8761..21442a9 100644 (file)
@@ -2043,8 +2043,7 @@ static irqreturn_t hclgevf_misc_irq_handle(int irq, void *data)
                break;
        }
 
-       if (event_cause != HCLGEVF_VECTOR0_EVENT_OTHER)
-               hclgevf_enable_vector(&hdev->misc_vector, true);
+       hclgevf_enable_vector(&hdev->misc_vector, true);
 
        return IRQ_HANDLED;
 }
index c612ef5..3e7d7c4 100644 (file)
@@ -986,6 +986,7 @@ static int
 ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
        struct net_device *dev;
+       u8 addr[ETH_ALEN];
        int i, ret = 0;
 
        ether1_banner();
@@ -1015,7 +1016,8 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
        }
 
        for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = readb(IDPROM_ADDRESS + (i << 2));
+               addr[i] = readb(IDPROM_ADDRESS + (i << 2));
+       eth_hw_addr_set(dev, addr);
 
        if (ether1_init_2(dev)) {
                ret = -ENODEV;
index 59536bd..dee05a3 100644 (file)
@@ -110,6 +110,7 @@ static void ibmvnic_tx_scrq_clean_buffer(struct ibmvnic_adapter *adapter,
                                         struct ibmvnic_sub_crq_queue *tx_scrq);
 static void free_long_term_buff(struct ibmvnic_adapter *adapter,
                                struct ibmvnic_long_term_buff *ltb);
+static void ibmvnic_disable_irqs(struct ibmvnic_adapter *adapter);
 
 struct ibmvnic_stat {
        char name[ETH_GSTRING_LEN];
@@ -1424,7 +1425,7 @@ static int __ibmvnic_open(struct net_device *netdev)
        rc = set_link_state(adapter, IBMVNIC_LOGICAL_LNK_UP);
        if (rc) {
                ibmvnic_napi_disable(adapter);
-               release_resources(adapter);
+               ibmvnic_disable_irqs(adapter);
                return rc;
        }
 
@@ -1474,9 +1475,6 @@ static int ibmvnic_open(struct net_device *netdev)
                rc = init_resources(adapter);
                if (rc) {
                        netdev_err(netdev, "failed to initialize resources\n");
-                       release_resources(adapter);
-                       release_rx_pools(adapter);
-                       release_tx_pools(adapter);
                        goto out;
                }
        }
@@ -1493,6 +1491,13 @@ out:
                adapter->state = VNIC_OPEN;
                rc = 0;
        }
+
+       if (rc) {
+               release_resources(adapter);
+               release_rx_pools(adapter);
+               release_tx_pools(adapter);
+       }
+
        return rc;
 }
 
@@ -2602,6 +2607,7 @@ static void __ibmvnic_reset(struct work_struct *work)
        struct ibmvnic_rwi *rwi;
        unsigned long flags;
        u32 reset_state;
+       int num_fails = 0;
        int rc = 0;
 
        adapter = container_of(work, struct ibmvnic_adapter, ibmvnic_reset);
@@ -2655,11 +2661,23 @@ static void __ibmvnic_reset(struct work_struct *work)
                                rc = do_hard_reset(adapter, rwi, reset_state);
                                rtnl_unlock();
                        }
-                       if (rc) {
-                               /* give backing device time to settle down */
+                       if (rc)
+                               num_fails++;
+                       else
+                               num_fails = 0;
+
+                       /* If auto-priority-failover is enabled we can get
+                        * back to back failovers during resets, resulting
+                        * in at least two failed resets (from high-priority
+                        * backing device to low-priority one and then back)
+                        * If resets continue to fail beyond that, give the
+                        * adapter some time to settle down before retrying.
+                        */
+                       if (num_fails >= 3) {
                                netdev_dbg(adapter->netdev,
-                                          "[S:%s] Hard reset failed, waiting 60 secs\n",
-                                          adapter_state_to_string(adapter->state));
+                                          "[S:%s] Hard reset failed %d times, waiting 60 secs\n",
+                                          adapter_state_to_string(adapter->state),
+                                          num_fails);
                                set_current_state(TASK_UNINTERRUPTIBLE);
                                schedule_timeout(60 * HZ);
                        }
@@ -3844,11 +3862,25 @@ static void send_request_cap(struct ibmvnic_adapter *adapter, int retry)
        struct device *dev = &adapter->vdev->dev;
        union ibmvnic_crq crq;
        int max_entries;
+       int cap_reqs;
+
+       /* We send out 6 or 7 REQUEST_CAPABILITY CRQs below (depending on
+        * the PROMISC flag). Initialize this count upfront. When the tasklet
+        * receives a response to all of these, it will send the next protocol
+        * message (QUERY_IP_OFFLOAD).
+        */
+       if (!(adapter->netdev->flags & IFF_PROMISC) ||
+           adapter->promisc_supported)
+               cap_reqs = 7;
+       else
+               cap_reqs = 6;
 
        if (!retry) {
                /* Sub-CRQ entries are 32 byte long */
                int entries_page = 4 * PAGE_SIZE / (sizeof(u64) * 4);
 
+               atomic_set(&adapter->running_cap_crqs, cap_reqs);
+
                if (adapter->min_tx_entries_per_subcrq > entries_page ||
                    adapter->min_rx_add_entries_per_subcrq > entries_page) {
                        dev_err(dev, "Fatal, invalid entries per sub-crq\n");
@@ -3909,44 +3941,45 @@ static void send_request_cap(struct ibmvnic_adapter *adapter, int retry)
                                        adapter->opt_rx_comp_queues;
 
                adapter->req_rx_add_queues = adapter->max_rx_add_queues;
+       } else {
+               atomic_add(cap_reqs, &adapter->running_cap_crqs);
        }
-
        memset(&crq, 0, sizeof(crq));
        crq.request_capability.first = IBMVNIC_CRQ_CMD;
        crq.request_capability.cmd = REQUEST_CAPABILITY;
 
        crq.request_capability.capability = cpu_to_be16(REQ_TX_QUEUES);
        crq.request_capability.number = cpu_to_be64(adapter->req_tx_queues);
-       atomic_inc(&adapter->running_cap_crqs);
+       cap_reqs--;
        ibmvnic_send_crq(adapter, &crq);
 
        crq.request_capability.capability = cpu_to_be16(REQ_RX_QUEUES);
        crq.request_capability.number = cpu_to_be64(adapter->req_rx_queues);
-       atomic_inc(&adapter->running_cap_crqs);
+       cap_reqs--;
        ibmvnic_send_crq(adapter, &crq);
 
        crq.request_capability.capability = cpu_to_be16(REQ_RX_ADD_QUEUES);
        crq.request_capability.number = cpu_to_be64(adapter->req_rx_add_queues);
-       atomic_inc(&adapter->running_cap_crqs);
+       cap_reqs--;
        ibmvnic_send_crq(adapter, &crq);
 
        crq.request_capability.capability =
            cpu_to_be16(REQ_TX_ENTRIES_PER_SUBCRQ);
        crq.request_capability.number =
            cpu_to_be64(adapter->req_tx_entries_per_subcrq);
-       atomic_inc(&adapter->running_cap_crqs);
+       cap_reqs--;
        ibmvnic_send_crq(adapter, &crq);
 
        crq.request_capability.capability =
            cpu_to_be16(REQ_RX_ADD_ENTRIES_PER_SUBCRQ);
        crq.request_capability.number =
            cpu_to_be64(adapter->req_rx_add_entries_per_subcrq);
-       atomic_inc(&adapter->running_cap_crqs);
+       cap_reqs--;
        ibmvnic_send_crq(adapter, &crq);
 
        crq.request_capability.capability = cpu_to_be16(REQ_MTU);
        crq.request_capability.number = cpu_to_be64(adapter->req_mtu);
-       atomic_inc(&adapter->running_cap_crqs);
+       cap_reqs--;
        ibmvnic_send_crq(adapter, &crq);
 
        if (adapter->netdev->flags & IFF_PROMISC) {
@@ -3954,16 +3987,21 @@ static void send_request_cap(struct ibmvnic_adapter *adapter, int retry)
                        crq.request_capability.capability =
                            cpu_to_be16(PROMISC_REQUESTED);
                        crq.request_capability.number = cpu_to_be64(1);
-                       atomic_inc(&adapter->running_cap_crqs);
+                       cap_reqs--;
                        ibmvnic_send_crq(adapter, &crq);
                }
        } else {
                crq.request_capability.capability =
                    cpu_to_be16(PROMISC_REQUESTED);
                crq.request_capability.number = cpu_to_be64(0);
-               atomic_inc(&adapter->running_cap_crqs);
+               cap_reqs--;
                ibmvnic_send_crq(adapter, &crq);
        }
+
+       /* Keep at end to catch any discrepancy between expected and actual
+        * CRQs sent.
+        */
+       WARN_ON(cap_reqs != 0);
 }
 
 static int pending_scrq(struct ibmvnic_adapter *adapter,
@@ -4357,118 +4395,132 @@ static void send_query_map(struct ibmvnic_adapter *adapter)
 static void send_query_cap(struct ibmvnic_adapter *adapter)
 {
        union ibmvnic_crq crq;
+       int cap_reqs;
+
+       /* We send out 25 QUERY_CAPABILITY CRQs below.  Initialize this count
+        * upfront. When the tasklet receives a response to all of these, it
+        * can send out the next protocol messaage (REQUEST_CAPABILITY).
+        */
+       cap_reqs = 25;
+
+       atomic_set(&adapter->running_cap_crqs, cap_reqs);
 
-       atomic_set(&adapter->running_cap_crqs, 0);
        memset(&crq, 0, sizeof(crq));
        crq.query_capability.first = IBMVNIC_CRQ_CMD;
        crq.query_capability.cmd = QUERY_CAPABILITY;
 
        crq.query_capability.capability = cpu_to_be16(MIN_TX_QUEUES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MIN_RX_QUEUES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MIN_RX_ADD_QUEUES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MAX_TX_QUEUES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MAX_RX_QUEUES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MAX_RX_ADD_QUEUES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability =
            cpu_to_be16(MIN_TX_ENTRIES_PER_SUBCRQ);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability =
            cpu_to_be16(MIN_RX_ADD_ENTRIES_PER_SUBCRQ);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability =
            cpu_to_be16(MAX_TX_ENTRIES_PER_SUBCRQ);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability =
            cpu_to_be16(MAX_RX_ADD_ENTRIES_PER_SUBCRQ);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(TCP_IP_OFFLOAD);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(PROMISC_SUPPORTED);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MIN_MTU);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MAX_MTU);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MAX_MULTICAST_FILTERS);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(VLAN_HEADER_INSERTION);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(RX_VLAN_HEADER_INSERTION);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(MAX_TX_SG_ENTRIES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(RX_SG_SUPPORTED);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(OPT_TX_COMP_SUB_QUEUES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(OPT_RX_COMP_QUEUES);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability =
                        cpu_to_be16(OPT_RX_BUFADD_Q_PER_RX_COMP_Q);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability =
                        cpu_to_be16(OPT_TX_ENTRIES_PER_SUBCRQ);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability =
                        cpu_to_be16(OPT_RXBA_ENTRIES_PER_SUBCRQ);
-       atomic_inc(&adapter->running_cap_crqs);
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
 
        crq.query_capability.capability = cpu_to_be16(TX_RX_DESC_REQ);
-       atomic_inc(&adapter->running_cap_crqs);
+
        ibmvnic_send_crq(adapter, &crq);
+       cap_reqs--;
+
+       /* Keep at end to catch any discrepancy between expected and actual
+        * CRQs sent.
+        */
+       WARN_ON(cap_reqs != 0);
 }
 
 static void send_query_ip_offload(struct ibmvnic_adapter *adapter)
@@ -4772,6 +4824,8 @@ static void handle_request_cap_rsp(union ibmvnic_crq *crq,
        char *name;
 
        atomic_dec(&adapter->running_cap_crqs);
+       netdev_dbg(adapter->netdev, "Outstanding request-caps: %d\n",
+                  atomic_read(&adapter->running_cap_crqs));
        switch (be16_to_cpu(crq->request_capability_rsp.capability)) {
        case REQ_TX_QUEUES:
                req_value = &adapter->req_tx_queues;
@@ -4835,10 +4889,8 @@ static void handle_request_cap_rsp(union ibmvnic_crq *crq,
        }
 
        /* Done receiving requested capabilities, query IP offload support */
-       if (atomic_read(&adapter->running_cap_crqs) == 0) {
-               adapter->wait_capability = false;
+       if (atomic_read(&adapter->running_cap_crqs) == 0)
                send_query_ip_offload(adapter);
-       }
 }
 
 static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq,
@@ -5136,10 +5188,8 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq,
        }
 
 out:
-       if (atomic_read(&adapter->running_cap_crqs) == 0) {
-               adapter->wait_capability = false;
+       if (atomic_read(&adapter->running_cap_crqs) == 0)
                send_request_cap(adapter, 0);
-       }
 }
 
 static int send_query_phys_parms(struct ibmvnic_adapter *adapter)
@@ -5435,33 +5485,21 @@ static void ibmvnic_tasklet(struct tasklet_struct *t)
        struct ibmvnic_crq_queue *queue = &adapter->crq;
        union ibmvnic_crq *crq;
        unsigned long flags;
-       bool done = false;
 
        spin_lock_irqsave(&queue->lock, flags);
-       while (!done) {
-               /* Pull all the valid messages off the CRQ */
-               while ((crq = ibmvnic_next_crq(adapter)) != NULL) {
-                       /* This barrier makes sure ibmvnic_next_crq()'s
-                        * crq->generic.first & IBMVNIC_CRQ_CMD_RSP is loaded
-                        * before ibmvnic_handle_crq()'s
-                        * switch(gen_crq->first) and switch(gen_crq->cmd).
-                        */
-                       dma_rmb();
-                       ibmvnic_handle_crq(crq, adapter);
-                       crq->generic.first = 0;
-               }
 
-               /* remain in tasklet until all
-                * capabilities responses are received
+       /* Pull all the valid messages off the CRQ */
+       while ((crq = ibmvnic_next_crq(adapter)) != NULL) {
+               /* This barrier makes sure ibmvnic_next_crq()'s
+                * crq->generic.first & IBMVNIC_CRQ_CMD_RSP is loaded
+                * before ibmvnic_handle_crq()'s
+                * switch(gen_crq->first) and switch(gen_crq->cmd).
                 */
-               if (!adapter->wait_capability)
-                       done = true;
+               dma_rmb();
+               ibmvnic_handle_crq(crq, adapter);
+               crq->generic.first = 0;
        }
-       /* if capabilities CRQ's were sent in this tasklet, the following
-        * tasklet must wait until all responses are received
-        */
-       if (atomic_read(&adapter->running_cap_crqs) != 0)
-               adapter->wait_capability = true;
+
        spin_unlock_irqrestore(&queue->lock, flags);
 }
 
@@ -5879,10 +5917,14 @@ static ssize_t failover_store(struct device *dev, struct device_attribute *attr,
                   be64_to_cpu(session_token));
        rc = plpar_hcall_norets(H_VIOCTL, adapter->vdev->unit_address,
                                H_SESSION_ERR_DETECTED, session_token, 0, 0);
-       if (rc)
+       if (rc) {
                netdev_err(netdev,
                           "H_VIOCTL initiated failover failed, rc %ld\n",
                           rc);
+               goto last_resort;
+       }
+
+       return count;
 
 last_resort:
        netdev_dbg(netdev, "Trying to send CRQ_CMD, the last resort\n");
index 4a8f36e..4a7a56f 100644 (file)
@@ -919,7 +919,6 @@ struct ibmvnic_adapter {
        int login_rsp_buf_sz;
 
        atomic_t running_cap_crqs;
-       bool wait_capability;
 
        struct ibmvnic_sub_crq_queue **tx_scrq ____cacheline_aligned;
        struct ibmvnic_sub_crq_queue **rx_scrq ____cacheline_aligned;
index c3def0e..8d06c9d 100644 (file)
@@ -115,7 +115,8 @@ enum e1000_boards {
        board_pch_lpt,
        board_pch_spt,
        board_pch_cnp,
-       board_pch_tgp
+       board_pch_tgp,
+       board_pch_adp
 };
 
 struct e1000_ps_page {
@@ -502,6 +503,7 @@ extern const struct e1000_info e1000_pch_lpt_info;
 extern const struct e1000_info e1000_pch_spt_info;
 extern const struct e1000_info e1000_pch_cnp_info;
 extern const struct e1000_info e1000_pch_tgp_info;
+extern const struct e1000_info e1000_pch_adp_info;
 extern const struct e1000_info e1000_es2_info;
 
 void e1000e_ptp_init(struct e1000_adapter *adapter);
index 5e4fc9b..c908c84 100644 (file)
@@ -6021,3 +6021,23 @@ const struct e1000_info e1000_pch_tgp_info = {
        .phy_ops                = &ich8_phy_ops,
        .nvm_ops                = &spt_nvm_ops,
 };
+
+const struct e1000_info e1000_pch_adp_info = {
+       .mac                    = e1000_pch_adp,
+       .flags                  = FLAG_IS_ICH
+                                 | FLAG_HAS_WOL
+                                 | FLAG_HAS_HW_TIMESTAMP
+                                 | FLAG_HAS_CTRLEXT_ON_LOAD
+                                 | FLAG_HAS_AMT
+                                 | FLAG_HAS_FLASH
+                                 | FLAG_HAS_JUMBO_FRAMES
+                                 | FLAG_APME_IN_WUC,
+       .flags2                 = FLAG2_HAS_PHY_STATS
+                                 | FLAG2_HAS_EEE,
+       .pba                    = 26,
+       .max_hw_frame_size      = 9022,
+       .get_variants           = e1000_get_variants_ich8lan,
+       .mac_ops                = &ich8_mac_ops,
+       .phy_ops                = &ich8_phy_ops,
+       .nvm_ops                = &spt_nvm_ops,
+};
index 635a959..a42aeb5 100644 (file)
@@ -52,6 +52,7 @@ static const struct e1000_info *e1000_info_tbl[] = {
        [board_pch_spt]         = &e1000_pch_spt_info,
        [board_pch_cnp]         = &e1000_pch_cnp_info,
        [board_pch_tgp]         = &e1000_pch_tgp_info,
+       [board_pch_adp]         = &e1000_pch_adp_info,
 };
 
 struct e1000_reg_info {
@@ -6341,7 +6342,8 @@ static void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter)
        u32 mac_data;
        u16 phy_data;
 
-       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) {
+       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID &&
+           hw->mac.type >= e1000_pch_adp) {
                /* Request ME configure the device for S0ix */
                mac_data = er32(H2ME);
                mac_data |= E1000_H2ME_START_DPG;
@@ -6490,7 +6492,8 @@ static void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter)
        u16 phy_data;
        u32 i = 0;
 
-       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) {
+       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID &&
+           hw->mac.type >= e1000_pch_adp) {
                /* Request ME unconfigure the device from S0ix */
                mac_data = er32(H2ME);
                mac_data &= ~E1000_H2ME_START_DPG;
@@ -7898,22 +7901,22 @@ static const struct pci_device_id e1000_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V14), board_pch_tgp },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM15), board_pch_tgp },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V15), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_LM23), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_V23), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM16), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V16), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM17), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V17), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_LM22), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_V22), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_LM18), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_V18), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_LM19), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_V19), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_LM20), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V20), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_LM21), board_pch_tgp },
-       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V21), board_pch_tgp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_LM23), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_V23), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM16), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V16), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_LM17), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ADP_I219_V17), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_LM22), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_RPL_I219_V22), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_LM18), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_V18), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_LM19), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_MTP_I219_V19), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_LM20), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V20), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_LM21), board_pch_adp },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V21), board_pch_adp },
 
        { 0, 0, 0, 0, 0, 0, 0 } /* terminate list */
 };
index 4d939af..80c5cec 100644 (file)
@@ -144,6 +144,7 @@ enum i40e_state_t {
        __I40E_VIRTCHNL_OP_PENDING,
        __I40E_RECOVERY_MODE,
        __I40E_VF_RESETS_DISABLED,      /* disable resets during i40e_remove */
+       __I40E_IN_REMOVE,
        __I40E_VFS_RELEASING,
        /* This must be last as it determines the size of the BITMAP */
        __I40E_STATE_SIZE__,
@@ -174,7 +175,6 @@ enum i40e_interrupt_policy {
 
 struct i40e_lump_tracking {
        u16 num_entries;
-       u16 search_hint;
        u16 list[0];
 #define I40E_PILE_VALID_BIT  0x8000
 #define I40E_IWARP_IRQ_PILE_ID  (I40E_PILE_VALID_BIT - 2)
@@ -848,12 +848,12 @@ struct i40e_vsi {
        struct rtnl_link_stats64 net_stats_offsets;
        struct i40e_eth_stats eth_stats;
        struct i40e_eth_stats eth_stats_offsets;
-       u32 tx_restart;
-       u32 tx_busy;
+       u64 tx_restart;
+       u64 tx_busy;
        u64 tx_linearize;
        u64 tx_force_wb;
-       u32 rx_buf_failed;
-       u32 rx_page_failed;
+       u64 rx_buf_failed;
+       u64 rx_page_failed;
 
        /* These are containers of ring pointers, allocated at run-time */
        struct i40e_ring **rx_rings;
index 2c1b1da..1e57cc8 100644 (file)
@@ -240,7 +240,7 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
                 (unsigned long int)vsi->net_stats_offsets.rx_compressed,
                 (unsigned long int)vsi->net_stats_offsets.tx_compressed);
        dev_info(&pf->pdev->dev,
-                "    tx_restart = %d, tx_busy = %d, rx_buf_failed = %d, rx_page_failed = %d\n",
+                "    tx_restart = %llu, tx_busy = %llu, rx_buf_failed = %llu, rx_page_failed = %llu\n",
                 vsi->tx_restart, vsi->tx_busy,
                 vsi->rx_buf_failed, vsi->rx_page_failed);
        rcu_read_lock();
index 2a3d8ae..31b03fe 100644 (file)
@@ -196,10 +196,6 @@ int i40e_free_virt_mem_d(struct i40e_hw *hw, struct i40e_virt_mem *mem)
  * @id: an owner id to stick on the items assigned
  *
  * Returns the base item index of the lump, or negative for error
- *
- * The search_hint trick and lack of advanced fit-finding only work
- * because we're highly likely to have all the same size lump requests.
- * Linear search time and any fragmentation should be minimal.
  **/
 static int i40e_get_lump(struct i40e_pf *pf, struct i40e_lump_tracking *pile,
                         u16 needed, u16 id)
@@ -214,8 +210,21 @@ static int i40e_get_lump(struct i40e_pf *pf, struct i40e_lump_tracking *pile,
                return -EINVAL;
        }
 
-       /* start the linear search with an imperfect hint */
-       i = pile->search_hint;
+       /* Allocate last queue in the pile for FDIR VSI queue
+        * so it doesn't fragment the qp_pile
+        */
+       if (pile == pf->qp_pile && pf->vsi[id]->type == I40E_VSI_FDIR) {
+               if (pile->list[pile->num_entries - 1] & I40E_PILE_VALID_BIT) {
+                       dev_err(&pf->pdev->dev,
+                               "Cannot allocate queue %d for I40E_VSI_FDIR\n",
+                               pile->num_entries - 1);
+                       return -ENOMEM;
+               }
+               pile->list[pile->num_entries - 1] = id | I40E_PILE_VALID_BIT;
+               return pile->num_entries - 1;
+       }
+
+       i = 0;
        while (i < pile->num_entries) {
                /* skip already allocated entries */
                if (pile->list[i] & I40E_PILE_VALID_BIT) {
@@ -234,7 +243,6 @@ static int i40e_get_lump(struct i40e_pf *pf, struct i40e_lump_tracking *pile,
                        for (j = 0; j < needed; j++)
                                pile->list[i+j] = id | I40E_PILE_VALID_BIT;
                        ret = i;
-                       pile->search_hint = i + j;
                        break;
                }
 
@@ -257,7 +265,7 @@ static int i40e_put_lump(struct i40e_lump_tracking *pile, u16 index, u16 id)
 {
        int valid_id = (id | I40E_PILE_VALID_BIT);
        int count = 0;
-       int i;
+       u16 i;
 
        if (!pile || index >= pile->num_entries)
                return -EINVAL;
@@ -269,8 +277,6 @@ static int i40e_put_lump(struct i40e_lump_tracking *pile, u16 index, u16 id)
                count++;
        }
 
-       if (count && index < pile->search_hint)
-               pile->search_hint = index;
 
        return count;
 }
@@ -772,9 +778,9 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi)
        struct rtnl_link_stats64 *ns;   /* netdev stats */
        struct i40e_eth_stats *oes;
        struct i40e_eth_stats *es;     /* device's eth stats */
-       u32 tx_restart, tx_busy;
+       u64 tx_restart, tx_busy;
        struct i40e_ring *p;
-       u32 rx_page, rx_buf;
+       u64 rx_page, rx_buf;
        u64 bytes, packets;
        unsigned int start;
        u64 tx_linearize;
@@ -10574,15 +10580,9 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
        }
        i40e_get_oem_version(&pf->hw);
 
-       if (test_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state) &&
-           ((hw->aq.fw_maj_ver == 4 && hw->aq.fw_min_ver <= 33) ||
-            hw->aq.fw_maj_ver < 4) && hw->mac.type == I40E_MAC_XL710) {
-               /* The following delay is necessary for 4.33 firmware and older
-                * to recover after EMP reset. 200 ms should suffice but we
-                * put here 300 ms to be sure that FW is ready to operate
-                * after reset.
-                */
-               mdelay(300);
+       if (test_and_clear_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state)) {
+               /* The following delay is necessary for firmware update. */
+               mdelay(1000);
        }
 
        /* re-verify the eeprom if we just had an EMP reset */
@@ -10853,6 +10853,9 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit,
                                   bool lock_acquired)
 {
        int ret;
+
+       if (test_bit(__I40E_IN_REMOVE, pf->state))
+               return;
        /* Now we wait for GRST to settle out.
         * We don't have to delete the VEBs or VSIs from the hw switch
         * because the reset will make them disappear.
@@ -11792,7 +11795,6 @@ static int i40e_init_interrupt_scheme(struct i40e_pf *pf)
                return -ENOMEM;
 
        pf->irq_pile->num_entries = vectors;
-       pf->irq_pile->search_hint = 0;
 
        /* track first vector for misc interrupts, ignore return */
        (void)i40e_get_lump(pf, pf->irq_pile, 1, I40E_PILE_VALID_BIT - 1);
@@ -12213,6 +12215,8 @@ int i40e_reconfig_rss_queues(struct i40e_pf *pf, int queue_count)
 
                vsi->req_queue_pairs = queue_count;
                i40e_prep_for_reset(pf);
+               if (test_bit(__I40E_IN_REMOVE, pf->state))
+                       return pf->alloc_rss_size;
 
                pf->alloc_rss_size = new_rss_size;
 
@@ -12595,7 +12599,6 @@ static int i40e_sw_init(struct i40e_pf *pf)
                goto sw_init_done;
        }
        pf->qp_pile->num_entries = pf->hw.func_caps.num_tx_qp;
-       pf->qp_pile->search_hint = 0;
 
        pf->tx_timeout_recovery_level = 1;
 
@@ -13040,6 +13043,10 @@ static int i40e_xdp_setup(struct i40e_vsi *vsi, struct bpf_prog *prog,
        if (need_reset)
                i40e_prep_for_reset(pf);
 
+       /* VSI shall be deleted in a moment, just return EINVAL */
+       if (test_bit(__I40E_IN_REMOVE, pf->state))
+               return -EINVAL;
+
        old_prog = xchg(&vsi->xdp_prog, prog);
 
        if (need_reset) {
@@ -15930,8 +15937,13 @@ static void i40e_remove(struct pci_dev *pdev)
        i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), 0);
        i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), 0);
 
-       while (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
+       /* Grab __I40E_RESET_RECOVERY_PENDING and set __I40E_IN_REMOVE
+        * flags, once they are set, i40e_rebuild should not be called as
+        * i40e_prep_for_reset always returns early.
+        */
+       while (test_and_set_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
                usleep_range(1000, 2000);
+       set_bit(__I40E_IN_REMOVE, pf->state);
 
        if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
                set_bit(__I40E_VF_RESETS_DISABLED, pf->state);
@@ -16130,6 +16142,9 @@ static void i40e_pci_error_reset_done(struct pci_dev *pdev)
 {
        struct i40e_pf *pf = pci_get_drvdata(pdev);
 
+       if (test_bit(__I40E_IN_REMOVE, pf->state))
+               return;
+
        i40e_reset_and_rebuild(pf, false, false);
 }
 
index 8d0588a..1908eed 100644 (file)
 #define I40E_VFINT_DYN_CTLN(_INTVF) (0x00024800 + ((_INTVF) * 4)) /* _i=0...511 */ /* Reset: VFR */
 #define I40E_VFINT_DYN_CTLN_CLEARPBA_SHIFT 1
 #define I40E_VFINT_DYN_CTLN_CLEARPBA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_CLEARPBA_SHIFT)
+#define I40E_VFINT_ICR0_ADMINQ_SHIFT 30
+#define I40E_VFINT_ICR0_ADMINQ_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ADMINQ_SHIFT)
+#define I40E_VFINT_ICR0_ENA(_VF) (0x0002C000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */
 #define I40E_VPINT_AEQCTL(_VF) (0x0002B800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */
 #define I40E_VPINT_AEQCTL_MSIX_INDX_SHIFT 0
 #define I40E_VPINT_AEQCTL_ITR_INDX_SHIFT 11
index b785d09..dfdb6e7 100644 (file)
@@ -1376,6 +1376,32 @@ static i40e_status i40e_config_vf_promiscuous_mode(struct i40e_vf *vf,
        return aq_ret;
 }
 
+/**
+ * i40e_sync_vfr_reset
+ * @hw: pointer to hw struct
+ * @vf_id: VF identifier
+ *
+ * Before trigger hardware reset, we need to know if no other process has
+ * reserved the hardware for any reset operations. This check is done by
+ * examining the status of the RSTAT1 register used to signal the reset.
+ **/
+static int i40e_sync_vfr_reset(struct i40e_hw *hw, int vf_id)
+{
+       u32 reg;
+       int i;
+
+       for (i = 0; i < I40E_VFR_WAIT_COUNT; i++) {
+               reg = rd32(hw, I40E_VFINT_ICR0_ENA(vf_id)) &
+                          I40E_VFINT_ICR0_ADMINQ_MASK;
+               if (reg)
+                       return 0;
+
+               usleep_range(100, 200);
+       }
+
+       return -EAGAIN;
+}
+
 /**
  * i40e_trigger_vf_reset
  * @vf: pointer to the VF structure
@@ -1390,9 +1416,11 @@ static void i40e_trigger_vf_reset(struct i40e_vf *vf, bool flr)
        struct i40e_pf *pf = vf->pf;
        struct i40e_hw *hw = &pf->hw;
        u32 reg, reg_idx, bit_idx;
+       bool vf_active;
+       u32 radq;
 
        /* warn the VF */
-       clear_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states);
+       vf_active = test_and_clear_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states);
 
        /* Disable VF's configuration API during reset. The flag is re-enabled
         * in i40e_alloc_vf_res(), when it's safe again to access VF's VSI.
@@ -1406,7 +1434,19 @@ static void i40e_trigger_vf_reset(struct i40e_vf *vf, bool flr)
         * just need to clean up, so don't hit the VFRTRIG register.
         */
        if (!flr) {
-               /* reset VF using VPGEN_VFRTRIG reg */
+               /* Sync VFR reset before trigger next one */
+               radq = rd32(hw, I40E_VFINT_ICR0_ENA(vf->vf_id)) &
+                           I40E_VFINT_ICR0_ADMINQ_MASK;
+               if (vf_active && !radq)
+                       /* waiting for finish reset by virtual driver */
+                       if (i40e_sync_vfr_reset(hw, vf->vf_id))
+                               dev_info(&pf->pdev->dev,
+                                        "Reset VF %d never finished\n",
+                               vf->vf_id);
+
+               /* Reset VF using VPGEN_VFRTRIG reg. It is also setting
+                * in progress state in rstat1 register.
+                */
                reg = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id));
                reg |= I40E_VPGEN_VFRTRIG_VFSWR_MASK;
                wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg);
@@ -2617,6 +2657,59 @@ error_param:
                                       aq_ret);
 }
 
+/**
+ * i40e_check_enough_queue - find big enough queue number
+ * @vf: pointer to the VF info
+ * @needed: the number of items needed
+ *
+ * Returns the base item index of the queue, or negative for error
+ **/
+static int i40e_check_enough_queue(struct i40e_vf *vf, u16 needed)
+{
+       unsigned int  i, cur_queues, more, pool_size;
+       struct i40e_lump_tracking *pile;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi;
+
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       cur_queues = vsi->alloc_queue_pairs;
+
+       /* if current allocated queues are enough for need */
+       if (cur_queues >= needed)
+               return vsi->base_queue;
+
+       pile = pf->qp_pile;
+       if (cur_queues > 0) {
+               /* if the allocated queues are not zero
+                * just check if there are enough queues for more
+                * behind the allocated queues.
+                */
+               more = needed - cur_queues;
+               for (i = vsi->base_queue + cur_queues;
+                       i < pile->num_entries; i++) {
+                       if (pile->list[i] & I40E_PILE_VALID_BIT)
+                               break;
+
+                       if (more-- == 1)
+                               /* there is enough */
+                               return vsi->base_queue;
+               }
+       }
+
+       pool_size = 0;
+       for (i = 0; i < pile->num_entries; i++) {
+               if (pile->list[i] & I40E_PILE_VALID_BIT) {
+                       pool_size = 0;
+                       continue;
+               }
+               if (needed <= ++pool_size)
+                       /* there is enough */
+                       return i;
+       }
+
+       return -ENOMEM;
+}
+
 /**
  * i40e_vc_request_queues_msg
  * @vf: pointer to the VF info
@@ -2651,6 +2744,12 @@ static int i40e_vc_request_queues_msg(struct i40e_vf *vf, u8 *msg)
                         req_pairs - cur_pairs,
                         pf->queues_left);
                vfres->num_queue_pairs = pf->queues_left + cur_pairs;
+       } else if (i40e_check_enough_queue(vf, req_pairs) < 0) {
+               dev_warn(&pf->pdev->dev,
+                        "VF %d requested %d more queues, but there is not enough for it.\n",
+                        vf->vf_id,
+                        req_pairs - cur_pairs);
+               vfres->num_queue_pairs = cur_pairs;
        } else {
                /* successful request */
                vf->num_req_queues = req_pairs;
index 49575a6..03c42fd 100644 (file)
@@ -19,6 +19,7 @@
 #define I40E_MAX_VF_PROMISC_FLAGS      3
 
 #define I40E_VF_STATE_WAIT_COUNT       20
+#define I40E_VFR_WAIT_COUNT            100
 
 /* Various queue ctrls */
 enum i40e_queue_ctrl {
index 4e16d18..473b1f6 100644 (file)
@@ -280,7 +280,6 @@ enum ice_pf_state {
        ICE_VFLR_EVENT_PENDING,
        ICE_FLTR_OVERFLOW_PROMISC,
        ICE_VF_DIS,
-       ICE_VF_DEINIT_IN_PROGRESS,
        ICE_CFG_BUSY,
        ICE_SERVICE_SCHED,
        ICE_SERVICE_DIS,
@@ -483,6 +482,7 @@ enum ice_pf_flags {
        ICE_FLAG_VF_TRUE_PROMISC_ENA,
        ICE_FLAG_MDD_AUTO_RESET_VF,
        ICE_FLAG_LINK_LENIENT_MODE_ENA,
+       ICE_FLAG_PLUG_AUX_DEV,
        ICE_PF_FLAGS_NBITS              /* must be last */
 };
 
@@ -887,7 +887,7 @@ static inline void ice_set_rdma_cap(struct ice_pf *pf)
        if (pf->hw.func_caps.common_cap.rdma && pf->num_rdma_msix) {
                set_bit(ICE_FLAG_RDMA_ENA, pf->flags);
                set_bit(ICE_FLAG_AUX_ENA, pf->flags);
-               ice_plug_aux_dev(pf);
+               set_bit(ICE_FLAG_PLUG_AUX_DEV, pf->flags);
        }
 }
 
index 408d15a..e2af99a 100644 (file)
@@ -3340,9 +3340,10 @@ ice_cfg_phy_fec(struct ice_port_info *pi, struct ice_aqc_set_phy_cfg_data *cfg,
 
        if (fec == ICE_FEC_AUTO && ice_fw_supports_link_override(hw) &&
            !ice_fw_supports_report_dflt_cfg(hw)) {
-               struct ice_link_default_override_tlv tlv;
+               struct ice_link_default_override_tlv tlv = { 0 };
 
-               if (ice_get_link_default_override(&tlv, pi))
+               status = ice_get_link_default_override(&tlv, pi);
+               if (status)
                        goto out;
 
                if (!(tlv.options & ICE_LINK_OVERRIDE_STRICT_MODE) &&
index 864692b..73edc24 100644 (file)
@@ -44,6 +44,7 @@ ice_eswitch_add_vf_mac_rule(struct ice_pf *pf, struct ice_vf *vf, const u8 *mac)
                                       ctrl_vsi->rxq_map[vf->vf_id];
        rule_info.flags_info.act |= ICE_SINGLE_ACT_LB_ENABLE;
        rule_info.flags_info.act_valid = true;
+       rule_info.tun_type = ICE_SW_TUN_AND_NON_TUN;
 
        err = ice_add_adv_rule(hw, list, lkups_cnt, &rule_info,
                               vf->repr->mac_rule);
index e375ac8..4f954db 100644 (file)
@@ -204,17 +204,39 @@ ice_lag_unlink(struct ice_lag *lag,
                lag->upper_netdev = NULL;
        }
 
-       if (lag->peer_netdev) {
-               dev_put(lag->peer_netdev);
-               lag->peer_netdev = NULL;
-       }
-
+       lag->peer_netdev = NULL;
        ice_set_sriov_cap(pf);
        ice_set_rdma_cap(pf);
        lag->bonded = false;
        lag->role = ICE_LAG_NONE;
 }
 
+/**
+ * ice_lag_unregister - handle netdev unregister events
+ * @lag: LAG info struct
+ * @netdev: netdev reporting the event
+ */
+static void ice_lag_unregister(struct ice_lag *lag, struct net_device *netdev)
+{
+       struct ice_pf *pf = lag->pf;
+
+       /* check to see if this event is for this netdev
+        * check that we are in an aggregate
+        */
+       if (netdev != lag->netdev || !lag->bonded)
+               return;
+
+       if (lag->upper_netdev) {
+               dev_put(lag->upper_netdev);
+               lag->upper_netdev = NULL;
+               ice_set_sriov_cap(pf);
+               ice_set_rdma_cap(pf);
+       }
+       /* perform some cleanup in case we come back */
+       lag->bonded = false;
+       lag->role = ICE_LAG_NONE;
+}
+
 /**
  * ice_lag_changeupper_event - handle LAG changeupper event
  * @lag: LAG info struct
@@ -307,7 +329,7 @@ ice_lag_event_handler(struct notifier_block *notif_blk, unsigned long event,
                ice_lag_info_event(lag, ptr);
                break;
        case NETDEV_UNREGISTER:
-               ice_lag_unlink(lag, ptr);
+               ice_lag_unregister(lag, netdev);
                break;
        default:
                break;
index d981dc6..85a6128 100644 (file)
@@ -568,6 +568,7 @@ struct ice_tx_ctx_desc {
                        (0x3FFFFULL << ICE_TXD_CTX_QW1_TSO_LEN_S)
 
 #define ICE_TXD_CTX_QW1_MSS_S  50
+#define ICE_TXD_CTX_MIN_MSS    64
 
 #define ICE_TXD_CTX_QW1_VSI_S  50
 #define ICE_TXD_CTX_QW1_VSI_M  (0x3FFULL << ICE_TXD_CTX_QW1_VSI_S)
index 0c187cf..53256ac 100644 (file)
@@ -1684,6 +1684,12 @@ static void ice_vsi_set_rss_flow_fld(struct ice_vsi *vsi)
        if (status)
                dev_dbg(dev, "ice_add_rss_cfg failed for sctp6 flow, vsi = %d, error = %d\n",
                        vsi_num, status);
+
+       status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_ESP_SPI,
+                                ICE_FLOW_SEG_HDR_ESP);
+       if (status)
+               dev_dbg(dev, "ice_add_rss_cfg failed for esp/spi flow, vsi = %d, error = %d\n",
+                       vsi_num, status);
 }
 
 /**
index 3081443..f3c346e 100644 (file)
@@ -1799,7 +1799,9 @@ static void ice_handle_mdd_event(struct ice_pf *pf)
                                 * reset, so print the event prior to reset.
                                 */
                                ice_print_vf_rx_mdd_event(vf);
+                               mutex_lock(&pf->vf[i].cfg_lock);
                                ice_reset_vf(&pf->vf[i], false);
+                               mutex_unlock(&pf->vf[i].cfg_lock);
                        }
                }
        }
@@ -2253,6 +2255,9 @@ static void ice_service_task(struct work_struct *work)
                return;
        }
 
+       if (test_and_clear_bit(ICE_FLAG_PLUG_AUX_DEV, pf->flags))
+               ice_plug_aux_dev(pf);
+
        ice_clean_adminq_subtask(pf);
        ice_check_media_subtask(pf);
        ice_check_for_hang_subtask(pf);
@@ -8525,6 +8530,7 @@ ice_features_check(struct sk_buff *skb,
                   struct net_device __always_unused *netdev,
                   netdev_features_t features)
 {
+       bool gso = skb_is_gso(skb);
        size_t len;
 
        /* No point in doing any of this if neither checksum nor GSO are
@@ -8537,24 +8543,32 @@ ice_features_check(struct sk_buff *skb,
        /* We cannot support GSO if the MSS is going to be less than
         * 64 bytes. If it is then we need to drop support for GSO.
         */
-       if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_size < 64))
+       if (gso && (skb_shinfo(skb)->gso_size < ICE_TXD_CTX_MIN_MSS))
                features &= ~NETIF_F_GSO_MASK;
 
-       len = skb_network_header(skb) - skb->data;
+       len = skb_network_offset(skb);
        if (len > ICE_TXD_MACLEN_MAX || len & 0x1)
                goto out_rm_features;
 
-       len = skb_transport_header(skb) - skb_network_header(skb);
+       len = skb_network_header_len(skb);
        if (len > ICE_TXD_IPLEN_MAX || len & 0x1)
                goto out_rm_features;
 
        if (skb->encapsulation) {
-               len = skb_inner_network_header(skb) - skb_transport_header(skb);
-               if (len > ICE_TXD_L4LEN_MAX || len & 0x1)
-                       goto out_rm_features;
+               /* this must work for VXLAN frames AND IPIP/SIT frames, and in
+                * the case of IPIP frames, the transport header pointer is
+                * after the inner header! So check to make sure that this
+                * is a GRE or UDP_TUNNEL frame before doing that math.
+                */
+               if (gso && (skb_shinfo(skb)->gso_type &
+                           (SKB_GSO_GRE | SKB_GSO_UDP_TUNNEL))) {
+                       len = skb_inner_network_header(skb) -
+                             skb_transport_header(skb);
+                       if (len > ICE_TXD_L4LEN_MAX || len & 0x1)
+                               goto out_rm_features;
+               }
 
-               len = skb_inner_transport_header(skb) -
-                     skb_inner_network_header(skb);
+               len = skb_inner_network_header_len(skb);
                if (len > ICE_TXD_IPLEN_MAX || len & 0x1)
                        goto out_rm_features;
        }
index dc1b0e9..695b6dd 100644 (file)
@@ -47,6 +47,7 @@ enum ice_protocol_type {
 
 enum ice_sw_tunnel_type {
        ICE_NON_TUN = 0,
+       ICE_SW_TUN_AND_NON_TUN,
        ICE_SW_TUN_VXLAN,
        ICE_SW_TUN_GENEVE,
        ICE_SW_TUN_NVGRE,
index ae291d4..000c39d 100644 (file)
@@ -1533,9 +1533,12 @@ exit:
 static int ice_ptp_adjtime_nonatomic(struct ptp_clock_info *info, s64 delta)
 {
        struct timespec64 now, then;
+       int ret;
 
        then = ns_to_timespec64(delta);
-       ice_ptp_gettimex64(info, &now, NULL);
+       ret = ice_ptp_gettimex64(info, &now, NULL);
+       if (ret)
+               return ret;
        now = timespec64_add(now, then);
 
        return ice_ptp_settime64(info, (const struct timespec64 *)&now);
index 11ae0be..475ec2a 100644 (file)
@@ -4537,6 +4537,7 @@ ice_get_compat_fv_bitmap(struct ice_hw *hw, struct ice_adv_rule_info *rinfo,
        case ICE_SW_TUN_NVGRE:
                prof_type = ICE_PROF_TUN_GRE;
                break;
+       case ICE_SW_TUN_AND_NON_TUN:
        default:
                prof_type = ICE_PROF_ALL;
                break;
@@ -5305,7 +5306,8 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
        if (status)
                goto err_ice_add_adv_rule;
 
-       if (rinfo->tun_type != ICE_NON_TUN) {
+       if (rinfo->tun_type != ICE_NON_TUN &&
+           rinfo->tun_type != ICE_SW_TUN_AND_NON_TUN) {
                status = ice_fill_adv_packet_tun(hw, rinfo->tun_type,
                                                 s_rule->pdata.lkup_tx_rx.hdr,
                                                 pkt_offsets);
index e8aab66..65cf32e 100644 (file)
@@ -709,7 +709,7 @@ ice_tc_set_port(struct flow_match_ports match,
                        fltr->flags |= ICE_TC_FLWR_FIELD_ENC_DEST_L4_PORT;
                else
                        fltr->flags |= ICE_TC_FLWR_FIELD_DEST_L4_PORT;
-               fltr->flags |= ICE_TC_FLWR_FIELD_DEST_L4_PORT;
+
                headers->l4_key.dst_port = match.key->dst;
                headers->l4_mask.dst_port = match.mask->dst;
        }
@@ -718,7 +718,7 @@ ice_tc_set_port(struct flow_match_ports match,
                        fltr->flags |= ICE_TC_FLWR_FIELD_ENC_SRC_L4_PORT;
                else
                        fltr->flags |= ICE_TC_FLWR_FIELD_SRC_L4_PORT;
-               fltr->flags |= ICE_TC_FLWR_FIELD_SRC_L4_PORT;
+
                headers->l4_key.src_port = match.key->src;
                headers->l4_mask.src_port = match.mask->src;
        }
index 39b8012..408f78e 100644 (file)
@@ -500,8 +500,6 @@ void ice_free_vfs(struct ice_pf *pf)
        struct ice_hw *hw = &pf->hw;
        unsigned int tmp, i;
 
-       set_bit(ICE_VF_DEINIT_IN_PROGRESS, pf->state);
-
        if (!pf->vf)
                return;
 
@@ -519,22 +517,26 @@ void ice_free_vfs(struct ice_pf *pf)
        else
                dev_warn(dev, "VFs are assigned - not disabling SR-IOV\n");
 
-       /* Avoid wait time by stopping all VFs at the same time */
-       ice_for_each_vf(pf, i)
-               ice_dis_vf_qs(&pf->vf[i]);
-
        tmp = pf->num_alloc_vfs;
        pf->num_qps_per_vf = 0;
        pf->num_alloc_vfs = 0;
        for (i = 0; i < tmp; i++) {
-               if (test_bit(ICE_VF_STATE_INIT, pf->vf[i].vf_states)) {
+               struct ice_vf *vf = &pf->vf[i];
+
+               mutex_lock(&vf->cfg_lock);
+
+               ice_dis_vf_qs(vf);
+
+               if (test_bit(ICE_VF_STATE_INIT, vf->vf_states)) {
                        /* disable VF qp mappings and set VF disable state */
-                       ice_dis_vf_mappings(&pf->vf[i]);
-                       set_bit(ICE_VF_STATE_DIS, pf->vf[i].vf_states);
-                       ice_free_vf_res(&pf->vf[i]);
+                       ice_dis_vf_mappings(vf);
+                       set_bit(ICE_VF_STATE_DIS, vf->vf_states);
+                       ice_free_vf_res(vf);
                }
 
-               mutex_destroy(&pf->vf[i].cfg_lock);
+               mutex_unlock(&vf->cfg_lock);
+
+               mutex_destroy(&vf->cfg_lock);
        }
 
        if (ice_sriov_free_msix_res(pf))
@@ -570,7 +572,6 @@ void ice_free_vfs(struct ice_pf *pf)
                                i);
 
        clear_bit(ICE_VF_DIS, pf->state);
-       clear_bit(ICE_VF_DEINIT_IN_PROGRESS, pf->state);
        clear_bit(ICE_FLAG_SRIOV_ENA, pf->flags);
 }
 
@@ -1498,6 +1499,8 @@ bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr)
        ice_for_each_vf(pf, v) {
                vf = &pf->vf[v];
 
+               mutex_lock(&vf->cfg_lock);
+
                vf->driver_caps = 0;
                ice_vc_set_default_allowlist(vf);
 
@@ -1512,6 +1515,8 @@ bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr)
                ice_vf_pre_vsi_rebuild(vf);
                ice_vf_rebuild_vsi(vf);
                ice_vf_post_vsi_rebuild(vf);
+
+               mutex_unlock(&vf->cfg_lock);
        }
 
        if (ice_is_eswitch_mode_switchdev(pf))
@@ -1562,6 +1567,8 @@ bool ice_reset_vf(struct ice_vf *vf, bool is_vflr)
        u32 reg;
        int i;
 
+       lockdep_assert_held(&vf->cfg_lock);
+
        dev = ice_pf_to_dev(pf);
 
        if (test_bit(ICE_VF_RESETS_DISABLED, pf->state)) {
@@ -2061,9 +2068,12 @@ void ice_process_vflr_event(struct ice_pf *pf)
                bit_idx = (hw->func_caps.vf_base_id + vf_id) % 32;
                /* read GLGEN_VFLRSTAT register to find out the flr VFs */
                reg = rd32(hw, GLGEN_VFLRSTAT(reg_idx));
-               if (reg & BIT(bit_idx))
+               if (reg & BIT(bit_idx)) {
                        /* GLGEN_VFLRSTAT bit will be cleared in ice_reset_vf */
+                       mutex_lock(&vf->cfg_lock);
                        ice_reset_vf(vf, true);
+                       mutex_unlock(&vf->cfg_lock);
+               }
        }
 }
 
@@ -2140,7 +2150,9 @@ ice_vf_lan_overflow_event(struct ice_pf *pf, struct ice_rq_event_info *event)
        if (!vf)
                return;
 
+       mutex_lock(&vf->cfg_lock);
        ice_vc_reset_vf(vf);
+       mutex_unlock(&vf->cfg_lock);
 }
 
 /**
@@ -4625,10 +4637,6 @@ void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event)
        struct device *dev;
        int err = 0;
 
-       /* if de-init is underway, don't process messages from VF */
-       if (test_bit(ICE_VF_DEINIT_IN_PROGRESS, pf->state))
-               return;
-
        dev = ice_pf_to_dev(pf);
        if (ice_validate_vf_id(pf, vf_id)) {
                err = -EINVAL;
index 0015fcf..0f293ac 100644 (file)
@@ -1984,14 +1984,15 @@ static void ixgbevf_set_rx_buffer_len(struct ixgbevf_adapter *adapter,
        if (adapter->flags & IXGBEVF_FLAGS_LEGACY_RX)
                return;
 
-       set_ring_build_skb_enabled(rx_ring);
+       if (PAGE_SIZE < 8192)
+               if (max_frame > IXGBEVF_MAX_FRAME_BUILD_SKB)
+                       set_ring_uses_large_buffer(rx_ring);
 
-       if (PAGE_SIZE < 8192) {
-               if (max_frame <= IXGBEVF_MAX_FRAME_BUILD_SKB)
-                       return;
+       /* 82599 can't rely on RXDCTL.RLPML to restrict the size of the frame */
+       if (adapter->hw.mac.type == ixgbe_mac_82599_vf && !ring_uses_large_buffer(rx_ring))
+               return;
 
-               set_ring_uses_large_buffer(rx_ring);
-       }
+       set_ring_build_skb_enabled(rx_ring);
 }
 
 /**
index f99adbf..04345b9 100644 (file)
@@ -17,7 +17,7 @@ if NET_VENDOR_LITEX
 
 config LITEX_LITEETH
        tristate "LiteX Ethernet support"
-       depends on OF
+       depends on OF && HAS_IOMEM
        help
          If you wish to compile a kernel for hardware with a LiteX LiteEth
          device then you should answer Y to this.
index 1052475..143ca8b 100644 (file)
@@ -2704,6 +2704,16 @@ MODULE_DEVICE_TABLE(of, mv643xx_eth_shared_ids);
 
 static struct platform_device *port_platdev[3];
 
+static void mv643xx_eth_shared_of_remove(void)
+{
+       int n;
+
+       for (n = 0; n < 3; n++) {
+               platform_device_del(port_platdev[n]);
+               port_platdev[n] = NULL;
+       }
+}
+
 static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
                                          struct device_node *pnp)
 {
@@ -2740,7 +2750,9 @@ static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
                return -EINVAL;
        }
 
-       of_get_mac_address(pnp, ppd.mac_addr);
+       ret = of_get_mac_address(pnp, ppd.mac_addr);
+       if (ret)
+               return ret;
 
        mv643xx_eth_property(pnp, "tx-queue-size", ppd.tx_queue_size);
        mv643xx_eth_property(pnp, "tx-sram-addr", ppd.tx_sram_addr);
@@ -2804,21 +2816,13 @@ static int mv643xx_eth_shared_of_probe(struct platform_device *pdev)
                ret = mv643xx_eth_shared_of_add_port(pdev, pnp);
                if (ret) {
                        of_node_put(pnp);
+                       mv643xx_eth_shared_of_remove();
                        return ret;
                }
        }
        return 0;
 }
 
-static void mv643xx_eth_shared_of_remove(void)
-{
-       int n;
-
-       for (n = 0; n < 3; n++) {
-               platform_device_del(port_platdev[n]);
-               port_platdev[n] = NULL;
-       }
-}
 #else
 static inline int mv643xx_eth_shared_of_probe(struct platform_device *pdev)
 {
index 7cdbf8b..1a835b4 100644 (file)
@@ -6870,6 +6870,9 @@ static int mvpp2_port_probe(struct platform_device *pdev,
        dev->max_mtu = MVPP2_BM_JUMBO_PKT_SIZE;
        dev->dev.of_node = port_node;
 
+       port->pcs_gmac.ops = &mvpp2_phylink_gmac_pcs_ops;
+       port->pcs_xlg.ops = &mvpp2_phylink_xlg_pcs_ops;
+
        if (!mvpp2_use_acpi_compat_mode(port_fwnode)) {
                port->phylink_config.dev = &dev->dev;
                port->phylink_config.type = PHYLINK_NETDEV;
@@ -6940,9 +6943,6 @@ static int mvpp2_port_probe(struct platform_device *pdev,
                                  port->phylink_config.supported_interfaces);
                }
 
-               port->pcs_gmac.ops = &mvpp2_phylink_gmac_pcs_ops;
-               port->pcs_xlg.ops = &mvpp2_phylink_xlg_pcs_ops;
-
                phylink = phylink_create(&port->phylink_config, port_fwnode,
                                         phy_mode, &mvpp2_phylink_ops);
                if (IS_ERR(phylink)) {
index 186d00a..3631d61 100644 (file)
@@ -1570,6 +1570,8 @@ static struct mac_ops     cgx_mac_ops    = {
        .mac_enadis_pause_frm =         cgx_lmac_enadis_pause_frm,
        .mac_pause_frm_config =         cgx_lmac_pause_frm_config,
        .mac_enadis_ptp_config =        cgx_lmac_ptp_config,
+       .mac_rx_tx_enable =             cgx_lmac_rx_tx_enable,
+       .mac_tx_enable =                cgx_lmac_tx_enable,
 };
 
 static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id)
index fc6e742..b33e7d1 100644 (file)
@@ -107,6 +107,9 @@ struct mac_ops {
        void                    (*mac_enadis_ptp_config)(void  *cgxd,
                                                         int lmac_id,
                                                         bool enable);
+
+       int                     (*mac_rx_tx_enable)(void *cgxd, int lmac_id, bool enable);
+       int                     (*mac_tx_enable)(void *cgxd, int lmac_id, bool enable);
 };
 
 struct cgx {
index 4e79e91..58e2aee 100644 (file)
@@ -732,6 +732,7 @@ enum nix_af_status {
        NIX_AF_ERR_BANDPROF_INVAL_REQ  = -428,
        NIX_AF_ERR_CQ_CTX_WRITE_ERR  = -429,
        NIX_AF_ERR_AQ_CTX_RETRY_WRITE  = -430,
+       NIX_AF_ERR_LINK_CREDITS  = -431,
 };
 
 /* For NIX RX vtag action  */
index 0fe7ad3..4180376 100644 (file)
@@ -185,7 +185,6 @@ enum npc_kpu_parser_state {
        NPC_S_KPU2_QINQ,
        NPC_S_KPU2_ETAG,
        NPC_S_KPU2_EXDSA,
-       NPC_S_KPU2_NGIO,
        NPC_S_KPU2_CPT_CTAG,
        NPC_S_KPU2_CPT_QINQ,
        NPC_S_KPU3_CTAG,
@@ -212,6 +211,7 @@ enum npc_kpu_parser_state {
        NPC_S_KPU5_NSH,
        NPC_S_KPU5_CPT_IP,
        NPC_S_KPU5_CPT_IP6,
+       NPC_S_KPU5_NGIO,
        NPC_S_KPU6_IP6_EXT,
        NPC_S_KPU6_IP6_HOP_DEST,
        NPC_S_KPU6_IP6_ROUT,
@@ -1120,15 +1120,6 @@ static struct npc_kpu_profile_cam kpu1_cam_entries[] = {
                0x0000,
                0x0000,
        },
-       {
-               NPC_S_KPU1_ETHER, 0xff,
-               NPC_ETYPE_CTAG,
-               0xffff,
-               NPC_ETYPE_NGIO,
-               0xffff,
-               0x0000,
-               0x0000,
-       },
        {
                NPC_S_KPU1_ETHER, 0xff,
                NPC_ETYPE_CTAG,
@@ -1966,6 +1957,15 @@ static struct npc_kpu_profile_cam kpu2_cam_entries[] = {
                0x0000,
                0x0000,
        },
+       {
+               NPC_S_KPU2_CTAG, 0xff,
+               NPC_ETYPE_NGIO,
+               0xffff,
+               0x0000,
+               0x0000,
+               0x0000,
+               0x0000,
+       },
        {
                NPC_S_KPU2_CTAG, 0xff,
                NPC_ETYPE_PPPOE,
@@ -2749,15 +2749,6 @@ static struct npc_kpu_profile_cam kpu2_cam_entries[] = {
                0x0000,
                0x0000,
        },
-       {
-               NPC_S_KPU2_NGIO, 0xff,
-               0x0000,
-               0x0000,
-               0x0000,
-               0x0000,
-               0x0000,
-               0x0000,
-       },
        {
                NPC_S_KPU2_CPT_CTAG, 0xff,
                NPC_ETYPE_IP,
@@ -5089,6 +5080,15 @@ static struct npc_kpu_profile_cam kpu5_cam_entries[] = {
                0x0000,
                0x0000,
        },
+       {
+               NPC_S_KPU5_NGIO, 0xff,
+               0x0000,
+               0x0000,
+               0x0000,
+               0x0000,
+               0x0000,
+               0x0000,
+       },
        {
                NPC_S_NA, 0X00,
                0x0000,
@@ -8422,14 +8422,6 @@ static struct npc_kpu_profile_action kpu1_action_entries[] = {
                0,
                0, 0, 0, 0,
        },
-       {
-               NPC_ERRLEV_RE, NPC_EC_NOERR,
-               8, 12, 0, 0, 0,
-               NPC_S_KPU2_NGIO, 12, 1,
-               NPC_LID_LA, NPC_LT_LA_ETHER,
-               0,
-               0, 0, 0, 0,
-       },
        {
                NPC_ERRLEV_RE, NPC_EC_NOERR,
                8, 12, 0, 0, 0,
@@ -9194,6 +9186,14 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = {
                0,
                0, 0, 0, 0,
        },
+       {
+               NPC_ERRLEV_RE, NPC_EC_NOERR,
+               0, 0, 0, 2, 0,
+               NPC_S_KPU5_NGIO, 6, 1,
+               NPC_LID_LB, NPC_LT_LB_CTAG,
+               0,
+               0, 0, 0, 0,
+       },
        {
                NPC_ERRLEV_RE, NPC_EC_NOERR,
                8, 0, 6, 2, 0,
@@ -9890,14 +9890,6 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = {
                NPC_F_LB_U_UNK_ETYPE | NPC_F_LB_L_EXDSA,
                0, 0, 0, 0,
        },
-       {
-               NPC_ERRLEV_RE, NPC_EC_NOERR,
-               0, 0, 0, 0, 1,
-               NPC_S_NA, 0, 1,
-               NPC_LID_LC, NPC_LT_LC_NGIO,
-               0,
-               0, 0, 0, 0,
-       },
        {
                NPC_ERRLEV_RE, NPC_EC_NOERR,
                8, 0, 6, 2, 0,
@@ -11973,6 +11965,14 @@ static struct npc_kpu_profile_action kpu5_action_entries[] = {
                0,
                0, 0, 0, 0,
        },
+       {
+               NPC_ERRLEV_RE, NPC_EC_NOERR,
+               0, 0, 0, 0, 1,
+               NPC_S_NA, 0, 1,
+               NPC_LID_LC, NPC_LT_LC_NGIO,
+               0,
+               0, 0, 0, 0,
+       },
        {
                NPC_ERRLEV_LC, NPC_EC_UNK,
                0, 0, 0, 0, 1,
index e695fa0..9ea2f6a 100644 (file)
@@ -30,6 +30,8 @@ static struct mac_ops rpm_mac_ops   = {
        .mac_enadis_pause_frm =         rpm_lmac_enadis_pause_frm,
        .mac_pause_frm_config =         rpm_lmac_pause_frm_config,
        .mac_enadis_ptp_config =        rpm_lmac_ptp_config,
+       .mac_rx_tx_enable =             rpm_lmac_rx_tx_enable,
+       .mac_tx_enable =                rpm_lmac_tx_enable,
 };
 
 struct mac_ops *rpm_get_mac_ops(void)
@@ -54,6 +56,43 @@ int rpm_get_nr_lmacs(void *rpmd)
        return hweight8(rpm_read(rpm, 0, CGXX_CMRX_RX_LMACS) & 0xFULL);
 }
 
+int rpm_lmac_tx_enable(void *rpmd, int lmac_id, bool enable)
+{
+       rpm_t *rpm = rpmd;
+       u64 cfg, last;
+
+       if (!is_lmac_valid(rpm, lmac_id))
+               return -ENODEV;
+
+       cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
+       last = cfg;
+       if (enable)
+               cfg |= RPM_TX_EN;
+       else
+               cfg &= ~(RPM_TX_EN);
+
+       if (cfg != last)
+               rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
+       return !!(last & RPM_TX_EN);
+}
+
+int rpm_lmac_rx_tx_enable(void *rpmd, int lmac_id, bool enable)
+{
+       rpm_t *rpm = rpmd;
+       u64 cfg;
+
+       if (!is_lmac_valid(rpm, lmac_id))
+               return -ENODEV;
+
+       cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
+       if (enable)
+               cfg |= RPM_RX_EN | RPM_TX_EN;
+       else
+               cfg &= ~(RPM_RX_EN | RPM_TX_EN);
+       rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
+       return 0;
+}
+
 void rpm_lmac_enadis_rx_pause_fwding(void *rpmd, int lmac_id, bool enable)
 {
        rpm_t *rpm = rpmd;
@@ -252,23 +291,20 @@ int rpm_lmac_internal_loopback(void *rpmd, int lmac_id, bool enable)
        if (!rpm || lmac_id >= rpm->lmac_count)
                return -ENODEV;
        lmac_type = rpm->mac_ops->get_lmac_type(rpm, lmac_id);
-       if (lmac_type == LMAC_MODE_100G_R) {
-               cfg = rpm_read(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1);
-
-               if (enable)
-                       cfg |= RPMX_MTI_PCS_LBK;
-               else
-                       cfg &= ~RPMX_MTI_PCS_LBK;
-               rpm_write(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1, cfg);
-       } else {
-               cfg = rpm_read(rpm, lmac_id, RPMX_MTI_LPCSX_CONTROL1);
-               if (enable)
-                       cfg |= RPMX_MTI_PCS_LBK;
-               else
-                       cfg &= ~RPMX_MTI_PCS_LBK;
-               rpm_write(rpm, lmac_id, RPMX_MTI_LPCSX_CONTROL1, cfg);
+
+       if (lmac_type == LMAC_MODE_QSGMII || lmac_type == LMAC_MODE_SGMII) {
+               dev_err(&rpm->pdev->dev, "loopback not supported for LPC mode\n");
+               return 0;
        }
 
+       cfg = rpm_read(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1);
+
+       if (enable)
+               cfg |= RPMX_MTI_PCS_LBK;
+       else
+               cfg &= ~RPMX_MTI_PCS_LBK;
+       rpm_write(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1, cfg);
+
        return 0;
 }
 
index 57c8a68..ff58031 100644 (file)
@@ -43,6 +43,8 @@
 #define RPMX_MTI_STAT_DATA_HI_CDC            0x10038
 
 #define RPM_LMAC_FWI                   0xa
+#define RPM_TX_EN                      BIT_ULL(0)
+#define RPM_RX_EN                      BIT_ULL(1)
 
 /* Function Declarations */
 int rpm_get_nr_lmacs(void *rpmd);
@@ -57,4 +59,6 @@ int rpm_lmac_enadis_pause_frm(void *rpmd, int lmac_id, u8 tx_pause,
 int rpm_get_tx_stats(void *rpmd, int lmac_id, int idx, u64 *tx_stat);
 int rpm_get_rx_stats(void *rpmd, int lmac_id, int idx, u64 *rx_stat);
 void rpm_lmac_ptp_config(void *rpmd, int lmac_id, bool enable);
+int rpm_lmac_rx_tx_enable(void *rpmd, int lmac_id, bool enable);
+int rpm_lmac_tx_enable(void *rpmd, int lmac_id, bool enable);
 #endif /* RPM_H */
index 3ca6b94..54e1b27 100644 (file)
@@ -520,8 +520,11 @@ static void rvu_block_reset(struct rvu *rvu, int blkaddr, u64 rst_reg)
 
        rvu_write64(rvu, blkaddr, rst_reg, BIT_ULL(0));
        err = rvu_poll_reg(rvu, blkaddr, rst_reg, BIT_ULL(63), true);
-       if (err)
-               dev_err(rvu->dev, "HW block:%d reset failed\n", blkaddr);
+       if (err) {
+               dev_err(rvu->dev, "HW block:%d reset timeout retrying again\n", blkaddr);
+               while (rvu_poll_reg(rvu, blkaddr, rst_reg, BIT_ULL(63), true) == -EBUSY)
+                       ;
+       }
 }
 
 static void rvu_reset_all_blocks(struct rvu *rvu)
index 66e45d7..5ed94cf 100644 (file)
@@ -806,6 +806,7 @@ bool is_mac_feature_supported(struct rvu *rvu, int pf, int feature);
 u32  rvu_cgx_get_fifolen(struct rvu *rvu);
 void *rvu_first_cgx_pdata(struct rvu *rvu);
 int cgxlmac_to_pf(struct rvu *rvu, int cgx_id, int lmac_id);
+int rvu_cgx_config_tx(void *cgxd, int lmac_id, bool enable);
 
 int npc_get_nixlf_mcam_index(struct npc_mcam *mcam, u16 pcifunc, int nixlf,
                             int type);
index 2ca182a..8a7ac5a 100644 (file)
@@ -441,16 +441,26 @@ void rvu_cgx_enadis_rx_bp(struct rvu *rvu, int pf, bool enable)
 int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start)
 {
        int pf = rvu_get_pf(pcifunc);
+       struct mac_ops *mac_ops;
        u8 cgx_id, lmac_id;
+       void *cgxd;
 
        if (!is_cgx_config_permitted(rvu, pcifunc))
                return LMAC_AF_ERR_PERM_DENIED;
 
        rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+       cgxd = rvu_cgx_pdata(cgx_id, rvu);
+       mac_ops = get_mac_ops(cgxd);
+
+       return mac_ops->mac_rx_tx_enable(cgxd, lmac_id, start);
+}
 
-       cgx_lmac_rx_tx_enable(rvu_cgx_pdata(cgx_id, rvu), lmac_id, start);
+int rvu_cgx_config_tx(void *cgxd, int lmac_id, bool enable)
+{
+       struct mac_ops *mac_ops;
 
-       return 0;
+       mac_ops = get_mac_ops(cgxd);
+       return mac_ops->mac_tx_enable(cgxd, lmac_id, enable);
 }
 
 void rvu_cgx_disable_dmac_entries(struct rvu *rvu, u16 pcifunc)
index a09a507..d1eddb7 100644 (file)
@@ -1224,6 +1224,8 @@ static void print_nix_cn10k_sq_ctx(struct seq_file *m,
        seq_printf(m, "W3: head_offset\t\t\t%d\nW3: smenq_next_sqb_vld\t\t%d\n\n",
                   sq_ctx->head_offset, sq_ctx->smenq_next_sqb_vld);
 
+       seq_printf(m, "W3: smq_next_sq_vld\t\t%d\nW3: smq_pend\t\t\t%d\n",
+                  sq_ctx->smq_next_sq_vld, sq_ctx->smq_pend);
        seq_printf(m, "W4: next_sqb \t\t\t%llx\n\n", sq_ctx->next_sqb);
        seq_printf(m, "W5: tail_sqb \t\t\t%llx\n\n", sq_ctx->tail_sqb);
        seq_printf(m, "W6: smenq_sqb \t\t\t%llx\n\n", sq_ctx->smenq_sqb);
index d8b1948..97fb619 100644 (file)
@@ -512,11 +512,11 @@ static int rvu_nix_get_bpid(struct rvu *rvu, struct nix_bp_cfg_req *req,
        cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST);
        lmac_chan_cnt = cfg & 0xFF;
 
-       cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST1);
-       sdp_chan_cnt = cfg & 0xFFF;
-
        cgx_bpid_cnt = hw->cgx_links * lmac_chan_cnt;
        lbk_bpid_cnt = hw->lbk_links * ((cfg >> 16) & 0xFF);
+
+       cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST1);
+       sdp_chan_cnt = cfg & 0xFFF;
        sdp_bpid_cnt = hw->sdp_links * sdp_chan_cnt;
 
        pfvf = rvu_get_pfvf(rvu, req->hdr.pcifunc);
@@ -2068,8 +2068,8 @@ static int nix_smq_flush(struct rvu *rvu, int blkaddr,
        /* enable cgx tx if disabled */
        if (is_pf_cgxmapped(rvu, pf)) {
                rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
-               restore_tx_en = !cgx_lmac_tx_enable(rvu_cgx_pdata(cgx_id, rvu),
-                                                   lmac_id, true);
+               restore_tx_en = !rvu_cgx_config_tx(rvu_cgx_pdata(cgx_id, rvu),
+                                                  lmac_id, true);
        }
 
        cfg = rvu_read64(rvu, blkaddr, NIX_AF_SMQX_CFG(smq));
@@ -2092,7 +2092,7 @@ static int nix_smq_flush(struct rvu *rvu, int blkaddr,
        rvu_cgx_enadis_rx_bp(rvu, pf, true);
        /* restore cgx tx state */
        if (restore_tx_en)
-               cgx_lmac_tx_enable(rvu_cgx_pdata(cgx_id, rvu), lmac_id, false);
+               rvu_cgx_config_tx(rvu_cgx_pdata(cgx_id, rvu), lmac_id, false);
        return err;
 }
 
@@ -3878,7 +3878,7 @@ nix_config_link_credits(struct rvu *rvu, int blkaddr, int link,
        /* Enable cgx tx if disabled for credits to be back */
        if (is_pf_cgxmapped(rvu, pf)) {
                rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
-               restore_tx_en = !cgx_lmac_tx_enable(rvu_cgx_pdata(cgx_id, rvu),
+               restore_tx_en = !rvu_cgx_config_tx(rvu_cgx_pdata(cgx_id, rvu),
                                                    lmac_id, true);
        }
 
@@ -3891,8 +3891,8 @@ nix_config_link_credits(struct rvu *rvu, int blkaddr, int link,
                            NIX_AF_TL1X_SW_XOFF(schq), BIT_ULL(0));
        }
 
-       rc = -EBUSY;
-       poll_tmo = jiffies + usecs_to_jiffies(10000);
+       rc = NIX_AF_ERR_LINK_CREDITS;
+       poll_tmo = jiffies + usecs_to_jiffies(200000);
        /* Wait for credits to return */
        do {
                if (time_after(jiffies, poll_tmo))
@@ -3918,7 +3918,7 @@ exit:
 
        /* Restore state of cgx tx */
        if (restore_tx_en)
-               cgx_lmac_tx_enable(rvu_cgx_pdata(cgx_id, rvu), lmac_id, false);
+               rvu_cgx_config_tx(rvu_cgx_pdata(cgx_id, rvu), lmac_id, false);
 
        mutex_unlock(&rvu->rsrc_lock);
        return rc;
index c0005a1..91f86d7 100644 (file)
@@ -402,6 +402,7 @@ static void npc_fixup_vf_rule(struct rvu *rvu, struct npc_mcam *mcam,
                              int blkaddr, int index, struct mcam_entry *entry,
                              bool *enable)
 {
+       struct rvu_npc_mcam_rule *rule;
        u16 owner, target_func;
        struct rvu_pfvf *pfvf;
        u64 rx_action;
@@ -423,6 +424,12 @@ static void npc_fixup_vf_rule(struct rvu *rvu, struct npc_mcam *mcam,
              test_bit(NIXLF_INITIALIZED, &pfvf->flags)))
                *enable = false;
 
+       /* fix up not needed for the rules added by user(ntuple filters) */
+       list_for_each_entry(rule, &mcam->mcam_rules, list) {
+               if (rule->entry == index)
+                       return;
+       }
+
        /* copy VF default entry action to the VF mcam entry */
        rx_action = npc_get_default_entry_action(rvu, mcam, blkaddr,
                                                 target_func);
@@ -489,8 +496,8 @@ static void npc_config_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
        }
 
        /* PF installing VF rule */
-       if (intf == NIX_INTF_RX && actindex < mcam->bmap_entries)
-               npc_fixup_vf_rule(rvu, mcam, blkaddr, index, entry, &enable);
+       if (is_npc_intf_rx(intf) && actindex < mcam->bmap_entries)
+               npc_fixup_vf_rule(rvu, mcam, blkaddr, actindex, entry, &enable);
 
        /* Set 'action' */
        rvu_write64(rvu, blkaddr,
@@ -916,7 +923,8 @@ static void npc_update_vf_flow_entry(struct rvu *rvu, struct npc_mcam *mcam,
                                     int blkaddr, u16 pcifunc, u64 rx_action)
 {
        int actindex, index, bank, entry;
-       bool enable;
+       struct rvu_npc_mcam_rule *rule;
+       bool enable, update;
 
        if (!(pcifunc & RVU_PFVF_FUNC_MASK))
                return;
@@ -924,6 +932,14 @@ static void npc_update_vf_flow_entry(struct rvu *rvu, struct npc_mcam *mcam,
        mutex_lock(&mcam->lock);
        for (index = 0; index < mcam->bmap_entries; index++) {
                if (mcam->entry2target_pffunc[index] == pcifunc) {
+                       update = true;
+                       /* update not needed for the rules added via ntuple filters */
+                       list_for_each_entry(rule, &mcam->mcam_rules, list) {
+                               if (rule->entry == index)
+                                       update = false;
+                       }
+                       if (!update)
+                               continue;
                        bank = npc_get_bank(mcam, index);
                        actindex = index;
                        entry = index & (mcam->banksize - 1);
index ff2b219..19c53e5 100644 (file)
@@ -1098,14 +1098,6 @@ find_rule:
                write_req.cntr = rule->cntr;
        }
 
-       err = rvu_mbox_handler_npc_mcam_write_entry(rvu, &write_req,
-                                                   &write_rsp);
-       if (err) {
-               rvu_mcam_remove_counter_from_rule(rvu, owner, rule);
-               if (new)
-                       kfree(rule);
-               return err;
-       }
        /* update rule */
        memcpy(&rule->packet, &dummy.packet, sizeof(rule->packet));
        memcpy(&rule->mask, &dummy.mask, sizeof(rule->mask));
@@ -1132,6 +1124,18 @@ find_rule:
        if (req->default_rule)
                pfvf->def_ucast_rule = rule;
 
+       /* write to mcam entry registers */
+       err = rvu_mbox_handler_npc_mcam_write_entry(rvu, &write_req,
+                                                   &write_rsp);
+       if (err) {
+               rvu_mcam_remove_counter_from_rule(rvu, owner, rule);
+               if (new) {
+                       list_del(&rule->list);
+                       kfree(rule);
+               }
+               return err;
+       }
+
        /* VF's MAC address is being changed via PF  */
        if (pf_set_vfs_mac) {
                ether_addr_copy(pfvf->default_mac, req->packet.dmac);
index 61e5281..14509fc 100644 (file)
@@ -603,6 +603,7 @@ static inline void __cn10k_aura_freeptr(struct otx2_nic *pfvf, u64 aura,
                        size++;
                tar_addr |=  ((size - 1) & 0x7) << 4;
        }
+       dma_wmb();
        memcpy((u64 *)lmt_info->lmt_addr, ptrs, sizeof(u64) * num_ptrs);
        /* Perform LMTST flush */
        cn10k_lmt_flush(val, tar_addr);
index 6080ebd..d39341e 100644 (file)
@@ -394,7 +394,12 @@ static int otx2_forward_vf_mbox_msgs(struct otx2_nic *pf,
                dst_mdev->msg_size = mbox_hdr->msg_size;
                dst_mdev->num_msgs = num_msgs;
                err = otx2_sync_mbox_msg(dst_mbox);
-               if (err) {
+               /* Error code -EIO indicate there is a communication failure
+                * to the AF. Rest of the error codes indicate that AF processed
+                * VF messages and set the error codes in response messages
+                * (if any) so simply forward responses to VF.
+                */
+               if (err == -EIO) {
                        dev_warn(pf->dev,
                                 "AF not responding to VF%d messages\n", vf);
                        /* restore PF mbase and exit */
index 812e681..c14e06c 100644 (file)
@@ -224,7 +224,7 @@ static inline int mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev)
 struct mlx5e_tx_wqe {
        struct mlx5_wqe_ctrl_seg ctrl;
        struct mlx5_wqe_eth_seg  eth;
-       struct mlx5_wqe_data_seg data[0];
+       struct mlx5_wqe_data_seg data[];
 };
 
 struct mlx5e_rx_wqe_ll {
@@ -241,8 +241,8 @@ struct mlx5e_umr_wqe {
        struct mlx5_wqe_umr_ctrl_seg   uctrl;
        struct mlx5_mkey_seg           mkc;
        union {
-               struct mlx5_mtt inline_mtts[0];
-               struct mlx5_klm inline_klms[0];
+               DECLARE_FLEX_ARRAY(struct mlx5_mtt, inline_mtts);
+               DECLARE_FLEX_ARRAY(struct mlx5_klm, inline_klms);
        };
 };
 
index 00449df..c1e0749 100644 (file)
@@ -570,7 +570,8 @@ static int mlx5e_htb_convert_rate(struct mlx5e_priv *priv, u64 rate,
 
 static void mlx5e_htb_convert_ceil(struct mlx5e_priv *priv, u64 ceil, u32 *max_average_bw)
 {
-       *max_average_bw = div_u64(ceil, BYTES_IN_MBIT);
+       /* Hardware treats 0 as "unlimited", set at least 1. */
+       *max_average_bw = max_t(u32, div_u64(ceil, BYTES_IN_MBIT), 1);
 
        qos_dbg(priv->mdev, "Convert: ceil %llu -> max_average_bw %u\n",
                ceil, *max_average_bw);
index 9c076aa..b6f5c1b 100644 (file)
@@ -183,18 +183,7 @@ void mlx5e_rep_bond_unslave(struct mlx5_eswitch *esw,
 
 static bool mlx5e_rep_is_lag_netdev(struct net_device *netdev)
 {
-       struct mlx5e_rep_priv *rpriv;
-       struct mlx5e_priv *priv;
-
-       /* A given netdev is not a representor or not a slave of LAG configuration */
-       if (!mlx5e_eswitch_rep(netdev) || !netif_is_lag_port(netdev))
-               return false;
-
-       priv = netdev_priv(netdev);
-       rpriv = priv->ppriv;
-
-       /* Egress acl forward to vport is supported only non-uplink representor */
-       return rpriv->rep->vport != MLX5_VPORT_UPLINK;
+       return netif_is_lag_port(netdev) && mlx5e_eswitch_vf_rep(netdev);
 }
 
 static void mlx5e_rep_changelowerstate_event(struct net_device *netdev, void *ptr)
@@ -210,9 +199,6 @@ static void mlx5e_rep_changelowerstate_event(struct net_device *netdev, void *pt
        u16 fwd_vport_num;
        int err;
 
-       if (!mlx5e_rep_is_lag_netdev(netdev))
-               return;
-
        info = ptr;
        lag_info = info->lower_state_info;
        /* This is not an event of a representor becoming active slave */
@@ -266,9 +252,6 @@ static void mlx5e_rep_changeupper_event(struct net_device *netdev, void *ptr)
        struct net_device *lag_dev;
        struct mlx5e_priv *priv;
 
-       if (!mlx5e_rep_is_lag_netdev(netdev))
-               return;
-
        priv = netdev_priv(netdev);
        rpriv = priv->ppriv;
        lag_dev = info->upper_dev;
@@ -293,6 +276,19 @@ static int mlx5e_rep_esw_bond_netevent(struct notifier_block *nb,
                                       unsigned long event, void *ptr)
 {
        struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
+       struct mlx5e_rep_priv *rpriv;
+       struct mlx5e_rep_bond *bond;
+       struct mlx5e_priv *priv;
+
+       if (!mlx5e_rep_is_lag_netdev(netdev))
+               return NOTIFY_DONE;
+
+       bond = container_of(nb, struct mlx5e_rep_bond, nb);
+       priv = netdev_priv(netdev);
+       rpriv = mlx5_eswitch_get_uplink_priv(priv->mdev->priv.eswitch, REP_ETH);
+       /* Verify VF representor is on the same device of the bond handling the netevent. */
+       if (rpriv->uplink_priv.bond != bond)
+               return NOTIFY_DONE;
 
        switch (event) {
        case NETDEV_CHANGELOWERSTATE:
index c6d2f8c..48dc121 100644 (file)
@@ -491,7 +491,7 @@ void mlx5e_rep_bridge_init(struct mlx5e_priv *priv)
        }
 
        br_offloads->netdev_nb.notifier_call = mlx5_esw_bridge_switchdev_port_event;
-       err = register_netdevice_notifier(&br_offloads->netdev_nb);
+       err = register_netdevice_notifier_net(&init_net, &br_offloads->netdev_nb);
        if (err) {
                esw_warn(mdev, "Failed to register bridge offloads netdevice notifier (err=%d)\n",
                         err);
@@ -509,7 +509,9 @@ err_register_swdev_blk:
 err_register_swdev:
        destroy_workqueue(br_offloads->wq);
 err_alloc_wq:
+       rtnl_lock();
        mlx5_esw_bridge_cleanup(esw);
+       rtnl_unlock();
 }
 
 void mlx5e_rep_bridge_cleanup(struct mlx5e_priv *priv)
@@ -524,7 +526,7 @@ void mlx5e_rep_bridge_cleanup(struct mlx5e_priv *priv)
                return;
 
        cancel_delayed_work_sync(&br_offloads->update_work);
-       unregister_netdevice_notifier(&br_offloads->netdev_nb);
+       unregister_netdevice_notifier_net(&init_net, &br_offloads->netdev_nb);
        unregister_switchdev_blocking_notifier(&br_offloads->nb_blk);
        unregister_switchdev_notifier(&br_offloads->nb);
        destroy_workqueue(br_offloads->wq);
index 26efa33..9cc844b 100644 (file)
@@ -16,11 +16,13 @@ struct mlx5e_tc_act_parse_state {
        unsigned int num_actions;
        struct mlx5e_tc_flow *flow;
        struct netlink_ext_ack *extack;
+       bool ct_clear;
        bool encap;
        bool decap;
        bool mpls_push;
        bool ptype_host;
        const struct ip_tunnel_info *tun_info;
+       struct mlx5e_mpls_info mpls_info;
        struct pedit_headers_action hdrs[__PEDIT_CMD_MAX];
        int ifindexes[MLX5_MAX_FLOW_FWD_VPORTS];
        int if_count;
index 06ec30c..58cc33f 100644 (file)
@@ -27,8 +27,13 @@ tc_act_parse_ct(struct mlx5e_tc_act_parse_state *parse_state,
                struct mlx5e_priv *priv,
                struct mlx5_flow_attr *attr)
 {
+       bool clear_action = act->ct.action & TCA_CT_ACT_CLEAR;
        int err;
 
+       /* It's redundant to do ct clear more than once. */
+       if (clear_action && parse_state->ct_clear)
+               return 0;
+
        err = mlx5_tc_ct_parse_action(parse_state->ct_priv, attr,
                                      &attr->parse_attr->mod_hdr_acts,
                                      act, parse_state->extack);
@@ -40,6 +45,8 @@ tc_act_parse_ct(struct mlx5e_tc_act_parse_state *parse_state,
        if (mlx5e_is_eswitch_flow(parse_state->flow))
                attr->esw_attr->split_count = attr->esw_attr->out_count;
 
+       parse_state->ct_clear = clear_action;
+
        return 0;
 }
 
index c614fc7..2e615e0 100644 (file)
@@ -177,6 +177,12 @@ parse_mirred_encap(struct mlx5e_tc_act_parse_state *parse_state,
                return -ENOMEM;
 
        parse_state->encap = false;
+
+       if (parse_state->mpls_push) {
+               memcpy(&parse_attr->mpls_info[esw_attr->out_count],
+                      &parse_state->mpls_info, sizeof(parse_state->mpls_info));
+               parse_state->mpls_push = false;
+       }
        esw_attr->dests[esw_attr->out_count].flags |= MLX5_ESW_DEST_ENCAP;
        esw_attr->out_count++;
        /* attr->dests[].rep is resolved when we handle encap */
index 784fc4f..89ca88c 100644 (file)
@@ -22,6 +22,16 @@ tc_act_can_offload_mpls_push(struct mlx5e_tc_act_parse_state *parse_state,
        return true;
 }
 
+static void
+copy_mpls_info(struct mlx5e_mpls_info *mpls_info,
+              const struct flow_action_entry *act)
+{
+       mpls_info->label = act->mpls_push.label;
+       mpls_info->tc = act->mpls_push.tc;
+       mpls_info->bos = act->mpls_push.bos;
+       mpls_info->ttl = act->mpls_push.ttl;
+}
+
 static int
 tc_act_parse_mpls_push(struct mlx5e_tc_act_parse_state *parse_state,
                       const struct flow_action_entry *act,
@@ -29,6 +39,7 @@ tc_act_parse_mpls_push(struct mlx5e_tc_act_parse_state *parse_state,
                       struct mlx5_flow_attr *attr)
 {
        parse_state->mpls_push = true;
+       copy_mpls_info(&parse_state->mpls_info, act);
 
        return 0;
 }
index f832c26..70b40ae 100644 (file)
@@ -35,6 +35,7 @@ enum {
 
 struct mlx5e_tc_flow_parse_attr {
        const struct ip_tunnel_info *tun_info[MLX5_MAX_FLOW_FWD_VPORTS];
+       struct mlx5e_mpls_info mpls_info[MLX5_MAX_FLOW_FWD_VPORTS];
        struct net_device *filter_dev;
        struct mlx5_flow_spec spec;
        struct mlx5e_tc_mod_hdr_acts mod_hdr_acts;
index 9918ed8..d39d0da 100644 (file)
@@ -750,6 +750,7 @@ int mlx5e_attach_encap(struct mlx5e_priv *priv,
        struct mlx5e_tc_flow_parse_attr *parse_attr;
        struct mlx5_flow_attr *attr = flow->attr;
        const struct ip_tunnel_info *tun_info;
+       const struct mlx5e_mpls_info *mpls_info;
        unsigned long tbl_time_before = 0;
        struct mlx5e_encap_entry *e;
        struct mlx5e_encap_key key;
@@ -760,6 +761,7 @@ int mlx5e_attach_encap(struct mlx5e_priv *priv,
 
        parse_attr = attr->parse_attr;
        tun_info = parse_attr->tun_info[out_index];
+       mpls_info = &parse_attr->mpls_info[out_index];
        family = ip_tunnel_info_af(tun_info);
        key.ip_tun_key = &tun_info->key;
        key.tc_tunnel = mlx5e_get_tc_tun(mirred_dev);
@@ -810,6 +812,7 @@ int mlx5e_attach_encap(struct mlx5e_priv *priv,
                goto out_err_init;
        }
        e->tun_info = tun_info;
+       memcpy(&e->mpls_info, mpls_info, sizeof(*mpls_info));
        err = mlx5e_tc_tun_init_encap_attr(mirred_dev, priv, e, extack);
        if (err)
                goto out_err_init;
index 60952b3..c5b1617 100644 (file)
@@ -30,16 +30,15 @@ static int generate_ip_tun_hdr(char buf[],
                               struct mlx5e_encap_entry *r)
 {
        const struct ip_tunnel_key *tun_key = &r->tun_info->key;
+       const struct mlx5e_mpls_info *mpls_info = &r->mpls_info;
        struct udphdr *udp = (struct udphdr *)(buf);
        struct mpls_shim_hdr *mpls;
-       u32 tun_id;
 
-       tun_id = be32_to_cpu(tunnel_id_to_key32(tun_key->tun_id));
        mpls = (struct mpls_shim_hdr *)(udp + 1);
        *ip_proto = IPPROTO_UDP;
 
        udp->dest = tun_key->tp_dst;
-       *mpls = mpls_entry_encode(tun_id, tun_key->ttl, tun_key->tos, true);
+       *mpls = mpls_entry_encode(mpls_info->label, mpls_info->ttl, mpls_info->tc, mpls_info->bos);
 
        return 0;
 }
@@ -60,37 +59,31 @@ static int parse_tunnel(struct mlx5e_priv *priv,
                        void *headers_v)
 {
        struct flow_rule *rule = flow_cls_offload_flow_rule(f);
-       struct flow_match_enc_keyid enc_keyid;
        struct flow_match_mpls match;
        void *misc2_c;
        void *misc2_v;
 
-       misc2_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
-                              misc_parameters_2);
-       misc2_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
-                              misc_parameters_2);
-
-       if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_MPLS))
-               return 0;
-
-       if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID))
-               return 0;
-
-       flow_rule_match_enc_keyid(rule, &enc_keyid);
-
-       if (!enc_keyid.mask->keyid)
-               return 0;
-
        if (!MLX5_CAP_ETH(priv->mdev, tunnel_stateless_mpls_over_udp) &&
            !(MLX5_CAP_GEN(priv->mdev, flex_parser_protocols) & MLX5_FLEX_PROTO_CW_MPLS_UDP))
                return -EOPNOTSUPP;
 
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID))
+               return -EOPNOTSUPP;
+
+       if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_MPLS))
+               return 0;
+
        flow_rule_match_mpls(rule, &match);
 
        /* Only support matching the first LSE */
        if (match.mask->used_lses != 1)
                return -EOPNOTSUPP;
 
+       misc2_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
+                              misc_parameters_2);
+       misc2_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
+                              misc_parameters_2);
+
        MLX5_SET(fte_match_set_misc2, misc2_c,
                 outer_first_mpls_over_udp.mpls_label,
                 match.mask->ls[0].mpls_label);
index 4cdf8e5..b789af0 100644 (file)
@@ -167,6 +167,11 @@ static inline u16 mlx5e_txqsq_get_next_pi(struct mlx5e_txqsq *sq, u16 size)
        return pi;
 }
 
+static inline u16 mlx5e_shampo_get_cqe_header_index(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
+{
+       return be16_to_cpu(cqe->shampo.header_entry_index) & (rq->mpwqe.shampo->hd_per_wq - 1);
+}
+
 struct mlx5e_shampo_umr {
        u16 len;
 };
index 338d65e..56e10c8 100644 (file)
@@ -341,8 +341,10 @@ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
 
        /* copy the inline part if required */
        if (sq->min_inline_mode != MLX5_INLINE_MODE_NONE) {
-               memcpy(eseg->inline_hdr.start, xdptxd->data, MLX5E_XDP_MIN_INLINE);
+               memcpy(eseg->inline_hdr.start, xdptxd->data, sizeof(eseg->inline_hdr.start));
                eseg->inline_hdr.sz = cpu_to_be16(MLX5E_XDP_MIN_INLINE);
+               memcpy(dseg, xdptxd->data + sizeof(eseg->inline_hdr.start),
+                      MLX5E_XDP_MIN_INLINE - sizeof(eseg->inline_hdr.start));
                dma_len  -= MLX5E_XDP_MIN_INLINE;
                dma_addr += MLX5E_XDP_MIN_INLINE;
                dseg++;
index 2db9573..b56fea1 100644 (file)
@@ -157,11 +157,20 @@ static void mlx5e_ipsec_set_swp(struct sk_buff *skb,
        /* Tunnel mode */
        if (mode == XFRM_MODE_TUNNEL) {
                eseg->swp_inner_l3_offset = skb_inner_network_offset(skb) / 2;
-               eseg->swp_inner_l4_offset = skb_inner_transport_offset(skb) / 2;
                if (xo->proto == IPPROTO_IPV6)
                        eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6;
-               if (inner_ip_hdr(skb)->protocol == IPPROTO_UDP)
+
+               switch (xo->inner_ipproto) {
+               case IPPROTO_UDP:
                        eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L4_UDP;
+                       fallthrough;
+               case IPPROTO_TCP:
+                       /* IP | ESP | IP | [TCP | UDP] */
+                       eseg->swp_inner_l4_offset = skb_inner_transport_offset(skb) / 2;
+                       break;
+               default:
+                       break;
+               }
                return;
        }
 
index b98db50..428881e 100644 (file)
@@ -131,14 +131,17 @@ static inline bool
 mlx5e_ipsec_txwqe_build_eseg_csum(struct mlx5e_txqsq *sq, struct sk_buff *skb,
                                  struct mlx5_wqe_eth_seg *eseg)
 {
-       struct xfrm_offload *xo = xfrm_offload(skb);
+       u8 inner_ipproto;
 
        if (!mlx5e_ipsec_eseg_meta(eseg))
                return false;
 
        eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM;
-       if (xo->inner_ipproto) {
-               eseg->cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM | MLX5_ETH_WQE_L3_INNER_CSUM;
+       inner_ipproto = xfrm_offload(skb)->inner_ipproto;
+       if (inner_ipproto) {
+               eseg->cs_flags |= MLX5_ETH_WQE_L3_INNER_CSUM;
+               if (inner_ipproto == IPPROTO_TCP || inner_ipproto == IPPROTO_UDP)
+                       eseg->cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM;
        } else if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
                eseg->cs_flags |= MLX5_ETH_WQE_L4_CSUM;
                sq->stats->csum_partial_inner++;
index 57d755d..6e80585 100644 (file)
@@ -1792,7 +1792,7 @@ static int mlx5e_get_module_eeprom(struct net_device *netdev,
                if (size_read < 0) {
                        netdev_err(priv->netdev, "%s: mlx5_query_eeprom failed:0x%x\n",
                                   __func__, size_read);
-                       return 0;
+                       return size_read;
                }
 
                i += size_read;
index b01dacb..b3f7520 100644 (file)
@@ -183,6 +183,13 @@ struct mlx5e_decap_entry {
        struct rcu_head rcu;
 };
 
+struct mlx5e_mpls_info {
+       u32             label;
+       u8              tc;
+       u8              bos;
+       u8              ttl;
+};
+
 struct mlx5e_encap_entry {
        /* attached neigh hash entry */
        struct mlx5e_neigh_hash_entry *nhe;
@@ -196,6 +203,7 @@ struct mlx5e_encap_entry {
        struct list_head route_list;
        struct mlx5_pkt_reformat *pkt_reformat;
        const struct ip_tunnel_info *tun_info;
+       struct mlx5e_mpls_info mpls_info;
        unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
 
        struct net_device *out_dev;
index e86ccc2..6530d7b 100644 (file)
@@ -1117,7 +1117,7 @@ static void mlx5e_shampo_update_ipv6_udp_hdr(struct mlx5e_rq *rq, struct ipv6hdr
 static void mlx5e_shampo_update_fin_psh_flags(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe,
                                              struct tcphdr *skb_tcp_hd)
 {
-       u16 header_index = be16_to_cpu(cqe->shampo.header_entry_index);
+       u16 header_index = mlx5e_shampo_get_cqe_header_index(rq, cqe);
        struct tcphdr *last_tcp_hd;
        void *last_hd_addr;
 
@@ -1349,7 +1349,8 @@ static inline void mlx5e_handle_csum(struct net_device *netdev,
        }
 
        /* True when explicitly set via priv flag, or XDP prog is loaded */
-       if (test_bit(MLX5E_RQ_STATE_NO_CSUM_COMPLETE, &rq->state))
+       if (test_bit(MLX5E_RQ_STATE_NO_CSUM_COMPLETE, &rq->state) ||
+           get_cqe_tls_offload(cqe))
                goto csum_unnecessary;
 
        /* CQE csum doesn't cover padding octets in short ethernet
@@ -1871,7 +1872,7 @@ mlx5e_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
        return skb;
 }
 
-static void
+static struct sk_buff *
 mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
                          struct mlx5_cqe64 *cqe, u16 header_index)
 {
@@ -1895,7 +1896,7 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
                skb = mlx5e_build_linear_skb(rq, hdr, frag_size, rx_headroom, head_size);
 
                if (unlikely(!skb))
-                       return;
+                       return NULL;
 
                /* queue up for recycling/reuse */
                page_ref_inc(head->page);
@@ -1907,7 +1908,7 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
                                     ALIGN(head_size, sizeof(long)));
                if (unlikely(!skb)) {
                        rq->stats->buff_alloc_err++;
-                       return;
+                       return NULL;
                }
 
                prefetchw(skb->data);
@@ -1918,9 +1919,7 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
                skb->tail += head_size;
                skb->len  += head_size;
        }
-       rq->hw_gro_data->skb = skb;
-       NAPI_GRO_CB(skb)->count = 1;
-       skb_shinfo(skb)->gso_size = mpwrq_get_cqe_byte_cnt(cqe) - head_size;
+       return skb;
 }
 
 static void
@@ -1973,13 +1972,14 @@ mlx5e_free_rx_shampo_hd_entry(struct mlx5e_rq *rq, u16 header_index)
 static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
 {
        u16 data_bcnt           = mpwrq_get_cqe_byte_cnt(cqe) - cqe->shampo.header_size;
-       u16 header_index        = be16_to_cpu(cqe->shampo.header_entry_index);
+       u16 header_index        = mlx5e_shampo_get_cqe_header_index(rq, cqe);
        u32 wqe_offset          = be32_to_cpu(cqe->shampo.data_offset);
        u16 cstrides            = mpwrq_get_cqe_consumed_strides(cqe);
        u32 data_offset         = wqe_offset & (PAGE_SIZE - 1);
        u32 cqe_bcnt            = mpwrq_get_cqe_byte_cnt(cqe);
        u16 wqe_id              = be16_to_cpu(cqe->wqe_id);
        u32 page_idx            = wqe_offset >> PAGE_SHIFT;
+       u16 head_size           = cqe->shampo.header_size;
        struct sk_buff **skb    = &rq->hw_gro_data->skb;
        bool flush              = cqe->shampo.flush;
        bool match              = cqe->shampo.match;
@@ -2011,9 +2011,16 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq
        }
 
        if (!*skb) {
-               mlx5e_skb_from_cqe_shampo(rq, wi, cqe, header_index);
+               if (likely(head_size))
+                       *skb = mlx5e_skb_from_cqe_shampo(rq, wi, cqe, header_index);
+               else
+                       *skb = mlx5e_skb_from_cqe_mpwrq_nonlinear(rq, wi, cqe_bcnt, data_offset,
+                                                                 page_idx);
                if (unlikely(!*skb))
                        goto free_hd_entry;
+
+               NAPI_GRO_CB(*skb)->count = 1;
+               skb_shinfo(*skb)->gso_size = cqe_bcnt - head_size;
        } else {
                NAPI_GRO_CB(*skb)->count++;
                if (NAPI_GRO_CB(*skb)->count == 2 &&
@@ -2027,8 +2034,10 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq
                }
        }
 
-       di = &wi->umr.dma_info[page_idx];
-       mlx5e_fill_skb_data(*skb, rq, di, data_bcnt, data_offset);
+       if (likely(head_size)) {
+               di = &wi->umr.dma_info[page_idx];
+               mlx5e_fill_skb_data(*skb, rq, di, data_bcnt, data_offset);
+       }
 
        mlx5e_shampo_complete_rx_cqe(rq, cqe, cqe_bcnt, *skb);
        if (flush)
index 8c9163d..08a7565 100644 (file)
@@ -334,6 +334,7 @@ void mlx5e_self_test(struct net_device *ndev, struct ethtool_test *etest,
                netdev_info(ndev, "\t[%d] %s start..\n", i, st.name);
                buf[count] = st.st_func(priv);
                netdev_info(ndev, "\t[%d] %s end: result(%lld)\n", i, st.name, buf[count]);
+               count++;
        }
 
        mutex_unlock(&priv->state_lock);
index 26e326f..00f1d16 100644 (file)
@@ -1254,9 +1254,6 @@ static void fec_set_corrected_bits_total(struct mlx5e_priv *priv,
        u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {};
        int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);
 
-       if (!MLX5_CAP_PCAM_FEATURE(mdev, ppcnt_statistical_group))
-               return;
-
        MLX5_SET(ppcnt_reg, in, local_port, 1);
        MLX5_SET(ppcnt_reg, in, grp, MLX5_PHYSICAL_LAYER_STATISTICAL_GROUP);
        if (mlx5_core_access_reg(mdev, in, sz, ppcnt_phy_statistical,
@@ -1272,6 +1269,9 @@ static void fec_set_corrected_bits_total(struct mlx5e_priv *priv,
 void mlx5e_stats_fec_get(struct mlx5e_priv *priv,
                         struct ethtool_fec_stats *fec_stats)
 {
+       if (!MLX5_CAP_PCAM_FEATURE(priv->mdev, ppcnt_statistical_group))
+               return;
+
        fec_set_corrected_bits_total(priv, fec_stats);
        fec_set_block_stats(priv, fec_stats);
 }
index 3d908a7..b27532a 100644 (file)
@@ -1414,7 +1414,8 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
                if (err)
                        goto err_out;
 
-               if (!attr->chain && esw_attr->int_port) {
+               if (!attr->chain && esw_attr->int_port &&
+                   attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
                        /* If decap route device is internal port, change the
                         * source vport value in reg_c0 back to uplink just in
                         * case the rule performs goto chain > 0. If we have a miss
@@ -3191,6 +3192,30 @@ actions_match_supported(struct mlx5e_priv *priv,
                return false;
        }
 
+       if (!(~actions &
+             (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) {
+               NL_SET_ERR_MSG_MOD(extack, "Rule cannot support forward+drop action");
+               return false;
+       }
+
+       if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR &&
+           actions & MLX5_FLOW_CONTEXT_ACTION_DROP) {
+               NL_SET_ERR_MSG_MOD(extack, "Drop with modify header action is not supported");
+               return false;
+       }
+
+       if (!(~actions &
+             (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) {
+               NL_SET_ERR_MSG_MOD(extack, "Rule cannot support forward+drop action");
+               return false;
+       }
+
+       if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR &&
+           actions & MLX5_FLOW_CONTEXT_ACTION_DROP) {
+               NL_SET_ERR_MSG_MOD(extack, "Drop with modify header action is not supported");
+               return false;
+       }
+
        if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR &&
            !modify_header_match_supported(priv, &parse_attr->spec, flow_action,
                                           actions, ct_flow, ct_clear, extack))
index 7fd33b3..ee7ecb8 100644 (file)
@@ -208,7 +208,7 @@ static inline void mlx5e_insert_vlan(void *start, struct sk_buff *skb, u16 ihs)
        int cpy1_sz = 2 * ETH_ALEN;
        int cpy2_sz = ihs - cpy1_sz;
 
-       memcpy(vhdr, skb->data, cpy1_sz);
+       memcpy(&vhdr->addrs, skb->data, cpy1_sz);
        vhdr->h_vlan_proto = skb->vlan_proto;
        vhdr->h_vlan_TCI = cpu_to_be16(skb_vlan_tag_get(skb));
        memcpy(&vhdr->h_vlan_encapsulated_proto, skb->data + cpy1_sz, cpy2_sz);
index f690f43..05e08ce 100644 (file)
@@ -1574,6 +1574,8 @@ struct mlx5_esw_bridge_offloads *mlx5_esw_bridge_init(struct mlx5_eswitch *esw)
 {
        struct mlx5_esw_bridge_offloads *br_offloads;
 
+       ASSERT_RTNL();
+
        br_offloads = kvzalloc(sizeof(*br_offloads), GFP_KERNEL);
        if (!br_offloads)
                return ERR_PTR(-ENOMEM);
@@ -1590,6 +1592,8 @@ void mlx5_esw_bridge_cleanup(struct mlx5_eswitch *esw)
 {
        struct mlx5_esw_bridge_offloads *br_offloads = esw->br_offloads;
 
+       ASSERT_RTNL();
+
        if (!br_offloads)
                return;
 
index 3401188..51ac24e 100644 (file)
@@ -21,7 +21,7 @@ DECLARE_EVENT_CLASS(mlx5_esw_bridge_fdb_template,
                            __field(unsigned int, used)
                            ),
                    TP_fast_assign(
-                           strncpy(__entry->dev_name,
+                           strscpy(__entry->dev_name,
                                    netdev_name(fdb->dev),
                                    IFNAMSIZ);
                            memcpy(__entry->addr, fdb->key.addr, ETH_ALEN);
index 11bbcd5..694c540 100644 (file)
@@ -697,7 +697,7 @@ void mlx5_esw_qos_vport_disable(struct mlx5_eswitch *esw, struct mlx5_vport *vpo
 }
 
 int mlx5_esw_qos_set_vport_rate(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
-                               u32 min_rate, u32 max_rate)
+                               u32 max_rate, u32 min_rate)
 {
        int err;
 
index 9a7b256..cfcd72b 100644 (file)
@@ -2838,10 +2838,6 @@ bool mlx5_esw_vport_match_metadata_supported(const struct mlx5_eswitch *esw)
        if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source))
                return false;
 
-       if (mlx5_core_is_ecpf_esw_manager(esw->dev) ||
-           mlx5_ecpf_vport_exists(esw->dev))
-               return false;
-
        return true;
 }
 
index b628917..537c82b 100644 (file)
@@ -2074,6 +2074,8 @@ void mlx5_del_flow_rules(struct mlx5_flow_handle *handle)
                fte->node.del_hw_func = NULL;
                up_write_ref_node(&fte->node, false);
                tree_put_node(&fte->node, false);
+       } else {
+               up_write_ref_node(&fte->node, false);
        }
        kfree(handle);
 }
index 0b0234f..84dbe46 100644 (file)
@@ -132,7 +132,7 @@ static void mlx5_stop_sync_reset_poll(struct mlx5_core_dev *dev)
 {
        struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
 
-       del_timer(&fw_reset->timer);
+       del_timer_sync(&fw_reset->timer);
 }
 
 static void mlx5_sync_reset_clear_reset_requested(struct mlx5_core_dev *dev, bool poll_health)
index d5e4763..1e8ec4f 100644 (file)
@@ -127,6 +127,10 @@ u32 mlx5_chains_get_prio_range(struct mlx5_fs_chains *chains)
        if (mlx5_chains_ignore_flow_level_supported(chains))
                return UINT_MAX;
 
+       if (!chains->dev->priv.eswitch ||
+           chains->dev->priv.eswitch->mode != MLX5_ESWITCH_OFFLOADS)
+               return 1;
+
        /* We should get here only for eswitch case */
        return FDB_TC_MAX_PRIO;
 }
@@ -211,7 +215,7 @@ static int
 create_chain_restore(struct fs_chain *chain)
 {
        struct mlx5_eswitch *esw = chain->chains->dev->priv.eswitch;
-       char modact[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)];
+       u8 modact[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
        struct mlx5_fs_chains *chains = chain->chains;
        enum mlx5e_tc_attr_to_reg chain_to_reg;
        struct mlx5_modify_hdr *mod_hdr;
index 2c774f3..bba72b2 100644 (file)
@@ -526,7 +526,7 @@ static int handle_hca_cap(struct mlx5_core_dev *dev, void *set_ctx)
 
        /* Check log_max_qp from HCA caps to set in current profile */
        if (prof->log_max_qp == LOG_MAX_SUPPORTED_QPS) {
-               prof->log_max_qp = MLX5_CAP_GEN_MAX(dev, log_max_qp);
+               prof->log_max_qp = min_t(u8, 17, MLX5_CAP_GEN_MAX(dev, log_max_qp));
        } else if (MLX5_CAP_GEN_MAX(dev, log_max_qp) < prof->log_max_qp) {
                mlx5_core_warn(dev, "log_max_qp value in current profile is %d, changing it to HCA capability limit (%d)\n",
                               prof->log_max_qp,
@@ -1840,10 +1840,12 @@ static const struct pci_device_id mlx5_core_pci_table[] = {
        { PCI_VDEVICE(MELLANOX, 0x101e), MLX5_PCI_DEV_IS_VF},   /* ConnectX Family mlx5Gen Virtual Function */
        { PCI_VDEVICE(MELLANOX, 0x101f) },                      /* ConnectX-6 LX */
        { PCI_VDEVICE(MELLANOX, 0x1021) },                      /* ConnectX-7 */
+       { PCI_VDEVICE(MELLANOX, 0x1023) },                      /* ConnectX-8 */
        { PCI_VDEVICE(MELLANOX, 0xa2d2) },                      /* BlueField integrated ConnectX-5 network controller */
        { PCI_VDEVICE(MELLANOX, 0xa2d3), MLX5_PCI_DEV_IS_VF},   /* BlueField integrated ConnectX-5 network controller VF */
        { PCI_VDEVICE(MELLANOX, 0xa2d6) },                      /* BlueField-2 integrated ConnectX-6 Dx network controller */
        { PCI_VDEVICE(MELLANOX, 0xa2dc) },                      /* BlueField-3 integrated ConnectX-7 network controller */
+       { PCI_VDEVICE(MELLANOX, 0xa2df) },                      /* BlueField-4 integrated ConnectX-8 network controller */
        { 0, }
 };
 
index 1ef2b6a..7b16a11 100644 (file)
@@ -406,23 +406,24 @@ int mlx5_query_module_eeprom(struct mlx5_core_dev *dev,
 
        switch (module_id) {
        case MLX5_MODULE_ID_SFP:
-               mlx5_sfp_eeprom_params_set(&query.i2c_address, &query.page, &query.offset);
+               mlx5_sfp_eeprom_params_set(&query.i2c_address, &query.page, &offset);
                break;
        case MLX5_MODULE_ID_QSFP:
        case MLX5_MODULE_ID_QSFP_PLUS:
        case MLX5_MODULE_ID_QSFP28:
-               mlx5_qsfp_eeprom_params_set(&query.i2c_address, &query.page, &query.offset);
+               mlx5_qsfp_eeprom_params_set(&query.i2c_address, &query.page, &offset);
                break;
        default:
                mlx5_core_err(dev, "Module ID not recognized: 0x%x\n", module_id);
                return -EINVAL;
        }
 
-       if (query.offset + size > MLX5_EEPROM_PAGE_LENGTH)
+       if (offset + size > MLX5_EEPROM_PAGE_LENGTH)
                /* Cross pages read, read until offset 256 in low page */
-               size -= offset + size - MLX5_EEPROM_PAGE_LENGTH;
+               size = MLX5_EEPROM_PAGE_LENGTH - offset;
 
        query.size = size;
+       query.offset = offset;
 
        return mlx5_query_mcia(dev, &query, data);
 }
index 7f6fd9c..e289cfd 100644 (file)
@@ -4,7 +4,6 @@
 #include "dr_types.h"
 
 #define DR_ICM_MODIFY_HDR_ALIGN_BASE 64
-#define DR_ICM_SYNC_THRESHOLD_POOL (64 * 1024 * 1024)
 
 struct mlx5dr_icm_pool {
        enum mlx5dr_icm_type icm_type;
@@ -136,37 +135,35 @@ static void dr_icm_pool_mr_destroy(struct mlx5dr_icm_mr *icm_mr)
        kvfree(icm_mr);
 }
 
-static int dr_icm_chunk_ste_init(struct mlx5dr_icm_chunk *chunk)
+static int dr_icm_buddy_get_ste_size(struct mlx5dr_icm_buddy_mem *buddy)
 {
-       chunk->ste_arr = kvzalloc(chunk->num_of_entries *
-                                 sizeof(chunk->ste_arr[0]), GFP_KERNEL);
-       if (!chunk->ste_arr)
-               return -ENOMEM;
-
-       chunk->hw_ste_arr = kvzalloc(chunk->num_of_entries *
-                                    DR_STE_SIZE_REDUCED, GFP_KERNEL);
-       if (!chunk->hw_ste_arr)
-               goto out_free_ste_arr;
-
-       chunk->miss_list = kvmalloc(chunk->num_of_entries *
-                                   sizeof(chunk->miss_list[0]), GFP_KERNEL);
-       if (!chunk->miss_list)
-               goto out_free_hw_ste_arr;
+       /* We support only one type of STE size, both for ConnectX-5 and later
+        * devices. Once the support for match STE which has a larger tag is
+        * added (32B instead of 16B), the STE size for devices later than
+        * ConnectX-5 needs to account for that.
+        */
+       return DR_STE_SIZE_REDUCED;
+}
 
-       return 0;
+static void dr_icm_chunk_ste_init(struct mlx5dr_icm_chunk *chunk, int offset)
+{
+       struct mlx5dr_icm_buddy_mem *buddy = chunk->buddy_mem;
+       int index = offset / DR_STE_SIZE;
 
-out_free_hw_ste_arr:
-       kvfree(chunk->hw_ste_arr);
-out_free_ste_arr:
-       kvfree(chunk->ste_arr);
-       return -ENOMEM;
+       chunk->ste_arr = &buddy->ste_arr[index];
+       chunk->miss_list = &buddy->miss_list[index];
+       chunk->hw_ste_arr = buddy->hw_ste_arr +
+                           index * dr_icm_buddy_get_ste_size(buddy);
 }
 
 static void dr_icm_chunk_ste_cleanup(struct mlx5dr_icm_chunk *chunk)
 {
-       kvfree(chunk->miss_list);
-       kvfree(chunk->hw_ste_arr);
-       kvfree(chunk->ste_arr);
+       struct mlx5dr_icm_buddy_mem *buddy = chunk->buddy_mem;
+
+       memset(chunk->hw_ste_arr, 0,
+              chunk->num_of_entries * dr_icm_buddy_get_ste_size(buddy));
+       memset(chunk->ste_arr, 0,
+              chunk->num_of_entries * sizeof(chunk->ste_arr[0]));
 }
 
 static enum mlx5dr_icm_type
@@ -189,6 +186,44 @@ static void dr_icm_chunk_destroy(struct mlx5dr_icm_chunk *chunk,
        kvfree(chunk);
 }
 
+static int dr_icm_buddy_init_ste_cache(struct mlx5dr_icm_buddy_mem *buddy)
+{
+       int num_of_entries =
+               mlx5dr_icm_pool_chunk_size_to_entries(buddy->pool->max_log_chunk_sz);
+
+       buddy->ste_arr = kvcalloc(num_of_entries,
+                                 sizeof(struct mlx5dr_ste), GFP_KERNEL);
+       if (!buddy->ste_arr)
+               return -ENOMEM;
+
+       /* Preallocate full STE size on non-ConnectX-5 devices since
+        * we need to support both full and reduced with the same cache.
+        */
+       buddy->hw_ste_arr = kvcalloc(num_of_entries,
+                                    dr_icm_buddy_get_ste_size(buddy), GFP_KERNEL);
+       if (!buddy->hw_ste_arr)
+               goto free_ste_arr;
+
+       buddy->miss_list = kvmalloc(num_of_entries * sizeof(struct list_head), GFP_KERNEL);
+       if (!buddy->miss_list)
+               goto free_hw_ste_arr;
+
+       return 0;
+
+free_hw_ste_arr:
+       kvfree(buddy->hw_ste_arr);
+free_ste_arr:
+       kvfree(buddy->ste_arr);
+       return -ENOMEM;
+}
+
+static void dr_icm_buddy_cleanup_ste_cache(struct mlx5dr_icm_buddy_mem *buddy)
+{
+       kvfree(buddy->ste_arr);
+       kvfree(buddy->hw_ste_arr);
+       kvfree(buddy->miss_list);
+}
+
 static int dr_icm_buddy_create(struct mlx5dr_icm_pool *pool)
 {
        struct mlx5dr_icm_buddy_mem *buddy;
@@ -208,11 +243,19 @@ static int dr_icm_buddy_create(struct mlx5dr_icm_pool *pool)
        buddy->icm_mr = icm_mr;
        buddy->pool = pool;
 
+       if (pool->icm_type == DR_ICM_TYPE_STE) {
+               /* Reduce allocations by preallocating and reusing the STE structures */
+               if (dr_icm_buddy_init_ste_cache(buddy))
+                       goto err_cleanup_buddy;
+       }
+
        /* add it to the -start- of the list in order to search in it first */
        list_add(&buddy->list_node, &pool->buddy_mem_list);
 
        return 0;
 
+err_cleanup_buddy:
+       mlx5dr_buddy_cleanup(buddy);
 err_free_buddy:
        kvfree(buddy);
 free_mr:
@@ -234,6 +277,9 @@ static void dr_icm_buddy_destroy(struct mlx5dr_icm_buddy_mem *buddy)
 
        mlx5dr_buddy_cleanup(buddy);
 
+       if (buddy->pool->icm_type == DR_ICM_TYPE_STE)
+               dr_icm_buddy_cleanup_ste_cache(buddy);
+
        kvfree(buddy);
 }
 
@@ -261,34 +307,30 @@ dr_icm_chunk_create(struct mlx5dr_icm_pool *pool,
        chunk->byte_size =
                mlx5dr_icm_pool_chunk_size_to_byte(chunk_size, pool->icm_type);
        chunk->seg = seg;
+       chunk->buddy_mem = buddy_mem_pool;
 
-       if (pool->icm_type == DR_ICM_TYPE_STE && dr_icm_chunk_ste_init(chunk)) {
-               mlx5dr_err(pool->dmn,
-                          "Failed to init ste arrays (order: %d)\n",
-                          chunk_size);
-               goto out_free_chunk;
-       }
+       if (pool->icm_type == DR_ICM_TYPE_STE)
+               dr_icm_chunk_ste_init(chunk, offset);
 
        buddy_mem_pool->used_memory += chunk->byte_size;
-       chunk->buddy_mem = buddy_mem_pool;
        INIT_LIST_HEAD(&chunk->chunk_list);
 
        /* chunk now is part of the used_list */
        list_add_tail(&chunk->chunk_list, &buddy_mem_pool->used_list);
 
        return chunk;
-
-out_free_chunk:
-       kvfree(chunk);
-       return NULL;
 }
 
 static bool dr_icm_pool_is_sync_required(struct mlx5dr_icm_pool *pool)
 {
-       if (pool->hot_memory_size > DR_ICM_SYNC_THRESHOLD_POOL)
-               return true;
+       int allow_hot_size;
+
+       /* sync when hot memory reaches half of the pool size */
+       allow_hot_size =
+               mlx5dr_icm_pool_chunk_size_to_byte(pool->max_log_chunk_sz,
+                                                  pool->icm_type) / 2;
 
-       return false;
+       return pool->hot_memory_size > allow_hot_size;
 }
 
 static int dr_icm_pool_sync_all_buddy_pools(struct mlx5dr_icm_pool *pool)
index e87cf49..38971fe 100644 (file)
@@ -13,18 +13,6 @@ static bool dr_mask_is_dmac_set(struct mlx5dr_match_spec *spec)
        return (spec->dmac_47_16 || spec->dmac_15_0);
 }
 
-static bool dr_mask_is_src_addr_set(struct mlx5dr_match_spec *spec)
-{
-       return (spec->src_ip_127_96 || spec->src_ip_95_64 ||
-               spec->src_ip_63_32 || spec->src_ip_31_0);
-}
-
-static bool dr_mask_is_dst_addr_set(struct mlx5dr_match_spec *spec)
-{
-       return (spec->dst_ip_127_96 || spec->dst_ip_95_64 ||
-               spec->dst_ip_63_32 || spec->dst_ip_31_0);
-}
-
 static bool dr_mask_is_l3_base_set(struct mlx5dr_match_spec *spec)
 {
        return (spec->ip_protocol || spec->frag || spec->tcp_flags ||
@@ -503,11 +491,11 @@ static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher,
                                                    &mask, inner, rx);
 
                if (outer_ipv == DR_RULE_IPV6) {
-                       if (dr_mask_is_dst_addr_set(&mask.outer))
+                       if (DR_MASK_IS_DST_IP_SET(&mask.outer))
                                mlx5dr_ste_build_eth_l3_ipv6_dst(ste_ctx, &sb[idx++],
                                                                 &mask, inner, rx);
 
-                       if (dr_mask_is_src_addr_set(&mask.outer))
+                       if (DR_MASK_IS_SRC_IP_SET(&mask.outer))
                                mlx5dr_ste_build_eth_l3_ipv6_src(ste_ctx, &sb[idx++],
                                                                 &mask, inner, rx);
 
@@ -610,11 +598,11 @@ static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher,
                                                    &mask, inner, rx);
 
                if (inner_ipv == DR_RULE_IPV6) {
-                       if (dr_mask_is_dst_addr_set(&mask.inner))
+                       if (DR_MASK_IS_DST_IP_SET(&mask.inner))
                                mlx5dr_ste_build_eth_l3_ipv6_dst(ste_ctx, &sb[idx++],
                                                                 &mask, inner, rx);
 
-                       if (dr_mask_is_src_addr_set(&mask.inner))
+                       if (DR_MASK_IS_SRC_IP_SET(&mask.inner))
                                mlx5dr_ste_build_eth_l3_ipv6_src(ste_ctx, &sb[idx++],
                                                                 &mask, inner, rx);
 
index 7e61742..187e29b 100644 (file)
@@ -602,12 +602,34 @@ int mlx5dr_ste_set_action_decap_l3_list(struct mlx5dr_ste_ctx *ste_ctx,
                                                 used_hw_action_num);
 }
 
+static int dr_ste_build_pre_check_spec(struct mlx5dr_domain *dmn,
+                                      struct mlx5dr_match_spec *spec)
+{
+       if (spec->ip_version) {
+               if (spec->ip_version != 0xf) {
+                       mlx5dr_err(dmn,
+                                  "Partial ip_version mask with src/dst IP is not supported\n");
+                       return -EINVAL;
+               }
+       } else if (spec->ethertype != 0xffff &&
+                  (DR_MASK_IS_SRC_IP_SET(spec) || DR_MASK_IS_DST_IP_SET(spec))) {
+               mlx5dr_err(dmn,
+                          "Partial/no ethertype mask with src/dst IP is not supported\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 int mlx5dr_ste_build_pre_check(struct mlx5dr_domain *dmn,
                               u8 match_criteria,
                               struct mlx5dr_match_param *mask,
                               struct mlx5dr_match_param *value)
 {
-       if (!value && (match_criteria & DR_MATCHER_CRITERIA_MISC)) {
+       if (value)
+               return 0;
+
+       if (match_criteria & DR_MATCHER_CRITERIA_MISC) {
                if (mask->misc.source_port && mask->misc.source_port != 0xffff) {
                        mlx5dr_err(dmn,
                                   "Partial mask source_port is not supported\n");
@@ -621,6 +643,14 @@ int mlx5dr_ste_build_pre_check(struct mlx5dr_domain *dmn,
                }
        }
 
+       if ((match_criteria & DR_MATCHER_CRITERIA_OUTER) &&
+           dr_ste_build_pre_check_spec(dmn, &mask->outer))
+               return -EINVAL;
+
+       if ((match_criteria & DR_MATCHER_CRITERIA_INNER) &&
+           dr_ste_build_pre_check_spec(dmn, &mask->inner))
+               return -EINVAL;
+
        return 0;
 }
 
index 1b3d484..55fcb75 100644 (file)
@@ -798,6 +798,16 @@ struct mlx5dr_match_param {
                                       (_misc3)->icmpv4_code || \
                                       (_misc3)->icmpv4_header_data)
 
+#define DR_MASK_IS_SRC_IP_SET(_spec) ((_spec)->src_ip_127_96 || \
+                                     (_spec)->src_ip_95_64  || \
+                                     (_spec)->src_ip_63_32  || \
+                                     (_spec)->src_ip_31_0)
+
+#define DR_MASK_IS_DST_IP_SET(_spec) ((_spec)->dst_ip_127_96 || \
+                                     (_spec)->dst_ip_95_64  || \
+                                     (_spec)->dst_ip_63_32  || \
+                                     (_spec)->dst_ip_31_0)
+
 struct mlx5dr_esw_caps {
        u64 drop_icm_address_rx;
        u64 drop_icm_address_tx;
index a476da2..3f31146 100644 (file)
@@ -233,7 +233,11 @@ static bool contain_vport_reformat_action(struct mlx5_flow_rule *dst)
                dst->dest_attr.vport.flags & MLX5_FLOW_DEST_VPORT_REFORMAT_ID;
 }
 
-#define MLX5_FLOW_CONTEXT_ACTION_MAX  32
+/* We want to support a rule with 32 destinations, which means we need to
+ * account for 32 destinations plus usually a counter plus one more action
+ * for a multi-destination flow table.
+ */
+#define MLX5_FLOW_CONTEXT_ACTION_MAX  34
 static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
                                  struct mlx5_flow_table *ft,
                                  struct mlx5_flow_group *group,
@@ -403,9 +407,9 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
                        enum mlx5_flow_destination_type type = dst->dest_attr.type;
                        u32 id;
 
-                       if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX ||
-                           num_term_actions >= MLX5_FLOW_CONTEXT_ACTION_MAX) {
-                               err = -ENOSPC;
+                       if (fs_dr_num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX ||
+                           num_term_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) {
+                               err = -EOPNOTSUPP;
                                goto free_actions;
                        }
 
@@ -478,8 +482,9 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
                            MLX5_FLOW_DESTINATION_TYPE_COUNTER)
                                continue;
 
-                       if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) {
-                               err = -ENOSPC;
+                       if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX ||
+                           fs_dr_num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) {
+                               err = -EOPNOTSUPP;
                                goto free_actions;
                        }
 
@@ -499,14 +504,28 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
        params.match_sz = match_sz;
        params.match_buf = (u64 *)fte->val;
        if (num_term_actions == 1) {
-               if (term_actions->reformat)
+               if (term_actions->reformat) {
+                       if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) {
+                               err = -EOPNOTSUPP;
+                               goto free_actions;
+                       }
                        actions[num_actions++] = term_actions->reformat;
+               }
 
+               if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) {
+                       err = -EOPNOTSUPP;
+                       goto free_actions;
+               }
                actions[num_actions++] = term_actions->dest;
        } else if (num_term_actions > 1) {
                bool ignore_flow_level =
                        !!(fte->action.flags & FLOW_ACT_IGNORE_FLOW_LEVEL);
 
+               if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX ||
+                   fs_dr_num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) {
+                       err = -EOPNOTSUPP;
+                       goto free_actions;
+               }
                tmp_action = mlx5dr_action_create_mult_dest_tbl(domain,
                                                                term_actions,
                                                                num_term_actions,
index c7c9313..dfa2234 100644 (file)
@@ -160,6 +160,11 @@ struct mlx5dr_icm_buddy_mem {
         * sync_ste command sets them free.
         */
        struct list_head        hot_list;
+
+       /* Memory optimisation */
+       struct mlx5dr_ste       *ste_arr;
+       struct list_head        *miss_list;
+       u8                      *hw_ste_arr;
 };
 
 int mlx5dr_buddy_init(struct mlx5dr_icm_buddy_mem *buddy,
index ca5f117..ce5970b 100644 (file)
@@ -40,11 +40,12 @@ static int lan966x_mac_wait_for_completion(struct lan966x *lan966x)
 {
        u32 val;
 
-       return readx_poll_timeout(lan966x_mac_get_status,
-               lan966x, val,
-               (ANA_MACACCESS_MAC_TABLE_CMD_GET(val)) ==
-               MACACCESS_CMD_IDLE,
-               TABLE_UPDATE_SLEEP_US, TABLE_UPDATE_TIMEOUT_US);
+       return readx_poll_timeout_atomic(lan966x_mac_get_status,
+                                        lan966x, val,
+                                        (ANA_MACACCESS_MAC_TABLE_CMD_GET(val)) ==
+                                        MACACCESS_CMD_IDLE,
+                                        TABLE_UPDATE_SLEEP_US,
+                                        TABLE_UPDATE_TIMEOUT_US);
 }
 
 static void lan966x_mac_select(struct lan966x *lan966x,
index 2cb70da..1f60fd1 100644 (file)
@@ -182,9 +182,9 @@ static int lan966x_port_inj_ready(struct lan966x *lan966x, u8 grp)
 {
        u32 val;
 
-       return readx_poll_timeout(lan966x_port_inj_status, lan966x, val,
-                                 QS_INJ_STATUS_FIFO_RDY_GET(val) & BIT(grp),
-                                 READL_SLEEP_US, READL_TIMEOUT_US);
+       return readx_poll_timeout_atomic(lan966x_port_inj_status, lan966x, val,
+                                        QS_INJ_STATUS_FIFO_RDY_GET(val) & BIT(grp),
+                                        READL_SLEEP_US, READL_TIMEOUT_US);
 }
 
 static int lan966x_port_ifh_xmit(struct sk_buff *skb,
index 59783fc..10b866e 100644 (file)
@@ -1103,7 +1103,7 @@ void sparx5_get_stats64(struct net_device *ndev,
        stats->tx_carrier_errors = portstats[spx5_stats_tx_csense_cnt];
        stats->tx_window_errors = portstats[spx5_stats_tx_late_coll_cnt];
        stats->rx_dropped = portstats[spx5_stats_ana_ac_port_stat_lsb_cnt];
-       for (idx = 0; idx < 2 * SPX5_PRIOS; ++idx, ++stats)
+       for (idx = 0; idx < 2 * SPX5_PRIOS; ++idx)
                stats->rx_dropped += portstats[spx5_stats_green_p0_rx_port_drop
                                               + idx];
        stats->tx_dropped = portstats[spx5_stats_tx_local_drop];
index dc7e5ea..148d431 100644 (file)
@@ -145,9 +145,9 @@ static void sparx5_xtr_grp(struct sparx5 *sparx5, u8 grp, bool byte_swap)
        skb_put(skb, byte_cnt - ETH_FCS_LEN);
        eth_skb_pad(skb);
        skb->protocol = eth_type_trans(skb, netdev);
-       netif_rx(skb);
        netdev->stats.rx_bytes += skb->len;
        netdev->stats.rx_packets++;
+       netif_rx(skb);
 }
 
 static int sparx5_inject(struct sparx5 *sparx5,
index 455293a..fd3ceb7 100644 (file)
@@ -549,14 +549,18 @@ EXPORT_SYMBOL(ocelot_vlan_add);
 int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid)
 {
        struct ocelot_port *ocelot_port = ocelot->ports[port];
+       bool del_pvid = false;
        int err;
 
+       if (ocelot_port->pvid_vlan && ocelot_port->pvid_vlan->vid == vid)
+               del_pvid = true;
+
        err = ocelot_vlan_member_del(ocelot, port, vid);
        if (err)
                return err;
 
        /* Ingress */
-       if (ocelot_port->pvid_vlan && ocelot_port->pvid_vlan->vid == vid)
+       if (del_pvid)
                ocelot_port_set_pvid(ocelot, port, NULL);
 
        /* Egress */
@@ -1432,6 +1436,8 @@ static void
 ocelot_populate_ipv4_ptp_event_trap_key(struct ocelot_vcap_filter *trap)
 {
        trap->key_type = OCELOT_VCAP_KEY_IPV4;
+       trap->key.ipv4.proto.value[0] = IPPROTO_UDP;
+       trap->key.ipv4.proto.mask[0] = 0xff;
        trap->key.ipv4.dport.value = PTP_EV_PORT;
        trap->key.ipv4.dport.mask = 0xffff;
 }
@@ -1440,6 +1446,8 @@ static void
 ocelot_populate_ipv6_ptp_event_trap_key(struct ocelot_vcap_filter *trap)
 {
        trap->key_type = OCELOT_VCAP_KEY_IPV6;
+       trap->key.ipv4.proto.value[0] = IPPROTO_UDP;
+       trap->key.ipv4.proto.mask[0] = 0xff;
        trap->key.ipv6.dport.value = PTP_EV_PORT;
        trap->key.ipv6.dport.mask = 0xffff;
 }
@@ -1448,6 +1456,8 @@ static void
 ocelot_populate_ipv4_ptp_general_trap_key(struct ocelot_vcap_filter *trap)
 {
        trap->key_type = OCELOT_VCAP_KEY_IPV4;
+       trap->key.ipv4.proto.value[0] = IPPROTO_UDP;
+       trap->key.ipv4.proto.mask[0] = 0xff;
        trap->key.ipv4.dport.value = PTP_GEN_PORT;
        trap->key.ipv4.dport.mask = 0xffff;
 }
@@ -1456,6 +1466,8 @@ static void
 ocelot_populate_ipv6_ptp_general_trap_key(struct ocelot_vcap_filter *trap)
 {
        trap->key_type = OCELOT_VCAP_KEY_IPV6;
+       trap->key.ipv4.proto.value[0] = IPPROTO_UDP;
+       trap->key.ipv4.proto.mask[0] = 0xff;
        trap->key.ipv6.dport.value = PTP_GEN_PORT;
        trap->key.ipv6.dport.mask = 0xffff;
 }
@@ -1737,12 +1749,11 @@ void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data)
 }
 EXPORT_SYMBOL(ocelot_get_strings);
 
+/* Caller must hold &ocelot->stats_lock */
 static void ocelot_update_stats(struct ocelot *ocelot)
 {
        int i, j;
 
-       mutex_lock(&ocelot->stats_lock);
-
        for (i = 0; i < ocelot->num_phys_ports; i++) {
                /* Configure the port to read the stats from */
                ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(i), SYS_STAT_CFG);
@@ -1761,8 +1772,6 @@ static void ocelot_update_stats(struct ocelot *ocelot)
                                              ~(u64)U32_MAX) + val;
                }
        }
-
-       mutex_unlock(&ocelot->stats_lock);
 }
 
 static void ocelot_check_stats_work(struct work_struct *work)
@@ -1771,7 +1780,9 @@ static void ocelot_check_stats_work(struct work_struct *work)
        struct ocelot *ocelot = container_of(del_work, struct ocelot,
                                             stats_work);
 
+       mutex_lock(&ocelot->stats_lock);
        ocelot_update_stats(ocelot);
+       mutex_unlock(&ocelot->stats_lock);
 
        queue_delayed_work(ocelot->stats_queue, &ocelot->stats_work,
                           OCELOT_STATS_CHECK_DELAY);
@@ -1781,12 +1792,16 @@ void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data)
 {
        int i;
 
+       mutex_lock(&ocelot->stats_lock);
+
        /* check and update now */
        ocelot_update_stats(ocelot);
 
        /* Copy all counters */
        for (i = 0; i < ocelot->num_stats; i++)
                *data++ = ocelot->stats[port * ocelot->num_stats + i];
+
+       mutex_unlock(&ocelot->stats_lock);
 }
 EXPORT_SYMBOL(ocelot_get_ethtool_stats);
 
index 784292b..1543e47 100644 (file)
@@ -723,6 +723,8 @@ static inline bool nfp_fl_is_netdev_to_offload(struct net_device *netdev)
                return true;
        if (netif_is_gretap(netdev))
                return true;
+       if (netif_is_ip6gretap(netdev))
+               return true;
 
        return false;
 }
index dfb4468..cb43651 100644 (file)
@@ -922,8 +922,8 @@ nfp_tunnel_add_shared_mac(struct nfp_app *app, struct net_device *netdev,
                          int port, bool mod)
 {
        struct nfp_flower_priv *priv = app->priv;
-       int ida_idx = NFP_MAX_MAC_INDEX, err;
        struct nfp_tun_offloaded_mac *entry;
+       int ida_idx = -1, err;
        u16 nfp_mac_idx = 0;
 
        entry = nfp_tunnel_lookup_offloaded_macs(app, netdev->dev_addr);
@@ -997,7 +997,7 @@ err_remove_hash:
 err_free_entry:
        kfree(entry);
 err_free_ida:
-       if (ida_idx != NFP_MAX_MAC_INDEX)
+       if (ida_idx != -1)
                ida_simple_remove(&priv->tun.mac_off_ids, ida_idx);
 
        return err;
@@ -1011,6 +1011,7 @@ nfp_tunnel_del_shared_mac(struct nfp_app *app, struct net_device *netdev,
        struct nfp_flower_repr_priv *repr_priv;
        struct nfp_tun_offloaded_mac *entry;
        struct nfp_repr *repr;
+       u16 nfp_mac_idx;
        int ida_idx;
 
        entry = nfp_tunnel_lookup_offloaded_macs(app, mac);
@@ -1029,8 +1030,6 @@ nfp_tunnel_del_shared_mac(struct nfp_app *app, struct net_device *netdev,
                entry->bridge_count--;
 
                if (!entry->bridge_count && entry->ref_count) {
-                       u16 nfp_mac_idx;
-
                        nfp_mac_idx = entry->index & ~NFP_TUN_PRE_TUN_IDX_BIT;
                        if (__nfp_tunnel_offload_mac(app, mac, nfp_mac_idx,
                                                     false)) {
@@ -1046,7 +1045,6 @@ nfp_tunnel_del_shared_mac(struct nfp_app *app, struct net_device *netdev,
 
        /* If MAC is now used by 1 repr set the offloaded MAC index to port. */
        if (entry->ref_count == 1 && list_is_singular(&entry->repr_list)) {
-               u16 nfp_mac_idx;
                int port, err;
 
                repr_priv = list_first_entry(&entry->repr_list,
@@ -1074,8 +1072,14 @@ nfp_tunnel_del_shared_mac(struct nfp_app *app, struct net_device *netdev,
        WARN_ON_ONCE(rhashtable_remove_fast(&priv->tun.offloaded_macs,
                                            &entry->ht_node,
                                            offloaded_macs_params));
+
+       if (nfp_flower_is_supported_bridge(netdev))
+               nfp_mac_idx = entry->index & ~NFP_TUN_PRE_TUN_IDX_BIT;
+       else
+               nfp_mac_idx = entry->index;
+
        /* If MAC has global ID then extract and free the ida entry. */
-       if (nfp_tunnel_is_mac_idx_global(entry->index)) {
+       if (nfp_tunnel_is_mac_idx_global(nfp_mac_idx)) {
                ida_idx = nfp_tunnel_get_ida_from_global_mac_idx(entry->index);
                ida_simple_remove(&priv->tun.mac_off_ids, ida_idx);
        }
index 16a4cba..c672f92 100644 (file)
@@ -749,6 +749,7 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id)
        const struct ether3_data *data = id->data;
        struct net_device *dev;
        int bus_type, ret;
+       u8 addr[ETH_ALEN];
 
        ether3_banner();
 
@@ -776,7 +777,8 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id)
        priv(dev)->seeq = priv(dev)->base + data->base_offset;
        dev->irq = ec->irq;
 
-       ether3_addr(dev->dev_addr, ec);
+       ether3_addr(addr, ec);
+       eth_hw_addr_set(dev, addr);
 
        priv(dev)->dev = dev;
        timer_setup(&priv(dev)->timer, ether3_ledoff, 0);
index dd6f69c..fc9cef9 100644 (file)
@@ -1648,7 +1648,7 @@ static int smc911x_ethtool_geteeprom(struct net_device *dev,
                        return ret;
                if ((ret=smc911x_ethtool_read_eeprom_byte(dev, &eebuf[i]))!=0)
                        return ret;
-               }
+       }
        memcpy(data, eebuf+eeprom->offset, eeprom->len);
        return 0;
 }
@@ -1667,11 +1667,11 @@ static int smc911x_ethtool_seteeprom(struct net_device *dev,
                        return ret;
                /* write byte */
                if ((ret=smc911x_ethtool_write_eeprom_byte(dev, *data))!=0)
-                        return ret;
+                       return ret;
                if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_WRITE_, i ))!=0)
                        return ret;
-               }
-        return 0;
+       }
+       return 0;
 }
 
 static int smc911x_ethtool_geteeprom_len(struct net_device *dev)
index 617d0e4..09644ab 100644 (file)
@@ -756,7 +756,7 @@ static int sun8i_dwmac_reset(struct stmmac_priv *priv)
 
        if (err) {
                dev_err(priv->device, "EMAC reset timeout\n");
-               return -EFAULT;
+               return err;
        }
        return 0;
 }
index e2e0f97..c3f10a9 100644 (file)
 #define ETHER_CLK_SEL_RMII_CLK_EN BIT(2)
 #define ETHER_CLK_SEL_RMII_CLK_RST BIT(3)
 #define ETHER_CLK_SEL_DIV_SEL_2 BIT(4)
-#define ETHER_CLK_SEL_DIV_SEL_20 BIT(0)
+#define ETHER_CLK_SEL_DIV_SEL_20 0
 #define ETHER_CLK_SEL_FREQ_SEL_125M    (BIT(9) | BIT(8))
 #define ETHER_CLK_SEL_FREQ_SEL_50M     BIT(9)
 #define ETHER_CLK_SEL_FREQ_SEL_25M     BIT(8)
 #define ETHER_CLK_SEL_FREQ_SEL_2P5M    0
-#define ETHER_CLK_SEL_TX_CLK_EXT_SEL_IN BIT(0)
+#define ETHER_CLK_SEL_TX_CLK_EXT_SEL_IN 0
 #define ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC BIT(10)
 #define ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV BIT(11)
-#define ETHER_CLK_SEL_RX_CLK_EXT_SEL_IN  BIT(0)
+#define ETHER_CLK_SEL_RX_CLK_EXT_SEL_IN  0
 #define ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC BIT(12)
 #define ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV BIT(13)
-#define ETHER_CLK_SEL_TX_CLK_O_TX_I     BIT(0)
+#define ETHER_CLK_SEL_TX_CLK_O_TX_I     0
 #define ETHER_CLK_SEL_TX_CLK_O_RMII_I   BIT(14)
 #define ETHER_CLK_SEL_TX_O_E_N_IN       BIT(15)
-#define ETHER_CLK_SEL_RMII_CLK_SEL_IN   BIT(0)
+#define ETHER_CLK_SEL_RMII_CLK_SEL_IN   0
 #define ETHER_CLK_SEL_RMII_CLK_SEL_RX_C         BIT(16)
 
 #define ETHER_CLK_SEL_RX_TX_CLK_EN (ETHER_CLK_SEL_RX_CLK_EN | ETHER_CLK_SEL_TX_CLK_EN)
@@ -49,13 +49,15 @@ struct visconti_eth {
        void __iomem *reg;
        u32 phy_intf_sel;
        struct clk *phy_ref_clk;
+       struct device *dev;
        spinlock_t lock; /* lock to protect register update */
 };
 
 static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed)
 {
        struct visconti_eth *dwmac = priv;
-       unsigned int val, clk_sel_val;
+       struct net_device *netdev = dev_get_drvdata(dwmac->dev);
+       unsigned int val, clk_sel_val = 0;
        unsigned long flags;
 
        spin_lock_irqsave(&dwmac->lock, flags);
@@ -85,7 +87,9 @@ static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed)
                break;
        default:
                /* No bit control */
-               break;
+               netdev_err(netdev, "Unsupported speed request (%d)", speed);
+               spin_unlock_irqrestore(&dwmac->lock, flags);
+               return;
        }
 
        writel(val, dwmac->reg + MAC_CTRL_REG);
@@ -96,31 +100,41 @@ static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed)
        val |= ETHER_CLK_SEL_TX_O_E_N_IN;
        writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
 
+       /* Set Clock-Mux, Start clock, Set TX_O direction */
        switch (dwmac->phy_intf_sel) {
        case ETHER_CONFIG_INTF_RGMII:
                val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC;
+               writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
+
+               val |= ETHER_CLK_SEL_RX_TX_CLK_EN;
+               writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
+
+               val &= ~ETHER_CLK_SEL_TX_O_E_N_IN;
+               writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
                break;
        case ETHER_CONFIG_INTF_RMII:
                val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV |
-                       ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC | ETHER_CLK_SEL_TX_O_E_N_IN |
+                       ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV | ETHER_CLK_SEL_TX_O_E_N_IN |
                        ETHER_CLK_SEL_RMII_CLK_SEL_RX_C;
+               writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
+
+               val |= ETHER_CLK_SEL_RMII_CLK_RST;
+               writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
+
+               val |= ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN;
+               writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
                break;
        case ETHER_CONFIG_INTF_MII:
        default:
                val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC |
-                       ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV | ETHER_CLK_SEL_TX_O_E_N_IN |
-                       ETHER_CLK_SEL_RMII_CLK_EN;
+                       ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC | ETHER_CLK_SEL_TX_O_E_N_IN;
+               writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
+
+               val |= ETHER_CLK_SEL_RX_TX_CLK_EN;
+               writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
                break;
        }
 
-       /* Start clock */
-       writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
-       val |= ETHER_CLK_SEL_RX_TX_CLK_EN;
-       writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
-
-       val &= ~ETHER_CLK_SEL_TX_O_E_N_IN;
-       writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
-
        spin_unlock_irqrestore(&dwmac->lock, flags);
 }
 
@@ -219,6 +233,7 @@ static int visconti_eth_dwmac_probe(struct platform_device *pdev)
 
        spin_lock_init(&dwmac->lock);
        dwmac->reg = stmmac_res.addr;
+       dwmac->dev = &pdev->dev;
        plat_dat->bsp_priv = dwmac;
        plat_dat->fix_mac_speed = visconti_eth_fix_mac_speed;
 
index 1914ad6..acd70b9 100644 (file)
 
 #define NUM_DWMAC100_DMA_REGS  9
 #define NUM_DWMAC1000_DMA_REGS 23
+#define NUM_DWMAC4_DMA_REGS    27
 
 void dwmac_enable_dma_transmission(void __iomem *ioaddr);
 void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan, bool rx, bool tx);
index 40b5ed9..5b195d5 100644 (file)
@@ -194,7 +194,6 @@ struct stmmac_priv {
        u32 tx_coal_timer[MTL_MAX_TX_QUEUES];
        u32 rx_coal_frames[MTL_MAX_TX_QUEUES];
 
-       int tx_coalesce;
        int hwts_tx_en;
        bool tx_path_in_lpi_mode;
        bool tso;
@@ -229,7 +228,6 @@ struct stmmac_priv {
        unsigned int flow_ctrl;
        unsigned int pause;
        struct mii_bus *mii;
-       int mii_irq[PHY_MAX_ADDR];
 
        struct phylink_config phylink_config;
        struct phylink *phylink;
index 164dff5..abfb3cd 100644 (file)
 #include "dwxgmac2.h"
 
 #define REG_SPACE_SIZE 0x1060
+#define GMAC4_REG_SPACE_SIZE   0x116C
 #define MAC100_ETHTOOL_NAME    "st_mac100"
 #define GMAC_ETHTOOL_NAME      "st_gmac"
 #define XGMAC_ETHTOOL_NAME     "st_xgmac"
 
+/* Same as DMA_CHAN_BASE_ADDR defined in dwmac4_dma.h
+ *
+ * It is here because dwmac_dma.h and dwmac4_dam.h can not be included at the
+ * same time due to the conflicting macro names.
+ */
+#define GMAC4_DMA_CHAN_BASE_ADDR  0x00001100
+
 #define ETHTOOL_DMA_OFFSET     55
 
 struct stmmac_stats {
@@ -434,6 +442,8 @@ static int stmmac_ethtool_get_regs_len(struct net_device *dev)
 
        if (priv->plat->has_xgmac)
                return XGMAC_REGSIZE * 4;
+       else if (priv->plat->has_gmac4)
+               return GMAC4_REG_SPACE_SIZE;
        return REG_SPACE_SIZE;
 }
 
@@ -446,8 +456,13 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
        stmmac_dump_mac_regs(priv, priv->hw, reg_space);
        stmmac_dump_dma_regs(priv, priv->ioaddr, reg_space);
 
-       if (!priv->plat->has_xgmac) {
-               /* Copy DMA registers to where ethtool expects them */
+       /* Copy DMA registers to where ethtool expects them */
+       if (priv->plat->has_gmac4) {
+               /* GMAC4 dumps its DMA registers at its DMA_CHAN_BASE_ADDR */
+               memcpy(&reg_space[ETHTOOL_DMA_OFFSET],
+                      &reg_space[GMAC4_DMA_CHAN_BASE_ADDR / 4],
+                      NUM_DWMAC4_DMA_REGS * 4);
+       } else if (!priv->plat->has_xgmac) {
                memcpy(&reg_space[ETHTOOL_DMA_OFFSET],
                       &reg_space[DMA_BUS_MODE / 4],
                       NUM_DWMAC1000_DMA_REGS * 4);
index 074e2cd..a7ec9f4 100644 (file)
@@ -145,15 +145,20 @@ static int adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
 
 static void get_systime(void __iomem *ioaddr, u64 *systime)
 {
-       u64 ns;
-
-       /* Get the TSSS value */
-       ns = readl(ioaddr + PTP_STNSR);
-       /* Get the TSS and convert sec time value to nanosecond */
-       ns += readl(ioaddr + PTP_STSR) * 1000000000ULL;
+       u64 ns, sec0, sec1;
+
+       /* Get the TSS value */
+       sec1 = readl_relaxed(ioaddr + PTP_STSR);
+       do {
+               sec0 = sec1;
+               /* Get the TSSS value */
+               ns = readl_relaxed(ioaddr + PTP_STNSR);
+               /* Get the TSS value */
+               sec1 = readl_relaxed(ioaddr + PTP_STSR);
+       } while (sec0 != sec1);
 
        if (systime)
-               *systime = ns;
+               *systime = ns + (sec1 * 1000000000ULL);
 }
 
 static void get_ptptime(void __iomem *ptpaddr, u64 *ptp_time)
index 6708ca2..bde76ea 100644 (file)
@@ -402,7 +402,7 @@ static void stmmac_lpi_entry_timer_config(struct stmmac_priv *priv, bool en)
  * Description: this function is to verify and enter in LPI mode in case of
  * EEE.
  */
-static void stmmac_enable_eee_mode(struct stmmac_priv *priv)
+static int stmmac_enable_eee_mode(struct stmmac_priv *priv)
 {
        u32 tx_cnt = priv->plat->tx_queues_to_use;
        u32 queue;
@@ -412,13 +412,14 @@ static void stmmac_enable_eee_mode(struct stmmac_priv *priv)
                struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue];
 
                if (tx_q->dirty_tx != tx_q->cur_tx)
-                       return; /* still unfinished work */
+                       return -EBUSY; /* still unfinished work */
        }
 
        /* Check and enter in LPI mode */
        if (!priv->tx_path_in_lpi_mode)
                stmmac_set_eee_mode(priv, priv->hw,
                                priv->plat->en_tx_lpi_clockgating);
+       return 0;
 }
 
 /**
@@ -450,8 +451,8 @@ static void stmmac_eee_ctrl_timer(struct timer_list *t)
 {
        struct stmmac_priv *priv = from_timer(priv, t, eee_ctrl_timer);
 
-       stmmac_enable_eee_mode(priv);
-       mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer));
+       if (stmmac_enable_eee_mode(priv))
+               mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer));
 }
 
 /**
@@ -889,6 +890,9 @@ static int stmmac_init_ptp(struct stmmac_priv *priv)
        bool xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac;
        int ret;
 
+       if (priv->plat->ptp_clk_freq_config)
+               priv->plat->ptp_clk_freq_config(priv);
+
        ret = stmmac_init_tstamp_counter(priv, STMMAC_HWTS_ACTIVE);
        if (ret)
                return ret;
@@ -911,8 +915,6 @@ static int stmmac_init_ptp(struct stmmac_priv *priv)
        priv->hwts_tx_en = 0;
        priv->hwts_rx_en = 0;
 
-       stmmac_ptp_register(priv);
-
        return 0;
 }
 
@@ -2647,8 +2649,8 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue)
 
        if (priv->eee_enabled && !priv->tx_path_in_lpi_mode &&
            priv->eee_sw_timer_en) {
-               stmmac_enable_eee_mode(priv);
-               mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer));
+               if (stmmac_enable_eee_mode(priv))
+                       mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(priv->tx_lpi_timer));
        }
 
        /* We still have pending packets, let's call for a new scheduling */
@@ -3238,7 +3240,7 @@ static int stmmac_fpe_start_wq(struct stmmac_priv *priv)
 /**
  * stmmac_hw_setup - setup mac in a usable state.
  *  @dev : pointer to the device structure.
- *  @init_ptp: initialize PTP if set
+ *  @ptp_register: register PTP if set
  *  Description:
  *  this is the main function to setup the HW in a usable state because the
  *  dma engine is reset, the core registers are configured (e.g. AXI,
@@ -3248,7 +3250,7 @@ static int stmmac_fpe_start_wq(struct stmmac_priv *priv)
  *  0 on success and an appropriate (-)ve integer as defined in errno.h
  *  file on failure.
  */
-static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
+static int stmmac_hw_setup(struct net_device *dev, bool ptp_register)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
        u32 rx_cnt = priv->plat->rx_queues_to_use;
@@ -3305,13 +3307,13 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
 
        stmmac_mmc_setup(priv);
 
-       if (init_ptp) {
-               ret = stmmac_init_ptp(priv);
-               if (ret == -EOPNOTSUPP)
-                       netdev_warn(priv->dev, "PTP not supported by HW\n");
-               else if (ret)
-                       netdev_warn(priv->dev, "PTP init failed\n");
-       }
+       ret = stmmac_init_ptp(priv);
+       if (ret == -EOPNOTSUPP)
+               netdev_warn(priv->dev, "PTP not supported by HW\n");
+       else if (ret)
+               netdev_warn(priv->dev, "PTP init failed\n");
+       else if (ptp_register)
+               stmmac_ptp_register(priv);
 
        priv->eee_tw_timer = STMMAC_DEFAULT_TWT_LS;
 
@@ -7250,6 +7252,10 @@ int stmmac_dvr_remove(struct device *dev)
 
        netdev_info(priv->dev, "%s: removing driver", __func__);
 
+       pm_runtime_get_sync(dev);
+       pm_runtime_disable(dev);
+       pm_runtime_put_noidle(dev);
+
        stmmac_stop_all_dma(priv);
        stmmac_mac_set(priv, priv->ioaddr, false);
        netif_carrier_off(ndev);
@@ -7268,8 +7274,6 @@ int stmmac_dvr_remove(struct device *dev)
        if (priv->plat->stmmac_rst)
                reset_control_assert(priv->plat->stmmac_rst);
        reset_control_assert(priv->plat->stmmac_ahb_rst);
-       pm_runtime_put(dev);
-       pm_runtime_disable(dev);
        if (priv->hw->pcs != STMMAC_PCS_TBI &&
            priv->hw->pcs != STMMAC_PCS_RTBI)
                stmmac_mdio_unregister(ndev);
index 0d24ebd..1c9f02f 100644 (file)
@@ -297,9 +297,6 @@ void stmmac_ptp_register(struct stmmac_priv *priv)
 {
        int i;
 
-       if (priv->plat->ptp_clk_freq_config)
-               priv->plat->ptp_clk_freq_config(priv);
-
        for (i = 0; i < priv->dma_cap.pps_out_num; i++) {
                if (i >= STMMAC_PPS_MAX)
                        break;
index ba22059..8f6817f 100644 (file)
@@ -1146,7 +1146,7 @@ int cpsw_fill_rx_channels(struct cpsw_priv *priv)
 static struct page_pool *cpsw_create_page_pool(struct cpsw_common *cpsw,
                                               int size)
 {
-       struct page_pool_params pp_params;
+       struct page_pool_params pp_params = {};
        struct page_pool *pool;
 
        pp_params.order = 0;
index cf0917b..5251fc3 100644 (file)
@@ -1091,20 +1091,22 @@ static int tsi108_get_mac(struct net_device *dev)
        struct tsi108_prv_data *data = netdev_priv(dev);
        u32 word1 = TSI_READ(TSI108_MAC_ADDR1);
        u32 word2 = TSI_READ(TSI108_MAC_ADDR2);
+       u8 addr[ETH_ALEN];
 
        /* Note that the octets are reversed from what the manual says,
         * producing an even weirder ordering...
         */
        if (word2 == 0 && word1 == 0) {
-               dev->dev_addr[0] = 0x00;
-               dev->dev_addr[1] = 0x06;
-               dev->dev_addr[2] = 0xd2;
-               dev->dev_addr[3] = 0x00;
-               dev->dev_addr[4] = 0x00;
+               addr[0] = 0x00;
+               addr[1] = 0x06;
+               addr[2] = 0xd2;
+               addr[3] = 0x00;
+               addr[4] = 0x00;
                if (0x8 == data->phy)
-                       dev->dev_addr[5] = 0x01;
+                       addr[5] = 0x01;
                else
-                       dev->dev_addr[5] = 0x02;
+                       addr[5] = 0x02;
+               eth_hw_addr_set(dev, addr);
 
                word2 = (dev->dev_addr[0] << 16) | (dev->dev_addr[1] << 24);
 
@@ -1114,12 +1116,13 @@ static int tsi108_get_mac(struct net_device *dev)
                TSI_WRITE(TSI108_MAC_ADDR1, word1);
                TSI_WRITE(TSI108_MAC_ADDR2, word2);
        } else {
-               dev->dev_addr[0] = (word2 >> 16) & 0xff;
-               dev->dev_addr[1] = (word2 >> 24) & 0xff;
-               dev->dev_addr[2] = (word1 >> 0) & 0xff;
-               dev->dev_addr[3] = (word1 >> 8) & 0xff;
-               dev->dev_addr[4] = (word1 >> 16) & 0xff;
-               dev->dev_addr[5] = (word1 >> 24) & 0xff;
+               addr[0] = (word2 >> 16) & 0xff;
+               addr[1] = (word2 >> 24) & 0xff;
+               addr[2] = (word1 >> 0) & 0xff;
+               addr[3] = (word1 >> 8) & 0xff;
+               addr[4] = (word1 >> 16) & 0xff;
+               addr[5] = (word1 >> 24) & 0xff;
+               eth_hw_addr_set(dev, addr);
        }
 
        if (!is_valid_ether_addr(dev->dev_addr)) {
@@ -1136,14 +1139,12 @@ static int tsi108_set_mac(struct net_device *dev, void *addr)
 {
        struct tsi108_prv_data *data = netdev_priv(dev);
        u32 word1, word2;
-       int i;
 
        if (!is_valid_ether_addr(addr))
                return -EADDRNOTAVAIL;
 
-       for (i = 0; i < 6; i++)
-               /* +2 is for the offset of the HW addr type */
-               dev->dev_addr[i] = ((unsigned char *)addr)[i + 2];
+       /* +2 is for the offset of the HW addr type */
+       eth_hw_addr_set(dev, ((unsigned char *)addr) + 2);
 
        word2 = (dev->dev_addr[0] << 16) | (dev->dev_addr[1] << 24);
 
index b900ab5..64c7e26 100644 (file)
@@ -1433,6 +1433,8 @@ static int temac_probe(struct platform_device *pdev)
                lp->indirect_lock = devm_kmalloc(&pdev->dev,
                                                 sizeof(*lp->indirect_lock),
                                                 GFP_KERNEL);
+               if (!lp->indirect_lock)
+                       return -ENOMEM;
                spin_lock_init(lp->indirect_lock);
        }
 
index b1fc153..45c3c4a 100644 (file)
@@ -668,11 +668,11 @@ static void sixpack_close(struct tty_struct *tty)
         */
        netif_stop_queue(sp->dev);
 
+       unregister_netdev(sp->dev);
+
        del_timer_sync(&sp->tx_t);
        del_timer_sync(&sp->resync_t);
 
-       unregister_netdev(sp->dev);
-
        /* Free all 6pack frame buffers after unreg. */
        kfree(sp->rbuff);
        kfree(sp->xbuff);
index 6376b84..980f2be 100644 (file)
@@ -950,9 +950,7 @@ static int yam_siocdevprivate(struct net_device *dev, struct ifreq *ifr, void __
                ym = memdup_user(data, sizeof(struct yamdrv_ioctl_mcs));
                if (IS_ERR(ym))
                        return PTR_ERR(ym);
-               if (ym->cmd != SIOCYAMSMCS)
-                       return -EINVAL;
-               if (ym->bitrate > YAM_MAXBITRATE) {
+               if (ym->cmd != SIOCYAMSMCS || ym->bitrate > YAM_MAXBITRATE) {
                        kfree(ym);
                        return -EINVAL;
                }
index 7d67f41..4f5ef8a 100644 (file)
@@ -100,6 +100,7 @@ struct at86rf230_local {
        unsigned long cal_timeout;
        bool is_tx;
        bool is_tx_from_off;
+       bool was_tx;
        u8 tx_retry;
        struct sk_buff *tx_skb;
        struct at86rf230_state_change tx;
@@ -343,7 +344,11 @@ at86rf230_async_error_recover_complete(void *context)
        if (ctx->free)
                kfree(ctx);
 
-       ieee802154_wake_queue(lp->hw);
+       if (lp->was_tx) {
+               lp->was_tx = 0;
+               dev_kfree_skb_any(lp->tx_skb);
+               ieee802154_wake_queue(lp->hw);
+       }
 }
 
 static void
@@ -352,7 +357,11 @@ at86rf230_async_error_recover(void *context)
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
 
-       lp->is_tx = 0;
+       if (lp->is_tx) {
+               lp->was_tx = 1;
+               lp->is_tx = 0;
+       }
+
        at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON,
                                     at86rf230_async_error_recover_complete);
 }
index ece6ff6..2bc730f 100644 (file)
@@ -1771,6 +1771,7 @@ static int ca8210_async_xmit_complete(
                        status
                );
                if (status != MAC_TRANSACTION_OVERFLOW) {
+                       dev_kfree_skb_any(priv->tx_skb);
                        ieee802154_wake_queue(priv->hw);
                        return 0;
                }
@@ -2974,8 +2975,8 @@ static void ca8210_hw_setup(struct ieee802154_hw *ca8210_hw)
        ca8210_hw->phy->cca.opt = NL802154_CCA_OPT_ENERGY_CARRIER_AND;
        ca8210_hw->phy->cca_ed_level = -9800;
        ca8210_hw->phy->symbol_duration = 16;
-       ca8210_hw->phy->lifs_period = 40;
-       ca8210_hw->phy->sifs_period = 12;
+       ca8210_hw->phy->lifs_period = 40 * ca8210_hw->phy->symbol_duration;
+       ca8210_hw->phy->sifs_period = 12 * ca8210_hw->phy->symbol_duration;
        ca8210_hw->flags =
                IEEE802154_HW_AFILT |
                IEEE802154_HW_OMIT_CKSUM |
index 8caa61e..36f1c5a 100644 (file)
@@ -786,6 +786,7 @@ static int hwsim_add_one(struct genl_info *info, struct device *dev,
                goto err_pib;
        }
 
+       pib->channel = 13;
        rcu_assign_pointer(phy->pib, pib);
        phy->idx = idx;
        INIT_LIST_HEAD(&phy->edges);
index 8dc04e2..383231b 100644 (file)
@@ -976,8 +976,8 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
        dev_dbg(printdev(lp), "%s\n", __func__);
 
        phy->symbol_duration = 16;
-       phy->lifs_period = 40;
-       phy->sifs_period = 12;
+       phy->lifs_period = 40 * phy->symbol_duration;
+       phy->sifs_period = 12 * phy->symbol_duration;
 
        hw->flags = IEEE802154_HW_TX_OMIT_CKSUM |
                        IEEE802154_HW_AFILT |
index b1c6c0f..f2989aa 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/pm_runtime.h>
 #include <linux/bitops.h>
 
+#include "linux/soc/qcom/qcom_aoss.h"
+
 #include "ipa.h"
 #include "ipa_power.h"
 #include "ipa_endpoint.h"
@@ -64,6 +66,7 @@ enum ipa_power_flag {
  * struct ipa_power - IPA power management information
  * @dev:               IPA device pointer
  * @core:              IPA core clock
+ * @qmp:               QMP handle for AOSS communication
  * @spinlock:          Protects modem TX queue enable/disable
  * @flags:             Boolean state flags
  * @interconnect_count:        Number of elements in interconnect[]
@@ -72,6 +75,7 @@ enum ipa_power_flag {
 struct ipa_power {
        struct device *dev;
        struct clk *core;
+       struct qmp *qmp;
        spinlock_t spinlock;    /* used with STOPPED/STARTED power flags */
        DECLARE_BITMAP(flags, IPA_POWER_FLAG_COUNT);
        u32 interconnect_count;
@@ -382,6 +386,47 @@ void ipa_power_modem_queue_active(struct ipa *ipa)
        clear_bit(IPA_POWER_FLAG_STARTED, ipa->power->flags);
 }
 
+static int ipa_power_retention_init(struct ipa_power *power)
+{
+       struct qmp *qmp = qmp_get(power->dev);
+
+       if (IS_ERR(qmp)) {
+               if (PTR_ERR(qmp) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+
+               /* We assume any other error means it's not defined/needed */
+               qmp = NULL;
+       }
+       power->qmp = qmp;
+
+       return 0;
+}
+
+static void ipa_power_retention_exit(struct ipa_power *power)
+{
+       qmp_put(power->qmp);
+       power->qmp = NULL;
+}
+
+/* Control register retention on power collapse */
+void ipa_power_retention(struct ipa *ipa, bool enable)
+{
+       static const char fmt[] = "{ class: bcm, res: ipa_pc, val: %c }";
+       struct ipa_power *power = ipa->power;
+       char buf[36];   /* Exactly enough for fmt[]; size a multiple of 4 */
+       int ret;
+
+       if (!power->qmp)
+               return;         /* Not needed on this platform */
+
+       (void)snprintf(buf, sizeof(buf), fmt, enable ? '1' : '0');
+
+       ret = qmp_send(power->qmp, buf, sizeof(buf));
+       if (ret)
+               dev_err(power->dev, "error %d sending QMP %sable request\n",
+                       ret, enable ? "en" : "dis");
+}
+
 int ipa_power_setup(struct ipa *ipa)
 {
        int ret;
@@ -438,12 +483,18 @@ ipa_power_init(struct device *dev, const struct ipa_power_data *data)
        if (ret)
                goto err_kfree;
 
+       ret = ipa_power_retention_init(power);
+       if (ret)
+               goto err_interconnect_exit;
+
        pm_runtime_set_autosuspend_delay(dev, IPA_AUTOSUSPEND_DELAY);
        pm_runtime_use_autosuspend(dev);
        pm_runtime_enable(dev);
 
        return power;
 
+err_interconnect_exit:
+       ipa_interconnect_exit(power);
 err_kfree:
        kfree(power);
 err_clk_put:
@@ -460,6 +511,7 @@ void ipa_power_exit(struct ipa_power *power)
 
        pm_runtime_disable(dev);
        pm_runtime_dont_use_autosuspend(dev);
+       ipa_power_retention_exit(power);
        ipa_interconnect_exit(power);
        kfree(power);
        clk_put(clk);
index 2151805..6f84f05 100644 (file)
@@ -40,6 +40,13 @@ void ipa_power_modem_queue_wake(struct ipa *ipa);
  */
 void ipa_power_modem_queue_active(struct ipa *ipa);
 
+/**
+ * ipa_power_retention() - Control register retention on power collapse
+ * @ipa:       IPA pointer
+ * @enable:    Whether retention should be enabled or disabled
+ */
+void ipa_power_retention(struct ipa *ipa, bool enable);
+
 /**
  * ipa_power_setup() - Set up IPA power management
  * @ipa:       IPA pointer
index 856e55a..fe11910 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "ipa.h"
 #include "ipa_uc.h"
+#include "ipa_power.h"
 
 /**
  * DOC:  The IPA embedded microcontroller
@@ -154,6 +155,7 @@ static void ipa_uc_response_hdlr(struct ipa *ipa, enum ipa_irq_id irq_id)
        case IPA_UC_RESPONSE_INIT_COMPLETED:
                if (ipa->uc_powered) {
                        ipa->uc_loaded = true;
+                       ipa_power_retention(ipa, true);
                        pm_runtime_mark_last_busy(dev);
                        (void)pm_runtime_put_autosuspend(dev);
                        ipa->uc_powered = false;
@@ -184,6 +186,9 @@ void ipa_uc_deconfig(struct ipa *ipa)
 
        ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_1);
        ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_0);
+       if (ipa->uc_loaded)
+               ipa_power_retention(ipa, false);
+
        if (!ipa->uc_powered)
                return;
 
index 16aa3a4..3d08743 100644 (file)
@@ -3870,6 +3870,18 @@ static void macsec_common_dellink(struct net_device *dev, struct list_head *head
        struct macsec_dev *macsec = macsec_priv(dev);
        struct net_device *real_dev = macsec->real_dev;
 
+       /* If h/w offloading is available, propagate to the device */
+       if (macsec_is_offloaded(macsec)) {
+               const struct macsec_ops *ops;
+               struct macsec_context ctx;
+
+               ops = macsec_get_ops(netdev_priv(dev), &ctx);
+               if (ops) {
+                       ctx.secy = &macsec->secy;
+                       macsec_offload(ops->mdo_del_secy, &ctx);
+               }
+       }
+
        unregister_netdevice_queue(dev, head);
        list_del_rcu(&macsec->secys);
        macsec_del_dev(macsec);
@@ -3884,18 +3896,6 @@ static void macsec_dellink(struct net_device *dev, struct list_head *head)
        struct net_device *real_dev = macsec->real_dev;
        struct macsec_rxh_data *rxd = macsec_data_rtnl(real_dev);
 
-       /* If h/w offloading is available, propagate to the device */
-       if (macsec_is_offloaded(macsec)) {
-               const struct macsec_ops *ops;
-               struct macsec_context ctx;
-
-               ops = macsec_get_ops(netdev_priv(dev), &ctx);
-               if (ops) {
-                       ctx.secy = &macsec->secy;
-                       macsec_offload(ops->mdo_del_secy, &ctx);
-               }
-       }
-
        macsec_common_dellink(dev, head);
 
        if (list_empty(&rxd->secys)) {
@@ -4018,6 +4018,15 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
            !macsec_check_offload(macsec->offload, macsec))
                return -EOPNOTSUPP;
 
+       /* send_sci must be set to true when transmit sci explicitly is set */
+       if ((data && data[IFLA_MACSEC_SCI]) &&
+           (data && data[IFLA_MACSEC_INC_SCI])) {
+               u8 send_sci = !!nla_get_u8(data[IFLA_MACSEC_INC_SCI]);
+
+               if (!send_sci)
+                       return -EINVAL;
+       }
+
        if (data && data[IFLA_MACSEC_ICV_LEN])
                icv_len = nla_get_u8(data[IFLA_MACSEC_ICV_LEN]);
        mtu = real_dev->mtu - icv_len - macsec_extra_len(true);
index eaa6fb3..62723a7 100644 (file)
@@ -403,8 +403,16 @@ static void mctp_serial_tty_receive_buf(struct tty_struct *tty,
                mctp_serial_push(dev, c[i]);
 }
 
+static void mctp_serial_uninit(struct net_device *ndev)
+{
+       struct mctp_serial *dev = netdev_priv(ndev);
+
+       cancel_work_sync(&dev->tx_work);
+}
+
 static const struct net_device_ops mctp_serial_netdev_ops = {
        .ndo_start_xmit = mctp_serial_tx,
+       .ndo_uninit = mctp_serial_uninit,
 };
 
 static void mctp_serial_setup(struct net_device *ndev)
@@ -483,7 +491,6 @@ static void mctp_serial_close(struct tty_struct *tty)
        int idx = dev->idx;
 
        unregister_netdev(dev->netdev);
-       cancel_work_sync(&dev->tx_work);
        ida_free(&mctp_serial_ida, idx);
 }
 
index 966c3b4..e227358 100644 (file)
@@ -148,6 +148,7 @@ static const struct of_device_id aspeed_mdio_of_match[] = {
        { .compatible = "aspeed,ast2600-mdio", },
        { },
 };
+MODULE_DEVICE_TABLE(of, aspeed_mdio_of_match);
 
 static struct platform_driver aspeed_mdio_driver = {
        .driver = {
index 5f4cd24..4eba5a9 100644 (file)
@@ -200,7 +200,11 @@ static int ipq_mdio_reset(struct mii_bus *bus)
        if (ret)
                return ret;
 
-       return clk_prepare_enable(priv->mdio_clk);
+       ret = clk_prepare_enable(priv->mdio_clk);
+       if (ret == 0)
+               mdelay(10);
+
+       return ret;
 }
 
 static int ipq4019_mdio_probe(struct platform_device *pdev)
index 4300261..378ee77 100644 (file)
@@ -623,14 +623,14 @@ static int nsim_fib6_rt_append(struct nsim_fib_data *data,
                if (err)
                        goto err_fib6_rt_nh_del;
 
-               fib6_event->rt_arr[i]->trap = true;
+               WRITE_ONCE(fib6_event->rt_arr[i]->trap, true);
        }
 
        return 0;
 
 err_fib6_rt_nh_del:
        for (i--; i >= 0; i--) {
-               fib6_event->rt_arr[i]->trap = false;
+               WRITE_ONCE(fib6_event->rt_arr[i]->trap, false);
                nsim_fib6_rt_nh_del(fib6_rt, fib6_event->rt_arr[i]);
        }
        return err;
index 5b6c0d1..29aa811 100644 (file)
@@ -1688,19 +1688,19 @@ static int qca808x_read_status(struct phy_device *phydev)
        if (ret < 0)
                return ret;
 
-       if (phydev->link && phydev->speed == SPEED_2500)
-               phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
-       else
-               phydev->interface = PHY_INTERFACE_MODE_SMII;
-
-       /* generate seed as a lower random value to make PHY linked as SLAVE easily,
-        * except for master/slave configuration fault detected.
-        * the reason for not putting this code into the function link_change_notify is
-        * the corner case where the link partner is also the qca8081 PHY and the seed
-        * value is configured as the same value, the link can't be up and no link change
-        * occurs.
-        */
-       if (!phydev->link) {
+       if (phydev->link) {
+               if (phydev->speed == SPEED_2500)
+                       phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
+               else
+                       phydev->interface = PHY_INTERFACE_MODE_SGMII;
+       } else {
+               /* generate seed as a lower random value to make PHY linked as SLAVE easily,
+                * except for master/slave configuration fault detected.
+                * the reason for not putting this code into the function link_change_notify is
+                * the corner case where the link partner is also the qca8081 PHY and the seed
+                * value is configured as the same value, the link can't be up and no link change
+                * occurs.
+                */
                if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR) {
                        qca808x_phy_ms_seed_enable(phydev, false);
                } else {
index bb5104a..3c683e0 100644 (file)
@@ -854,6 +854,7 @@ static struct phy_driver broadcom_drivers[] = {
        .phy_id_mask    = 0xfffffff0,
        .name           = "Broadcom BCM54616S",
        /* PHY_GBIT_FEATURES */
+       .soft_reset     = genphy_soft_reset,
        .config_init    = bcm54xx_config_init,
        .config_aneg    = bcm54616s_config_aneg,
        .config_intr    = bcm_phy_config_intr,
index fa71fb7..2429db6 100644 (file)
@@ -553,9 +553,9 @@ static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev)
        else
                mscr = 0;
 
-       return phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
-                               MII_88E1121_PHY_MSCR_REG,
-                               MII_88E1121_PHY_MSCR_DELAY_MASK, mscr);
+       return phy_modify_paged_changed(phydev, MII_MARVELL_MSCR_PAGE,
+                                       MII_88E1121_PHY_MSCR_REG,
+                                       MII_88E1121_PHY_MSCR_DELAY_MASK, mscr);
 }
 
 static int m88e1121_config_aneg(struct phy_device *phydev)
@@ -569,11 +569,13 @@ static int m88e1121_config_aneg(struct phy_device *phydev)
                        return err;
        }
 
+       changed = err;
+
        err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
        if (err < 0)
                return err;
 
-       changed = err;
+       changed |= err;
 
        err = genphy_config_aneg(phydev);
        if (err < 0)
@@ -1213,16 +1215,15 @@ static int m88e1118_config_aneg(struct phy_device *phydev)
 {
        int err;
 
-       err = genphy_soft_reset(phydev);
+       err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
        if (err < 0)
                return err;
 
-       err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
+       err = genphy_config_aneg(phydev);
        if (err < 0)
                return err;
 
-       err = genphy_config_aneg(phydev);
-       return 0;
+       return genphy_soft_reset(phydev);
 }
 
 static int m88e1118_config_init(struct phy_device *phydev)
index b7a5ae2..68ee434 100644 (file)
@@ -55,9 +55,6 @@ static int mt7530_phy_config_init(struct phy_device *phydev)
 
 static int mt7531_phy_config_init(struct phy_device *phydev)
 {
-       if (phydev->interface != PHY_INTERFACE_MODE_INTERNAL)
-               return -EINVAL;
-
        mtk_gephy_config_init(phydev);
 
        /* PHY link down power saving enable */
index 74d8e1d..ce0bb59 100644 (file)
@@ -1746,6 +1746,9 @@ void phy_detach(struct phy_device *phydev)
            phy_driver_is_genphy_10g(phydev))
                device_release_driver(&phydev->mdio.dev);
 
+       /* Assert the reset signal */
+       phy_device_reset(phydev, 1);
+
        /*
         * The phydev might go away on the put_device() below, so avoid
         * a use-after-free bug by reading the underlying bus first.
@@ -1757,9 +1760,6 @@ void phy_detach(struct phy_device *phydev)
                ndev_owner = dev->dev.parent->driver->owner;
        if (ndev_owner != bus->owner)
                module_put(bus->owner);
-
-       /* Assert the reset signal */
-       phy_device_reset(phydev, 1);
 }
 EXPORT_SYMBOL(phy_detach);
 
index 0c6c0d1..c1512c9 100644 (file)
@@ -651,6 +651,11 @@ struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode)
        else if (ret < 0)
                return ERR_PTR(ret);
 
+       if (!fwnode_device_is_available(ref.fwnode)) {
+               fwnode_handle_put(ref.fwnode);
+               return NULL;
+       }
+
        bus = sfp_bus_get(ref.fwnode);
        fwnode_handle_put(ref.fwnode);
        if (!bus)
index 1a627ba..a310989 100644 (file)
@@ -1468,58 +1468,68 @@ static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
        u16 hdr_off;
        u32 *pkt_hdr;
 
-       /* This check is no longer done by usbnet */
-       if (skb->len < dev->net->hard_header_len)
+       /* At the end of the SKB, there's a header telling us how many packets
+        * are bundled into this buffer and where we can find an array of
+        * per-packet metadata (which contains elements encoded into u16).
+        */
+       if (skb->len < 4)
                return 0;
-
        skb_trim(skb, skb->len - 4);
        rx_hdr = get_unaligned_le32(skb_tail_pointer(skb));
-
        pkt_cnt = (u16)rx_hdr;
        hdr_off = (u16)(rx_hdr >> 16);
+
+       if (pkt_cnt == 0)
+               return 0;
+
+       /* Make sure that the bounds of the metadata array are inside the SKB
+        * (and in front of the counter at the end).
+        */
+       if (pkt_cnt * 2 + hdr_off > skb->len)
+               return 0;
        pkt_hdr = (u32 *)(skb->data + hdr_off);
 
-       while (pkt_cnt--) {
+       /* Packets must not overlap the metadata array */
+       skb_trim(skb, hdr_off);
+
+       for (; ; pkt_cnt--, pkt_hdr++) {
                u16 pkt_len;
 
                le32_to_cpus(pkt_hdr);
                pkt_len = (*pkt_hdr >> 16) & 0x1fff;
 
-               /* Check CRC or runt packet */
-               if ((*pkt_hdr & AX_RXHDR_CRC_ERR) ||
-                   (*pkt_hdr & AX_RXHDR_DROP_ERR)) {
-                       skb_pull(skb, (pkt_len + 7) & 0xFFF8);
-                       pkt_hdr++;
-                       continue;
-               }
-
-               if (pkt_cnt == 0) {
-                       skb->len = pkt_len;
-                       /* Skip IP alignment pseudo header */
-                       skb_pull(skb, 2);
-                       skb_set_tail_pointer(skb, skb->len);
-                       skb->truesize = pkt_len + sizeof(struct sk_buff);
-                       ax88179_rx_checksum(skb, pkt_hdr);
-                       return 1;
-               }
+               if (pkt_len > skb->len)
+                       return 0;
 
-               ax_skb = skb_clone(skb, GFP_ATOMIC);
-               if (ax_skb) {
+               /* Check CRC or runt packet */
+               if (((*pkt_hdr & (AX_RXHDR_CRC_ERR | AX_RXHDR_DROP_ERR)) == 0) &&
+                   pkt_len >= 2 + ETH_HLEN) {
+                       bool last = (pkt_cnt == 0);
+
+                       if (last) {
+                               ax_skb = skb;
+                       } else {
+                               ax_skb = skb_clone(skb, GFP_ATOMIC);
+                               if (!ax_skb)
+                                       return 0;
+                       }
                        ax_skb->len = pkt_len;
                        /* Skip IP alignment pseudo header */
                        skb_pull(ax_skb, 2);
                        skb_set_tail_pointer(ax_skb, ax_skb->len);
                        ax_skb->truesize = pkt_len + sizeof(struct sk_buff);
                        ax88179_rx_checksum(ax_skb, pkt_hdr);
+
+                       if (last)
+                               return 1;
+
                        usbnet_skb_return(dev, ax_skb);
-               } else {
-                       return 0;
                }
 
-               skb_pull(skb, (pkt_len + 7) & 0xFFF8);
-               pkt_hdr++;
+               /* Trim this packet away from the SKB */
+               if (!skb_pull(skb, (pkt_len + 7) & 0xFFF8))
+                       return 0;
        }
-       return 1;
 }
 
 static struct sk_buff *
index eb3817d..9b4dfa3 100644 (file)
@@ -583,6 +583,11 @@ static const struct usb_device_id  products[] = {
        .bInterfaceSubClass     = USB_CDC_SUBCLASS_ETHERNET, \
        .bInterfaceProtocol     = USB_CDC_PROTO_NONE
 
+#define ZAURUS_FAKE_INTERFACE \
+       .bInterfaceClass        = USB_CLASS_COMM, \
+       .bInterfaceSubClass     = USB_CDC_SUBCLASS_MDLM, \
+       .bInterfaceProtocol     = USB_CDC_PROTO_NONE
+
 /* SA-1100 based Sharp Zaurus ("collie"), or compatible;
  * wire-incompatible with true CDC Ethernet implementations.
  * (And, it seems, needlessly so...)
@@ -636,6 +641,13 @@ static const struct usb_device_id  products[] = {
        .idProduct              = 0x9032,       /* SL-6000 */
        ZAURUS_MASTER_INTERFACE,
        .driver_info            = 0,
+}, {
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x04DD,
+       .idProduct              = 0x9032,       /* SL-6000 */
+       ZAURUS_FAKE_INTERFACE,
+       .driver_info            = 0,
 }, {
        .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
                 | USB_DEVICE_ID_MATCH_DEVICE,
index 82bb5ed..c0b8b4a 100644 (file)
@@ -659,6 +659,11 @@ static const struct usb_device_id mbim_devs[] = {
          .driver_info = (unsigned long)&cdc_mbim_info_avoid_altsetting_toggle,
        },
 
+       /* Telit FN990 */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x1bc7, 0x1071, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
+         .driver_info = (unsigned long)&cdc_mbim_info_avoid_altsetting_toggle,
+       },
+
        /* default entry */
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
          .driver_info = (unsigned long)&cdc_mbim_info_zlp,
index e303b52..15f91d6 100644 (file)
@@ -1715,10 +1715,10 @@ int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
 {
        struct sk_buff *skb;
        struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
-       int len;
+       unsigned int len;
        int nframes;
        int x;
-       int offset;
+       unsigned int offset;
        union {
                struct usb_cdc_ncm_ndp16 *ndp16;
                struct usb_cdc_ncm_ndp32 *ndp32;
@@ -1790,8 +1790,8 @@ next_ndp:
                        break;
                }
 
-               /* sanity checking */
-               if (((offset + len) > skb_in->len) ||
+               /* sanity checking - watch out for integer wrap*/
+               if ((offset > skb_in->len) || (len > skb_in->len - offset) ||
                                (len > ctx->rx_max) || (len < ETH_HLEN)) {
                        netif_dbg(dev, rx_err, dev->net,
                                  "invalid frame detected (ignored) offset[%u]=%u, length=%u, skb=%p\n",
index cd33955..6a769df 100644 (file)
@@ -121,7 +121,7 @@ static int ipheth_alloc_urbs(struct ipheth_device *iphone)
        if (tx_buf == NULL)
                goto free_rx_urb;
 
-       rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE,
+       rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN,
                                    GFP_KERNEL, &rx_urb->transfer_dma);
        if (rx_buf == NULL)
                goto free_tx_buf;
@@ -146,7 +146,7 @@ error_nomem:
 
 static void ipheth_free_urbs(struct ipheth_device *iphone)
 {
-       usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->rx_buf,
+       usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN, iphone->rx_buf,
                          iphone->rx_urb->transfer_dma);
        usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf,
                          iphone->tx_urb->transfer_dma);
@@ -317,7 +317,7 @@ static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags)
 
        usb_fill_bulk_urb(dev->rx_urb, udev,
                          usb_rcvbulkpipe(udev, dev->bulk_in),
-                         dev->rx_buf, IPHETH_BUF_SIZE,
+                         dev->rx_buf, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN,
                          ipheth_rcvbulk_callback,
                          dev);
        dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
index 37e5f34..3353e76 100644 (file)
@@ -1400,6 +1400,8 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x413c, 0x81d7, 0)},    /* Dell Wireless 5821e */
        {QMI_FIXED_INTF(0x413c, 0x81d7, 1)},    /* Dell Wireless 5821e preproduction config */
        {QMI_FIXED_INTF(0x413c, 0x81e0, 0)},    /* Dell Wireless 5821e with eSIM support*/
+       {QMI_FIXED_INTF(0x413c, 0x81e4, 0)},    /* Dell Wireless 5829e with eSIM support*/
+       {QMI_FIXED_INTF(0x413c, 0x81e6, 0)},    /* Dell Wireless 5829e */
        {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)},    /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
        {QMI_FIXED_INTF(0x03f0, 0x9d1d, 1)},    /* HP lt4120 Snapdragon X5 LTE */
        {QMI_QUIRK_SET_DTR(0x22de, 0x9051, 2)}, /* Hucom Wireless HM-211S/K */
index b658510..5a53e63 100644 (file)
@@ -413,7 +413,7 @@ static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                /* ignore the CRC length */
                len = (skb->data[1] | (skb->data[2] << 8)) - 4;
 
-               if (len > ETH_FRAME_LEN)
+               if (len > ETH_FRAME_LEN || len > skb->len)
                        return 0;
 
                /* the last packet of current skb */
index 8e717a0..7984f21 100644 (file)
@@ -256,6 +256,11 @@ static const struct usb_device_id  products [] = {
        .bInterfaceSubClass     = USB_CDC_SUBCLASS_ETHERNET, \
        .bInterfaceProtocol     = USB_CDC_PROTO_NONE
 
+#define ZAURUS_FAKE_INTERFACE \
+       .bInterfaceClass        = USB_CLASS_COMM, \
+       .bInterfaceSubClass     = USB_CDC_SUBCLASS_MDLM, \
+       .bInterfaceProtocol     = USB_CDC_PROTO_NONE
+
 /* SA-1100 based Sharp Zaurus ("collie"), or compatible. */
 {
        .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
@@ -313,6 +318,13 @@ static const struct usb_device_id  products [] = {
        .idProduct              = 0x9032,       /* SL-6000 */
        ZAURUS_MASTER_INTERFACE,
        .driver_info = ZAURUS_PXA_INFO,
+}, {
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                           | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x04DD,
+       .idProduct              = 0x9032,       /* SL-6000 */
+       ZAURUS_FAKE_INTERFACE,
+       .driver_info = (unsigned long)&bogus_mdlm_info,
 }, {
        .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
                 | USB_DEVICE_ID_MATCH_DEVICE,
index 354a963..d29fb97 100644 (file)
@@ -265,9 +265,10 @@ static void __veth_xdp_flush(struct veth_rq *rq)
 {
        /* Write ptr_ring before reading rx_notify_masked */
        smp_mb();
-       if (!rq->rx_notify_masked) {
-               rq->rx_notify_masked = true;
-               napi_schedule(&rq->xdp_napi);
+       if (!READ_ONCE(rq->rx_notify_masked) &&
+           napi_schedule_prep(&rq->xdp_napi)) {
+               WRITE_ONCE(rq->rx_notify_masked, true);
+               __napi_schedule(&rq->xdp_napi);
        }
 }
 
@@ -912,8 +913,10 @@ static int veth_poll(struct napi_struct *napi, int budget)
                /* Write rx_notify_masked before reading ptr_ring */
                smp_store_mb(rq->rx_notify_masked, false);
                if (unlikely(!__ptr_ring_empty(&rq->xdp_ring))) {
-                       rq->rx_notify_masked = true;
-                       napi_schedule(&rq->xdp_napi);
+                       if (napi_schedule_prep(&rq->xdp_napi)) {
+                               WRITE_ONCE(rq->rx_notify_masked, true);
+                               __napi_schedule(&rq->xdp_napi);
+                       }
                }
        }
 
index 0eb13e5..d991409 100644 (file)
@@ -693,7 +693,7 @@ int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req,
 {
        struct brcmf_fw_item *first = &req->items[0];
        struct brcmf_fw *fwctx;
-       char *alt_path;
+       char *alt_path = NULL;
        int ret;
 
        brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
@@ -712,7 +712,9 @@ int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req,
        fwctx->done = fw_cb;
 
        /* First try alternative board-specific path if any */
-       alt_path = brcm_alt_fw_path(first->path, fwctx->req->board_type);
+       if (fwctx->req->board_type)
+               alt_path = brcm_alt_fw_path(first->path,
+                                           fwctx->req->board_type);
        if (alt_path) {
                ret = request_firmware_nowait(THIS_MODULE, true, alt_path,
                                              fwctx->dev, GFP_KERNEL, fwctx,
index c21c0c6..85e7042 100644 (file)
@@ -80,19 +80,6 @@ config IWLWIFI_OPMODE_MODULAR
 comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM"
        depends on IWLDVM=n && IWLMVM=n
 
-config IWLWIFI_BCAST_FILTERING
-       bool "Enable broadcast filtering"
-       depends on IWLMVM
-       help
-         Say Y here to enable default bcast filtering configuration.
-
-         Enabling broadcast filtering will drop any incoming wireless
-         broadcast frames, except some very specific predefined
-         patterns (e.g. incoming arp requests).
-
-         If unsure, don't enable this option, as some programs might
-         expect incoming broadcasts for their normal operations.
-
 menu "Debugging Options"
 
 config IWLWIFI_DEBUG
index 790c96d..c17ab53 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
  * Copyright (C) 2017 Intel Deutschland GmbH
- * Copyright (C) 2019-2021 Intel Corporation
+ * Copyright (C) 2019-2022 Intel Corporation
  */
 #include <linux/uuid.h>
 #include "iwl-drv.h"
@@ -888,10 +888,11 @@ bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt)
         * only one using version 36, so skip this version entirely.
         */
        return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 ||
-              IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 ||
-              (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 &&
-               ((fwrt->trans->hw_rev & CSR_HW_REV_TYPE_MSK) ==
-                CSR_HW_REV_TYPE_7265D));
+               (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 &&
+                fwrt->trans->hw_rev != CSR_HW_REV_TYPE_3160) ||
+               (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 &&
+                ((fwrt->trans->hw_rev & CSR_HW_REV_TYPE_MSK) ==
+                 CSR_HW_REV_TYPE_7265D));
 }
 IWL_EXPORT_SYMBOL(iwl_sar_geo_support);
 
index 0703e41..35b8856 100644 (file)
@@ -501,11 +501,6 @@ enum iwl_legacy_cmds {
         */
        DEBUG_LOG_MSG = 0xf7,
 
-       /**
-        * @BCAST_FILTER_CMD: &struct iwl_bcast_filter_cmd
-        */
-       BCAST_FILTER_CMD = 0xcf,
-
        /**
         * @MCAST_FILTER_CMD: &struct iwl_mcast_filter_cmd
         */
index dd62a63..e44c70b 100644 (file)
@@ -36,92 +36,4 @@ struct iwl_mcast_filter_cmd {
        u8 addr_list[0];
 } __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */
 
-#define MAX_BCAST_FILTERS 8
-#define MAX_BCAST_FILTER_ATTRS 2
-
-/**
- * enum iwl_mvm_bcast_filter_attr_offset - written by fw for each Rx packet
- * @BCAST_FILTER_OFFSET_PAYLOAD_START: offset is from payload start.
- * @BCAST_FILTER_OFFSET_IP_END: offset is from ip header end (i.e.
- *     start of ip payload).
- */
-enum iwl_mvm_bcast_filter_attr_offset {
-       BCAST_FILTER_OFFSET_PAYLOAD_START = 0,
-       BCAST_FILTER_OFFSET_IP_END = 1,
-};
-
-/**
- * struct iwl_fw_bcast_filter_attr - broadcast filter attribute
- * @offset_type:       &enum iwl_mvm_bcast_filter_attr_offset.
- * @offset:    starting offset of this pattern.
- * @reserved1: reserved
- * @val:       value to match - big endian (MSB is the first
- *             byte to match from offset pos).
- * @mask:      mask to match (big endian).
- */
-struct iwl_fw_bcast_filter_attr {
-       u8 offset_type;
-       u8 offset;
-       __le16 reserved1;
-       __be32 val;
-       __be32 mask;
-} __packed; /* BCAST_FILTER_ATT_S_VER_1 */
-
-/**
- * enum iwl_mvm_bcast_filter_frame_type - filter frame type
- * @BCAST_FILTER_FRAME_TYPE_ALL: consider all frames.
- * @BCAST_FILTER_FRAME_TYPE_IPV4: consider only ipv4 frames
- */
-enum iwl_mvm_bcast_filter_frame_type {
-       BCAST_FILTER_FRAME_TYPE_ALL = 0,
-       BCAST_FILTER_FRAME_TYPE_IPV4 = 1,
-};
-
-/**
- * struct iwl_fw_bcast_filter - broadcast filter
- * @discard: discard frame (1) or let it pass (0).
- * @frame_type: &enum iwl_mvm_bcast_filter_frame_type.
- * @reserved1: reserved
- * @num_attrs: number of valid attributes in this filter.
- * @attrs: attributes of this filter. a filter is considered matched
- *     only when all its attributes are matched (i.e. AND relationship)
- */
-struct iwl_fw_bcast_filter {
-       u8 discard;
-       u8 frame_type;
-       u8 num_attrs;
-       u8 reserved1;
-       struct iwl_fw_bcast_filter_attr attrs[MAX_BCAST_FILTER_ATTRS];
-} __packed; /* BCAST_FILTER_S_VER_1 */
-
-/**
- * struct iwl_fw_bcast_mac - per-mac broadcast filtering configuration.
- * @default_discard: default action for this mac (discard (1) / pass (0)).
- * @reserved1: reserved
- * @attached_filters: bitmap of relevant filters for this mac.
- */
-struct iwl_fw_bcast_mac {
-       u8 default_discard;
-       u8 reserved1;
-       __le16 attached_filters;
-} __packed; /* BCAST_MAC_CONTEXT_S_VER_1 */
-
-/**
- * struct iwl_bcast_filter_cmd - broadcast filtering configuration
- * @disable: enable (0) / disable (1)
- * @max_bcast_filters: max number of filters (MAX_BCAST_FILTERS)
- * @max_macs: max number of macs (NUM_MAC_INDEX_DRIVER)
- * @reserved1: reserved
- * @filters: broadcast filters
- * @macs: broadcast filtering configuration per-mac
- */
-struct iwl_bcast_filter_cmd {
-       u8 disable;
-       u8 max_bcast_filters;
-       u8 max_macs;
-       u8 reserved1;
-       struct iwl_fw_bcast_filter filters[MAX_BCAST_FILTERS];
-       struct iwl_fw_bcast_mac macs[NUM_MAC_INDEX_DRIVER];
-} __packed; /* BCAST_FILTERING_HCMD_API_S_VER_1 */
-
 #endif /* __iwl_fw_api_filter_h__ */
index 173a699..4a7723e 100644 (file)
@@ -752,7 +752,6 @@ struct iwl_lq_cmd {
 
 u8 iwl_fw_rate_idx_to_plcp(int idx);
 u32 iwl_new_rate_from_v1(u32 rate_v1);
-u32 iwl_legacy_rate_to_fw_idx(u32 rate_n_flags);
 const struct iwl_rate_mcs_info *iwl_rate_mcs(int idx);
 const char *iwl_rs_pretty_ant(u8 ant);
 const char *iwl_rs_pretty_bw(int bw);
index e4ebda6..efc6540 100644 (file)
@@ -181,7 +181,6 @@ struct iwl_ucode_capa {
  * @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version)
  * @IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT: General support for uAPSD
  * @IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD: P2P client supports uAPSD power save
- * @IWL_UCODE_TLV_FLAGS_BCAST_FILTERING: uCode supports broadcast filtering.
  * @IWL_UCODE_TLV_FLAGS_EBS_SUPPORT: this uCode image supports EBS.
  */
 enum iwl_ucode_tlv_flag {
@@ -196,7 +195,6 @@ enum iwl_ucode_tlv_flag {
        IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT       = BIT(24),
        IWL_UCODE_TLV_FLAGS_EBS_SUPPORT         = BIT(25),
        IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD        = BIT(26),
-       IWL_UCODE_TLV_FLAGS_BCAST_FILTERING     = BIT(29),
 };
 
 typedef unsigned int __bitwise iwl_ucode_tlv_api_t;
index a21c3be..a835214 100644 (file)
@@ -91,6 +91,20 @@ const char *iwl_rs_pretty_bw(int bw)
 }
 IWL_EXPORT_SYMBOL(iwl_rs_pretty_bw);
 
+static u32 iwl_legacy_rate_to_fw_idx(u32 rate_n_flags)
+{
+       int rate = rate_n_flags & RATE_LEGACY_RATE_MSK_V1;
+       int idx;
+       bool ofdm = !(rate_n_flags & RATE_MCS_CCK_MSK_V1);
+       int offset = ofdm ? IWL_FIRST_OFDM_RATE : 0;
+       int last = ofdm ? IWL_RATE_COUNT_LEGACY : IWL_FIRST_OFDM_RATE;
+
+       for (idx = offset; idx < last; idx++)
+               if (iwl_fw_rate_idx_to_plcp(idx) == rate)
+                       return idx - offset;
+       return IWL_RATE_INVALID;
+}
+
 u32 iwl_new_rate_from_v1(u32 rate_v1)
 {
        u32 rate_v2 = 0;
@@ -144,7 +158,10 @@ u32 iwl_new_rate_from_v1(u32 rate_v1)
        } else {
                u32 legacy_rate = iwl_legacy_rate_to_fw_idx(rate_v1);
 
-               WARN_ON(legacy_rate < 0);
+               if (WARN_ON_ONCE(legacy_rate == IWL_RATE_INVALID))
+                       legacy_rate = (rate_v1 & RATE_MCS_CCK_MSK_V1) ?
+                               IWL_FIRST_CCK_RATE : IWL_FIRST_OFDM_RATE;
+
                rate_v2 |= legacy_rate;
                if (!(rate_v1 & RATE_MCS_CCK_MSK_V1))
                        rate_v2 |= RATE_MCS_LEGACY_OFDM_MSK;
@@ -172,20 +189,6 @@ u32 iwl_new_rate_from_v1(u32 rate_v1)
 }
 IWL_EXPORT_SYMBOL(iwl_new_rate_from_v1);
 
-u32 iwl_legacy_rate_to_fw_idx(u32 rate_n_flags)
-{
-       int rate = rate_n_flags & RATE_LEGACY_RATE_MSK_V1;
-       int idx;
-       bool ofdm = !(rate_n_flags & RATE_MCS_CCK_MSK_V1);
-       int offset = ofdm ? IWL_FIRST_OFDM_RATE : 0;
-       int last = ofdm ? IWL_RATE_COUNT_LEGACY : IWL_FIRST_OFDM_RATE;
-
-       for (idx = offset; idx < last; idx++)
-               if (iwl_fw_rate_idx_to_plcp(idx) == rate)
-                       return idx - offset;
-       return -1;
-}
-
 int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate)
 {
        char *type;
index f90d466..8e10ba8 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2005-2014, 2018-2021 Intel Corporation
+ * Copyright (C) 2005-2014, 2018-2022 Intel Corporation
  * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
  * Copyright (C) 2016 Intel Deutschland GmbH
  */
@@ -329,6 +329,7 @@ enum {
 #define CSR_HW_REV_TYPE_2x00           (0x0000100)
 #define CSR_HW_REV_TYPE_105            (0x0000110)
 #define CSR_HW_REV_TYPE_135            (0x0000120)
+#define CSR_HW_REV_TYPE_3160           (0x0000164)
 #define CSR_HW_REV_TYPE_7265D          (0x0000210)
 #define CSR_HW_REV_TYPE_NONE           (0x00001F0)
 #define CSR_HW_REV_TYPE_QNJ            (0x0000360)
index 83e3b73..6651e78 100644 (file)
@@ -1707,6 +1707,8 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
  out_unbind:
        complete(&drv->request_firmware_complete);
        device_release_driver(drv->trans->dev);
+       /* drv has just been freed by the release */
+       failure = false;
  free:
        if (failure)
                iwl_dealloc_ucode(drv);
index d9733aa..2f7f0f9 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (C) 2021 Intel Corporation
+ * Copyright (C) 2021-2022 Intel Corporation
  */
 
 #include <linux/etherdevice.h>
@@ -146,6 +146,7 @@ struct iwl_mei_filters {
  * @csme_taking_ownership: true when CSME is taking ownership. Used to remember
  *     to send CSME_OWNERSHIP_CONFIRMED when the driver completes its down
  *     flow.
+ * @link_prot_state: true when we are in link protection PASSIVE
  * @csa_throttle_end_wk: used when &csa_throttled is true
  * @data_q_lock: protects the access to the data queues which are
  *     accessed without the mutex.
@@ -165,6 +166,7 @@ struct iwl_mei {
        bool amt_enabled;
        bool csa_throttled;
        bool csme_taking_ownership;
+       bool link_prot_state;
        struct delayed_work csa_throttle_end_wk;
        spinlock_t data_q_lock;
 
@@ -229,8 +231,6 @@ static int iwl_mei_alloc_shared_mem(struct mei_cl_device *cldev)
        if (IS_ERR(mem->ctrl)) {
                int ret = PTR_ERR(mem->ctrl);
 
-               dev_err(&cldev->dev, "Couldn't allocate the shared memory: %d\n",
-                       ret);
                mem->ctrl = NULL;
 
                return ret;
@@ -669,6 +669,8 @@ iwl_mei_handle_conn_status(struct mei_cl_device *cldev,
 
        iwl_mei_cache.ops->me_conn_status(iwl_mei_cache.priv, &conn_info);
 
+       mei->link_prot_state = status->link_prot_state;
+
        /*
         * Update the Rfkill state in case the host does not own the device:
         * if we are in Link Protection, ask to not touch the device, else,
@@ -1663,9 +1665,11 @@ int iwl_mei_register(void *priv, const struct iwl_mei_ops *ops)
                        mei_cldev_get_drvdata(iwl_mei_global_cldev);
 
                /* we have already a SAP connection */
-               if (iwl_mei_is_connected())
+               if (iwl_mei_is_connected()) {
                        iwl_mei_send_sap_msg(mei->cldev,
                                             SAP_MSG_NOTIF_WIFIDR_UP);
+                       ops->rfkill(priv, mei->link_prot_state);
+               }
        }
        ret = 0;
 
@@ -1784,6 +1788,8 @@ static void iwl_mei_dbgfs_unregister(struct iwl_mei *mei) {}
 
 #endif /* CONFIG_DEBUG_FS */
 
+#define ALLOC_SHARED_MEM_RETRY_MAX_NUM 3
+
 /*
  * iwl_mei_probe - the probe function called by the mei bus enumeration
  *
@@ -1795,6 +1801,7 @@ static void iwl_mei_dbgfs_unregister(struct iwl_mei *mei) {}
 static int iwl_mei_probe(struct mei_cl_device *cldev,
                         const struct mei_cl_device_id *id)
 {
+       int alloc_retry = ALLOC_SHARED_MEM_RETRY_MAX_NUM;
        struct iwl_mei *mei;
        int ret;
 
@@ -1812,15 +1819,31 @@ static int iwl_mei_probe(struct mei_cl_device *cldev,
        mei_cldev_set_drvdata(cldev, mei);
        mei->cldev = cldev;
 
-       /*
-        * The CSME firmware needs to boot the internal WLAN client. Wait here
-        * so that the DMA map request will succeed.
-        */
-       msleep(20);
+       do {
+               ret = iwl_mei_alloc_shared_mem(cldev);
+               if (!ret)
+                       break;
+               /*
+                * The CSME firmware needs to boot the internal WLAN client.
+                * This can take time in certain configurations (usually
+                * upon resume and when the whole CSME firmware is shut down
+                * during suspend).
+                *
+                * Wait a bit before retrying and hope we'll succeed next time.
+                */
 
-       ret = iwl_mei_alloc_shared_mem(cldev);
-       if (ret)
+               dev_dbg(&cldev->dev,
+                       "Couldn't allocate the shared memory: %d, attempt %d / %d\n",
+                       ret, alloc_retry, ALLOC_SHARED_MEM_RETRY_MAX_NUM);
+               msleep(100);
+               alloc_retry--;
+       } while (alloc_retry);
+
+       if (ret) {
+               dev_err(&cldev->dev, "Couldn't allocate the shared memory: %d\n",
+                       ret);
                goto free;
+       }
 
        iwl_mei_init_shared_mem(mei);
 
index 5f966af..468102a 100644 (file)
@@ -195,8 +195,7 @@ static bool iwl_mei_rx_filter_ipv4(struct sk_buff *skb,
        bool match;
 
        if (!pskb_may_pull(skb, skb_network_offset(skb) + sizeof(*iphdr)) ||
-           !pskb_may_pull(skb, skb_network_offset(skb) +
-                          sizeof(ip_hdrlen(skb) - sizeof(*iphdr))))
+           !pskb_may_pull(skb, skb_network_offset(skb) + ip_hdrlen(skb)))
                return false;
 
        iphdrlen = ip_hdrlen(skb);
index fb4920b..63432c2 100644 (file)
@@ -1369,189 +1369,6 @@ static ssize_t iwl_dbgfs_dbg_time_point_write(struct iwl_mvm *mvm,
        return count;
 }
 
-#define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__)
-#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
-static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file,
-                                           char __user *user_buf,
-                                           size_t count, loff_t *ppos)
-{
-       struct iwl_mvm *mvm = file->private_data;
-       struct iwl_bcast_filter_cmd cmd;
-       const struct iwl_fw_bcast_filter *filter;
-       char *buf;
-       int bufsz = 1024;
-       int i, j, pos = 0;
-       ssize_t ret;
-
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       mutex_lock(&mvm->mutex);
-       if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) {
-               ADD_TEXT("None\n");
-               mutex_unlock(&mvm->mutex);
-               goto out;
-       }
-       mutex_unlock(&mvm->mutex);
-
-       for (i = 0; cmd.filters[i].attrs[0].mask; i++) {
-               filter = &cmd.filters[i];
-
-               ADD_TEXT("Filter [%d]:\n", i);
-               ADD_TEXT("\tDiscard=%d\n", filter->discard);
-               ADD_TEXT("\tFrame Type: %s\n",
-                        filter->frame_type ? "IPv4" : "Generic");
-
-               for (j = 0; j < ARRAY_SIZE(filter->attrs); j++) {
-                       const struct iwl_fw_bcast_filter_attr *attr;
-
-                       attr = &filter->attrs[j];
-                       if (!attr->mask)
-                               break;
-
-                       ADD_TEXT("\tAttr [%d]: offset=%d (from %s), mask=0x%x, value=0x%x reserved=0x%x\n",
-                                j, attr->offset,
-                                attr->offset_type ? "IP End" :
-                                                    "Payload Start",
-                                be32_to_cpu(attr->mask),
-                                be32_to_cpu(attr->val),
-                                le16_to_cpu(attr->reserved1));
-               }
-       }
-out:
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_bcast_filters_write(struct iwl_mvm *mvm, char *buf,
-                                            size_t count, loff_t *ppos)
-{
-       int pos, next_pos;
-       struct iwl_fw_bcast_filter filter = {};
-       struct iwl_bcast_filter_cmd cmd;
-       u32 filter_id, attr_id, mask, value;
-       int err = 0;
-
-       if (sscanf(buf, "%d %hhi %hhi %n", &filter_id, &filter.discard,
-                  &filter.frame_type, &pos) != 3)
-               return -EINVAL;
-
-       if (filter_id >= ARRAY_SIZE(mvm->dbgfs_bcast_filtering.cmd.filters) ||
-           filter.frame_type > BCAST_FILTER_FRAME_TYPE_IPV4)
-               return -EINVAL;
-
-       for (attr_id = 0; attr_id < ARRAY_SIZE(filter.attrs);
-            attr_id++) {
-               struct iwl_fw_bcast_filter_attr *attr =
-                               &filter.attrs[attr_id];
-
-               if (pos >= count)
-                       break;
-
-               if (sscanf(&buf[pos], "%hhi %hhi %i %i %n",
-                          &attr->offset, &attr->offset_type,
-                          &mask, &value, &next_pos) != 4)
-                       return -EINVAL;
-
-               attr->mask = cpu_to_be32(mask);
-               attr->val = cpu_to_be32(value);
-               if (mask)
-                       filter.num_attrs++;
-
-               pos += next_pos;
-       }
-
-       mutex_lock(&mvm->mutex);
-       memcpy(&mvm->dbgfs_bcast_filtering.cmd.filters[filter_id],
-              &filter, sizeof(filter));
-
-       /* send updated bcast filtering configuration */
-       if (iwl_mvm_firmware_running(mvm) &&
-           mvm->dbgfs_bcast_filtering.override &&
-           iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
-               err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0,
-                                          sizeof(cmd), &cmd);
-       mutex_unlock(&mvm->mutex);
-
-       return err ?: count;
-}
-
-static ssize_t iwl_dbgfs_bcast_filters_macs_read(struct file *file,
-                                                char __user *user_buf,
-                                                size_t count, loff_t *ppos)
-{
-       struct iwl_mvm *mvm = file->private_data;
-       struct iwl_bcast_filter_cmd cmd;
-       char *buf;
-       int bufsz = 1024;
-       int i, pos = 0;
-       ssize_t ret;
-
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       mutex_lock(&mvm->mutex);
-       if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) {
-               ADD_TEXT("None\n");
-               mutex_unlock(&mvm->mutex);
-               goto out;
-       }
-       mutex_unlock(&mvm->mutex);
-
-       for (i = 0; i < ARRAY_SIZE(cmd.macs); i++) {
-               const struct iwl_fw_bcast_mac *mac = &cmd.macs[i];
-
-               ADD_TEXT("Mac [%d]: discard=%d attached_filters=0x%x\n",
-                        i, mac->default_discard, mac->attached_filters);
-       }
-out:
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm,
-                                                 char *buf, size_t count,
-                                                 loff_t *ppos)
-{
-       struct iwl_bcast_filter_cmd cmd;
-       struct iwl_fw_bcast_mac mac = {};
-       u32 mac_id, attached_filters;
-       int err = 0;
-
-       if (!mvm->bcast_filters)
-               return -ENOENT;
-
-       if (sscanf(buf, "%d %hhi %i", &mac_id, &mac.default_discard,
-                  &attached_filters) != 3)
-               return -EINVAL;
-
-       if (mac_id >= ARRAY_SIZE(cmd.macs) ||
-           mac.default_discard > 1 ||
-           attached_filters >= BIT(ARRAY_SIZE(cmd.filters)))
-               return -EINVAL;
-
-       mac.attached_filters = cpu_to_le16(attached_filters);
-
-       mutex_lock(&mvm->mutex);
-       memcpy(&mvm->dbgfs_bcast_filtering.cmd.macs[mac_id],
-              &mac, sizeof(mac));
-
-       /* send updated bcast filtering configuration */
-       if (iwl_mvm_firmware_running(mvm) &&
-           mvm->dbgfs_bcast_filtering.override &&
-           iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
-               err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0,
-                                          sizeof(cmd), &cmd);
-       mutex_unlock(&mvm->mutex);
-
-       return err ?: count;
-}
-#endif
-
 #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
        _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
 #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
@@ -1881,11 +1698,6 @@ MVM_DEBUGFS_WRITE_FILE_OPS(inject_beacon_ie_restore, 512);
 
 MVM_DEBUGFS_READ_FILE_OPS(uapsd_noagg_bssids);
 
-#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
-MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
-MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
-#endif
-
 #ifdef CONFIG_ACPI
 MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile);
 #endif
@@ -2097,21 +1909,6 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm)
 
        MVM_DEBUGFS_ADD_FILE(uapsd_noagg_bssids, mvm->debugfs_dir, S_IRUSR);
 
-#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
-       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) {
-               bcast_dir = debugfs_create_dir("bcast_filtering",
-                                              mvm->debugfs_dir);
-
-               debugfs_create_bool("override", 0600, bcast_dir,
-                                   &mvm->dbgfs_bcast_filtering.override);
-
-               MVM_DEBUGFS_ADD_FILE_ALIAS("filters", bcast_filters,
-                                          bcast_dir, 0600);
-               MVM_DEBUGFS_ADD_FILE_ALIAS("macs", bcast_filters_macs,
-                                          bcast_dir, 0600);
-       }
-#endif
-
 #ifdef CONFIG_PM_SLEEP
        MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, 0400);
        debugfs_create_bool("d3_wake_sysassert", 0600, mvm->debugfs_dir,
index 6f4690e..ae589b3 100644 (file)
@@ -1741,7 +1741,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        ret = iwl_mvm_sar_init(mvm);
        if (ret == 0)
                ret = iwl_mvm_sar_geo_init(mvm);
-       else if (ret < 0)
+       if (ret < 0)
                goto error;
 
        ret = iwl_mvm_sgom_init(mvm);
index 65f4fe3..4ac599f 100644 (file)
@@ -55,79 +55,6 @@ static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = {
        },
 };
 
-#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
-/*
- * Use the reserved field to indicate magic values.
- * these values will only be used internally by the driver,
- * and won't make it to the fw (reserved will be 0).
- * BC_FILTER_MAGIC_IP - configure the val of this attribute to
- *     be the vif's ip address. in case there is not a single
- *     ip address (0, or more than 1), this attribute will
- *     be skipped.
- * BC_FILTER_MAGIC_MAC - set the val of this attribute to
- *     the LSB bytes of the vif's mac address
- */
-enum {
-       BC_FILTER_MAGIC_NONE = 0,
-       BC_FILTER_MAGIC_IP,
-       BC_FILTER_MAGIC_MAC,
-};
-
-static const struct iwl_fw_bcast_filter iwl_mvm_default_bcast_filters[] = {
-       {
-               /* arp */
-               .discard = 0,
-               .frame_type = BCAST_FILTER_FRAME_TYPE_ALL,
-               .attrs = {
-                       {
-                               /* frame type - arp, hw type - ethernet */
-                               .offset_type =
-                                       BCAST_FILTER_OFFSET_PAYLOAD_START,
-                               .offset = sizeof(rfc1042_header),
-                               .val = cpu_to_be32(0x08060001),
-                               .mask = cpu_to_be32(0xffffffff),
-                       },
-                       {
-                               /* arp dest ip */
-                               .offset_type =
-                                       BCAST_FILTER_OFFSET_PAYLOAD_START,
-                               .offset = sizeof(rfc1042_header) + 2 +
-                                         sizeof(struct arphdr) +
-                                         ETH_ALEN + sizeof(__be32) +
-                                         ETH_ALEN,
-                               .mask = cpu_to_be32(0xffffffff),
-                               /* mark it as special field */
-                               .reserved1 = cpu_to_le16(BC_FILTER_MAGIC_IP),
-                       },
-               },
-       },
-       {
-               /* dhcp offer bcast */
-               .discard = 0,
-               .frame_type = BCAST_FILTER_FRAME_TYPE_IPV4,
-               .attrs = {
-                       {
-                               /* udp dest port - 68 (bootp client)*/
-                               .offset_type = BCAST_FILTER_OFFSET_IP_END,
-                               .offset = offsetof(struct udphdr, dest),
-                               .val = cpu_to_be32(0x00440000),
-                               .mask = cpu_to_be32(0xffff0000),
-                       },
-                       {
-                               /* dhcp - lsb bytes of client hw address */
-                               .offset_type = BCAST_FILTER_OFFSET_IP_END,
-                               .offset = 38,
-                               .mask = cpu_to_be32(0xffffffff),
-                               /* mark it as special field */
-                               .reserved1 = cpu_to_le16(BC_FILTER_MAGIC_MAC),
-                       },
-               },
-       },
-       /* last filter must be empty */
-       {},
-};
-#endif
-
 static const struct cfg80211_pmsr_capabilities iwl_mvm_pmsr_capa = {
        .max_peers = IWL_MVM_TOF_MAX_APS,
        .report_ap_tsf = 1,
@@ -693,11 +620,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        }
 #endif
 
-#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
-       /* assign default bcast filtering configuration */
-       mvm->bcast_filters = iwl_mvm_default_bcast_filters;
-#endif
-
        ret = iwl_mvm_leds_init(mvm);
        if (ret)
                return ret;
@@ -1853,162 +1775,6 @@ static void iwl_mvm_config_iface_filter(struct ieee80211_hw *hw,
        mutex_unlock(&mvm->mutex);
 }
 
-#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
-struct iwl_bcast_iter_data {
-       struct iwl_mvm *mvm;
-       struct iwl_bcast_filter_cmd *cmd;
-       u8 current_filter;
-};
-
-static void
-iwl_mvm_set_bcast_filter(struct ieee80211_vif *vif,
-                        const struct iwl_fw_bcast_filter *in_filter,
-                        struct iwl_fw_bcast_filter *out_filter)
-{
-       struct iwl_fw_bcast_filter_attr *attr;
-       int i;
-
-       memcpy(out_filter, in_filter, sizeof(*out_filter));
-
-       for (i = 0; i < ARRAY_SIZE(out_filter->attrs); i++) {
-               attr = &out_filter->attrs[i];
-
-               if (!attr->mask)
-                       break;
-
-               switch (attr->reserved1) {
-               case cpu_to_le16(BC_FILTER_MAGIC_IP):
-                       if (vif->bss_conf.arp_addr_cnt != 1) {
-                               attr->mask = 0;
-                               continue;
-                       }
-
-                       attr->val = vif->bss_conf.arp_addr_list[0];
-                       break;
-               case cpu_to_le16(BC_FILTER_MAGIC_MAC):
-                       attr->val = *(__be32 *)&vif->addr[2];
-                       break;
-               default:
-                       break;
-               }
-               attr->reserved1 = 0;
-               out_filter->num_attrs++;
-       }
-}
-
-static void iwl_mvm_bcast_filter_iterator(void *_data, u8 *mac,
-                                         struct ieee80211_vif *vif)
-{
-       struct iwl_bcast_iter_data *data = _data;
-       struct iwl_mvm *mvm = data->mvm;
-       struct iwl_bcast_filter_cmd *cmd = data->cmd;
-       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       struct iwl_fw_bcast_mac *bcast_mac;
-       int i;
-
-       if (WARN_ON(mvmvif->id >= ARRAY_SIZE(cmd->macs)))
-               return;
-
-       bcast_mac = &cmd->macs[mvmvif->id];
-
-       /*
-        * enable filtering only for associated stations, but not for P2P
-        * Clients
-        */
-       if (vif->type != NL80211_IFTYPE_STATION || vif->p2p ||
-           !vif->bss_conf.assoc)
-               return;
-
-       bcast_mac->default_discard = 1;
-
-       /* copy all configured filters */
-       for (i = 0; mvm->bcast_filters[i].attrs[0].mask; i++) {
-               /*
-                * Make sure we don't exceed our filters limit.
-                * if there is still a valid filter to be configured,
-                * be on the safe side and just allow bcast for this mac.
-                */
-               if (WARN_ON_ONCE(data->current_filter >=
-                                ARRAY_SIZE(cmd->filters))) {
-                       bcast_mac->default_discard = 0;
-                       bcast_mac->attached_filters = 0;
-                       break;
-               }
-
-               iwl_mvm_set_bcast_filter(vif,
-                                        &mvm->bcast_filters[i],
-                                        &cmd->filters[data->current_filter]);
-
-               /* skip current filter if it contains no attributes */
-               if (!cmd->filters[data->current_filter].num_attrs)
-                       continue;
-
-               /* attach the filter to current mac */
-               bcast_mac->attached_filters |=
-                               cpu_to_le16(BIT(data->current_filter));
-
-               data->current_filter++;
-       }
-}
-
-bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm,
-                                   struct iwl_bcast_filter_cmd *cmd)
-{
-       struct iwl_bcast_iter_data iter_data = {
-               .mvm = mvm,
-               .cmd = cmd,
-       };
-
-       if (IWL_MVM_FW_BCAST_FILTER_PASS_ALL)
-               return false;
-
-       memset(cmd, 0, sizeof(*cmd));
-       cmd->max_bcast_filters = ARRAY_SIZE(cmd->filters);
-       cmd->max_macs = ARRAY_SIZE(cmd->macs);
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-       /* use debugfs filters/macs if override is configured */
-       if (mvm->dbgfs_bcast_filtering.override) {
-               memcpy(cmd->filters, &mvm->dbgfs_bcast_filtering.cmd.filters,
-                      sizeof(cmd->filters));
-               memcpy(cmd->macs, &mvm->dbgfs_bcast_filtering.cmd.macs,
-                      sizeof(cmd->macs));
-               return true;
-       }
-#endif
-
-       /* if no filters are configured, do nothing */
-       if (!mvm->bcast_filters)
-               return false;
-
-       /* configure and attach these filters for each associated sta vif */
-       ieee80211_iterate_active_interfaces(
-               mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
-               iwl_mvm_bcast_filter_iterator, &iter_data);
-
-       return true;
-}
-
-static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm)
-{
-       struct iwl_bcast_filter_cmd cmd;
-
-       if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING))
-               return 0;
-
-       if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
-               return 0;
-
-       return iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0,
-                                   sizeof(cmd), &cmd);
-}
-#else
-static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm)
-{
-       return 0;
-}
-#endif
-
 static int iwl_mvm_update_mu_groups(struct iwl_mvm *mvm,
                                    struct ieee80211_vif *vif)
 {
@@ -2520,7 +2286,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                }
 
                iwl_mvm_recalc_multicast(mvm);
-               iwl_mvm_configure_bcast_filter(mvm);
 
                /* reset rssi values */
                mvmvif->bf_data.ave_beacon_signal = 0;
@@ -2570,11 +2335,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                }
        }
 
-       if (changes & BSS_CHANGED_ARP_FILTER) {
-               IWL_DEBUG_MAC80211(mvm, "arp filter changed\n");
-               iwl_mvm_configure_bcast_filter(mvm);
-       }
-
        if (changes & BSS_CHANGED_BANDWIDTH)
                iwl_mvm_apply_fw_smps_request(vif);
 }
index 1dcbb0e..d78f407 100644 (file)
@@ -884,17 +884,6 @@ struct iwl_mvm {
        /* rx chain antennas set through debugfs for the scan command */
        u8 scan_rx_ant;
 
-#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
-       /* broadcast filters to configure for each associated station */
-       const struct iwl_fw_bcast_filter *bcast_filters;
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-       struct {
-               bool override;
-               struct iwl_bcast_filter_cmd cmd;
-       } dbgfs_bcast_filtering;
-#endif
-#endif
-
        /* Internal station */
        struct iwl_mvm_int_sta aux_sta;
        struct iwl_mvm_int_sta snif_sta;
@@ -1593,8 +1582,6 @@ int iwl_mvm_up(struct iwl_mvm *mvm);
 int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm);
 
 int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm);
-bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm,
-                                   struct iwl_bcast_filter_cmd *cmd);
 
 /*
  * FW notifications / CMD responses handlers
@@ -2225,7 +2212,7 @@ static inline void iwl_mvm_mei_device_down(struct iwl_mvm *mvm)
 static inline void iwl_mvm_mei_set_sw_rfkill_state(struct iwl_mvm *mvm)
 {
        bool sw_rfkill =
-               mvm->hw_registered ? rfkill_blocked(mvm->hw->wiphy->rfkill) : false;
+               mvm->hw_registered ? rfkill_soft_blocked(mvm->hw->wiphy->rfkill) : false;
 
        if (mvm->mei_registered)
                iwl_mei_set_rfkill_state(iwl_mvm_is_radio_killed(mvm),
index 87630d3..1f8b979 100644 (file)
@@ -469,7 +469,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {
        HCMD_NAME(MCC_CHUB_UPDATE_CMD),
        HCMD_NAME(MARKER_CMD),
        HCMD_NAME(BT_PROFILE_NOTIFICATION),
-       HCMD_NAME(BCAST_FILTER_CMD),
        HCMD_NAME(MCAST_FILTER_CMD),
        HCMD_NAME(REPLY_SF_CFG_CMD),
        HCMD_NAME(REPLY_BEACON_FILTERING_CMD),
index 6fa2c12..9213f85 100644 (file)
@@ -1427,7 +1427,7 @@ static void iwl_mvm_hwrate_to_tx_status(const struct iwl_fw *fw,
        struct ieee80211_tx_rate *r = &info->status.rates[0];
 
        if (iwl_fw_lookup_notif_ver(fw, LONG_GROUP,
-                                   TX_CMD, 0) > 6)
+                                   TX_CMD, 0) <= 6)
                rate_n_flags = iwl_new_rate_from_v1(rate_n_flags);
 
        info->status.antenna =
index 0febdca..94f40c4 100644 (file)
@@ -385,8 +385,7 @@ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans,
        /* This may fail if AMT took ownership of the device */
        if (iwl_pcie_prepare_card_hw(trans)) {
                IWL_WARN(trans, "Exit HW not ready\n");
-               ret = -EIO;
-               goto out;
+               return -EIO;
        }
 
        iwl_enable_rfkill_int(trans);
index a63386a..ef14584 100644 (file)
@@ -1329,8 +1329,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
        /* This may fail if AMT took ownership of the device */
        if (iwl_pcie_prepare_card_hw(trans)) {
                IWL_WARN(trans, "Exit HW not ready\n");
-               ret = -EIO;
-               goto out;
+               return -EIO;
        }
 
        iwl_enable_rfkill_int(trans);
index 8d54f9f..fc5725f 100644 (file)
@@ -2336,6 +2336,15 @@ static void hw_scan_work(struct work_struct *work)
                        if (req->ie_len)
                                skb_put_data(probe, req->ie, req->ie_len);
 
+                       if (!ieee80211_tx_prepare_skb(hwsim->hw,
+                                                     hwsim->hw_scan_vif,
+                                                     probe,
+                                                     hwsim->tmp_chan->band,
+                                                     NULL)) {
+                               kfree_skb(probe);
+                               continue;
+                       }
+
                        local_bh_disable();
                        mac80211_hwsim_tx_frame(hwsim->hw, probe,
                                                hwsim->tmp_chan);
@@ -3770,6 +3779,10 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
                }
                txi->flags |= IEEE80211_TX_STAT_ACK;
        }
+
+       if (hwsim_flags & HWSIM_TX_CTL_NO_ACK)
+               txi->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
+
        ieee80211_tx_status_irqsafe(data2->hw, skb);
        return 0;
 out:
index d24b7a7..990360d 100644 (file)
@@ -256,6 +256,7 @@ static void backend_disconnect(struct backend_info *be)
                unsigned int queue_index;
 
                xen_unregister_watchers(vif);
+               xenbus_rm(XBT_NIL, be->dev->nodename, "hotplug-status");
 #ifdef CONFIG_DEBUG_FS
                xenvif_debugfs_delif(vif);
 #endif /* CONFIG_DEBUG_FS */
@@ -675,7 +676,6 @@ static void hotplug_status_changed(struct xenbus_watch *watch,
 
                /* Not interested in this watch anymore. */
                unregister_hotplug_status_watch(be);
-               xenbus_rm(XBT_NIL, be->dev->nodename, "hotplug-status");
        }
        kfree(str);
 }
@@ -824,15 +824,11 @@ static void connect(struct backend_info *be)
        xenvif_carrier_on(be->vif);
 
        unregister_hotplug_status_watch(be);
-       if (xenbus_exists(XBT_NIL, dev->nodename, "hotplug-status")) {
-               err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch,
-                                          NULL, hotplug_status_changed,
-                                          "%s/%s", dev->nodename,
-                                          "hotplug-status");
-               if (err)
-                       goto err;
+       err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch, NULL,
+                                  hotplug_status_changed,
+                                  "%s/%s", dev->nodename, "hotplug-status");
+       if (!err)
                be->have_hotplug_status_watch = 1;
-       }
 
        netif_tx_wake_all_queues(be->vif->dev);
 
index 5e0bfda..fd4720d 100644 (file)
@@ -368,6 +368,7 @@ EXPORT_SYMBOL_GPL(nvme_complete_rq);
 
 void nvme_complete_batch_req(struct request *req)
 {
+       trace_nvme_complete_rq(req);
        nvme_cleanup_cmd(req);
        nvme_end_req_zoned(req);
 }
@@ -1722,7 +1723,7 @@ static int nvme_setup_streams_ns(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
        return 0;
 }
 
-static int nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id)
+static void nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id)
 {
        struct nvme_ctrl *ctrl = ns->ctrl;
 
@@ -1738,7 +1739,8 @@ static int nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id)
 
        ns->features &= ~(NVME_NS_METADATA_SUPPORTED | NVME_NS_EXT_LBAS);
        if (!ns->ms || !(ctrl->ops->flags & NVME_F_METADATA_SUPPORTED))
-               return 0;
+               return;
+
        if (ctrl->ops->flags & NVME_F_FABRICS) {
                /*
                 * The NVMe over Fabrics specification only supports metadata as
@@ -1746,7 +1748,7 @@ static int nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id)
                 * remap the separate metadata buffer from the block layer.
                 */
                if (WARN_ON_ONCE(!(id->flbas & NVME_NS_FLBAS_META_EXT)))
-                       return -EINVAL;
+                       return;
 
                ns->features |= NVME_NS_EXT_LBAS;
 
@@ -1773,8 +1775,6 @@ static int nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id)
                else
                        ns->features |= NVME_NS_METADATA_SUPPORTED;
        }
-
-       return 0;
 }
 
 static void nvme_set_queue_limits(struct nvme_ctrl *ctrl,
@@ -1915,9 +1915,7 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
        ns->lba_shift = id->lbaf[lbaf].ds;
        nvme_set_queue_limits(ns->ctrl, ns->queue);
 
-       ret = nvme_configure_metadata(ns, id);
-       if (ret)
-               goto out_unfreeze;
+       nvme_configure_metadata(ns, id);
        nvme_set_chunk_sectors(ns, id);
        nvme_update_disk_info(ns->disk, ns, id);
 
@@ -1933,7 +1931,7 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
        if (blk_queue_is_zoned(ns->queue)) {
                ret = nvme_revalidate_zones(ns);
                if (ret && !nvme_first_scan(ns->disk))
-                       goto out;
+                       return ret;
        }
 
        if (nvme_ns_head_multipath(ns->head)) {
@@ -1948,16 +1946,16 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
        return 0;
 
 out_unfreeze:
-       blk_mq_unfreeze_queue(ns->disk->queue);
-out:
        /*
         * If probing fails due an unsupported feature, hide the block device,
         * but still allow other access.
         */
        if (ret == -ENODEV) {
                ns->disk->flags |= GENHD_FL_HIDDEN;
+               set_bit(NVME_NS_READY, &ns->flags);
                ret = 0;
        }
+       blk_mq_unfreeze_queue(ns->disk->queue);
        return ret;
 }
 
@@ -4253,7 +4251,14 @@ static void nvme_async_event_work(struct work_struct *work)
                container_of(work, struct nvme_ctrl, async_event_work);
 
        nvme_aen_uevent(ctrl);
-       ctrl->ops->submit_async_event(ctrl);
+
+       /*
+        * The transport drivers must guarantee AER submission here is safe by
+        * flushing ctrl async_event_work after changing the controller state
+        * from LIVE and before freeing the admin queue.
+       */
+       if (ctrl->state == NVME_CTRL_LIVE)
+               ctrl->ops->submit_async_event(ctrl);
 }
 
 static bool nvme_ctrl_pp_status(struct nvme_ctrl *ctrl)
@@ -4566,7 +4571,7 @@ static void nvme_set_queue_dying(struct nvme_ns *ns)
        if (test_and_set_bit(NVME_NS_DEAD, &ns->flags))
                return;
 
-       blk_set_queue_dying(ns->queue);
+       blk_mark_disk_dead(ns->disk);
        nvme_start_ns_queue(ns);
 
        set_capacity_and_notify(ns->disk, 0);
index 7ae041e..f79a66d 100644 (file)
@@ -1092,7 +1092,6 @@ static void __nvmf_concat_opt_tokens(struct seq_file *seq_file)
 static int nvmf_dev_show(struct seq_file *seq_file, void *private)
 {
        struct nvme_ctrl *ctrl;
-       int ret = 0;
 
        mutex_lock(&nvmf_dev_mutex);
        ctrl = seq_file->private;
@@ -1106,7 +1105,7 @@ static int nvmf_dev_show(struct seq_file *seq_file, void *private)
 
 out_unlock:
        mutex_unlock(&nvmf_dev_mutex);
-       return ret;
+       return 0;
 }
 
 static int nvmf_dev_open(struct inode *inode, struct file *file)
index c3203ff..1e3a09c 100644 (file)
@@ -170,6 +170,7 @@ nvmf_ctlr_matches_baseopts(struct nvme_ctrl *ctrl,
                        struct nvmf_ctrl_options *opts)
 {
        if (ctrl->state == NVME_CTRL_DELETING ||
+           ctrl->state == NVME_CTRL_DELETING_NOIO ||
            ctrl->state == NVME_CTRL_DEAD ||
            strcmp(opts->subsysnqn, ctrl->opts->subsysnqn) ||
            strcmp(opts->host->nqn, ctrl->opts->host->nqn) ||
index f8bf660..ff77523 100644 (file)
@@ -848,7 +848,7 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head)
 {
        if (!head->disk)
                return;
-       blk_set_queue_dying(head->disk->queue);
+       blk_mark_disk_dead(head->disk);
        /* make sure all pending bios are cleaned up */
        kblockd_schedule_work(&head->requeue_work);
        flush_work(&head->requeue_work);
index d8585df..6a99ed6 100644 (file)
@@ -3391,7 +3391,8 @@ static const struct pci_device_id nvme_id_table[] = {
                                NVME_QUIRK_DEALLOCATE_ZEROES, },
        { PCI_VDEVICE(INTEL, 0x0a54),   /* Intel P4500/P4600 */
                .driver_data = NVME_QUIRK_STRIPE_SIZE |
-                               NVME_QUIRK_DEALLOCATE_ZEROES, },
+                               NVME_QUIRK_DEALLOCATE_ZEROES |
+                               NVME_QUIRK_IGNORE_DEV_SUBNQN, },
        { PCI_VDEVICE(INTEL, 0x0a55),   /* Dell Express Flash P4600 */
                .driver_data = NVME_QUIRK_STRIPE_SIZE |
                                NVME_QUIRK_DEALLOCATE_ZEROES, },
index 850f84d..9c55e4b 100644 (file)
@@ -1200,6 +1200,7 @@ static void nvme_rdma_error_recovery_work(struct work_struct *work)
                        struct nvme_rdma_ctrl, err_work);
 
        nvme_stop_keep_alive(&ctrl->ctrl);
+       flush_work(&ctrl->ctrl.async_event_work);
        nvme_rdma_teardown_io_queues(ctrl, false);
        nvme_start_queues(&ctrl->ctrl);
        nvme_rdma_teardown_admin_queue(ctrl, false);
index 4ceb286..65e00c6 100644 (file)
@@ -44,6 +44,8 @@ struct nvme_tcp_request {
        u32                     data_len;
        u32                     pdu_len;
        u32                     pdu_sent;
+       u32                     h2cdata_left;
+       u32                     h2cdata_offset;
        u16                     ttag;
        __le16                  status;
        struct list_head        entry;
@@ -95,6 +97,7 @@ struct nvme_tcp_queue {
        struct nvme_tcp_request *request;
 
        int                     queue_size;
+       u32                     maxh2cdata;
        size_t                  cmnd_capsule_len;
        struct nvme_tcp_ctrl    *ctrl;
        unsigned long           flags;
@@ -572,23 +575,26 @@ static int nvme_tcp_handle_comp(struct nvme_tcp_queue *queue,
        return ret;
 }
 
-static void nvme_tcp_setup_h2c_data_pdu(struct nvme_tcp_request *req,
-               struct nvme_tcp_r2t_pdu *pdu)
+static void nvme_tcp_setup_h2c_data_pdu(struct nvme_tcp_request *req)
 {
        struct nvme_tcp_data_pdu *data = req->pdu;
        struct nvme_tcp_queue *queue = req->queue;
        struct request *rq = blk_mq_rq_from_pdu(req);
+       u32 h2cdata_sent = req->pdu_len;
        u8 hdgst = nvme_tcp_hdgst_len(queue);
        u8 ddgst = nvme_tcp_ddgst_len(queue);
 
        req->state = NVME_TCP_SEND_H2C_PDU;
        req->offset = 0;
-       req->pdu_len = le32_to_cpu(pdu->r2t_length);
+       req->pdu_len = min(req->h2cdata_left, queue->maxh2cdata);
        req->pdu_sent = 0;
+       req->h2cdata_left -= req->pdu_len;
+       req->h2cdata_offset += h2cdata_sent;
 
        memset(data, 0, sizeof(*data));
        data->hdr.type = nvme_tcp_h2c_data;
-       data->hdr.flags = NVME_TCP_F_DATA_LAST;
+       if (!req->h2cdata_left)
+               data->hdr.flags = NVME_TCP_F_DATA_LAST;
        if (queue->hdr_digest)
                data->hdr.flags |= NVME_TCP_F_HDGST;
        if (queue->data_digest)
@@ -597,9 +603,9 @@ static void nvme_tcp_setup_h2c_data_pdu(struct nvme_tcp_request *req,
        data->hdr.pdo = data->hdr.hlen + hdgst;
        data->hdr.plen =
                cpu_to_le32(data->hdr.hlen + hdgst + req->pdu_len + ddgst);
-       data->ttag = pdu->ttag;
+       data->ttag = req->ttag;
        data->command_id = nvme_cid(rq);
-       data->data_offset = pdu->r2t_offset;
+       data->data_offset = cpu_to_le32(req->h2cdata_offset);
        data->data_length = cpu_to_le32(req->pdu_len);
 }
 
@@ -609,6 +615,7 @@ static int nvme_tcp_handle_r2t(struct nvme_tcp_queue *queue,
        struct nvme_tcp_request *req;
        struct request *rq;
        u32 r2t_length = le32_to_cpu(pdu->r2t_length);
+       u32 r2t_offset = le32_to_cpu(pdu->r2t_offset);
 
        rq = nvme_find_rq(nvme_tcp_tagset(queue), pdu->command_id);
        if (!rq) {
@@ -633,14 +640,19 @@ static int nvme_tcp_handle_r2t(struct nvme_tcp_queue *queue,
                return -EPROTO;
        }
 
-       if (unlikely(le32_to_cpu(pdu->r2t_offset) < req->data_sent)) {
+       if (unlikely(r2t_offset < req->data_sent)) {
                dev_err(queue->ctrl->ctrl.device,
                        "req %d unexpected r2t offset %u (expected %zu)\n",
-                       rq->tag, le32_to_cpu(pdu->r2t_offset), req->data_sent);
+                       rq->tag, r2t_offset, req->data_sent);
                return -EPROTO;
        }
 
-       nvme_tcp_setup_h2c_data_pdu(req, pdu);
+       req->pdu_len = 0;
+       req->h2cdata_left = r2t_length;
+       req->h2cdata_offset = r2t_offset;
+       req->ttag = pdu->ttag;
+
+       nvme_tcp_setup_h2c_data_pdu(req);
        nvme_tcp_queue_request(req, false, true);
 
        return 0;
@@ -913,13 +925,22 @@ static inline void nvme_tcp_done_send_req(struct nvme_tcp_queue *queue)
 
 static void nvme_tcp_fail_request(struct nvme_tcp_request *req)
 {
-       nvme_tcp_end_request(blk_mq_rq_from_pdu(req), NVME_SC_HOST_PATH_ERROR);
+       if (nvme_tcp_async_req(req)) {
+               union nvme_result res = {};
+
+               nvme_complete_async_event(&req->queue->ctrl->ctrl,
+                               cpu_to_le16(NVME_SC_HOST_PATH_ERROR), &res);
+       } else {
+               nvme_tcp_end_request(blk_mq_rq_from_pdu(req),
+                               NVME_SC_HOST_PATH_ERROR);
+       }
 }
 
 static int nvme_tcp_try_send_data(struct nvme_tcp_request *req)
 {
        struct nvme_tcp_queue *queue = req->queue;
        int req_data_len = req->data_len;
+       u32 h2cdata_left = req->h2cdata_left;
 
        while (true) {
                struct page *page = nvme_tcp_req_cur_page(req);
@@ -964,7 +985,10 @@ static int nvme_tcp_try_send_data(struct nvme_tcp_request *req)
                                req->state = NVME_TCP_SEND_DDGST;
                                req->offset = 0;
                        } else {
-                               nvme_tcp_done_send_req(queue);
+                               if (h2cdata_left)
+                                       nvme_tcp_setup_h2c_data_pdu(req);
+                               else
+                                       nvme_tcp_done_send_req(queue);
                        }
                        return 1;
                }
@@ -1022,9 +1046,14 @@ static int nvme_tcp_try_send_data_pdu(struct nvme_tcp_request *req)
        if (queue->hdr_digest && !req->offset)
                nvme_tcp_hdgst(queue->snd_hash, pdu, sizeof(*pdu));
 
-       ret = kernel_sendpage(queue->sock, virt_to_page(pdu),
-                       offset_in_page(pdu) + req->offset, len,
-                       MSG_DONTWAIT | MSG_MORE | MSG_SENDPAGE_NOTLAST);
+       if (!req->h2cdata_left)
+               ret = kernel_sendpage(queue->sock, virt_to_page(pdu),
+                               offset_in_page(pdu) + req->offset, len,
+                               MSG_DONTWAIT | MSG_MORE | MSG_SENDPAGE_NOTLAST);
+       else
+               ret = sock_no_sendpage(queue->sock, virt_to_page(pdu),
+                               offset_in_page(pdu) + req->offset, len,
+                               MSG_DONTWAIT | MSG_MORE);
        if (unlikely(ret <= 0))
                return ret;
 
@@ -1044,6 +1073,7 @@ static int nvme_tcp_try_send_ddgst(struct nvme_tcp_request *req)
 {
        struct nvme_tcp_queue *queue = req->queue;
        size_t offset = req->offset;
+       u32 h2cdata_left = req->h2cdata_left;
        int ret;
        struct msghdr msg = { .msg_flags = MSG_DONTWAIT };
        struct kvec iov = {
@@ -1061,7 +1091,10 @@ static int nvme_tcp_try_send_ddgst(struct nvme_tcp_request *req)
                return ret;
 
        if (offset + ret == NVME_TCP_DIGEST_LENGTH) {
-               nvme_tcp_done_send_req(queue);
+               if (h2cdata_left)
+                       nvme_tcp_setup_h2c_data_pdu(req);
+               else
+                       nvme_tcp_done_send_req(queue);
                return 1;
        }
 
@@ -1253,6 +1286,7 @@ static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue)
        struct msghdr msg = {};
        struct kvec iov;
        bool ctrl_hdgst, ctrl_ddgst;
+       u32 maxh2cdata;
        int ret;
 
        icreq = kzalloc(sizeof(*icreq), GFP_KERNEL);
@@ -1336,6 +1370,14 @@ static int nvme_tcp_init_connection(struct nvme_tcp_queue *queue)
                goto free_icresp;
        }
 
+       maxh2cdata = le32_to_cpu(icresp->maxdata);
+       if ((maxh2cdata % 4) || (maxh2cdata < NVME_TCP_MIN_MAXH2CDATA)) {
+               pr_err("queue %d: invalid maxh2cdata returned %u\n",
+                      nvme_tcp_queue_id(queue), maxh2cdata);
+               goto free_icresp;
+       }
+       queue->maxh2cdata = maxh2cdata;
+
        ret = 0;
 free_icresp:
        kfree(icresp);
@@ -2096,6 +2138,7 @@ static void nvme_tcp_error_recovery_work(struct work_struct *work)
        struct nvme_ctrl *ctrl = &tcp_ctrl->ctrl;
 
        nvme_stop_keep_alive(ctrl);
+       flush_work(&ctrl->async_event_work);
        nvme_tcp_teardown_io_queues(ctrl, false);
        /* unquiesce to fail fast pending requests */
        nvme_start_queues(ctrl);
@@ -2320,6 +2363,7 @@ static blk_status_t nvme_tcp_setup_cmd_pdu(struct nvme_ns *ns,
        req->data_sent = 0;
        req->pdu_len = 0;
        req->pdu_sent = 0;
+       req->h2cdata_left = 0;
        req->data_len = blk_rq_nr_phys_segments(rq) ?
                                blk_rq_payload_bytes(rq) : 0;
        req->curr_bio = rq->bio;
index da41461..555aa77 100644 (file)
@@ -300,4 +300,28 @@ config NVMEM_BRCM_NVRAM
          This driver provides support for Broadcom's NVRAM that can be accessed
          using I/O mapping.
 
+config NVMEM_LAYERSCAPE_SFP
+       tristate "Layerscape SFP (Security Fuse Processor) support"
+       depends on ARCH_LAYERSCAPE || COMPILE_TEST
+       depends on HAS_IOMEM
+       help
+         This driver provides support to read the eFuses on Freescale
+         Layerscape SoC's. For example, the vendor provides a per part
+         unique ID there.
+
+         This driver can also be built as a module. If so, the module
+         will be called layerscape-sfp.
+
+config NVMEM_SUNPLUS_OCOTP
+       tristate "Sunplus SoC OTP support"
+       depends on SOC_SP7021 || COMPILE_TEST
+       depends on HAS_IOMEM
+       help
+         This is a driver for the On-chip OTP controller (OCOTP) available
+         on Sunplus SoCs. It provides access to 128 bytes of one-time
+         programmable eFuse.
+
+         This driver can also be built as a module. If so, the module
+         will be called nvmem-sunplus-ocotp.
+
 endif
index dcbbde3..891958e 100644 (file)
@@ -61,3 +61,7 @@ obj-$(CONFIG_NVMEM_RMEM)      += nvmem-rmem.o
 nvmem-rmem-y                   := rmem.o
 obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o
 nvmem_brcm_nvram-y             := brcm_nvram.o
+obj-$(CONFIG_NVMEM_LAYERSCAPE_SFP)     += nvmem-layerscape-sfp.o
+nvmem-layerscape-sfp-y         := layerscape-sfp.o
+obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP)      += nvmem_sunplus_ocotp.o
+nvmem_sunplus_ocotp-y          := sunplus-ocotp.o
index 23a38dc..f58d9bc 100644 (file)
@@ -771,7 +771,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
 
        if (config->wp_gpio)
                nvmem->wp_gpio = config->wp_gpio;
-       else
+       else if (!config->ignore_wp)
                nvmem->wp_gpio = gpiod_get_optional(config->dev, "wp",
                                                    GPIOD_OUT_HIGH);
        if (IS_ERR(nvmem->wp_gpio)) {
@@ -903,13 +903,14 @@ static void nvmem_device_release(struct kref *kref)
  */
 void nvmem_unregister(struct nvmem_device *nvmem)
 {
-       kref_put(&nvmem->refcnt, nvmem_device_release);
+       if (nvmem)
+               kref_put(&nvmem->refcnt, nvmem_device_release);
 }
 EXPORT_SYMBOL_GPL(nvmem_unregister);
 
-static void devm_nvmem_release(struct device *dev, void *res)
+static void devm_nvmem_unregister(void *nvmem)
 {
-       nvmem_unregister(*(struct nvmem_device **)res);
+       nvmem_unregister(nvmem);
 }
 
 /**
@@ -926,47 +927,21 @@ static void devm_nvmem_release(struct device *dev, void *res)
 struct nvmem_device *devm_nvmem_register(struct device *dev,
                                         const struct nvmem_config *config)
 {
-       struct nvmem_device **ptr, *nvmem;
-
-       ptr = devres_alloc(devm_nvmem_release, sizeof(*ptr), GFP_KERNEL);
-       if (!ptr)
-               return ERR_PTR(-ENOMEM);
+       struct nvmem_device *nvmem;
+       int ret;
 
        nvmem = nvmem_register(config);
+       if (IS_ERR(nvmem))
+               return nvmem;
 
-       if (!IS_ERR(nvmem)) {
-               *ptr = nvmem;
-               devres_add(dev, ptr);
-       } else {
-               devres_free(ptr);
-       }
+       ret = devm_add_action_or_reset(dev, devm_nvmem_unregister, nvmem);
+       if (ret)
+               return ERR_PTR(ret);
 
        return nvmem;
 }
 EXPORT_SYMBOL_GPL(devm_nvmem_register);
 
-static int devm_nvmem_match(struct device *dev, void *res, void *data)
-{
-       struct nvmem_device **r = res;
-
-       return *r == data;
-}
-
-/**
- * devm_nvmem_unregister() - Unregister previously registered managed nvmem
- * device.
- *
- * @dev: Device that uses the nvmem device.
- * @nvmem: Pointer to previously registered nvmem device.
- *
- * Return: Will be negative on error or zero on success.
- */
-int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem)
-{
-       return devres_release(dev, devm_nvmem_release, devm_nvmem_match, nvmem);
-}
-EXPORT_SYMBOL(devm_nvmem_unregister);
-
 static struct nvmem_device *__nvmem_device_get(void *data,
                        int (*match)(struct device *dev, const void *data))
 {
diff --git a/drivers/nvmem/layerscape-sfp.c b/drivers/nvmem/layerscape-sfp.c
new file mode 100644 (file)
index 0000000..e591c15
--- /dev/null
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Layerscape SFP driver
+ *
+ * Copyright (c) 2022 Michael Walle <michael@walle.cc>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+#define LAYERSCAPE_SFP_OTP_OFFSET      0x0200
+
+struct layerscape_sfp_priv {
+       void __iomem *base;
+};
+
+struct layerscape_sfp_data {
+       int size;
+};
+
+static int layerscape_sfp_read(void *context, unsigned int offset, void *val,
+                              size_t bytes)
+{
+       struct layerscape_sfp_priv *priv = context;
+
+       memcpy_fromio(val, priv->base + LAYERSCAPE_SFP_OTP_OFFSET + offset,
+                     bytes);
+
+       return 0;
+}
+
+static struct nvmem_config layerscape_sfp_nvmem_config = {
+       .name = "fsl-sfp",
+       .reg_read = layerscape_sfp_read,
+};
+
+static int layerscape_sfp_probe(struct platform_device *pdev)
+{
+       const struct layerscape_sfp_data *data;
+       struct layerscape_sfp_priv *priv;
+       struct nvmem_device *nvmem;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(priv->base))
+               return PTR_ERR(priv->base);
+
+       data = device_get_match_data(&pdev->dev);
+
+       layerscape_sfp_nvmem_config.size = data->size;
+       layerscape_sfp_nvmem_config.dev = &pdev->dev;
+       layerscape_sfp_nvmem_config.priv = priv;
+
+       nvmem = devm_nvmem_register(&pdev->dev, &layerscape_sfp_nvmem_config);
+
+       return PTR_ERR_OR_ZERO(nvmem);
+}
+
+static const struct layerscape_sfp_data ls1028a_data = {
+       .size = 0x88,
+};
+
+static const struct of_device_id layerscape_sfp_dt_ids[] = {
+       { .compatible = "fsl,ls1028a-sfp", .data = &ls1028a_data },
+       {},
+};
+MODULE_DEVICE_TABLE(of, layerscape_sfp_dt_ids);
+
+static struct platform_driver layerscape_sfp_driver = {
+       .probe  = layerscape_sfp_probe,
+       .driver = {
+               .name   = "layerscape_sfp",
+               .of_match_table = layerscape_sfp_dt_ids,
+       },
+};
+module_platform_driver(layerscape_sfp_driver);
+
+MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
+MODULE_DESCRIPTION("Layerscape Security Fuse Processor driver");
+MODULE_LICENSE("GPL");
index 07c9f38..13eb143 100644 (file)
@@ -209,8 +209,7 @@ static int meson_mx_efuse_probe(struct platform_device *pdev)
        if (IS_ERR(efuse->base))
                return PTR_ERR(efuse->base);
 
-       efuse->config.name = devm_kstrdup(&pdev->dev, drvdata->name,
-                                         GFP_KERNEL);
+       efuse->config.name = drvdata->name;
        efuse->config.owner = THIS_MODULE;
        efuse->config.dev = &pdev->dev;
        efuse->config.priv = efuse;
index c500d62..162132c 100644 (file)
@@ -22,7 +22,7 @@
 
 /* Amount of time required to hold charge to blow fuse in micro-seconds */
 #define QFPROM_FUSE_BLOW_POLL_US       100
-#define QFPROM_FUSE_BLOW_TIMEOUT_US    1000
+#define QFPROM_FUSE_BLOW_TIMEOUT_US    10000
 
 #define QFPROM_BLOW_STATUS_OFFSET      0x048
 #define QFPROM_BLOW_STATUS_BUSY                0x1
@@ -244,7 +244,7 @@ err_clk_prepared:
 }
 
 /**
- * qfprom_efuse_reg_write() - Write to fuses.
+ * qfprom_reg_write() - Write to fuses.
  * @context: Our driver data.
  * @reg:     The offset to write at.
  * @_val:    Pointer to data to write.
diff --git a/drivers/nvmem/sunplus-ocotp.c b/drivers/nvmem/sunplus-ocotp.c
new file mode 100644 (file)
index 0000000..2dc59c2
--- /dev/null
@@ -0,0 +1,228 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * The OCOTP driver for Sunplus        SP7021
+ *
+ * Copyright (C) 2019 Sunplus Technology Inc., All rights reserved.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+/*
+ * OTP memory
+ * Each bank contains 4 words (32 bits).
+ * Bank 0 starts at offset 0 from the base.
+ */
+
+#define OTP_WORDS_PER_BANK             4
+#define OTP_WORD_SIZE                  sizeof(u32)
+#define OTP_BIT_ADDR_OF_BANK           (8 * OTP_WORD_SIZE * OTP_WORDS_PER_BANK)
+#define QAC628_OTP_NUM_BANKS           8
+#define QAC628_OTP_SIZE                        (QAC628_OTP_NUM_BANKS * OTP_WORDS_PER_BANK * OTP_WORD_SIZE)
+#define OTP_READ_TIMEOUT_US            200000
+
+/* HB_GPIO */
+#define ADDRESS_8_DATA                 0x20
+
+/* OTP_RX */
+#define OTP_CONTROL_2                  0x48
+#define OTP_RD_PERIOD                  GENMASK(15, 8)
+#define OTP_RD_PERIOD_MASK             ~GENMASK(15, 8)
+#define CPU_CLOCK                      FIELD_PREP(OTP_RD_PERIOD, 30)
+#define SEL_BAK_KEY2                   BIT(5)
+#define SEL_BAK_KEY2_MASK              ~BIT(5)
+#define SW_TRIM_EN                     BIT(4)
+#define SW_TRIM_EN_MASK                        ~BIT(4)
+#define SEL_BAK_KEY                    BIT(3)
+#define SEL_BAK_KEY_MASK               ~BIT(3)
+#define OTP_READ                       BIT(2)
+#define OTP_LOAD_SECURE_DATA           BIT(1)
+#define OTP_LOAD_SECURE_DATA_MASK      ~BIT(1)
+#define OTP_DO_CRC                     BIT(0)
+#define OTP_DO_CRC_MASK                        ~BIT(0)
+#define OTP_STATUS                     0x4c
+#define OTP_READ_DONE                  BIT(4)
+#define OTP_READ_DONE_MASK             ~BIT(4)
+#define OTP_LOAD_SECURE_DONE_MASK      ~BIT(2)
+#define OTP_READ_ADDRESS               0x50
+
+enum base_type {
+       HB_GPIO,
+       OTPRX,
+       BASEMAX,
+};
+
+struct sp_ocotp_priv {
+       struct device *dev;
+       void __iomem *base[BASEMAX];
+       struct clk *clk;
+};
+
+struct sp_ocotp_data {
+       int size;
+};
+
+const struct sp_ocotp_data  sp_otp_v0 = {
+       .size = QAC628_OTP_SIZE,
+};
+
+static int sp_otp_read_real(struct sp_ocotp_priv *otp, int addr, char *value)
+{
+       unsigned int addr_data;
+       unsigned int byte_shift;
+       unsigned int status;
+       int ret;
+
+       addr_data = addr % (OTP_WORD_SIZE * OTP_WORDS_PER_BANK);
+       addr_data = addr_data / OTP_WORD_SIZE;
+
+       byte_shift = addr % (OTP_WORD_SIZE * OTP_WORDS_PER_BANK);
+       byte_shift = byte_shift % OTP_WORD_SIZE;
+
+       addr = addr / (OTP_WORD_SIZE * OTP_WORDS_PER_BANK);
+       addr = addr * OTP_BIT_ADDR_OF_BANK;
+
+       writel(readl(otp->base[OTPRX] + OTP_STATUS) & OTP_READ_DONE_MASK &
+              OTP_LOAD_SECURE_DONE_MASK, otp->base[OTPRX] + OTP_STATUS);
+       writel(addr, otp->base[OTPRX] + OTP_READ_ADDRESS);
+       writel(readl(otp->base[OTPRX] + OTP_CONTROL_2) | OTP_READ,
+              otp->base[OTPRX] + OTP_CONTROL_2);
+       writel(readl(otp->base[OTPRX] + OTP_CONTROL_2) & SEL_BAK_KEY2_MASK & SW_TRIM_EN_MASK
+              & SEL_BAK_KEY_MASK & OTP_LOAD_SECURE_DATA_MASK & OTP_DO_CRC_MASK,
+              otp->base[OTPRX] + OTP_CONTROL_2);
+       writel((readl(otp->base[OTPRX] + OTP_CONTROL_2) & OTP_RD_PERIOD_MASK) | CPU_CLOCK,
+              otp->base[OTPRX] + OTP_CONTROL_2);
+
+       ret = readl_poll_timeout(otp->base[OTPRX] + OTP_STATUS, status,
+                                status & OTP_READ_DONE, 10, OTP_READ_TIMEOUT_US);
+
+       if (ret < 0)
+               return ret;
+
+       *value = (readl(otp->base[HB_GPIO] + ADDRESS_8_DATA + addr_data * OTP_WORD_SIZE)
+                 >> (8 * byte_shift)) & 0xff;
+
+       return ret;
+}
+
+static int sp_ocotp_read(void *priv, unsigned int offset, void *value, size_t bytes)
+{
+       struct sp_ocotp_priv *otp = priv;
+       unsigned int addr;
+       char *buf = value;
+       char val[4];
+       int ret;
+
+       ret = clk_enable(otp->clk);
+       if (ret)
+               return ret;
+
+       *buf = 0;
+       for (addr = offset; addr < (offset + bytes); addr++) {
+               ret = sp_otp_read_real(otp, addr, val);
+               if (ret < 0) {
+                       dev_err(otp->dev, "OTP read fail:%d at %d", ret, addr);
+                       goto disable_clk;
+               }
+
+               *buf++ = *val;
+       }
+
+disable_clk:
+       clk_disable(otp->clk);
+
+       return ret;
+}
+
+static struct nvmem_config sp_ocotp_nvmem_config = {
+       .name = "sp-ocotp",
+       .read_only = true,
+       .word_size = 1,
+       .size = QAC628_OTP_SIZE,
+       .stride = 1,
+       .reg_read = sp_ocotp_read,
+       .owner = THIS_MODULE,
+};
+
+static int sp_ocotp_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct nvmem_device *nvmem;
+       struct sp_ocotp_priv *otp;
+       struct resource *res;
+       int ret;
+
+       otp = devm_kzalloc(dev, sizeof(*otp), GFP_KERNEL);
+       if (!otp)
+               return -ENOMEM;
+
+       otp->dev = dev;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hb_gpio");
+       otp->base[HB_GPIO] = devm_ioremap_resource(dev, res);
+       if (IS_ERR(otp->base[HB_GPIO]))
+               return PTR_ERR(otp->base[HB_GPIO]);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otprx");
+       otp->base[OTPRX] = devm_ioremap_resource(dev, res);
+       if (IS_ERR(otp->base[OTPRX]))
+               return PTR_ERR(otp->base[OTPRX]);
+
+       otp->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(otp->clk))
+               return dev_err_probe(&pdev->dev, PTR_ERR(otp->clk),
+                                               "devm_clk_get fail\n");
+
+       ret = clk_prepare(otp->clk);
+       if (ret < 0) {
+               dev_err(dev, "failed to prepare clk: %d\n", ret);
+               return ret;
+       }
+
+       sp_ocotp_nvmem_config.priv = otp;
+       sp_ocotp_nvmem_config.dev = dev;
+
+       nvmem = devm_nvmem_register(dev, &sp_ocotp_nvmem_config);
+       if (IS_ERR(nvmem))
+               return dev_err_probe(&pdev->dev, PTR_ERR(nvmem),
+                                               "register nvmem device fail\n");
+
+       platform_set_drvdata(pdev, nvmem);
+
+       dev_dbg(dev, "banks:%d x wpb:%d x wsize:%d = %d",
+               (int)QAC628_OTP_NUM_BANKS, (int)OTP_WORDS_PER_BANK,
+               (int)OTP_WORD_SIZE, (int)QAC628_OTP_SIZE);
+
+       dev_info(dev, "by Sunplus (C) 2020");
+
+       return 0;
+}
+
+static const struct of_device_id sp_ocotp_dt_ids[] = {
+       { .compatible = "sunplus,sp7021-ocotp", .data = &sp_otp_v0 },
+       { }
+};
+MODULE_DEVICE_TABLE(of, sp_ocotp_dt_ids);
+
+static struct platform_driver sp_otp_driver = {
+       .probe     = sp_ocotp_probe,
+       .driver    = {
+               .name           = "sunplus,sp7021-ocotp",
+               .of_match_table = sp_ocotp_dt_ids,
+       }
+};
+module_platform_driver(sp_otp_driver);
+
+MODULE_AUTHOR("Vincent Shih <vincent.sunplus@gmail.com>");
+MODULE_DESCRIPTION("Sunplus On-Chip OTP driver");
+MODULE_LICENSE("GPL");
+
index 275b915..5750e1f 100644 (file)
@@ -184,6 +184,11 @@ static const struct sunxi_sid_cfg sun8i_h3_cfg = {
        .need_register_readout = true,
 };
 
+static const struct sunxi_sid_cfg sun20i_d1_cfg = {
+       .value_offset = 0x200,
+       .size = 0x100,
+};
+
 static const struct sunxi_sid_cfg sun50i_a64_cfg = {
        .value_offset = 0x200,
        .size = 0x100,
@@ -200,6 +205,7 @@ static const struct of_device_id sunxi_sid_of_match[] = {
        { .compatible = "allwinner,sun7i-a20-sid", .data = &sun7i_a20_cfg },
        { .compatible = "allwinner,sun8i-a83t-sid", .data = &sun50i_a64_cfg },
        { .compatible = "allwinner,sun8i-h3-sid", .data = &sun8i_h3_cfg },
+       { .compatible = "allwinner,sun20i-d1-sid", .data = &sun20i_d1_cfg },
        { .compatible = "allwinner,sun50i-a64-sid", .data = &sun50i_a64_cfg },
        { .compatible = "allwinner,sun50i-h5-sid", .data = &sun50i_a64_cfg },
        { .compatible = "allwinner,sun50i-h6-sid", .data = &sun50i_h6_cfg },
index ad85ff6..ec315b0 100644 (file)
@@ -648,8 +648,8 @@ void __init early_init_fdt_scan_reserved_mem(void)
        }
 
        fdt_scan_reserved_mem();
-       fdt_init_reserved_mem();
        fdt_reserve_elfcorehdr();
+       fdt_init_reserved_mem();
 }
 
 /**
index 7933500..a16b74f 100644 (file)
@@ -514,6 +514,7 @@ static const struct of_device_id reserved_mem_matches[] = {
        { .compatible = "qcom,smem" },
        { .compatible = "ramoops" },
        { .compatible = "nvmem-rmem" },
+       { .compatible = "google,open-dice" },
        {}
 };
 
index 7099210..2c2fb16 100644 (file)
@@ -513,24 +513,24 @@ static void __init of_unittest_parse_phandle_with_args(void)
        memset(&args, 0, sizeof(args));
 
        EXPECT_BEGIN(KERN_INFO,
-                    "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found -1");
+                    "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found 1");
 
        rc = of_parse_phandle_with_args(np, "phandle-list-bad-args",
                                        "#phandle-cells", 1, &args);
 
        EXPECT_END(KERN_INFO,
-                  "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found -1");
+                  "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found 1");
 
        unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
 
        EXPECT_BEGIN(KERN_INFO,
-                    "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found -1");
+                    "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found 1");
 
        rc = of_count_phandle_with_args(np, "phandle-list-bad-args",
                                        "#phandle-cells");
 
        EXPECT_END(KERN_INFO,
-                  "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found -1");
+                  "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found 1");
 
        unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
 }
@@ -670,12 +670,12 @@ static void __init of_unittest_parse_phandle_with_args_map(void)
        memset(&args, 0, sizeof(args));
 
        EXPECT_BEGIN(KERN_INFO,
-                    "OF: /testcase-data/phandle-tests/consumer-b: #phandle-cells = 2 found -1");
+                    "OF: /testcase-data/phandle-tests/consumer-b: #phandle-cells = 2 found 1");
 
        rc = of_parse_phandle_with_args_map(np, "phandle-list-bad-args",
                                            "phandle", 1, &args);
        EXPECT_END(KERN_INFO,
-                  "OF: /testcase-data/phandle-tests/consumer-b: #phandle-cells = 2 found -1");
+                  "OF: /testcase-data/phandle-tests/consumer-b: #phandle-cells = 2 found 1");
 
        unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
 }
@@ -1257,12 +1257,12 @@ static void __init of_unittest_platform_populate(void)
                unittest(pdev, "device 2 creation failed\n");
 
                EXPECT_BEGIN(KERN_INFO,
-                            "platform testcase-data:testcase-device2: IRQ index 0 not found");
+                            "platform testcase-data:testcase-device2: error -ENXIO: IRQ index 0 not found");
 
                irq = platform_get_irq(pdev, 0);
 
                EXPECT_END(KERN_INFO,
-                          "platform testcase-data:testcase-device2: IRQ index 0 not found");
+                          "platform testcase-data:testcase-device2: error -ENXIO: IRQ index 0 not found");
 
                unittest(irq < 0 && irq != -EPROBE_DEFER,
                         "device parsing error failed - %d\n", irq);
index 059566f..9be007c 100644 (file)
@@ -1003,7 +1003,7 @@ ccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
        ioc->usg_calls++;
 #endif
 
-       while(sg_dma_len(sglist) && nents--) {
+       while (nents && sg_dma_len(sglist)) {
 
 #ifdef CCIO_COLLECT_STATS
                ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT;
@@ -1011,6 +1011,7 @@ ccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
                ccio_unmap_page(dev, sg_dma_address(sglist),
                                  sg_dma_len(sglist), direction, 0);
                ++sglist;
+               nents--;
        }
 
        DBG_RUN_SG("%s() DONE (nents %d)\n", __func__, nents);
index e60690d..374b919 100644 (file)
@@ -1047,7 +1047,7 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
        spin_unlock_irqrestore(&ioc->res_lock, flags);
 #endif
 
-       while (sg_dma_len(sglist) && nents--) {
+       while (nents && sg_dma_len(sglist)) {
 
                sba_unmap_page(dev, sg_dma_address(sglist), sg_dma_len(sglist),
                                direction, 0);
@@ -1056,6 +1056,7 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
                ioc->usingle_calls--;   /* kluge since call is unmap_sg() */
 #endif
                ++sglist;
+               nents--;
        }
 
        DBG_RUN_SG("%s() DONE (nents %d)\n", __func__,  nents);
index 489586a..768d33f 100644 (file)
@@ -356,8 +356,8 @@ static int j721e_pcie_probe(struct platform_device *pdev)
        const struct j721e_pcie_data *data;
        struct cdns_pcie *cdns_pcie;
        struct j721e_pcie *pcie;
-       struct cdns_pcie_rc *rc;
-       struct cdns_pcie_ep *ep;
+       struct cdns_pcie_rc *rc = NULL;
+       struct cdns_pcie_ep *ep = NULL;
        struct gpio_desc *gpiod;
        void __iomem *base;
        struct clk *clk;
@@ -376,6 +376,46 @@ static int j721e_pcie_probe(struct platform_device *pdev)
        if (!pcie)
                return -ENOMEM;
 
+       switch (mode) {
+       case PCI_MODE_RC:
+               if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST))
+                       return -ENODEV;
+
+               bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
+               if (!bridge)
+                       return -ENOMEM;
+
+               if (!data->byte_access_allowed)
+                       bridge->ops = &cdns_ti_pcie_host_ops;
+               rc = pci_host_bridge_priv(bridge);
+               rc->quirk_retrain_flag = data->quirk_retrain_flag;
+               rc->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
+
+               cdns_pcie = &rc->pcie;
+               cdns_pcie->dev = dev;
+               cdns_pcie->ops = &j721e_pcie_ops;
+               pcie->cdns_pcie = cdns_pcie;
+               break;
+       case PCI_MODE_EP:
+               if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP))
+                       return -ENODEV;
+
+               ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
+               if (!ep)
+                       return -ENOMEM;
+
+               ep->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
+
+               cdns_pcie = &ep->pcie;
+               cdns_pcie->dev = dev;
+               cdns_pcie->ops = &j721e_pcie_ops;
+               pcie->cdns_pcie = cdns_pcie;
+               break;
+       default:
+               dev_err(dev, "INVALID device type %d\n", mode);
+               return 0;
+       }
+
        pcie->mode = mode;
        pcie->linkdown_irq_regfield = data->linkdown_irq_regfield;
 
@@ -426,28 +466,6 @@ static int j721e_pcie_probe(struct platform_device *pdev)
 
        switch (mode) {
        case PCI_MODE_RC:
-               if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST)) {
-                       ret = -ENODEV;
-                       goto err_get_sync;
-               }
-
-               bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
-               if (!bridge) {
-                       ret = -ENOMEM;
-                       goto err_get_sync;
-               }
-
-               if (!data->byte_access_allowed)
-                       bridge->ops = &cdns_ti_pcie_host_ops;
-               rc = pci_host_bridge_priv(bridge);
-               rc->quirk_retrain_flag = data->quirk_retrain_flag;
-               rc->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
-
-               cdns_pcie = &rc->pcie;
-               cdns_pcie->dev = dev;
-               cdns_pcie->ops = &j721e_pcie_ops;
-               pcie->cdns_pcie = cdns_pcie;
-
                gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
                if (IS_ERR(gpiod)) {
                        ret = PTR_ERR(gpiod);
@@ -497,23 +515,6 @@ static int j721e_pcie_probe(struct platform_device *pdev)
 
                break;
        case PCI_MODE_EP:
-               if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP)) {
-                       ret = -ENODEV;
-                       goto err_get_sync;
-               }
-
-               ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
-               if (!ep) {
-                       ret = -ENOMEM;
-                       goto err_get_sync;
-               }
-               ep->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
-
-               cdns_pcie = &ep->pcie;
-               cdns_pcie->dev = dev;
-               cdns_pcie->ops = &j721e_pcie_ops;
-               pcie->cdns_pcie = cdns_pcie;
-
                ret = cdns_pcie_init_phy(dev, cdns_pcie);
                if (ret) {
                        dev_err(dev, "Failed to init phy\n");
@@ -525,8 +526,6 @@ static int j721e_pcie_probe(struct platform_device *pdev)
                        goto err_pcie_setup;
 
                break;
-       default:
-               dev_err(dev, "INVALID device type %d\n", mode);
        }
 
        return 0;
index fa6886d..c625fc6 100644 (file)
@@ -756,22 +756,28 @@ static int __exit kirin_pcie_remove(struct platform_device *pdev)
        return 0;
 }
 
+struct kirin_pcie_data {
+       enum pcie_kirin_phy_type        phy_type;
+};
+
+static const struct kirin_pcie_data kirin_960_data = {
+       .phy_type = PCIE_KIRIN_INTERNAL_PHY,
+};
+
+static const struct kirin_pcie_data kirin_970_data = {
+       .phy_type = PCIE_KIRIN_EXTERNAL_PHY,
+};
+
 static const struct of_device_id kirin_pcie_match[] = {
-       {
-               .compatible = "hisilicon,kirin960-pcie",
-               .data = (void *)PCIE_KIRIN_INTERNAL_PHY
-       },
-       {
-               .compatible = "hisilicon,kirin970-pcie",
-               .data = (void *)PCIE_KIRIN_EXTERNAL_PHY
-       },
+       { .compatible = "hisilicon,kirin960-pcie", .data = &kirin_960_data },
+       { .compatible = "hisilicon,kirin970-pcie", .data = &kirin_970_data },
        {},
 };
 
 static int kirin_pcie_probe(struct platform_device *pdev)
 {
-       enum pcie_kirin_phy_type phy_type;
        struct device *dev = &pdev->dev;
+       const struct kirin_pcie_data *data;
        struct kirin_pcie *kirin_pcie;
        struct dw_pcie *pci;
        int ret;
@@ -781,13 +787,12 @@ static int kirin_pcie_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       phy_type = (long)of_device_get_match_data(dev);
-       if (!phy_type) {
+       data = of_device_get_match_data(dev);
+       if (!data) {
                dev_err(dev, "OF data missing\n");
                return -EINVAL;
        }
 
-
        kirin_pcie = devm_kzalloc(dev, sizeof(struct kirin_pcie), GFP_KERNEL);
        if (!kirin_pcie)
                return -ENOMEM;
@@ -800,7 +805,7 @@ static int kirin_pcie_probe(struct platform_device *pdev)
        pci->ops = &kirin_dw_pcie_ops;
        pci->pp.ops = &kirin_pcie_host_ops;
        kirin_pcie->pci = pci;
-       kirin_pcie->type = phy_type;
+       kirin_pcie->type = data->phy_type;
 
        ret = kirin_pcie_get_resource(kirin_pcie, pdev);
        if (ret)
index 20ea2ee..ae0bc2f 100644 (file)
@@ -2155,8 +2155,17 @@ static void hv_pci_assign_numa_node(struct hv_pcibus_device *hbus)
                if (!hv_dev)
                        continue;
 
-               if (hv_dev->desc.flags & HV_PCI_DEVICE_FLAG_NUMA_AFFINITY)
-                       set_dev_node(&dev->dev, hv_dev->desc.virtual_numa_node);
+               if (hv_dev->desc.flags & HV_PCI_DEVICE_FLAG_NUMA_AFFINITY &&
+                   hv_dev->desc.virtual_numa_node < num_possible_nodes())
+                       /*
+                        * The kernel may boot with some NUMA nodes offline
+                        * (e.g. in a KDUMP kernel) or with NUMA disabled via
+                        * "numa=off". In those cases, adjust the host provided
+                        * NUMA node to a valid NUMA node used by the kernel.
+                        */
+                       set_dev_node(&dev->dev,
+                                    numa_map_to_online_node(
+                                            hv_dev->desc.virtual_numa_node));
 
                put_pcichild(hv_dev);
        }
index 71258ea..f8e82c5 100644 (file)
@@ -1329,7 +1329,8 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
                 * indirectly via kernel emulated PCI bridge driver.
                 */
                mvebu_pcie_setup_hw(port);
-               mvebu_pcie_set_local_dev_nr(port, 0);
+               mvebu_pcie_set_local_dev_nr(port, 1);
+               mvebu_pcie_set_local_bus_nr(port, 0);
        }
 
        pcie->nports = i;
index 3824862..33eb37a 100644 (file)
@@ -109,15 +109,6 @@ static inline void pcie_write(struct mt7621_pcie *pcie, u32 val, u32 reg)
        writel_relaxed(val, pcie->base + reg);
 }
 
-static inline void pcie_rmw(struct mt7621_pcie *pcie, u32 reg, u32 clr, u32 set)
-{
-       u32 val = readl_relaxed(pcie->base + reg);
-
-       val &= ~clr;
-       val |= set;
-       writel_relaxed(val, pcie->base + reg);
-}
-
 static inline u32 pcie_port_read(struct mt7621_pcie_port *port, u32 reg)
 {
        return readl_relaxed(port->base + reg);
@@ -557,7 +548,7 @@ static struct platform_driver mt7621_pcie_driver = {
        .remove = mt7621_pcie_remove,
        .driver = {
                .name = "mt7621-pci",
-               .of_match_table = of_match_ptr(mt7621_pcie_ids),
+               .of_match_table = mt7621_pcie_ids,
        },
 };
 builtin_platform_driver(mt7621_pcie_driver);
index cc166c6..eb05cce 100644 (file)
@@ -99,11 +99,13 @@ struct vmd_irq {
  * @srcu:      SRCU struct for local synchronization.
  * @count:     number of child IRQs assigned to this vector; used to track
  *             sharing.
+ * @virq:      The underlying VMD Linux interrupt number
  */
 struct vmd_irq_list {
        struct list_head        irq_list;
        struct srcu_struct      srcu;
        unsigned int            count;
+       unsigned int            virq;
 };
 
 struct vmd_dev {
@@ -253,7 +255,6 @@ static int vmd_msi_init(struct irq_domain *domain, struct msi_domain_info *info,
        struct msi_desc *desc = arg->desc;
        struct vmd_dev *vmd = vmd_from_bus(msi_desc_to_pci_dev(desc)->bus);
        struct vmd_irq *vmdirq = kzalloc(sizeof(*vmdirq), GFP_KERNEL);
-       unsigned int index, vector;
 
        if (!vmdirq)
                return -ENOMEM;
@@ -261,10 +262,8 @@ static int vmd_msi_init(struct irq_domain *domain, struct msi_domain_info *info,
        INIT_LIST_HEAD(&vmdirq->node);
        vmdirq->irq = vmd_next_irq(vmd, desc);
        vmdirq->virq = virq;
-       index = index_from_irqs(vmd, vmdirq->irq);
-       vector = pci_irq_vector(vmd->dev, index);
 
-       irq_domain_set_info(domain, virq, vector, info->chip, vmdirq,
+       irq_domain_set_info(domain, virq, vmdirq->irq->virq, info->chip, vmdirq,
                            handle_untracked_irq, vmd, NULL);
        return 0;
 }
@@ -685,7 +684,8 @@ static int vmd_alloc_irqs(struct vmd_dev *vmd)
                        return err;
 
                INIT_LIST_HEAD(&vmd->irqs[i].irq_list);
-               err = devm_request_irq(&dev->dev, pci_irq_vector(dev, i),
+               vmd->irqs[i].virq = pci_irq_vector(dev, i);
+               err = devm_request_irq(&dev->dev, vmd->irqs[i].virq,
                                       vmd_irq, IRQF_NO_THREAD,
                                       vmd->name, &vmd->irqs[i]);
                if (err)
@@ -969,7 +969,7 @@ static int vmd_suspend(struct device *dev)
        int i;
 
        for (i = 0; i < vmd->msix_count; i++)
-               devm_free_irq(dev, pci_irq_vector(pdev, i), &vmd->irqs[i]);
+               devm_free_irq(dev, vmd->irqs[i].virq, &vmd->irqs[i]);
 
        return 0;
 }
@@ -981,7 +981,7 @@ static int vmd_resume(struct device *dev)
        int err, i;
 
        for (i = 0; i < vmd->msix_count; i++) {
-               err = devm_request_irq(dev, pci_irq_vector(pdev, i),
+               err = devm_request_irq(dev, vmd->irqs[i].virq,
                                       vmd_irq, IRQF_NO_THREAD,
                                       vmd->name, &vmd->irqs[i]);
                if (err)
index 0d63541..e9cf318 100644 (file)
@@ -28,6 +28,7 @@ void pci_msi_teardown_msi_irqs(struct pci_dev *dev)
                msi_domain_free_irqs_descs_locked(domain, &dev->dev);
        else
                pci_msi_legacy_teardown_msi_irqs(dev);
+       msi_free_msi_descs(&dev->dev);
 }
 
 /**
@@ -171,8 +172,7 @@ struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
        if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
                pci_msi_domain_update_chip_ops(info);
 
-       info->flags |= MSI_FLAG_ACTIVATE_EARLY | MSI_FLAG_DEV_SYSFS |
-                      MSI_FLAG_FREE_MSI_DESCS;
+       info->flags |= MSI_FLAG_ACTIVATE_EARLY | MSI_FLAG_DEV_SYSFS;
        if (IS_ENABLED(CONFIG_GENERIC_IRQ_RESERVATION_MODE))
                info->flags |= MSI_FLAG_MUST_REACTIVATE;
 
index cdbb468..db761ad 100644 (file)
@@ -77,5 +77,4 @@ void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev)
 {
        msi_device_destroy_sysfs(&dev->dev);
        arch_teardown_msi_irqs(dev);
-       msi_free_msi_descs(&dev->dev);
 }
index c19c7ca..9037a78 100644 (file)
@@ -1111,7 +1111,8 @@ const struct cpumask *pci_irq_get_affinity(struct pci_dev *dev, int nr)
        if (!desc)
                return cpu_possible_mask;
 
-       if (WARN_ON_ONCE(!desc->affinity))
+       /* MSI[X] interrupts can be allocated without affinity descriptor */
+       if (!desc->affinity)
                return NULL;
 
        /*
index bda6308..604feeb 100644 (file)
@@ -166,6 +166,9 @@ static int pcie_init_service_irqs(struct pci_dev *dev, int *irqs, int mask)
 {
        int ret, i;
 
+       for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
+               irqs[i] = -1;
+
        /*
         * If we support PME but can't use MSI/MSI-X for it, we have to
         * fall back to INTx or other interrupts, e.g., a system shared
@@ -314,10 +317,8 @@ static int pcie_device_init(struct pci_dev *pdev, int service, int irq)
  */
 int pcie_port_device_register(struct pci_dev *dev)
 {
-       int status, capabilities, irq_services, i, nr_service;
-       int irqs[PCIE_PORT_DEVICE_MAXSERVICES] = {
-               [0 ... PCIE_PORT_DEVICE_MAXSERVICES-1] = -1
-       };
+       int status, capabilities, i, nr_service;
+       int irqs[PCIE_PORT_DEVICE_MAXSERVICES];
 
        /* Enable PCI Express port device */
        status = pci_enable_device(dev);
@@ -330,32 +331,18 @@ int pcie_port_device_register(struct pci_dev *dev)
                return 0;
 
        pci_set_master(dev);
-
-       irq_services = 0;
-       if (IS_ENABLED(CONFIG_PCIE_PME))
-               irq_services |= PCIE_PORT_SERVICE_PME;
-       if (IS_ENABLED(CONFIG_PCIEAER))
-               irq_services |= PCIE_PORT_SERVICE_AER;
-       if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE))
-               irq_services |= PCIE_PORT_SERVICE_HP;
-       if (IS_ENABLED(CONFIG_PCIE_DPC))
-               irq_services |= PCIE_PORT_SERVICE_DPC;
-       irq_services &= capabilities;
-
-       if (irq_services) {
-               /*
-                * Initialize service IRQs. Don't use service devices that
-                * require interrupts if there is no way to generate them.
-                * However, some drivers may have a polling mode (e.g.
-                * pciehp_poll_mode) that can be used in the absence of IRQs.
-                * Allow them to determine if that is to be used.
-                */
-               status = pcie_init_service_irqs(dev, irqs, irq_services);
-               if (status) {
-                       irq_services &= PCIE_PORT_SERVICE_HP;
-                       if (!irq_services)
-                               goto error_disable;
-               }
+       /*
+        * Initialize service irqs. Don't use service devices that
+        * require interrupts if there is no way to generate them.
+        * However, some drivers may have a polling mode (e.g. pciehp_poll_mode)
+        * that can be used in the absence of irqs.  Allow them to determine
+        * if that is to be used.
+        */
+       status = pcie_init_service_irqs(dev, irqs, capabilities);
+       if (status) {
+               capabilities &= PCIE_PORT_SERVICE_HP;
+               if (!capabilities)
+                       goto error_disable;
        }
 
        /* Allocate child services if any */
index d2dd6a6..65f7f6b 100644 (file)
@@ -5344,11 +5344,6 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0422, quirk_no_ext_tags);
  */
 static void quirk_amd_harvest_no_ats(struct pci_dev *pdev)
 {
-       if ((pdev->device == 0x7312 && pdev->revision != 0x00) ||
-           (pdev->device == 0x7340 && pdev->revision != 0xc5) ||
-           (pdev->device == 0x7341 && pdev->revision != 0x00))
-               return;
-
        if (pdev->device == 0x15d8) {
                if (pdev->revision == 0xcf &&
                    pdev->subsystem_vendor == 0xea50 &&
@@ -5370,10 +5365,19 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x98e4, quirk_amd_harvest_no_ats);
 /* AMD Iceland dGPU */
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x6900, quirk_amd_harvest_no_ats);
 /* AMD Navi10 dGPU */
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7310, quirk_amd_harvest_no_ats);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7312, quirk_amd_harvest_no_ats);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7318, quirk_amd_harvest_no_ats);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7319, quirk_amd_harvest_no_ats);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x731a, quirk_amd_harvest_no_ats);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x731b, quirk_amd_harvest_no_ats);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x731e, quirk_amd_harvest_no_ats);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x731f, quirk_amd_harvest_no_ats);
 /* AMD Navi14 dGPU */
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7340, quirk_amd_harvest_no_ats);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7341, quirk_amd_harvest_no_ats);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7347, quirk_amd_harvest_no_ats);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x734f, quirk_amd_harvest_no_ats);
 /* AMD Raven platform iGPU */
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x15d8, quirk_amd_harvest_no_ats);
 #endif /* CONFIG_PCI_ATS */
diff --git a/drivers/peci/Kconfig b/drivers/peci/Kconfig
new file mode 100644 (file)
index 0000000..89872ad
--- /dev/null
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+menuconfig PECI
+       tristate "PECI support"
+       help
+         The Platform Environment Control Interface (PECI) is an interface
+         that provides a communication channel to Intel processors and
+         chipset components from external monitoring or control devices.
+
+         If you are building a Baseboard Management Controller (BMC) kernel
+         for Intel platform say Y here and also to the specific driver for
+         your adapter(s) below. If unsure say N.
+
+         This support is also available as a module. If so, the module
+         will be called peci.
+
+if PECI
+
+config PECI_CPU
+       tristate "PECI CPU"
+       select AUXILIARY_BUS
+       help
+         This option enables peci-cpu driver for Intel processors. It is
+         responsible for creating auxiliary devices that can subsequently
+         be used by other drivers in order to perform various
+         functionalities such as e.g. temperature monitoring.
+
+         Additional drivers must be enabled in order to use the functionality
+         of the device.
+
+         This driver can also be built as a module. If so, the module
+         will be called peci-cpu.
+
+source "drivers/peci/controller/Kconfig"
+
+endif # PECI
diff --git a/drivers/peci/Makefile b/drivers/peci/Makefile
new file mode 100644 (file)
index 0000000..7de1813
--- /dev/null
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+# Core functionality
+peci-y := core.o request.o device.o sysfs.o
+obj-$(CONFIG_PECI) += peci.o
+peci-cpu-y := cpu.o
+obj-$(CONFIG_PECI_CPU) += peci-cpu.o
+
+# Hardware specific bus drivers
+obj-y += controller/
diff --git a/drivers/peci/controller/Kconfig b/drivers/peci/controller/Kconfig
new file mode 100644 (file)
index 0000000..2fc5e2a
--- /dev/null
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config PECI_ASPEED
+       tristate "ASPEED PECI support"
+       depends on ARCH_ASPEED || COMPILE_TEST
+       depends on OF
+       depends on HAS_IOMEM
+       depends on COMMON_CLK
+       help
+         This option enables PECI controller driver for ASPEED AST2400,
+         AST2500 and AST2600 SoCs. It allows BMC to discover devices
+         connected to it, and communicate with them using PECI protocol.
+
+         Say Y here if your system runs on ASPEED SoC and you are using it
+         as BMC for Intel platform.
+
+         This driver can also be built as a module. If so, the module will
+         be called peci-aspeed.
diff --git a/drivers/peci/controller/Makefile b/drivers/peci/controller/Makefile
new file mode 100644 (file)
index 0000000..022c28e
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_PECI_ASPEED)      += peci-aspeed.o
diff --git a/drivers/peci/controller/peci-aspeed.c b/drivers/peci/controller/peci-aspeed.c
new file mode 100644 (file)
index 0000000..1925ddc
--- /dev/null
@@ -0,0 +1,599 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2012-2017 ASPEED Technology Inc.
+// Copyright (c) 2018-2021 Intel Corporation
+
+#include <asm/unaligned.h>
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/jiffies.h>
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/peci.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+/* ASPEED PECI Registers */
+/* Control Register */
+#define ASPEED_PECI_CTRL                       0x00
+#define   ASPEED_PECI_CTRL_SAMPLING_MASK       GENMASK(19, 16)
+#define   ASPEED_PECI_CTRL_RD_MODE_MASK                GENMASK(13, 12)
+#define     ASPEED_PECI_CTRL_RD_MODE_DBG       BIT(13)
+#define     ASPEED_PECI_CTRL_RD_MODE_COUNT     BIT(12)
+#define   ASPEED_PECI_CTRL_CLK_SRC_HCLK                BIT(11)
+#define   ASPEED_PECI_CTRL_CLK_DIV_MASK                GENMASK(10, 8)
+#define   ASPEED_PECI_CTRL_INVERT_OUT          BIT(7)
+#define   ASPEED_PECI_CTRL_INVERT_IN           BIT(6)
+#define   ASPEED_PECI_CTRL_BUS_CONTENTION_EN   BIT(5)
+#define   ASPEED_PECI_CTRL_PECI_EN             BIT(4)
+#define   ASPEED_PECI_CTRL_PECI_CLK_EN         BIT(0)
+
+/* Timing Negotiation Register */
+#define ASPEED_PECI_TIMING_NEGOTIATION         0x04
+#define   ASPEED_PECI_T_NEGO_MSG_MASK          GENMASK(15, 8)
+#define   ASPEED_PECI_T_NEGO_ADDR_MASK         GENMASK(7, 0)
+
+/* Command Register */
+#define ASPEED_PECI_CMD                                0x08
+#define   ASPEED_PECI_CMD_PIN_MONITORING       BIT(31)
+#define   ASPEED_PECI_CMD_STS_MASK             GENMASK(27, 24)
+#define     ASPEED_PECI_CMD_STS_ADDR_T_NEGO    0x3
+#define   ASPEED_PECI_CMD_IDLE_MASK            \
+         (ASPEED_PECI_CMD_STS_MASK | ASPEED_PECI_CMD_PIN_MONITORING)
+#define   ASPEED_PECI_CMD_FIRE                 BIT(0)
+
+/* Read/Write Length Register */
+#define ASPEED_PECI_RW_LENGTH                  0x0c
+#define   ASPEED_PECI_AW_FCS_EN                        BIT(31)
+#define   ASPEED_PECI_RD_LEN_MASK              GENMASK(23, 16)
+#define   ASPEED_PECI_WR_LEN_MASK              GENMASK(15, 8)
+#define   ASPEED_PECI_TARGET_ADDR_MASK         GENMASK(7, 0)
+
+/* Expected FCS Data Register */
+#define ASPEED_PECI_EXPECTED_FCS               0x10
+#define   ASPEED_PECI_EXPECTED_RD_FCS_MASK     GENMASK(23, 16)
+#define   ASPEED_PECI_EXPECTED_AW_FCS_AUTO_MASK        GENMASK(15, 8)
+#define   ASPEED_PECI_EXPECTED_WR_FCS_MASK     GENMASK(7, 0)
+
+/* Captured FCS Data Register */
+#define ASPEED_PECI_CAPTURED_FCS               0x14
+#define   ASPEED_PECI_CAPTURED_RD_FCS_MASK     GENMASK(23, 16)
+#define   ASPEED_PECI_CAPTURED_WR_FCS_MASK     GENMASK(7, 0)
+
+/* Interrupt Register */
+#define ASPEED_PECI_INT_CTRL                   0x18
+#define   ASPEED_PECI_TIMING_NEGO_SEL_MASK     GENMASK(31, 30)
+#define     ASPEED_PECI_1ST_BIT_OF_ADDR_NEGO   0
+#define     ASPEED_PECI_2ND_BIT_OF_ADDR_NEGO   1
+#define     ASPEED_PECI_MESSAGE_NEGO           2
+#define   ASPEED_PECI_INT_MASK                 GENMASK(4, 0)
+#define     ASPEED_PECI_INT_BUS_TIMEOUT                BIT(4)
+#define     ASPEED_PECI_INT_BUS_CONTENTION     BIT(3)
+#define     ASPEED_PECI_INT_WR_FCS_BAD         BIT(2)
+#define     ASPEED_PECI_INT_WR_FCS_ABORT       BIT(1)
+#define     ASPEED_PECI_INT_CMD_DONE           BIT(0)
+
+/* Interrupt Status Register */
+#define ASPEED_PECI_INT_STS                    0x1c
+#define   ASPEED_PECI_INT_TIMING_RESULT_MASK   GENMASK(29, 16)
+         /* bits[4..0]: Same bit fields in the 'Interrupt Register' */
+
+/* Rx/Tx Data Buffer Registers */
+#define ASPEED_PECI_WR_DATA0                   0x20
+#define ASPEED_PECI_WR_DATA1                   0x24
+#define ASPEED_PECI_WR_DATA2                   0x28
+#define ASPEED_PECI_WR_DATA3                   0x2c
+#define ASPEED_PECI_RD_DATA0                   0x30
+#define ASPEED_PECI_RD_DATA1                   0x34
+#define ASPEED_PECI_RD_DATA2                   0x38
+#define ASPEED_PECI_RD_DATA3                   0x3c
+#define ASPEED_PECI_WR_DATA4                   0x40
+#define ASPEED_PECI_WR_DATA5                   0x44
+#define ASPEED_PECI_WR_DATA6                   0x48
+#define ASPEED_PECI_WR_DATA7                   0x4c
+#define ASPEED_PECI_RD_DATA4                   0x50
+#define ASPEED_PECI_RD_DATA5                   0x54
+#define ASPEED_PECI_RD_DATA6                   0x58
+#define ASPEED_PECI_RD_DATA7                   0x5c
+#define   ASPEED_PECI_DATA_BUF_SIZE_MAX                32
+
+/* Timing Negotiation */
+#define ASPEED_PECI_CLK_FREQUENCY_MIN          2000
+#define ASPEED_PECI_CLK_FREQUENCY_DEFAULT      1000000
+#define ASPEED_PECI_CLK_FREQUENCY_MAX          2000000
+#define ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT  8
+/* Timeout */
+#define ASPEED_PECI_IDLE_CHECK_TIMEOUT_US      (50 * USEC_PER_MSEC)
+#define ASPEED_PECI_IDLE_CHECK_INTERVAL_US     (10 * USEC_PER_MSEC)
+#define ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT     1000
+#define ASPEED_PECI_CMD_TIMEOUT_MS_MAX         1000
+
+#define ASPEED_PECI_CLK_DIV1(msg_timing) (4 * (msg_timing) + 1)
+#define ASPEED_PECI_CLK_DIV2(clk_div_exp) BIT(clk_div_exp)
+#define ASPEED_PECI_CLK_DIV(msg_timing, clk_div_exp) \
+       (4 * ASPEED_PECI_CLK_DIV1(msg_timing) * ASPEED_PECI_CLK_DIV2(clk_div_exp))
+
+struct aspeed_peci {
+       struct peci_controller *controller;
+       struct device *dev;
+       void __iomem *base;
+       struct reset_control *rst;
+       int irq;
+       spinlock_t lock; /* to sync completion status handling */
+       struct completion xfer_complete;
+       struct clk *clk;
+       u32 clk_frequency;
+       u32 status;
+       u32 cmd_timeout_ms;
+};
+
+struct clk_aspeed_peci {
+       struct clk_hw hw;
+       struct aspeed_peci *aspeed_peci;
+};
+
+static void aspeed_peci_controller_enable(struct aspeed_peci *priv)
+{
+       u32 val = readl(priv->base + ASPEED_PECI_CTRL);
+
+       val |= ASPEED_PECI_CTRL_PECI_CLK_EN;
+       val |= ASPEED_PECI_CTRL_PECI_EN;
+
+       writel(val, priv->base + ASPEED_PECI_CTRL);
+}
+
+static void aspeed_peci_init_regs(struct aspeed_peci *priv)
+{
+       u32 val;
+
+       /* Clear interrupts */
+       writel(ASPEED_PECI_INT_MASK, priv->base + ASPEED_PECI_INT_STS);
+
+       /* Set timing negotiation mode and enable interrupts */
+       val = FIELD_PREP(ASPEED_PECI_TIMING_NEGO_SEL_MASK, ASPEED_PECI_1ST_BIT_OF_ADDR_NEGO);
+       val |= ASPEED_PECI_INT_MASK;
+       writel(val, priv->base + ASPEED_PECI_INT_CTRL);
+
+       val = FIELD_PREP(ASPEED_PECI_CTRL_SAMPLING_MASK, ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT);
+       writel(val, priv->base + ASPEED_PECI_CTRL);
+}
+
+static int aspeed_peci_check_idle(struct aspeed_peci *priv)
+{
+       u32 cmd_sts = readl(priv->base + ASPEED_PECI_CMD);
+       int ret;
+
+       /*
+        * Under normal circumstances, we expect to be idle here.
+        * In case there were any errors/timeouts that led to the situation
+        * where the hardware is not in idle state - we need to reset and
+        * reinitialize it to avoid potential controller hang.
+        */
+       if (FIELD_GET(ASPEED_PECI_CMD_STS_MASK, cmd_sts)) {
+               ret = reset_control_assert(priv->rst);
+               if (ret) {
+                       dev_err(priv->dev, "cannot assert reset control\n");
+                       return ret;
+               }
+
+               ret = reset_control_deassert(priv->rst);
+               if (ret) {
+                       dev_err(priv->dev, "cannot deassert reset control\n");
+                       return ret;
+               }
+
+               aspeed_peci_init_regs(priv);
+
+               ret = clk_set_rate(priv->clk, priv->clk_frequency);
+               if (ret < 0) {
+                       dev_err(priv->dev, "cannot set clock frequency\n");
+                       return ret;
+               }
+
+               aspeed_peci_controller_enable(priv);
+       }
+
+       return readl_poll_timeout(priv->base + ASPEED_PECI_CMD,
+                                 cmd_sts,
+                                 !(cmd_sts & ASPEED_PECI_CMD_IDLE_MASK),
+                                 ASPEED_PECI_IDLE_CHECK_INTERVAL_US,
+                                 ASPEED_PECI_IDLE_CHECK_TIMEOUT_US);
+}
+
+static int aspeed_peci_xfer(struct peci_controller *controller,
+                           u8 addr, struct peci_request *req)
+{
+       struct aspeed_peci *priv = dev_get_drvdata(controller->dev.parent);
+       unsigned long timeout = msecs_to_jiffies(priv->cmd_timeout_ms);
+       u32 peci_head;
+       int ret, i;
+
+       if (req->tx.len > ASPEED_PECI_DATA_BUF_SIZE_MAX ||
+           req->rx.len > ASPEED_PECI_DATA_BUF_SIZE_MAX)
+               return -EINVAL;
+
+       /* Check command sts and bus idle state */
+       ret = aspeed_peci_check_idle(priv);
+       if (ret)
+               return ret; /* -ETIMEDOUT */
+
+       spin_lock_irq(&priv->lock);
+       reinit_completion(&priv->xfer_complete);
+
+       peci_head = FIELD_PREP(ASPEED_PECI_TARGET_ADDR_MASK, addr) |
+                   FIELD_PREP(ASPEED_PECI_WR_LEN_MASK, req->tx.len) |
+                   FIELD_PREP(ASPEED_PECI_RD_LEN_MASK, req->rx.len);
+
+       writel(peci_head, priv->base + ASPEED_PECI_RW_LENGTH);
+
+       for (i = 0; i < req->tx.len; i += 4) {
+               u32 reg = (i < 16 ? ASPEED_PECI_WR_DATA0 : ASPEED_PECI_WR_DATA4) + i % 16;
+
+               writel(get_unaligned_le32(&req->tx.buf[i]), priv->base + reg);
+       }
+
+#if IS_ENABLED(CONFIG_DYNAMIC_DEBUG)
+       dev_dbg(priv->dev, "HEAD : %#08x\n", peci_head);
+       print_hex_dump_bytes("TX : ", DUMP_PREFIX_NONE, req->tx.buf, req->tx.len);
+#endif
+
+       priv->status = 0;
+       writel(ASPEED_PECI_CMD_FIRE, priv->base + ASPEED_PECI_CMD);
+       spin_unlock_irq(&priv->lock);
+
+       ret = wait_for_completion_interruptible_timeout(&priv->xfer_complete, timeout);
+       if (ret < 0)
+               return ret;
+
+       if (ret == 0) {
+               dev_dbg(priv->dev, "timeout waiting for a response\n");
+               return -ETIMEDOUT;
+       }
+
+       spin_lock_irq(&priv->lock);
+
+       if (priv->status != ASPEED_PECI_INT_CMD_DONE) {
+               spin_unlock_irq(&priv->lock);
+               dev_dbg(priv->dev, "no valid response, status: %#02x\n", priv->status);
+               return -EIO;
+       }
+
+       spin_unlock_irq(&priv->lock);
+
+       /*
+        * We need to use dword reads for register access, make sure that the
+        * buffer size is multiple of 4-bytes.
+        */
+       BUILD_BUG_ON(PECI_REQUEST_MAX_BUF_SIZE % 4);
+
+       for (i = 0; i < req->rx.len; i += 4) {
+               u32 reg = (i < 16 ? ASPEED_PECI_RD_DATA0 : ASPEED_PECI_RD_DATA4) + i % 16;
+               u32 rx_data = readl(priv->base + reg);
+
+               put_unaligned_le32(rx_data, &req->rx.buf[i]);
+       }
+
+#if IS_ENABLED(CONFIG_DYNAMIC_DEBUG)
+       print_hex_dump_bytes("RX : ", DUMP_PREFIX_NONE, req->rx.buf, req->rx.len);
+#endif
+       return 0;
+}
+
+static irqreturn_t aspeed_peci_irq_handler(int irq, void *arg)
+{
+       struct aspeed_peci *priv = arg;
+       u32 status;
+
+       spin_lock(&priv->lock);
+       status = readl(priv->base + ASPEED_PECI_INT_STS);
+       writel(status, priv->base + ASPEED_PECI_INT_STS);
+       priv->status |= (status & ASPEED_PECI_INT_MASK);
+
+       /*
+        * All commands should be ended up with a ASPEED_PECI_INT_CMD_DONE bit
+        * set even in an error case.
+        */
+       if (status & ASPEED_PECI_INT_CMD_DONE)
+               complete(&priv->xfer_complete);
+
+       writel(0, priv->base + ASPEED_PECI_CMD);
+
+       spin_unlock(&priv->lock);
+
+       return IRQ_HANDLED;
+}
+
+static void clk_aspeed_peci_find_div_values(unsigned long rate, int *msg_timing, int *clk_div_exp)
+{
+       unsigned long best_diff = ~0ul, diff;
+       int msg_timing_temp, clk_div_exp_temp, i, j;
+
+       for (i = 1; i <= 255; i++)
+               for (j = 0; j < 8; j++) {
+                       diff = abs(rate - ASPEED_PECI_CLK_DIV1(i) * ASPEED_PECI_CLK_DIV2(j));
+                       if (diff < best_diff) {
+                               msg_timing_temp = i;
+                               clk_div_exp_temp = j;
+                               best_diff = diff;
+                       }
+               }
+
+       *msg_timing = msg_timing_temp;
+       *clk_div_exp = clk_div_exp_temp;
+}
+
+static int clk_aspeed_peci_get_div(unsigned long rate, const unsigned long *prate)
+{
+       unsigned long this_rate = *prate / (4 * rate);
+       int msg_timing, clk_div_exp;
+
+       clk_aspeed_peci_find_div_values(this_rate, &msg_timing, &clk_div_exp);
+
+       return ASPEED_PECI_CLK_DIV(msg_timing, clk_div_exp);
+}
+
+static int clk_aspeed_peci_set_rate(struct clk_hw *hw, unsigned long rate,
+                                   unsigned long prate)
+{
+       struct clk_aspeed_peci *peci_clk = container_of(hw, struct clk_aspeed_peci, hw);
+       struct aspeed_peci *aspeed_peci = peci_clk->aspeed_peci;
+       unsigned long this_rate = prate / (4 * rate);
+       int clk_div_exp, msg_timing;
+       u32 val;
+
+       clk_aspeed_peci_find_div_values(this_rate, &msg_timing, &clk_div_exp);
+
+       val = readl(aspeed_peci->base + ASPEED_PECI_CTRL);
+       val |= FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK, clk_div_exp);
+       writel(val, aspeed_peci->base + ASPEED_PECI_CTRL);
+
+       val = FIELD_PREP(ASPEED_PECI_T_NEGO_MSG_MASK, msg_timing);
+       val |= FIELD_PREP(ASPEED_PECI_T_NEGO_ADDR_MASK, msg_timing);
+       writel(val, aspeed_peci->base + ASPEED_PECI_TIMING_NEGOTIATION);
+
+       return 0;
+}
+
+static long clk_aspeed_peci_round_rate(struct clk_hw *hw, unsigned long rate,
+                                      unsigned long *prate)
+{
+       int div = clk_aspeed_peci_get_div(rate, prate);
+
+       return DIV_ROUND_UP_ULL(*prate, div);
+}
+
+static unsigned long clk_aspeed_peci_recalc_rate(struct clk_hw *hw, unsigned long prate)
+{
+       struct clk_aspeed_peci *peci_clk = container_of(hw, struct clk_aspeed_peci, hw);
+       struct aspeed_peci *aspeed_peci = peci_clk->aspeed_peci;
+       int div, msg_timing, addr_timing, clk_div_exp;
+       u32 reg;
+
+       reg = readl(aspeed_peci->base + ASPEED_PECI_TIMING_NEGOTIATION);
+       msg_timing = FIELD_GET(ASPEED_PECI_T_NEGO_MSG_MASK, reg);
+       addr_timing = FIELD_GET(ASPEED_PECI_T_NEGO_ADDR_MASK, reg);
+
+       if (msg_timing != addr_timing)
+               return 0;
+
+       reg = readl(aspeed_peci->base + ASPEED_PECI_CTRL);
+       clk_div_exp = FIELD_GET(ASPEED_PECI_CTRL_CLK_DIV_MASK, reg);
+
+       div = ASPEED_PECI_CLK_DIV(msg_timing, clk_div_exp);
+
+       return DIV_ROUND_UP_ULL(prate, div);
+}
+
+static const struct clk_ops clk_aspeed_peci_ops = {
+       .set_rate = clk_aspeed_peci_set_rate,
+       .round_rate = clk_aspeed_peci_round_rate,
+       .recalc_rate = clk_aspeed_peci_recalc_rate,
+};
+
+/*
+ * PECI HW contains a clock divider which is a combination of:
+ *  div0: 4 (fixed divider)
+ *  div1: x + 1
+ *  div2: 1 << y
+ * In other words, out_clk = in_clk / (div0 * div1 * div2)
+ * The resulting frequency is used by PECI Controller to drive the PECI bus to
+ * negotiate optimal transfer rate.
+ */
+static struct clk *devm_aspeed_peci_register_clk_div(struct device *dev, struct clk *parent,
+                                                    struct aspeed_peci *priv)
+{
+       struct clk_aspeed_peci *peci_clk;
+       struct clk_init_data init;
+       const char *parent_name;
+       char name[32];
+       int ret;
+
+       snprintf(name, sizeof(name), "%s_div", dev_name(dev));
+
+       parent_name = __clk_get_name(parent);
+
+       init.ops = &clk_aspeed_peci_ops;
+       init.name = name;
+       init.parent_names = (const char* []) { parent_name };
+       init.num_parents = 1;
+       init.flags = 0;
+
+       peci_clk = devm_kzalloc(dev, sizeof(struct clk_aspeed_peci), GFP_KERNEL);
+       if (!peci_clk)
+               return ERR_PTR(-ENOMEM);
+
+       peci_clk->hw.init = &init;
+       peci_clk->aspeed_peci = priv;
+
+       ret = devm_clk_hw_register(dev, &peci_clk->hw);
+       if (ret)
+               return ERR_PTR(ret);
+
+       return peci_clk->hw.clk;
+}
+
+static void aspeed_peci_property_sanitize(struct device *dev, const char *propname,
+                                         u32 min, u32 max, u32 default_val, u32 *propval)
+{
+       u32 val;
+       int ret;
+
+       ret = device_property_read_u32(dev, propname, &val);
+       if (ret) {
+               val = default_val;
+       } else if (val > max || val < min) {
+               dev_warn(dev, "invalid %s: %u, falling back to: %u\n",
+                        propname, val, default_val);
+
+               val = default_val;
+       }
+
+       *propval = val;
+}
+
+static void aspeed_peci_property_setup(struct aspeed_peci *priv)
+{
+       aspeed_peci_property_sanitize(priv->dev, "clock-frequency",
+                                     ASPEED_PECI_CLK_FREQUENCY_MIN, ASPEED_PECI_CLK_FREQUENCY_MAX,
+                                     ASPEED_PECI_CLK_FREQUENCY_DEFAULT, &priv->clk_frequency);
+       aspeed_peci_property_sanitize(priv->dev, "cmd-timeout-ms",
+                                     1, ASPEED_PECI_CMD_TIMEOUT_MS_MAX,
+                                     ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT, &priv->cmd_timeout_ms);
+}
+
+static struct peci_controller_ops aspeed_ops = {
+       .xfer = aspeed_peci_xfer,
+};
+
+static void aspeed_peci_reset_control_release(void *data)
+{
+       reset_control_assert(data);
+}
+
+static int devm_aspeed_peci_reset_control_deassert(struct device *dev, struct reset_control *rst)
+{
+       int ret;
+
+       ret = reset_control_deassert(rst);
+       if (ret)
+               return ret;
+
+       return devm_add_action_or_reset(dev, aspeed_peci_reset_control_release, rst);
+}
+
+static void aspeed_peci_clk_release(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
+static int devm_aspeed_peci_clk_enable(struct device *dev, struct clk *clk)
+{
+       int ret;
+
+       ret = clk_prepare_enable(clk);
+       if (ret)
+               return ret;
+
+       return devm_add_action_or_reset(dev, aspeed_peci_clk_release, clk);
+}
+
+static int aspeed_peci_probe(struct platform_device *pdev)
+{
+       struct peci_controller *controller;
+       struct aspeed_peci *priv;
+       struct clk *ref_clk;
+       int ret;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->dev = &pdev->dev;
+       dev_set_drvdata(priv->dev, priv);
+
+       priv->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(priv->base))
+               return PTR_ERR(priv->base);
+
+       priv->irq = platform_get_irq(pdev, 0);
+       if (!priv->irq)
+               return priv->irq;
+
+       ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_peci_irq_handler,
+                              0, "peci-aspeed", priv);
+       if (ret)
+               return ret;
+
+       init_completion(&priv->xfer_complete);
+       spin_lock_init(&priv->lock);
+
+       priv->rst = devm_reset_control_get(&pdev->dev, NULL);
+       if (IS_ERR(priv->rst))
+               return dev_err_probe(priv->dev, PTR_ERR(priv->rst),
+                                    "failed to get reset control\n");
+
+       ret = devm_aspeed_peci_reset_control_deassert(priv->dev, priv->rst);
+       if (ret)
+               return dev_err_probe(priv->dev, ret, "cannot deassert reset control\n");
+
+       aspeed_peci_property_setup(priv);
+
+       aspeed_peci_init_regs(priv);
+
+       ref_clk = devm_clk_get(priv->dev, NULL);
+       if (IS_ERR(ref_clk))
+               return dev_err_probe(priv->dev, PTR_ERR(ref_clk), "failed to get ref clock\n");
+
+       priv->clk = devm_aspeed_peci_register_clk_div(priv->dev, ref_clk, priv);
+       if (IS_ERR(priv->clk))
+               return dev_err_probe(priv->dev, PTR_ERR(priv->clk), "cannot register clock\n");
+
+       ret = clk_set_rate(priv->clk, priv->clk_frequency);
+       if (ret < 0)
+               return dev_err_probe(priv->dev, ret, "cannot set clock frequency\n");
+
+       ret = devm_aspeed_peci_clk_enable(priv->dev, priv->clk);
+       if (ret)
+               return dev_err_probe(priv->dev, ret, "failed to enable clock\n");
+
+       aspeed_peci_controller_enable(priv);
+
+       controller = devm_peci_controller_add(priv->dev, &aspeed_ops);
+       if (IS_ERR(controller))
+               return dev_err_probe(priv->dev, PTR_ERR(controller),
+                                    "failed to add aspeed peci controller\n");
+
+       priv->controller = controller;
+
+       return 0;
+}
+
+static const struct of_device_id aspeed_peci_of_table[] = {
+       { .compatible = "aspeed,ast2400-peci", },
+       { .compatible = "aspeed,ast2500-peci", },
+       { .compatible = "aspeed,ast2600-peci", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, aspeed_peci_of_table);
+
+static struct platform_driver aspeed_peci_driver = {
+       .probe  = aspeed_peci_probe,
+       .driver = {
+               .name           = "peci-aspeed",
+               .of_match_table = aspeed_peci_of_table,
+       },
+};
+module_platform_driver(aspeed_peci_driver);
+
+MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("ASPEED PECI driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PECI);
diff --git a/drivers/peci/core.c b/drivers/peci/core.c
new file mode 100644 (file)
index 0000000..9c8cf07
--- /dev/null
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018-2021 Intel Corporation
+
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/idr.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/peci.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+
+#include "internal.h"
+
+static DEFINE_IDA(peci_controller_ida);
+
+static void peci_controller_dev_release(struct device *dev)
+{
+       struct peci_controller *controller = to_peci_controller(dev);
+
+       mutex_destroy(&controller->bus_lock);
+       ida_free(&peci_controller_ida, controller->id);
+       kfree(controller);
+}
+
+struct device_type peci_controller_type = {
+       .release        = peci_controller_dev_release,
+};
+
+int peci_controller_scan_devices(struct peci_controller *controller)
+{
+       int ret;
+       u8 addr;
+
+       for (addr = PECI_BASE_ADDR; addr < PECI_BASE_ADDR + PECI_DEVICE_NUM_MAX; addr++) {
+               ret = peci_device_create(controller, addr);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static struct peci_controller *peci_controller_alloc(struct device *dev,
+                                                    struct peci_controller_ops *ops)
+{
+       struct peci_controller *controller;
+       int ret;
+
+       if (!ops->xfer)
+               return ERR_PTR(-EINVAL);
+
+       controller = kzalloc(sizeof(*controller), GFP_KERNEL);
+       if (!controller)
+               return ERR_PTR(-ENOMEM);
+
+       ret = ida_alloc_max(&peci_controller_ida, U8_MAX, GFP_KERNEL);
+       if (ret < 0)
+               goto err;
+       controller->id = ret;
+
+       controller->ops = ops;
+
+       controller->dev.parent = dev;
+       controller->dev.bus = &peci_bus_type;
+       controller->dev.type = &peci_controller_type;
+
+       device_initialize(&controller->dev);
+
+       mutex_init(&controller->bus_lock);
+
+       return controller;
+
+err:
+       kfree(controller);
+       return ERR_PTR(ret);
+}
+
+static int unregister_child(struct device *dev, void *dummy)
+{
+       peci_device_destroy(to_peci_device(dev));
+
+       return 0;
+}
+
+static void unregister_controller(void *_controller)
+{
+       struct peci_controller *controller = _controller;
+
+       /*
+        * Detach any active PECI devices. This can't fail, thus we do not
+        * check the returned value.
+        */
+       device_for_each_child_reverse(&controller->dev, NULL, unregister_child);
+
+       device_unregister(&controller->dev);
+
+       fwnode_handle_put(controller->dev.fwnode);
+
+       pm_runtime_disable(&controller->dev);
+}
+
+/**
+ * devm_peci_controller_add() - add PECI controller
+ * @dev: device for devm operations
+ * @ops: pointer to controller specific methods
+ *
+ * In final stage of its probe(), peci_controller driver calls
+ * devm_peci_controller_add() to register itself with the PECI bus.
+ *
+ * Return: Pointer to the newly allocated controller or ERR_PTR() in case of failure.
+ */
+struct peci_controller *devm_peci_controller_add(struct device *dev,
+                                                struct peci_controller_ops *ops)
+{
+       struct peci_controller *controller;
+       int ret;
+
+       controller = peci_controller_alloc(dev, ops);
+       if (IS_ERR(controller))
+               return controller;
+
+       ret = dev_set_name(&controller->dev, "peci-%d", controller->id);
+       if (ret)
+               goto err_put;
+
+       pm_runtime_no_callbacks(&controller->dev);
+       pm_suspend_ignore_children(&controller->dev, true);
+       pm_runtime_enable(&controller->dev);
+
+       device_set_node(&controller->dev, fwnode_handle_get(dev_fwnode(dev)));
+
+       ret = device_add(&controller->dev);
+       if (ret)
+               goto err_fwnode;
+
+       ret = devm_add_action_or_reset(dev, unregister_controller, controller);
+       if (ret)
+               return ERR_PTR(ret);
+
+       /*
+        * Ignoring retval since failures during scan are non-critical for
+        * controller itself.
+        */
+       peci_controller_scan_devices(controller);
+
+       return controller;
+
+err_fwnode:
+       fwnode_handle_put(controller->dev.fwnode);
+
+       pm_runtime_disable(&controller->dev);
+
+err_put:
+       put_device(&controller->dev);
+
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_NS_GPL(devm_peci_controller_add, PECI);
+
+static const struct peci_device_id *
+peci_bus_match_device_id(const struct peci_device_id *id, struct peci_device *device)
+{
+       while (id->family != 0) {
+               if (id->family == device->info.family &&
+                   id->model == device->info.model)
+                       return id;
+               id++;
+       }
+
+       return NULL;
+}
+
+static int peci_bus_device_match(struct device *dev, struct device_driver *drv)
+{
+       struct peci_device *device = to_peci_device(dev);
+       struct peci_driver *peci_drv = to_peci_driver(drv);
+
+       if (dev->type != &peci_device_type)
+               return 0;
+
+       return !!peci_bus_match_device_id(peci_drv->id_table, device);
+}
+
+static int peci_bus_device_probe(struct device *dev)
+{
+       struct peci_device *device = to_peci_device(dev);
+       struct peci_driver *driver = to_peci_driver(dev->driver);
+
+       return driver->probe(device, peci_bus_match_device_id(driver->id_table, device));
+}
+
+static void peci_bus_device_remove(struct device *dev)
+{
+       struct peci_device *device = to_peci_device(dev);
+       struct peci_driver *driver = to_peci_driver(dev->driver);
+
+       if (driver->remove)
+               driver->remove(device);
+}
+
+struct bus_type peci_bus_type = {
+       .name           = "peci",
+       .match          = peci_bus_device_match,
+       .probe          = peci_bus_device_probe,
+       .remove         = peci_bus_device_remove,
+       .bus_groups     = peci_bus_groups,
+};
+
+static int __init peci_init(void)
+{
+       int ret;
+
+       ret = bus_register(&peci_bus_type);
+       if (ret < 0) {
+               pr_err("peci: failed to register PECI bus type!\n");
+               return ret;
+       }
+
+       return 0;
+}
+module_init(peci_init);
+
+static void __exit peci_exit(void)
+{
+       bus_unregister(&peci_bus_type);
+}
+module_exit(peci_exit);
+
+MODULE_AUTHOR("Jason M Bills <jason.m.bills@linux.intel.com>");
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_AUTHOR("Iwona Winiarska <iwona.winiarska@intel.com>");
+MODULE_DESCRIPTION("PECI bus core module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/peci/cpu.c b/drivers/peci/cpu.c
new file mode 100644 (file)
index 0000000..68eb61c
--- /dev/null
@@ -0,0 +1,343 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2021 Intel Corporation
+
+#include <linux/auxiliary_bus.h>
+#include <linux/module.h>
+#include <linux/peci.h>
+#include <linux/peci-cpu.h>
+#include <linux/slab.h>
+
+#include "internal.h"
+
+/**
+ * peci_temp_read() - read the maximum die temperature from PECI target device
+ * @device: PECI device to which request is going to be sent
+ * @temp_raw: where to store the read temperature
+ *
+ * It uses GetTemp PECI command.
+ *
+ * Return: 0 if succeeded, other values in case errors.
+ */
+int peci_temp_read(struct peci_device *device, s16 *temp_raw)
+{
+       struct peci_request *req;
+
+       req = peci_xfer_get_temp(device);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       *temp_raw = peci_request_temp_read(req);
+
+       peci_request_free(req);
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(peci_temp_read, PECI_CPU);
+
+/**
+ * peci_pcs_read() - read PCS register
+ * @device: PECI device to which request is going to be sent
+ * @index: PCS index
+ * @param: PCS parameter
+ * @data: where to store the read data
+ *
+ * It uses RdPkgConfig PECI command.
+ *
+ * Return: 0 if succeeded, other values in case errors.
+ */
+int peci_pcs_read(struct peci_device *device, u8 index, u16 param, u32 *data)
+{
+       struct peci_request *req;
+       int ret;
+
+       req = peci_xfer_pkg_cfg_readl(device, index, param);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       ret = peci_request_status(req);
+       if (ret)
+               goto out_req_free;
+
+       *data = peci_request_data_readl(req);
+out_req_free:
+       peci_request_free(req);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(peci_pcs_read, PECI_CPU);
+
+/**
+ * peci_pci_local_read() - read 32-bit memory location using raw address
+ * @device: PECI device to which request is going to be sent
+ * @bus: bus
+ * @dev: device
+ * @func: function
+ * @reg: register
+ * @data: where to store the read data
+ *
+ * It uses RdPCIConfigLocal PECI command.
+ *
+ * Return: 0 if succeeded, other values in case errors.
+ */
+int peci_pci_local_read(struct peci_device *device, u8 bus, u8 dev, u8 func,
+                       u16 reg, u32 *data)
+{
+       struct peci_request *req;
+       int ret;
+
+       req = peci_xfer_pci_cfg_local_readl(device, bus, dev, func, reg);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       ret = peci_request_status(req);
+       if (ret)
+               goto out_req_free;
+
+       *data = peci_request_data_readl(req);
+out_req_free:
+       peci_request_free(req);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(peci_pci_local_read, PECI_CPU);
+
+/**
+ * peci_ep_pci_local_read() - read 32-bit memory location using raw address
+ * @device: PECI device to which request is going to be sent
+ * @seg: PCI segment
+ * @bus: bus
+ * @dev: device
+ * @func: function
+ * @reg: register
+ * @data: where to store the read data
+ *
+ * Like &peci_pci_local_read, but it uses RdEndpointConfig PECI command.
+ *
+ * Return: 0 if succeeded, other values in case errors.
+ */
+int peci_ep_pci_local_read(struct peci_device *device, u8 seg,
+                          u8 bus, u8 dev, u8 func, u16 reg, u32 *data)
+{
+       struct peci_request *req;
+       int ret;
+
+       req = peci_xfer_ep_pci_cfg_local_readl(device, seg, bus, dev, func, reg);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       ret = peci_request_status(req);
+       if (ret)
+               goto out_req_free;
+
+       *data = peci_request_data_readl(req);
+out_req_free:
+       peci_request_free(req);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(peci_ep_pci_local_read, PECI_CPU);
+
+/**
+ * peci_mmio_read() - read 32-bit memory location using 64-bit bar offset address
+ * @device: PECI device to which request is going to be sent
+ * @bar: PCI bar
+ * @seg: PCI segment
+ * @bus: bus
+ * @dev: device
+ * @func: function
+ * @address: 64-bit MMIO address
+ * @data: where to store the read data
+ *
+ * It uses RdEndpointConfig PECI command.
+ *
+ * Return: 0 if succeeded, other values in case errors.
+ */
+int peci_mmio_read(struct peci_device *device, u8 bar, u8 seg,
+                  u8 bus, u8 dev, u8 func, u64 address, u32 *data)
+{
+       struct peci_request *req;
+       int ret;
+
+       req = peci_xfer_ep_mmio64_readl(device, bar, seg, bus, dev, func, address);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       ret = peci_request_status(req);
+       if (ret)
+               goto out_req_free;
+
+       *data = peci_request_data_readl(req);
+out_req_free:
+       peci_request_free(req);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(peci_mmio_read, PECI_CPU);
+
+static const char * const peci_adev_types[] = {
+       "cputemp",
+       "dimmtemp",
+};
+
+struct peci_cpu {
+       struct peci_device *device;
+       const struct peci_device_id *id;
+};
+
+static void adev_release(struct device *dev)
+{
+       struct auxiliary_device *adev = to_auxiliary_dev(dev);
+
+       auxiliary_device_uninit(adev);
+
+       kfree(adev->name);
+       kfree(adev);
+}
+
+static struct auxiliary_device *adev_alloc(struct peci_cpu *priv, int idx)
+{
+       struct peci_controller *controller = to_peci_controller(priv->device->dev.parent);
+       struct auxiliary_device *adev;
+       const char *name;
+       int ret;
+
+       adev = kzalloc(sizeof(*adev), GFP_KERNEL);
+       if (!adev)
+               return ERR_PTR(-ENOMEM);
+
+       name = kasprintf(GFP_KERNEL, "%s.%s", peci_adev_types[idx], (const char *)priv->id->data);
+       if (!name) {
+               ret = -ENOMEM;
+               goto free_adev;
+       }
+
+       adev->name = name;
+       adev->dev.parent = &priv->device->dev;
+       adev->dev.release = adev_release;
+       adev->id = (controller->id << 16) | (priv->device->addr);
+
+       ret = auxiliary_device_init(adev);
+       if (ret)
+               goto free_name;
+
+       return adev;
+
+free_name:
+       kfree(name);
+free_adev:
+       kfree(adev);
+       return ERR_PTR(ret);
+}
+
+static void unregister_adev(void *_adev)
+{
+       struct auxiliary_device *adev = _adev;
+
+       auxiliary_device_delete(adev);
+}
+
+static int devm_adev_add(struct device *dev, int idx)
+{
+       struct peci_cpu *priv = dev_get_drvdata(dev);
+       struct auxiliary_device *adev;
+       int ret;
+
+       adev = adev_alloc(priv, idx);
+       if (IS_ERR(adev))
+               return PTR_ERR(adev);
+
+       ret = auxiliary_device_add(adev);
+       if (ret) {
+               auxiliary_device_uninit(adev);
+               return ret;
+       }
+
+       ret = devm_add_action_or_reset(&priv->device->dev, unregister_adev, adev);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static void peci_cpu_add_adevices(struct peci_cpu *priv)
+{
+       struct device *dev = &priv->device->dev;
+       int ret, i;
+
+       for (i = 0; i < ARRAY_SIZE(peci_adev_types); i++) {
+               ret = devm_adev_add(dev, i);
+               if (ret) {
+                       dev_warn(dev, "Failed to register PECI auxiliary: %s, ret = %d\n",
+                                peci_adev_types[i], ret);
+                       continue;
+               }
+       }
+}
+
+static int
+peci_cpu_probe(struct peci_device *device, const struct peci_device_id *id)
+{
+       struct device *dev = &device->dev;
+       struct peci_cpu *priv;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, priv);
+       priv->device = device;
+       priv->id = id;
+
+       peci_cpu_add_adevices(priv);
+
+       return 0;
+}
+
+static const struct peci_device_id peci_cpu_device_ids[] = {
+       { /* Haswell Xeon */
+               .family = 6,
+               .model  = INTEL_FAM6_HASWELL_X,
+               .data   = "hsx",
+       },
+       { /* Broadwell Xeon */
+               .family = 6,
+               .model  = INTEL_FAM6_BROADWELL_X,
+               .data   = "bdx",
+       },
+       { /* Broadwell Xeon D */
+               .family = 6,
+               .model  = INTEL_FAM6_BROADWELL_D,
+               .data   = "bdxd",
+       },
+       { /* Skylake Xeon */
+               .family = 6,
+               .model  = INTEL_FAM6_SKYLAKE_X,
+               .data   = "skx",
+       },
+       { /* Icelake Xeon */
+               .family = 6,
+               .model  = INTEL_FAM6_ICELAKE_X,
+               .data   = "icx",
+       },
+       { /* Icelake Xeon D */
+               .family = 6,
+               .model  = INTEL_FAM6_ICELAKE_D,
+               .data   = "icxd",
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(peci, peci_cpu_device_ids);
+
+static struct peci_driver peci_cpu_driver = {
+       .probe          = peci_cpu_probe,
+       .id_table       = peci_cpu_device_ids,
+       .driver         = {
+               .name           = "peci-cpu",
+       },
+};
+module_peci_driver(peci_cpu_driver);
+
+MODULE_AUTHOR("Iwona Winiarska <iwona.winiarska@intel.com>");
+MODULE_DESCRIPTION("PECI CPU driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PECI);
diff --git a/drivers/peci/device.c b/drivers/peci/device.c
new file mode 100644 (file)
index 0000000..e6b0bff
--- /dev/null
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018-2021 Intel Corporation
+
+#include <linux/bitfield.h>
+#include <linux/peci.h>
+#include <linux/peci-cpu.h>
+#include <linux/slab.h>
+
+#include "internal.h"
+
+/*
+ * PECI device can be removed using sysfs, but the removal can also happen as
+ * a result of controller being removed.
+ * Mutex is used to protect PECI device from being double-deleted.
+ */
+static DEFINE_MUTEX(peci_device_del_lock);
+
+#define REVISION_NUM_MASK GENMASK(15, 8)
+static int peci_get_revision(struct peci_device *device, u8 *revision)
+{
+       struct peci_request *req;
+       u64 dib;
+
+       req = peci_xfer_get_dib(device);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       /*
+        * PECI device may be in a state where it is unable to return a proper
+        * DIB, in which case it returns 0 as DIB value.
+        * Let's treat this as an error to avoid carrying on with the detection
+        * using invalid revision.
+        */
+       dib = peci_request_dib_read(req);
+       if (dib == 0) {
+               peci_request_free(req);
+               return -EIO;
+       }
+
+       *revision = FIELD_GET(REVISION_NUM_MASK, dib);
+
+       peci_request_free(req);
+
+       return 0;
+}
+
+static int peci_get_cpu_id(struct peci_device *device, u32 *cpu_id)
+{
+       struct peci_request *req;
+       int ret;
+
+       req = peci_xfer_pkg_cfg_readl(device, PECI_PCS_PKG_ID, PECI_PKG_ID_CPU_ID);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       ret = peci_request_status(req);
+       if (ret)
+               goto out_req_free;
+
+       *cpu_id = peci_request_data_readl(req);
+out_req_free:
+       peci_request_free(req);
+
+       return ret;
+}
+
+static unsigned int peci_x86_cpu_family(unsigned int sig)
+{
+       unsigned int x86;
+
+       x86 = (sig >> 8) & 0xf;
+
+       if (x86 == 0xf)
+               x86 += (sig >> 20) & 0xff;
+
+       return x86;
+}
+
+static unsigned int peci_x86_cpu_model(unsigned int sig)
+{
+       unsigned int fam, model;
+
+       fam = peci_x86_cpu_family(sig);
+
+       model = (sig >> 4) & 0xf;
+
+       if (fam >= 0x6)
+               model += ((sig >> 16) & 0xf) << 4;
+
+       return model;
+}
+
+static int peci_device_info_init(struct peci_device *device)
+{
+       u8 revision;
+       u32 cpu_id;
+       int ret;
+
+       ret = peci_get_cpu_id(device, &cpu_id);
+       if (ret)
+               return ret;
+
+       device->info.family = peci_x86_cpu_family(cpu_id);
+       device->info.model = peci_x86_cpu_model(cpu_id);
+
+       ret = peci_get_revision(device, &revision);
+       if (ret)
+               return ret;
+       device->info.peci_revision = revision;
+
+       device->info.socket_id = device->addr - PECI_BASE_ADDR;
+
+       return 0;
+}
+
+static int peci_detect(struct peci_controller *controller, u8 addr)
+{
+       /*
+        * PECI Ping is a command encoded by tx_len = 0, rx_len = 0.
+        * We expect correct Write FCS if the device at the target address
+        * is able to respond.
+        */
+       struct peci_request req = { 0 };
+       int ret;
+
+       mutex_lock(&controller->bus_lock);
+       ret = controller->ops->xfer(controller, addr, &req);
+       mutex_unlock(&controller->bus_lock);
+
+       return ret;
+}
+
+static bool peci_addr_valid(u8 addr)
+{
+       return addr >= PECI_BASE_ADDR && addr < PECI_BASE_ADDR + PECI_DEVICE_NUM_MAX;
+}
+
+static int peci_dev_exists(struct device *dev, void *data)
+{
+       struct peci_device *device = to_peci_device(dev);
+       u8 *addr = data;
+
+       if (device->addr == *addr)
+               return -EBUSY;
+
+       return 0;
+}
+
+int peci_device_create(struct peci_controller *controller, u8 addr)
+{
+       struct peci_device *device;
+       int ret;
+
+       if (!peci_addr_valid(addr))
+               return -EINVAL;
+
+       /* Check if we have already detected this device before. */
+       ret = device_for_each_child(&controller->dev, &addr, peci_dev_exists);
+       if (ret)
+               return 0;
+
+       ret = peci_detect(controller, addr);
+       if (ret) {
+               /*
+                * Device not present or host state doesn't allow successful
+                * detection at this time.
+                */
+               if (ret == -EIO || ret == -ETIMEDOUT)
+                       return 0;
+
+               return ret;
+       }
+
+       device = kzalloc(sizeof(*device), GFP_KERNEL);
+       if (!device)
+               return -ENOMEM;
+
+       device_initialize(&device->dev);
+
+       device->addr = addr;
+       device->dev.parent = &controller->dev;
+       device->dev.bus = &peci_bus_type;
+       device->dev.type = &peci_device_type;
+
+       ret = peci_device_info_init(device);
+       if (ret)
+               goto err_put;
+
+       ret = dev_set_name(&device->dev, "%d-%02x", controller->id, device->addr);
+       if (ret)
+               goto err_put;
+
+       ret = device_add(&device->dev);
+       if (ret)
+               goto err_put;
+
+       return 0;
+
+err_put:
+       put_device(&device->dev);
+
+       return ret;
+}
+
+void peci_device_destroy(struct peci_device *device)
+{
+       mutex_lock(&peci_device_del_lock);
+       if (!device->deleted) {
+               device_unregister(&device->dev);
+               device->deleted = true;
+       }
+       mutex_unlock(&peci_device_del_lock);
+}
+
+int __peci_driver_register(struct peci_driver *driver, struct module *owner,
+                          const char *mod_name)
+{
+       driver->driver.bus = &peci_bus_type;
+       driver->driver.owner = owner;
+       driver->driver.mod_name = mod_name;
+
+       if (!driver->probe) {
+               pr_err("peci: trying to register driver without probe callback\n");
+               return -EINVAL;
+       }
+
+       if (!driver->id_table) {
+               pr_err("peci: trying to register driver without device id table\n");
+               return -EINVAL;
+       }
+
+       return driver_register(&driver->driver);
+}
+EXPORT_SYMBOL_NS_GPL(__peci_driver_register, PECI);
+
+void peci_driver_unregister(struct peci_driver *driver)
+{
+       driver_unregister(&driver->driver);
+}
+EXPORT_SYMBOL_NS_GPL(peci_driver_unregister, PECI);
+
+static void peci_device_release(struct device *dev)
+{
+       struct peci_device *device = to_peci_device(dev);
+
+       kfree(device);
+}
+
+struct device_type peci_device_type = {
+       .groups         = peci_device_groups,
+       .release        = peci_device_release,
+};
diff --git a/drivers/peci/internal.h b/drivers/peci/internal.h
new file mode 100644 (file)
index 0000000..9d75ea5
--- /dev/null
@@ -0,0 +1,136 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2018-2021 Intel Corporation */
+
+#ifndef __PECI_INTERNAL_H
+#define __PECI_INTERNAL_H
+
+#include <linux/device.h>
+#include <linux/types.h>
+
+struct peci_controller;
+struct attribute_group;
+struct peci_device;
+struct peci_request;
+
+/* PECI CPU address range 0x30-0x37 */
+#define PECI_BASE_ADDR         0x30
+#define PECI_DEVICE_NUM_MAX    8
+
+struct peci_request *peci_request_alloc(struct peci_device *device, u8 tx_len, u8 rx_len);
+void peci_request_free(struct peci_request *req);
+
+int peci_request_status(struct peci_request *req);
+
+u64 peci_request_dib_read(struct peci_request *req);
+s16 peci_request_temp_read(struct peci_request *req);
+
+u8 peci_request_data_readb(struct peci_request *req);
+u16 peci_request_data_readw(struct peci_request *req);
+u32 peci_request_data_readl(struct peci_request *req);
+u64 peci_request_data_readq(struct peci_request *req);
+
+struct peci_request *peci_xfer_get_dib(struct peci_device *device);
+struct peci_request *peci_xfer_get_temp(struct peci_device *device);
+
+struct peci_request *peci_xfer_pkg_cfg_readb(struct peci_device *device, u8 index, u16 param);
+struct peci_request *peci_xfer_pkg_cfg_readw(struct peci_device *device, u8 index, u16 param);
+struct peci_request *peci_xfer_pkg_cfg_readl(struct peci_device *device, u8 index, u16 param);
+struct peci_request *peci_xfer_pkg_cfg_readq(struct peci_device *device, u8 index, u16 param);
+
+struct peci_request *peci_xfer_pci_cfg_local_readb(struct peci_device *device,
+                                                  u8 bus, u8 dev, u8 func, u16 reg);
+struct peci_request *peci_xfer_pci_cfg_local_readw(struct peci_device *device,
+                                                  u8 bus, u8 dev, u8 func, u16 reg);
+struct peci_request *peci_xfer_pci_cfg_local_readl(struct peci_device *device,
+                                                  u8 bus, u8 dev, u8 func, u16 reg);
+
+struct peci_request *peci_xfer_ep_pci_cfg_local_readb(struct peci_device *device, u8 seg,
+                                                     u8 bus, u8 dev, u8 func, u16 reg);
+struct peci_request *peci_xfer_ep_pci_cfg_local_readw(struct peci_device *device, u8 seg,
+                                                     u8 bus, u8 dev, u8 func, u16 reg);
+struct peci_request *peci_xfer_ep_pci_cfg_local_readl(struct peci_device *device, u8 seg,
+                                                     u8 bus, u8 dev, u8 func, u16 reg);
+
+struct peci_request *peci_xfer_ep_pci_cfg_readb(struct peci_device *device, u8 seg,
+                                               u8 bus, u8 dev, u8 func, u16 reg);
+struct peci_request *peci_xfer_ep_pci_cfg_readw(struct peci_device *device, u8 seg,
+                                               u8 bus, u8 dev, u8 func, u16 reg);
+struct peci_request *peci_xfer_ep_pci_cfg_readl(struct peci_device *device, u8 seg,
+                                               u8 bus, u8 dev, u8 func, u16 reg);
+
+struct peci_request *peci_xfer_ep_mmio32_readl(struct peci_device *device, u8 bar, u8 seg,
+                                              u8 bus, u8 dev, u8 func, u64 offset);
+
+struct peci_request *peci_xfer_ep_mmio64_readl(struct peci_device *device, u8 bar, u8 seg,
+                                              u8 bus, u8 dev, u8 func, u64 offset);
+/**
+ * struct peci_device_id - PECI device data to match
+ * @data: pointer to driver private data specific to device
+ * @family: device family
+ * @model: device model
+ */
+struct peci_device_id {
+       const void *data;
+       u16 family;
+       u8 model;
+};
+
+extern struct device_type peci_device_type;
+extern const struct attribute_group *peci_device_groups[];
+
+int peci_device_create(struct peci_controller *controller, u8 addr);
+void peci_device_destroy(struct peci_device *device);
+
+extern struct bus_type peci_bus_type;
+extern const struct attribute_group *peci_bus_groups[];
+
+/**
+ * struct peci_driver - PECI driver
+ * @driver: inherit device driver
+ * @probe: probe callback
+ * @remove: remove callback
+ * @id_table: PECI device match table to decide which device to bind
+ */
+struct peci_driver {
+       struct device_driver driver;
+       int (*probe)(struct peci_device *device, const struct peci_device_id *id);
+       void (*remove)(struct peci_device *device);
+       const struct peci_device_id *id_table;
+};
+
+static inline struct peci_driver *to_peci_driver(struct device_driver *d)
+{
+       return container_of(d, struct peci_driver, driver);
+}
+
+int __peci_driver_register(struct peci_driver *driver, struct module *owner,
+                          const char *mod_name);
+/**
+ * peci_driver_register() - register PECI driver
+ * @driver: the driver to be registered
+ *
+ * PECI drivers that don't need to do anything special in module init should
+ * use the convenience "module_peci_driver" macro instead
+ *
+ * Return: zero on success, else a negative error code.
+ */
+#define peci_driver_register(driver) \
+       __peci_driver_register(driver, THIS_MODULE, KBUILD_MODNAME)
+void peci_driver_unregister(struct peci_driver *driver);
+
+/**
+ * module_peci_driver() - helper macro for registering a modular PECI driver
+ * @__peci_driver: peci_driver struct
+ *
+ * Helper macro for PECI drivers which do not do anything special in module
+ * init/exit. This eliminates a lot of boilerplate. Each module may only
+ * use this macro once, and calling it replaces module_init() and module_exit()
+ */
+#define module_peci_driver(__peci_driver) \
+       module_driver(__peci_driver, peci_driver_register, peci_driver_unregister)
+
+extern struct device_type peci_controller_type;
+
+int peci_controller_scan_devices(struct peci_controller *controller);
+
+#endif /* __PECI_INTERNAL_H */
diff --git a/drivers/peci/request.c b/drivers/peci/request.c
new file mode 100644 (file)
index 0000000..8d6dd7b
--- /dev/null
@@ -0,0 +1,482 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2021 Intel Corporation
+
+#include <linux/bug.h>
+#include <linux/export.h>
+#include <linux/pci.h>
+#include <linux/peci.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <asm/unaligned.h>
+
+#include "internal.h"
+
+#define PECI_GET_DIB_CMD               0xf7
+#define  PECI_GET_DIB_WR_LEN           1
+#define  PECI_GET_DIB_RD_LEN           8
+
+#define PECI_GET_TEMP_CMD              0x01
+#define  PECI_GET_TEMP_WR_LEN          1
+#define  PECI_GET_TEMP_RD_LEN          2
+
+#define PECI_RDPKGCFG_CMD              0xa1
+#define  PECI_RDPKGCFG_WR_LEN          5
+#define  PECI_RDPKGCFG_RD_LEN_BASE     1
+#define PECI_WRPKGCFG_CMD              0xa5
+#define  PECI_WRPKGCFG_WR_LEN_BASE     6
+#define  PECI_WRPKGCFG_RD_LEN          1
+
+#define PECI_RDIAMSR_CMD               0xb1
+#define  PECI_RDIAMSR_WR_LEN           5
+#define  PECI_RDIAMSR_RD_LEN           9
+#define PECI_WRIAMSR_CMD               0xb5
+#define PECI_RDIAMSREX_CMD             0xd1
+#define  PECI_RDIAMSREX_WR_LEN         6
+#define  PECI_RDIAMSREX_RD_LEN         9
+
+#define PECI_RDPCICFG_CMD              0x61
+#define  PECI_RDPCICFG_WR_LEN          6
+#define  PECI_RDPCICFG_RD_LEN          5
+#define  PECI_RDPCICFG_RD_LEN_MAX      24
+#define PECI_WRPCICFG_CMD              0x65
+
+#define PECI_RDPCICFGLOCAL_CMD                 0xe1
+#define  PECI_RDPCICFGLOCAL_WR_LEN             5
+#define  PECI_RDPCICFGLOCAL_RD_LEN_BASE                1
+#define PECI_WRPCICFGLOCAL_CMD                 0xe5
+#define  PECI_WRPCICFGLOCAL_WR_LEN_BASE                6
+#define  PECI_WRPCICFGLOCAL_RD_LEN             1
+
+#define PECI_ENDPTCFG_TYPE_LOCAL_PCI           0x03
+#define PECI_ENDPTCFG_TYPE_PCI                 0x04
+#define PECI_ENDPTCFG_TYPE_MMIO                        0x05
+#define PECI_ENDPTCFG_ADDR_TYPE_PCI            0x04
+#define PECI_ENDPTCFG_ADDR_TYPE_MMIO_D         0x05
+#define PECI_ENDPTCFG_ADDR_TYPE_MMIO_Q         0x06
+#define PECI_RDENDPTCFG_CMD                    0xc1
+#define  PECI_RDENDPTCFG_PCI_WR_LEN            12
+#define  PECI_RDENDPTCFG_MMIO_WR_LEN_BASE      10
+#define  PECI_RDENDPTCFG_MMIO_D_WR_LEN         14
+#define  PECI_RDENDPTCFG_MMIO_Q_WR_LEN         18
+#define  PECI_RDENDPTCFG_RD_LEN_BASE           1
+#define PECI_WRENDPTCFG_CMD                    0xc5
+#define  PECI_WRENDPTCFG_PCI_WR_LEN_BASE       13
+#define  PECI_WRENDPTCFG_MMIO_D_WR_LEN_BASE    15
+#define  PECI_WRENDPTCFG_MMIO_Q_WR_LEN_BASE    19
+#define  PECI_WRENDPTCFG_RD_LEN                        1
+
+/* Device Specific Completion Code (CC) Definition */
+#define PECI_CC_SUCCESS                                0x40
+#define PECI_CC_NEED_RETRY                     0x80
+#define PECI_CC_OUT_OF_RESOURCE                        0x81
+#define PECI_CC_UNAVAIL_RESOURCE               0x82
+#define PECI_CC_INVALID_REQ                    0x90
+#define PECI_CC_MCA_ERROR                      0x91
+#define PECI_CC_CATASTROPHIC_MCA_ERROR         0x93
+#define PECI_CC_FATAL_MCA_ERROR                        0x94
+#define PECI_CC_PARITY_ERR_GPSB_OR_PMSB                0x98
+#define PECI_CC_PARITY_ERR_GPSB_OR_PMSB_IERR   0x9B
+#define PECI_CC_PARITY_ERR_GPSB_OR_PMSB_MCA    0x9C
+
+#define PECI_RETRY_BIT                 BIT(0)
+
+#define PECI_RETRY_TIMEOUT             msecs_to_jiffies(700)
+#define PECI_RETRY_INTERVAL_MIN                msecs_to_jiffies(1)
+#define PECI_RETRY_INTERVAL_MAX                msecs_to_jiffies(128)
+
+static u8 peci_request_data_cc(struct peci_request *req)
+{
+       return req->rx.buf[0];
+}
+
+/**
+ * peci_request_status() - return -errno based on PECI completion code
+ * @req: the PECI request that contains response data with completion code
+ *
+ * It can't be used for Ping(), GetDIB() and GetTemp() - for those commands we
+ * don't expect completion code in the response.
+ *
+ * Return: -errno
+ */
+int peci_request_status(struct peci_request *req)
+{
+       u8 cc = peci_request_data_cc(req);
+
+       if (cc != PECI_CC_SUCCESS)
+               dev_dbg(&req->device->dev, "ret: %#02x\n", cc);
+
+       switch (cc) {
+       case PECI_CC_SUCCESS:
+               return 0;
+       case PECI_CC_NEED_RETRY:
+       case PECI_CC_OUT_OF_RESOURCE:
+       case PECI_CC_UNAVAIL_RESOURCE:
+               return -EAGAIN;
+       case PECI_CC_INVALID_REQ:
+               return -EINVAL;
+       case PECI_CC_MCA_ERROR:
+       case PECI_CC_CATASTROPHIC_MCA_ERROR:
+       case PECI_CC_FATAL_MCA_ERROR:
+       case PECI_CC_PARITY_ERR_GPSB_OR_PMSB:
+       case PECI_CC_PARITY_ERR_GPSB_OR_PMSB_IERR:
+       case PECI_CC_PARITY_ERR_GPSB_OR_PMSB_MCA:
+               return -EIO;
+       }
+
+       WARN_ONCE(1, "Unknown PECI completion code: %#02x\n", cc);
+
+       return -EIO;
+}
+EXPORT_SYMBOL_NS_GPL(peci_request_status, PECI);
+
+static int peci_request_xfer(struct peci_request *req)
+{
+       struct peci_device *device = req->device;
+       struct peci_controller *controller = to_peci_controller(device->dev.parent);
+       int ret;
+
+       mutex_lock(&controller->bus_lock);
+       ret = controller->ops->xfer(controller, device->addr, req);
+       mutex_unlock(&controller->bus_lock);
+
+       return ret;
+}
+
+static int peci_request_xfer_retry(struct peci_request *req)
+{
+       long wait_interval = PECI_RETRY_INTERVAL_MIN;
+       struct peci_device *device = req->device;
+       struct peci_controller *controller = to_peci_controller(device->dev.parent);
+       unsigned long start = jiffies;
+       int ret;
+
+       /* Don't try to use it for ping */
+       if (WARN_ON(req->tx.len == 0))
+               return 0;
+
+       do {
+               ret = peci_request_xfer(req);
+               if (ret) {
+                       dev_dbg(&controller->dev, "xfer error: %d\n", ret);
+                       return ret;
+               }
+
+               if (peci_request_status(req) != -EAGAIN)
+                       return 0;
+
+               /* Set the retry bit to indicate a retry attempt */
+               req->tx.buf[1] |= PECI_RETRY_BIT;
+
+               if (schedule_timeout_interruptible(wait_interval))
+                       return -ERESTARTSYS;
+
+               wait_interval = min_t(long, wait_interval * 2, PECI_RETRY_INTERVAL_MAX);
+       } while (time_before(jiffies, start + PECI_RETRY_TIMEOUT));
+
+       dev_dbg(&controller->dev, "request timed out\n");
+
+       return -ETIMEDOUT;
+}
+
+/**
+ * peci_request_alloc() - allocate &struct peci_requests
+ * @device: PECI device to which request is going to be sent
+ * @tx_len: TX length
+ * @rx_len: RX length
+ *
+ * Return: A pointer to a newly allocated &struct peci_request on success or NULL otherwise.
+ */
+struct peci_request *peci_request_alloc(struct peci_device *device, u8 tx_len, u8 rx_len)
+{
+       struct peci_request *req;
+
+       /*
+        * TX and RX buffers are fixed length members of peci_request, this is
+        * just a warn for developers to make sure to expand the buffers (or
+        * change the allocation method) if we go over the current limit.
+        */
+       if (WARN_ON_ONCE(tx_len > PECI_REQUEST_MAX_BUF_SIZE || rx_len > PECI_REQUEST_MAX_BUF_SIZE))
+               return NULL;
+       /*
+        * PECI controllers that we are using now don't support DMA, this
+        * should be converted to DMA API once support for controllers that do
+        * allow it is added to avoid an extra copy.
+        */
+       req = kzalloc(sizeof(*req), GFP_KERNEL);
+       if (!req)
+               return NULL;
+
+       req->device = device;
+       req->tx.len = tx_len;
+       req->rx.len = rx_len;
+
+       return req;
+}
+EXPORT_SYMBOL_NS_GPL(peci_request_alloc, PECI);
+
+/**
+ * peci_request_free() - free peci_request
+ * @req: the PECI request to be freed
+ */
+void peci_request_free(struct peci_request *req)
+{
+       kfree(req);
+}
+EXPORT_SYMBOL_NS_GPL(peci_request_free, PECI);
+
+struct peci_request *peci_xfer_get_dib(struct peci_device *device)
+{
+       struct peci_request *req;
+       int ret;
+
+       req = peci_request_alloc(device, PECI_GET_DIB_WR_LEN, PECI_GET_DIB_RD_LEN);
+       if (!req)
+               return ERR_PTR(-ENOMEM);
+
+       req->tx.buf[0] = PECI_GET_DIB_CMD;
+
+       ret = peci_request_xfer(req);
+       if (ret) {
+               peci_request_free(req);
+               return ERR_PTR(ret);
+       }
+
+       return req;
+}
+EXPORT_SYMBOL_NS_GPL(peci_xfer_get_dib, PECI);
+
+struct peci_request *peci_xfer_get_temp(struct peci_device *device)
+{
+       struct peci_request *req;
+       int ret;
+
+       req = peci_request_alloc(device, PECI_GET_TEMP_WR_LEN, PECI_GET_TEMP_RD_LEN);
+       if (!req)
+               return ERR_PTR(-ENOMEM);
+
+       req->tx.buf[0] = PECI_GET_TEMP_CMD;
+
+       ret = peci_request_xfer(req);
+       if (ret) {
+               peci_request_free(req);
+               return ERR_PTR(ret);
+       }
+
+       return req;
+}
+EXPORT_SYMBOL_NS_GPL(peci_xfer_get_temp, PECI);
+
+static struct peci_request *
+__pkg_cfg_read(struct peci_device *device, u8 index, u16 param, u8 len)
+{
+       struct peci_request *req;
+       int ret;
+
+       req = peci_request_alloc(device, PECI_RDPKGCFG_WR_LEN, PECI_RDPKGCFG_RD_LEN_BASE + len);
+       if (!req)
+               return ERR_PTR(-ENOMEM);
+
+       req->tx.buf[0] = PECI_RDPKGCFG_CMD;
+       req->tx.buf[1] = 0;
+       req->tx.buf[2] = index;
+       put_unaligned_le16(param, &req->tx.buf[3]);
+
+       ret = peci_request_xfer_retry(req);
+       if (ret) {
+               peci_request_free(req);
+               return ERR_PTR(ret);
+       }
+
+       return req;
+}
+
+static u32 __get_pci_addr(u8 bus, u8 dev, u8 func, u16 reg)
+{
+       return reg | PCI_DEVID(bus, PCI_DEVFN(dev, func)) << 12;
+}
+
+static struct peci_request *
+__pci_cfg_local_read(struct peci_device *device, u8 bus, u8 dev, u8 func, u16 reg, u8 len)
+{
+       struct peci_request *req;
+       u32 pci_addr;
+       int ret;
+
+       req = peci_request_alloc(device, PECI_RDPCICFGLOCAL_WR_LEN,
+                                PECI_RDPCICFGLOCAL_RD_LEN_BASE + len);
+       if (!req)
+               return ERR_PTR(-ENOMEM);
+
+       pci_addr = __get_pci_addr(bus, dev, func, reg);
+
+       req->tx.buf[0] = PECI_RDPCICFGLOCAL_CMD;
+       req->tx.buf[1] = 0;
+       put_unaligned_le24(pci_addr, &req->tx.buf[2]);
+
+       ret = peci_request_xfer_retry(req);
+       if (ret) {
+               peci_request_free(req);
+               return ERR_PTR(ret);
+       }
+
+       return req;
+}
+
+static struct peci_request *
+__ep_pci_cfg_read(struct peci_device *device, u8 msg_type, u8 seg,
+                 u8 bus, u8 dev, u8 func, u16 reg, u8 len)
+{
+       struct peci_request *req;
+       u32 pci_addr;
+       int ret;
+
+       req = peci_request_alloc(device, PECI_RDENDPTCFG_PCI_WR_LEN,
+                                PECI_RDENDPTCFG_RD_LEN_BASE + len);
+       if (!req)
+               return ERR_PTR(-ENOMEM);
+
+       pci_addr = __get_pci_addr(bus, dev, func, reg);
+
+       req->tx.buf[0] = PECI_RDENDPTCFG_CMD;
+       req->tx.buf[1] = 0;
+       req->tx.buf[2] = msg_type;
+       req->tx.buf[3] = 0;
+       req->tx.buf[4] = 0;
+       req->tx.buf[5] = 0;
+       req->tx.buf[6] = PECI_ENDPTCFG_ADDR_TYPE_PCI;
+       req->tx.buf[7] = seg; /* PCI Segment */
+       put_unaligned_le32(pci_addr, &req->tx.buf[8]);
+
+       ret = peci_request_xfer_retry(req);
+       if (ret) {
+               peci_request_free(req);
+               return ERR_PTR(ret);
+       }
+
+       return req;
+}
+
+static struct peci_request *
+__ep_mmio_read(struct peci_device *device, u8 bar, u8 addr_type, u8 seg,
+              u8 bus, u8 dev, u8 func, u64 offset, u8 tx_len, u8 len)
+{
+       struct peci_request *req;
+       int ret;
+
+       req = peci_request_alloc(device, tx_len, PECI_RDENDPTCFG_RD_LEN_BASE + len);
+       if (!req)
+               return ERR_PTR(-ENOMEM);
+
+       req->tx.buf[0] = PECI_RDENDPTCFG_CMD;
+       req->tx.buf[1] = 0;
+       req->tx.buf[2] = PECI_ENDPTCFG_TYPE_MMIO;
+       req->tx.buf[3] = 0; /* Endpoint ID */
+       req->tx.buf[4] = 0; /* Reserved */
+       req->tx.buf[5] = bar;
+       req->tx.buf[6] = addr_type;
+       req->tx.buf[7] = seg; /* PCI Segment */
+       req->tx.buf[8] = PCI_DEVFN(dev, func);
+       req->tx.buf[9] = bus; /* PCI Bus */
+
+       if (addr_type == PECI_ENDPTCFG_ADDR_TYPE_MMIO_D)
+               put_unaligned_le32(offset, &req->tx.buf[10]);
+       else
+               put_unaligned_le64(offset, &req->tx.buf[10]);
+
+       ret = peci_request_xfer_retry(req);
+       if (ret) {
+               peci_request_free(req);
+               return ERR_PTR(ret);
+       }
+
+       return req;
+}
+
+u8 peci_request_data_readb(struct peci_request *req)
+{
+       return req->rx.buf[1];
+}
+EXPORT_SYMBOL_NS_GPL(peci_request_data_readb, PECI);
+
+u16 peci_request_data_readw(struct peci_request *req)
+{
+       return get_unaligned_le16(&req->rx.buf[1]);
+}
+EXPORT_SYMBOL_NS_GPL(peci_request_data_readw, PECI);
+
+u32 peci_request_data_readl(struct peci_request *req)
+{
+       return get_unaligned_le32(&req->rx.buf[1]);
+}
+EXPORT_SYMBOL_NS_GPL(peci_request_data_readl, PECI);
+
+u64 peci_request_data_readq(struct peci_request *req)
+{
+       return get_unaligned_le64(&req->rx.buf[1]);
+}
+EXPORT_SYMBOL_NS_GPL(peci_request_data_readq, PECI);
+
+u64 peci_request_dib_read(struct peci_request *req)
+{
+       return get_unaligned_le64(&req->rx.buf[0]);
+}
+EXPORT_SYMBOL_NS_GPL(peci_request_dib_read, PECI);
+
+s16 peci_request_temp_read(struct peci_request *req)
+{
+       return get_unaligned_le16(&req->rx.buf[0]);
+}
+EXPORT_SYMBOL_NS_GPL(peci_request_temp_read, PECI);
+
+#define __read_pkg_config(x, type) \
+struct peci_request *peci_xfer_pkg_cfg_##x(struct peci_device *device, u8 index, u16 param) \
+{ \
+       return __pkg_cfg_read(device, index, param, sizeof(type)); \
+} \
+EXPORT_SYMBOL_NS_GPL(peci_xfer_pkg_cfg_##x, PECI)
+
+__read_pkg_config(readb, u8);
+__read_pkg_config(readw, u16);
+__read_pkg_config(readl, u32);
+__read_pkg_config(readq, u64);
+
+#define __read_pci_config_local(x, type) \
+struct peci_request * \
+peci_xfer_pci_cfg_local_##x(struct peci_device *device, u8 bus, u8 dev, u8 func, u16 reg) \
+{ \
+       return __pci_cfg_local_read(device, bus, dev, func, reg, sizeof(type)); \
+} \
+EXPORT_SYMBOL_NS_GPL(peci_xfer_pci_cfg_local_##x, PECI)
+
+__read_pci_config_local(readb, u8);
+__read_pci_config_local(readw, u16);
+__read_pci_config_local(readl, u32);
+
+#define __read_ep_pci_config(x, msg_type, type) \
+struct peci_request * \
+peci_xfer_ep_pci_cfg_##x(struct peci_device *device, u8 seg, u8 bus, u8 dev, u8 func, u16 reg) \
+{ \
+       return __ep_pci_cfg_read(device, msg_type, seg, bus, dev, func, reg, sizeof(type)); \
+} \
+EXPORT_SYMBOL_NS_GPL(peci_xfer_ep_pci_cfg_##x, PECI)
+
+__read_ep_pci_config(local_readb, PECI_ENDPTCFG_TYPE_LOCAL_PCI, u8);
+__read_ep_pci_config(local_readw, PECI_ENDPTCFG_TYPE_LOCAL_PCI, u16);
+__read_ep_pci_config(local_readl, PECI_ENDPTCFG_TYPE_LOCAL_PCI, u32);
+__read_ep_pci_config(readb, PECI_ENDPTCFG_TYPE_PCI, u8);
+__read_ep_pci_config(readw, PECI_ENDPTCFG_TYPE_PCI, u16);
+__read_ep_pci_config(readl, PECI_ENDPTCFG_TYPE_PCI, u32);
+
+#define __read_ep_mmio(x, y, addr_type, type1, type2) \
+struct peci_request *peci_xfer_ep_mmio##y##_##x(struct peci_device *device, u8 bar, u8 seg, \
+                                          u8 bus, u8 dev, u8 func, u64 offset) \
+{ \
+       return __ep_mmio_read(device, bar, addr_type, seg, bus, dev, func, \
+                             offset, PECI_RDENDPTCFG_MMIO_WR_LEN_BASE + sizeof(type1), \
+                             sizeof(type2)); \
+} \
+EXPORT_SYMBOL_NS_GPL(peci_xfer_ep_mmio##y##_##x, PECI)
+
+__read_ep_mmio(readl, 32, PECI_ENDPTCFG_ADDR_TYPE_MMIO_D, u32, u32);
+__read_ep_mmio(readl, 64, PECI_ENDPTCFG_ADDR_TYPE_MMIO_Q, u64, u32);
diff --git a/drivers/peci/sysfs.c b/drivers/peci/sysfs.c
new file mode 100644 (file)
index 0000000..db9ef05
--- /dev/null
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2021 Intel Corporation
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/peci.h>
+
+#include "internal.h"
+
+static int rescan_controller(struct device *dev, void *data)
+{
+       if (dev->type != &peci_controller_type)
+               return 0;
+
+       return peci_controller_scan_devices(to_peci_controller(dev));
+}
+
+static ssize_t rescan_store(struct bus_type *bus, const char *buf, size_t count)
+{
+       bool res;
+       int ret;
+
+       ret = kstrtobool(buf, &res);
+       if (ret)
+               return ret;
+
+       if (!res)
+               return count;
+
+       ret = bus_for_each_dev(&peci_bus_type, NULL, NULL, rescan_controller);
+       if (ret)
+               return ret;
+
+       return count;
+}
+static BUS_ATTR_WO(rescan);
+
+static struct attribute *peci_bus_attrs[] = {
+       &bus_attr_rescan.attr,
+       NULL
+};
+
+static const struct attribute_group peci_bus_group = {
+       .attrs = peci_bus_attrs,
+};
+
+const struct attribute_group *peci_bus_groups[] = {
+       &peci_bus_group,
+       NULL
+};
+
+static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       struct peci_device *device = to_peci_device(dev);
+       bool res;
+       int ret;
+
+       ret = kstrtobool(buf, &res);
+       if (ret)
+               return ret;
+
+       if (res && device_remove_file_self(dev, attr))
+               peci_device_destroy(device);
+
+       return count;
+}
+static DEVICE_ATTR_IGNORE_LOCKDEP(remove, 0200, NULL, remove_store);
+
+static struct attribute *peci_device_attrs[] = {
+       &dev_attr_remove.attr,
+       NULL
+};
+
+static const struct attribute_group peci_device_group = {
+       .attrs = peci_device_attrs,
+};
+
+const struct attribute_group *peci_device_groups[] = {
+       &peci_device_group,
+       NULL
+};
index 08c364d..f64d29f 100644 (file)
@@ -42,9 +42,9 @@ obj-$(CONFIG_PINCTRL_PISTACHIO)       += pinctrl-pistachio.o
 obj-$(CONFIG_PINCTRL_RK805)    += pinctrl-rk805.o
 obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
 obj-$(CONFIG_PINCTRL_SINGLE)   += pinctrl-single.o
+obj-$(CONFIG_PINCTRL_ST)       += pinctrl-st.o
 obj-$(CONFIG_PINCTRL_STARFIVE) += pinctrl-starfive.o
 obj-$(CONFIG_PINCTRL_STMFX)    += pinctrl-stmfx.o
-obj-$(CONFIG_PINCTRL_ST)       += pinctrl-st.o
 obj-$(CONFIG_PINCTRL_SX150X)   += pinctrl-sx150x.o
 obj-$(CONFIG_PINCTRL_TB10X)    += pinctrl-tb10x.o
 obj-$(CONFIG_PINCTRL_THUNDERBAY) += pinctrl-thunderbay.o
index 5123f4c..ac1e400 100644 (file)
@@ -35,6 +35,7 @@ config PINCTRL_BCM63XX
        select PINCONF
        select GENERIC_PINCONF
        select GPIOLIB
+       select REGMAP
        select GPIO_REGMAP
 
 config PINCTRL_BCM6318
index c4ebfa8..47e433e 100644 (file)
@@ -1269,16 +1269,18 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
                                     sizeof(*girq->parents),
                                     GFP_KERNEL);
        if (!girq->parents) {
-               pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto out_remove;
        }
 
        if (is_7211) {
                pc->wake_irq = devm_kcalloc(dev, BCM2835_NUM_IRQS,
                                            sizeof(*pc->wake_irq),
                                            GFP_KERNEL);
-               if (!pc->wake_irq)
-                       return -ENOMEM;
+               if (!pc->wake_irq) {
+                       err = -ENOMEM;
+                       goto out_remove;
+               }
        }
 
        /*
@@ -1306,8 +1308,10 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
 
                len = strlen(dev_name(pc->dev)) + 16;
                name = devm_kzalloc(pc->dev, len, GFP_KERNEL);
-               if (!name)
-                       return -ENOMEM;
+               if (!name) {
+                       err = -ENOMEM;
+                       goto out_remove;
+               }
 
                snprintf(name, len, "%s:bank%d", dev_name(pc->dev), i);
 
@@ -1326,11 +1330,14 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
        err = gpiochip_add_data(&pc->gpio_chip, pc);
        if (err) {
                dev_err(dev, "could not add GPIO chip\n");
-               pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
-               return err;
+               goto out_remove;
        }
 
        return 0;
+
+out_remove:
+       pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
+       return err;
 }
 
 static struct platform_driver bcm2835_pinctrl_driver = {
index abffda1..1d58182 100644 (file)
@@ -1471,8 +1471,9 @@ static void chv_gpio_irq_handler(struct irq_desc *desc)
 
                offset = cctx->intr_lines[intr_line];
                if (offset == CHV_INVALID_HWIRQ) {
-                       dev_err(dev, "interrupt on unused interrupt line %u\n", intr_line);
-                       continue;
+                       dev_warn_once(dev, "interrupt on unmapped interrupt line %u\n", intr_line);
+                       /* Some boards expect hwirq 0 to trigger in this case */
+                       offset = 0;
                }
 
                generic_handle_domain_irq(gc->irq.domain, offset);
index 8575097..826d494 100644 (file)
@@ -451,8 +451,8 @@ static void intel_gpio_set_gpio_mode(void __iomem *padcfg0)
        value &= ~PADCFG0_PMODE_MASK;
        value |= PADCFG0_PMODE_GPIO;
 
-       /* Disable input and output buffers */
-       value |= PADCFG0_GPIORXDIS;
+       /* Disable TX buffer and enable RX (this will be input) */
+       value &= ~PADCFG0_GPIORXDIS;
        value |= PADCFG0_GPIOTXDIS;
 
        /* Disable SCI/SMI/NMI generation */
@@ -497,9 +497,6 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
 
        intel_gpio_set_gpio_mode(padcfg0);
 
-       /* Disable TX buffer and enable RX (this will be input) */
-       __intel_gpio_set_direction(padcfg0, true);
-
        raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        return 0;
@@ -1115,9 +1112,6 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned int type)
 
        intel_gpio_set_gpio_mode(reg);
 
-       /* Disable TX buffer and enable RX (this will be input) */
-       __intel_gpio_set_direction(reg, true);
-
        value = readl(reg);
 
        value &= ~(PADCFG0_RXEVCFG_MASK | PADCFG0_RXINV);
@@ -1216,6 +1210,39 @@ static irqreturn_t intel_gpio_irq(int irq, void *data)
        return IRQ_RETVAL(ret);
 }
 
+static void intel_gpio_irq_init(struct intel_pinctrl *pctrl)
+{
+       int i;
+
+       for (i = 0; i < pctrl->ncommunities; i++) {
+               const struct intel_community *community;
+               void __iomem *base;
+               unsigned int gpp;
+
+               community = &pctrl->communities[i];
+               base = community->regs;
+
+               for (gpp = 0; gpp < community->ngpps; gpp++) {
+                       /* Mask and clear all interrupts */
+                       writel(0, base + community->ie_offset + gpp * 4);
+                       writel(0xffff, base + community->is_offset + gpp * 4);
+               }
+       }
+}
+
+static int intel_gpio_irq_init_hw(struct gpio_chip *gc)
+{
+       struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
+
+       /*
+        * Make sure the interrupt lines are in a proper state before
+        * further configuration.
+        */
+       intel_gpio_irq_init(pctrl);
+
+       return 0;
+}
+
 static int intel_gpio_add_community_ranges(struct intel_pinctrl *pctrl,
                                const struct intel_community *community)
 {
@@ -1320,6 +1347,7 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq)
        girq->num_parents = 0;
        girq->default_type = IRQ_TYPE_NONE;
        girq->handler = handle_bad_irq;
+       girq->init_hw = intel_gpio_irq_init_hw;
 
        ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl);
        if (ret) {
@@ -1695,26 +1723,6 @@ int intel_pinctrl_suspend_noirq(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(intel_pinctrl_suspend_noirq);
 
-static void intel_gpio_irq_init(struct intel_pinctrl *pctrl)
-{
-       size_t i;
-
-       for (i = 0; i < pctrl->ncommunities; i++) {
-               const struct intel_community *community;
-               void __iomem *base;
-               unsigned int gpp;
-
-               community = &pctrl->communities[i];
-               base = community->regs;
-
-               for (gpp = 0; gpp < community->ngpps; gpp++) {
-                       /* Mask and clear all interrupts */
-                       writel(0, base + community->ie_offset + gpp * 4);
-                       writel(0xffff, base + community->is_offset + gpp * 4);
-               }
-       }
-}
-
 static bool intel_gpio_update_reg(void __iomem *reg, u32 mask, u32 value)
 {
        u32 curr, updated;
index 0bcd195..3ddaeff 100644 (file)
@@ -749,7 +749,6 @@ static const struct acpi_device_id tgl_pinctrl_acpi_match[] = {
        { "INT34C5", (kernel_ulong_t)&tgllp_soc_data },
        { "INT34C6", (kernel_ulong_t)&tglh_soc_data },
        { "INTC1055", (kernel_ulong_t)&tgllp_soc_data },
-       { "INTC1057", (kernel_ulong_t)&tgllp_soc_data },
        { }
 };
 MODULE_DEVICE_TABLE(acpi, tgl_pinctrl_acpi_match);
index 49e3268..ecab6bf 100644 (file)
@@ -482,7 +482,7 @@ static int k210_pinconf_get_drive(unsigned int max_strength_ua)
 {
        int i;
 
-       for (i = K210_PC_DRIVE_MAX; i; i--) {
+       for (i = K210_PC_DRIVE_MAX; i >= 0; i--) {
                if (k210_pinconf_drive_strength[i] <= max_strength_ua)
                        return i;
        }
@@ -527,7 +527,7 @@ static int k210_pinconf_set_param(struct pinctrl_dev *pctldev,
        case PIN_CONFIG_BIAS_PULL_UP:
                if (!arg)
                        return -EINVAL;
-               val |= K210_PC_PD;
+               val |= K210_PC_PU;
                break;
        case PIN_CONFIG_DRIVE_STRENGTH:
                arg *= 1000;
index 8e081c9..639f113 100644 (file)
@@ -137,7 +137,8 @@ static inline int sgpio_addr_to_pin(struct sgpio_priv *priv, int port, int bit)
 
 static inline u32 sgpio_get_addr(struct sgpio_priv *priv, u32 rno, u32 off)
 {
-       return priv->properties->regoff[rno] + off;
+       return (priv->properties->regoff[rno] + off) *
+               regmap_get_reg_stride(priv->regs);
 }
 
 static u32 sgpio_readl(struct sgpio_priv *priv, u32 rno, u32 off)
index 0b91215..266da41 100644 (file)
@@ -1164,6 +1164,7 @@ static int starfive_irq_set_type(struct irq_data *d, unsigned int trigger)
 }
 
 static struct irq_chip starfive_irq_chip = {
+       .name = "StarFive GPIO",
        .irq_ack = starfive_irq_ack,
        .irq_mask = starfive_irq_mask,
        .irq_mask_ack = starfive_irq_mask_ack,
@@ -1308,7 +1309,6 @@ static int starfive_probe(struct platform_device *pdev)
        sfp->gc.ngpio = NR_GPIOS;
 
        starfive_irq_chip.parent_device = dev;
-       starfive_irq_chip.name = sfp->gc.label;
 
        sfp->gc.irq.chip = &starfive_irq_chip;
        sfp->gc.irq.parent_handler = starfive_gpio_irq_handler;
index b5b47f4..79d44bc 100644 (file)
@@ -773,63 +773,42 @@ static int thunderbay_build_groups(struct thunderbay_pinctrl *tpc)
 
 static int thunderbay_add_functions(struct thunderbay_pinctrl *tpc, struct function_desc *funcs)
 {
-       struct function_desc *function = funcs;
        int i;
 
        /* Assign the groups for each function */
-       for (i = 0; i < tpc->soc->npins; i++) {
-               const struct pinctrl_pin_desc *pin_info = thunderbay_pins + i;
-               struct thunderbay_mux_desc *pin_mux = pin_info->drv_data;
-
-               while (pin_mux->name) {
-                       const char **grp;
-                       int j, grp_num, match = 0;
-                       size_t grp_size;
-                       struct function_desc *func;
-
-                       for (j = 0; j < tpc->nfuncs; j++) {
-                               if (!strcmp(pin_mux->name, function[j].name)) {
-                                       match = 1;
-                                       break;
-                               }
-                       }
-
-                       if (!match)
-                               return -EINVAL;
-
-                       func = function + j;
-                       grp_num = func->num_group_names;
-                       grp_size = sizeof(*func->group_names);
-
-                       if (!func->group_names) {
-                               func->group_names = devm_kcalloc(tpc->dev,
-                                                                grp_num,
-                                                                grp_size,
-                                                                GFP_KERNEL);
-                               if (!func->group_names) {
-                                       kfree(func);
-                                       return -ENOMEM;
-                               }
+       for (i = 0; i < tpc->nfuncs; i++) {
+               struct function_desc *func = &funcs[i];
+               const char **group_names;
+               unsigned int grp_idx = 0;
+               int j;
+
+               group_names = devm_kcalloc(tpc->dev, func->num_group_names,
+                                          sizeof(*group_names), GFP_KERNEL);
+               if (!group_names)
+                       return -ENOMEM;
+
+               for (j = 0; j < tpc->soc->npins; j++) {
+                       const struct pinctrl_pin_desc *pin_info = &thunderbay_pins[j];
+                       struct thunderbay_mux_desc *pin_mux;
+
+                       for (pin_mux = pin_info->drv_data; pin_mux->name; pin_mux++) {
+                               if (!strcmp(pin_mux->name, func->name))
+                                       group_names[grp_idx++] = pin_info->name;
                        }
-
-                       grp = func->group_names;
-                       while (*grp)
-                               grp++;
-
-                       *grp = pin_info->name;
-                       pin_mux++;
                }
+
+               func->group_names = group_names;
        }
 
        /* Add all functions */
        for (i = 0; i < tpc->nfuncs; i++) {
                pinmux_generic_add_function(tpc->pctrl,
-                                           function[i].name,
-                                           function[i].group_names,
-                                           function[i].num_group_names,
-                                           function[i].data);
+                                           funcs[i].name,
+                                           funcs[i].group_names,
+                                           funcs[i].num_group_names,
+                                           funcs[i].data);
        }
-       kfree(function);
+       kfree(funcs);
        return 0;
 }
 
@@ -839,27 +818,30 @@ static int thunderbay_build_functions(struct thunderbay_pinctrl *tpc)
        void *ptr;
        int pin;
 
-       /* Total number of functions is unknown at this point. Allocate first. */
+       /*
+        * Allocate maximum possible number of functions. Assume every pin
+        * being part of 8 (hw maximum) globally unique muxes.
+        */
        tpc->nfuncs = 0;
        thunderbay_funcs = kcalloc(tpc->soc->npins * 8,
                                   sizeof(*thunderbay_funcs), GFP_KERNEL);
        if (!thunderbay_funcs)
                return -ENOMEM;
 
-       /* Find total number of functions and each's properties */
+       /* Setup 1 function for each unique mux */
        for (pin = 0; pin < tpc->soc->npins; pin++) {
                const struct pinctrl_pin_desc *pin_info = thunderbay_pins + pin;
-               struct thunderbay_mux_desc *pin_mux = pin_info->drv_data;
+               struct thunderbay_mux_desc *pin_mux;
 
-               while (pin_mux->name) {
-                       struct function_desc *func = thunderbay_funcs;
+               for (pin_mux = pin_info->drv_data; pin_mux->name; pin_mux++) {
+                       struct function_desc *func;
 
-                       while (func->name) {
+                       /* Check if we already have function for this mux */
+                       for (func = thunderbay_funcs; func->name; func++) {
                                if (!strcmp(pin_mux->name, func->name)) {
                                        func->num_group_names++;
                                        break;
                                }
-                               func++;
                        }
 
                        if (!func->name) {
@@ -868,8 +850,6 @@ static int thunderbay_build_functions(struct thunderbay_pinctrl *tpc)
                                func->data = (int *)&pin_mux->mode;
                                tpc->nfuncs++;
                        }
-
-                       pin_mux++;
                }
        }
 
index 42da6bd..e140122 100644 (file)
@@ -809,7 +809,6 @@ static int zynqmp_pinctrl_prepare_pin_desc(struct device *dev,
                                           unsigned int *npins)
 {
        struct pinctrl_pin_desc *pins, *pin;
-       char **pin_names;
        int ret;
        int i;
 
@@ -821,14 +820,13 @@ static int zynqmp_pinctrl_prepare_pin_desc(struct device *dev,
        if (!pins)
                return -ENOMEM;
 
-       pin_names = devm_kasprintf_strarray(dev, ZYNQMP_PIN_PREFIX, *npins);
-       if (IS_ERR(pin_names))
-               return PTR_ERR(pin_names);
-
        for (i = 0; i < *npins; i++) {
                pin = &pins[i];
                pin->number = i;
-               pin->name = pin_names[i];
+               pin->name = devm_kasprintf(dev, GFP_KERNEL, "%s%d",
+                                          ZYNQMP_PIN_PREFIX, i);
+               if (!pin->name)
+                       return -ENOMEM;
        }
 
        *zynqmp_pins = pins;
index ce1917e..152b712 100644 (file)
@@ -363,16 +363,16 @@ static const struct sunxi_desc_pin h616_pins[] = {
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "uart2"),         /* CTS */
-                 SUNXI_FUNCTION(0x3, "i2s3"),  /* DO0 */
+                 SUNXI_FUNCTION(0x3, "i2s3_dout0"),    /* DO0 */
                  SUNXI_FUNCTION(0x4, "spi1"),          /* MISO */
-                 SUNXI_FUNCTION(0x5, "i2s3"),  /* DI1 */
+                 SUNXI_FUNCTION(0x5, "i2s3_din1"),     /* DI1 */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 6, 8)),  /* PH_EINT8 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 9),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x3, "i2s3"),  /* DI0 */
+                 SUNXI_FUNCTION(0x3, "i2s3_din0"),     /* DI0 */
                  SUNXI_FUNCTION(0x4, "spi1"),          /* CS1 */
-                 SUNXI_FUNCTION(0x3, "i2s3"),  /* DO1 */
+                 SUNXI_FUNCTION(0x5, "i2s3_dout1"),    /* DO1 */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 6, 9)),  /* PH_EINT9 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 10),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
index 5f0578e..463f1ec 100644 (file)
@@ -5,6 +5,7 @@
 
 menuconfig SURFACE_PLATFORMS
        bool "Microsoft Surface Platform-Specific Device Drivers"
+       depends on ARM64 || X86 || COMPILE_TEST
        default y
        help
          Say Y here to get to see options for platform-specific device drivers
index abac3ee..444ec81 100644 (file)
@@ -232,14 +232,21 @@ static int mshw0011_bix(struct mshw0011_data *cdata, struct bix *bix)
        }
        bix->last_full_charg_capacity = ret;
 
-       /* get serial number */
+       /*
+        * Get serial number, on some devices (with unofficial replacement
+        * battery?) reading any of the serial number range addresses gets
+        * nacked in this case just leave the serial number empty.
+        */
        ret = i2c_smbus_read_i2c_block_data(client, MSHW0011_BAT0_REG_SERIAL_NO,
                                            sizeof(buf), buf);
-       if (ret != sizeof(buf)) {
+       if (ret == -EREMOTEIO) {
+               /* no serial number available */
+       } else if (ret != sizeof(buf)) {
                dev_err(&client->dev, "Error reading serial no: %d\n", ret);
                return ret;
+       } else {
+               snprintf(bix->serial, ARRAY_SIZE(bix->serial), "%3pE%6pE", buf + 7, buf);
        }
-       snprintf(bix->serial, ARRAY_SIZE(bix->serial), "%3pE%6pE", buf + 7, buf);
 
        /* get cycle count */
        ret = i2c_smbus_read_word_data(client, MSHW0011_BAT0_REG_CYCLE_CNT);
index f794343..b1103f8 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
+#include <linux/pm_qos.h>
 #include <linux/rtc.h>
 #include <linux/suspend.h>
 #include <linux/seq_file.h>
@@ -85,6 +86,9 @@
 #define PMC_MSG_DELAY_MIN_US           50
 #define RESPONSE_REGISTER_LOOP_MAX     20000
 
+/* QoS request for letting CPUs in idle states, but not the deepest */
+#define AMD_PMC_MAX_IDLE_STATE_LATENCY 3
+
 #define SOC_SUBSYSTEM_IP_MAX   12
 #define DELAY_MIN_US           2000
 #define DELAY_MAX_US           3000
@@ -124,12 +128,14 @@ struct amd_pmc_dev {
        u32 cpu_id;
        u32 active_ips;
 /* SMU version information */
-       u16 major;
-       u16 minor;
-       u16 rev;
+       u8 smu_program;
+       u8 major;
+       u8 minor;
+       u8 rev;
        struct device *dev;
        struct pci_dev *rdev;
        struct mutex lock; /* generic mutex lock */
+       struct pm_qos_request amd_pmc_pm_qos_req;
 #if IS_ENABLED(CONFIG_DEBUG_FS)
        struct dentry *dbgfs_dir;
 #endif /* CONFIG_DEBUG_FS */
@@ -180,11 +186,13 @@ static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev)
        if (rc)
                return rc;
 
-       dev->major = (val >> 16) & GENMASK(15, 0);
+       dev->smu_program = (val >> 24) & GENMASK(7, 0);
+       dev->major = (val >> 16) & GENMASK(7, 0);
        dev->minor = (val >> 8) & GENMASK(7, 0);
        dev->rev = (val >> 0) & GENMASK(7, 0);
 
-       dev_dbg(dev->dev, "SMU version is %u.%u.%u\n", dev->major, dev->minor, dev->rev);
+       dev_dbg(dev->dev, "SMU program %u version is %u.%u.%u\n",
+               dev->smu_program, dev->major, dev->minor, dev->rev);
 
        return 0;
 }
@@ -226,7 +234,7 @@ static int amd_pmc_stb_debugfs_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
-const struct file_operations amd_pmc_stb_debugfs_fops = {
+static const struct file_operations amd_pmc_stb_debugfs_fops = {
        .owner = THIS_MODULE,
        .open = amd_pmc_stb_debugfs_open,
        .read = amd_pmc_stb_debugfs_read,
@@ -518,6 +526,14 @@ static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg)
        rc = rtc_alarm_irq_enable(rtc_device, 0);
        dev_dbg(pdev->dev, "wakeup timer programmed for %lld seconds\n", duration);
 
+       /*
+        * Prevent CPUs from getting into deep idle states while sending OS_HINT
+        * which is otherwise generally safe to send when at least one of the CPUs
+        * is not in deep idle states.
+        */
+       cpu_latency_qos_update_request(&pdev->amd_pmc_pm_qos_req, AMD_PMC_MAX_IDLE_STATE_LATENCY);
+       wake_up_all_idle_cpus();
+
        return rc;
 }
 
@@ -535,24 +551,31 @@ static int __maybe_unused amd_pmc_suspend(struct device *dev)
        /* Activate CZN specific RTC functionality */
        if (pdev->cpu_id == AMD_CPU_ID_CZN) {
                rc = amd_pmc_verify_czn_rtc(pdev, &arg);
-               if (rc < 0)
-                       return rc;
+               if (rc)
+                       goto fail;
        }
 
        /* Dump the IdleMask before we send hint to SMU */
        amd_pmc_idlemask_read(pdev, dev, NULL);
        msg = amd_pmc_get_os_hint(pdev);
        rc = amd_pmc_send_cmd(pdev, arg, NULL, msg, 0);
-       if (rc)
+       if (rc) {
                dev_err(pdev->dev, "suspend failed\n");
+               goto fail;
+       }
 
        if (enable_stb)
                rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_PREDEF);
-       if (rc) {
+       if (rc) {
                dev_err(pdev->dev, "error writing to STB\n");
-               return rc;
+               goto fail;
        }
 
+       return 0;
+fail:
+       if (pdev->cpu_id == AMD_CPU_ID_CZN)
+               cpu_latency_qos_update_request(&pdev->amd_pmc_pm_qos_req,
+                                               PM_QOS_DEFAULT_VALUE);
        return rc;
 }
 
@@ -576,12 +599,15 @@ static int __maybe_unused amd_pmc_resume(struct device *dev)
        /* Write data incremented by 1 to distinguish in stb_read */
        if (enable_stb)
                rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_PREDEF + 1);
-       if (rc) {
+       if (rc)
                dev_err(pdev->dev, "error writing to STB\n");
-               return rc;
-       }
 
-       return 0;
+       /* Restore the QoS request back to defaults if it was set */
+       if (pdev->cpu_id == AMD_CPU_ID_CZN)
+               cpu_latency_qos_update_request(&pdev->amd_pmc_pm_qos_req,
+                                               PM_QOS_DEFAULT_VALUE);
+
+       return rc;
 }
 
 static const struct dev_pm_ops amd_pmc_pm_ops = {
@@ -719,6 +745,7 @@ static int amd_pmc_probe(struct platform_device *pdev)
        amd_pmc_get_smu_version(dev);
        platform_set_drvdata(pdev, dev);
        amd_pmc_dbgfs_register(dev);
+       cpu_latency_qos_add_request(&dev->amd_pmc_pm_qos_req, PM_QOS_DEFAULT_VALUE);
        return 0;
 
 err_pci_dev_put:
index d4ef8f3..6fd0c9f 100644 (file)
@@ -250,7 +250,7 @@ static int tf103c_dock_hid_raw_request(struct hid_device *hid, u8 reportnum,
        return 0;
 }
 
-struct hid_ll_driver tf103c_dock_hid_ll_driver = {
+static struct hid_ll_driver tf103c_dock_hid_ll_driver = {
        .parse = tf103c_dock_hid_parse,
        .start = tf103c_dock_hid_start,
        .stop = tf103c_dock_hid_stop,
@@ -921,7 +921,7 @@ static int __maybe_unused tf103c_dock_resume(struct device *dev)
        return 0;
 }
 
-SIMPLE_DEV_PM_OPS(tf103c_dock_pm_ops, tf103c_dock_suspend, tf103c_dock_resume);
+static SIMPLE_DEV_PM_OPS(tf103c_dock_pm_ops, tf103c_dock_suspend, tf103c_dock_resume);
 
 static const struct acpi_device_id tf103c_dock_acpi_match[] = {
        {"NPCE69A"},
index a3b83b2..2104a26 100644 (file)
@@ -2223,7 +2223,7 @@ static int fan_curve_check_present(struct asus_wmi *asus, bool *available,
 
        err = fan_curve_get_factory_default(asus, fan_dev);
        if (err) {
-               if (err == -ENODEV)
+               if (err == -ENODEV || err == -ENODATA)
                        return 0;
                return err;
        }
index 0374bc7..e4299cf 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/regmap.h>
 
 #define CHGRIRQ_REG                                    0x0a
+#define MCHGRIRQ_REG                                   0x17
 
 struct crystal_cove_charger_data {
        struct mutex buslock; /* irq_bus_lock */
@@ -25,8 +26,8 @@ struct crystal_cove_charger_data {
        struct irq_domain *irq_domain;
        int irq;
        int charger_irq;
-       bool irq_enabled;
-       bool irq_is_enabled;
+       u8 mask;
+       u8 new_mask;
 };
 
 static irqreturn_t crystal_cove_charger_irq(int irq, void *data)
@@ -53,13 +54,9 @@ static void crystal_cove_charger_irq_bus_sync_unlock(struct irq_data *data)
 {
        struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);
 
-       if (charger->irq_is_enabled != charger->irq_enabled) {
-               if (charger->irq_enabled)
-                       enable_irq(charger->irq);
-               else
-                       disable_irq(charger->irq);
-
-               charger->irq_is_enabled = charger->irq_enabled;
+       if (charger->mask != charger->new_mask) {
+               regmap_write(charger->regmap, MCHGRIRQ_REG, charger->new_mask);
+               charger->mask = charger->new_mask;
        }
 
        mutex_unlock(&charger->buslock);
@@ -69,14 +66,14 @@ static void crystal_cove_charger_irq_unmask(struct irq_data *data)
 {
        struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);
 
-       charger->irq_enabled = true;
+       charger->new_mask &= ~BIT(data->hwirq);
 }
 
 static void crystal_cove_charger_irq_mask(struct irq_data *data)
 {
        struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);
 
-       charger->irq_enabled = false;
+       charger->new_mask |= BIT(data->hwirq);
 }
 
 static void crystal_cove_charger_rm_irq_domain(void *data)
@@ -130,10 +127,13 @@ static int crystal_cove_charger_probe(struct platform_device *pdev)
        irq_set_nested_thread(charger->charger_irq, true);
        irq_set_noprobe(charger->charger_irq);
 
+       /* Mask the single 2nd level IRQ before enabling the 1st level IRQ */
+       charger->mask = charger->new_mask = BIT(0);
+       regmap_write(charger->regmap, MCHGRIRQ_REG, charger->mask);
+
        ret = devm_request_threaded_irq(&pdev->dev, charger->irq, NULL,
                                        crystal_cove_charger_irq,
-                                       IRQF_ONESHOT | IRQF_NO_AUTOEN,
-                                       KBUILD_MODNAME, charger);
+                                       IRQF_ONESHOT, KBUILD_MODNAME, charger);
        if (ret)
                return dev_err_probe(&pdev->dev, ret, "requesting irq\n");
 
index f93d437..525f09a 100644 (file)
@@ -100,7 +100,8 @@ static struct gpiod_lookup_table surface_go_tps68470_gpios = {
        .dev_id = "i2c-INT347A:00",
        .table = {
                GPIO_LOOKUP("tps68470-gpio", 9, "reset", GPIO_ACTIVE_LOW),
-               GPIO_LOOKUP("tps68470-gpio", 7, "powerdown", GPIO_ACTIVE_LOW)
+               GPIO_LOOKUP("tps68470-gpio", 7, "powerdown", GPIO_ACTIVE_LOW),
+               { }
        }
 };
 
index c9a85eb..e8424e7 100644 (file)
@@ -596,7 +596,10 @@ static long isst_if_def_ioctl(struct file *file, unsigned int cmd,
        return ret;
 }
 
-static DEFINE_MUTEX(punit_misc_dev_lock);
+/* Lock to prevent module registration when already opened by user space */
+static DEFINE_MUTEX(punit_misc_dev_open_lock);
+/* Lock to allow one share misc device for all ISST interace */
+static DEFINE_MUTEX(punit_misc_dev_reg_lock);
 static int misc_usage_count;
 static int misc_device_ret;
 static int misc_device_open;
@@ -606,7 +609,7 @@ static int isst_if_open(struct inode *inode, struct file *file)
        int i, ret = 0;
 
        /* Fail open, if a module is going away */
-       mutex_lock(&punit_misc_dev_lock);
+       mutex_lock(&punit_misc_dev_open_lock);
        for (i = 0; i < ISST_IF_DEV_MAX; ++i) {
                struct isst_if_cmd_cb *cb = &punit_callbacks[i];
 
@@ -628,7 +631,7 @@ static int isst_if_open(struct inode *inode, struct file *file)
        } else {
                misc_device_open++;
        }
-       mutex_unlock(&punit_misc_dev_lock);
+       mutex_unlock(&punit_misc_dev_open_lock);
 
        return ret;
 }
@@ -637,7 +640,7 @@ static int isst_if_relase(struct inode *inode, struct file *f)
 {
        int i;
 
-       mutex_lock(&punit_misc_dev_lock);
+       mutex_lock(&punit_misc_dev_open_lock);
        misc_device_open--;
        for (i = 0; i < ISST_IF_DEV_MAX; ++i) {
                struct isst_if_cmd_cb *cb = &punit_callbacks[i];
@@ -645,7 +648,7 @@ static int isst_if_relase(struct inode *inode, struct file *f)
                if (cb->registered)
                        module_put(cb->owner);
        }
-       mutex_unlock(&punit_misc_dev_lock);
+       mutex_unlock(&punit_misc_dev_open_lock);
 
        return 0;
 }
@@ -662,6 +665,43 @@ static struct miscdevice isst_if_char_driver = {
        .fops           = &isst_if_char_driver_ops,
 };
 
+static int isst_misc_reg(void)
+{
+       mutex_lock(&punit_misc_dev_reg_lock);
+       if (misc_device_ret)
+               goto unlock_exit;
+
+       if (!misc_usage_count) {
+               misc_device_ret = isst_if_cpu_info_init();
+               if (misc_device_ret)
+                       goto unlock_exit;
+
+               misc_device_ret = misc_register(&isst_if_char_driver);
+               if (misc_device_ret) {
+                       isst_if_cpu_info_exit();
+                       goto unlock_exit;
+               }
+       }
+       misc_usage_count++;
+
+unlock_exit:
+       mutex_unlock(&punit_misc_dev_reg_lock);
+
+       return misc_device_ret;
+}
+
+static void isst_misc_unreg(void)
+{
+       mutex_lock(&punit_misc_dev_reg_lock);
+       if (misc_usage_count)
+               misc_usage_count--;
+       if (!misc_usage_count && !misc_device_ret) {
+               misc_deregister(&isst_if_char_driver);
+               isst_if_cpu_info_exit();
+       }
+       mutex_unlock(&punit_misc_dev_reg_lock);
+}
+
 /**
  * isst_if_cdev_register() - Register callback for IOCTL
  * @device_type: The device type this callback handling.
@@ -679,38 +719,31 @@ static struct miscdevice isst_if_char_driver = {
  */
 int isst_if_cdev_register(int device_type, struct isst_if_cmd_cb *cb)
 {
-       if (misc_device_ret)
-               return misc_device_ret;
+       int ret;
 
        if (device_type >= ISST_IF_DEV_MAX)
                return -EINVAL;
 
-       mutex_lock(&punit_misc_dev_lock);
+       mutex_lock(&punit_misc_dev_open_lock);
+       /* Device is already open, we don't want to add new callbacks */
        if (misc_device_open) {
-               mutex_unlock(&punit_misc_dev_lock);
+               mutex_unlock(&punit_misc_dev_open_lock);
                return -EAGAIN;
        }
-       if (!misc_usage_count) {
-               int ret;
-
-               misc_device_ret = misc_register(&isst_if_char_driver);
-               if (misc_device_ret)
-                       goto unlock_exit;
-
-               ret = isst_if_cpu_info_init();
-               if (ret) {
-                       misc_deregister(&isst_if_char_driver);
-                       misc_device_ret = ret;
-                       goto unlock_exit;
-               }
-       }
        memcpy(&punit_callbacks[device_type], cb, sizeof(*cb));
        punit_callbacks[device_type].registered = 1;
-       misc_usage_count++;
-unlock_exit:
-       mutex_unlock(&punit_misc_dev_lock);
+       mutex_unlock(&punit_misc_dev_open_lock);
 
-       return misc_device_ret;
+       ret = isst_misc_reg();
+       if (ret) {
+               /*
+                * No need of mutex as the misc device register failed
+                * as no one can open device yet. Hence no contention.
+                */
+               punit_callbacks[device_type].registered = 0;
+               return ret;
+       }
+       return 0;
 }
 EXPORT_SYMBOL_GPL(isst_if_cdev_register);
 
@@ -725,16 +758,12 @@ EXPORT_SYMBOL_GPL(isst_if_cdev_register);
  */
 void isst_if_cdev_unregister(int device_type)
 {
-       mutex_lock(&punit_misc_dev_lock);
-       misc_usage_count--;
+       isst_misc_unreg();
+       mutex_lock(&punit_misc_dev_open_lock);
        punit_callbacks[device_type].registered = 0;
        if (device_type == ISST_IF_DEV_MBOX)
                isst_delete_hash();
-       if (!misc_usage_count && !misc_device_ret) {
-               misc_deregister(&isst_if_char_driver);
-               isst_if_cpu_info_exit();
-       }
-       mutex_unlock(&punit_misc_dev_lock);
+       mutex_unlock(&punit_misc_dev_open_lock);
 }
 EXPORT_SYMBOL_GPL(isst_if_cdev_unregister);
 
index 098180f..3424b08 100644 (file)
@@ -8679,9 +8679,10 @@ static const struct attribute_group fan_driver_attr_group = {
        .attrs = fan_driver_attributes,
 };
 
-#define TPACPI_FAN_Q1  0x0001          /* Unitialized HFSP */
-#define TPACPI_FAN_2FAN        0x0002          /* EC 0x31 bit 0 selects fan2 */
-#define TPACPI_FAN_2CTL        0x0004          /* selects fan2 control */
+#define TPACPI_FAN_Q1          0x0001          /* Uninitialized HFSP */
+#define TPACPI_FAN_2FAN                0x0002          /* EC 0x31 bit 0 selects fan2 */
+#define TPACPI_FAN_2CTL                0x0004          /* selects fan2 control */
+#define TPACPI_FAN_NOFAN       0x0008          /* no fan available */
 
 static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
        TPACPI_QEC_IBM('1', 'Y', TPACPI_FAN_Q1),
@@ -8702,6 +8703,8 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
        TPACPI_Q_LNV3('N', '4', '0', TPACPI_FAN_2CTL),  /* P1 / X1 Extreme (4nd gen) */
        TPACPI_Q_LNV3('N', '3', '0', TPACPI_FAN_2CTL),  /* P15 (1st gen) / P15v (1st gen) */
        TPACPI_Q_LNV3('N', '3', '2', TPACPI_FAN_2CTL),  /* X1 Carbon (9th gen) */
+       TPACPI_Q_LNV3('N', '3', '7', TPACPI_FAN_2CTL),  /* T15g (2nd gen) */
+       TPACPI_Q_LNV3('N', '1', 'O', TPACPI_FAN_NOFAN), /* X1 Tablet (2nd gen) */
 };
 
 static int __init fan_init(struct ibm_init_struct *iibm)
@@ -8730,6 +8733,11 @@ static int __init fan_init(struct ibm_init_struct *iibm)
        quirks = tpacpi_check_quirks(fan_quirk_table,
                                     ARRAY_SIZE(fan_quirk_table));
 
+       if (quirks & TPACPI_FAN_NOFAN) {
+               pr_info("No integrated ThinkPad fan available\n");
+               return -ENODEV;
+       }
+
        if (gfan_handle) {
                /* 570, 600e/x, 770e, 770x */
                fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
@@ -10112,6 +10120,9 @@ static struct ibm_struct proxsensor_driver_data = {
 #define DYTC_CMD_MMC_GET      8 /* To get current MMC function and mode */
 #define DYTC_CMD_RESET    0x1ff /* To reset back to default */
 
+#define DYTC_CMD_FUNC_CAP     3 /* To get DYTC capabilities */
+#define DYTC_FC_MMC           27 /* MMC Mode supported */
+
 #define DYTC_GET_FUNCTION_BIT 8  /* Bits  8-11 - function setting */
 #define DYTC_GET_MODE_BIT     12 /* Bits 12-15 - mode setting */
 
@@ -10324,6 +10335,15 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
        if (dytc_version < 5)
                return -ENODEV;
 
+       /* Check what capabilities are supported. Currently MMC is needed */
+       err = dytc_command(DYTC_CMD_FUNC_CAP, &output);
+       if (err)
+               return err;
+       if (!(output & BIT(DYTC_FC_MMC))) {
+               dbg_printk(TPACPI_DBG_INIT, " DYTC MMC mode not supported\n");
+               return -ENODEV;
+       }
+
        dbg_printk(TPACPI_DBG_INIT,
                        "DYTC version %d: thermal mode available\n", dytc_version);
        /*
index 494f230..bc97bfa 100644 (file)
@@ -770,6 +770,21 @@ static const struct ts_dmi_data predia_basic_data = {
        .properties     = predia_basic_props,
 };
 
+static const struct property_entry rwc_nanote_p8_props[] = {
+       PROPERTY_ENTRY_U32("touchscreen-min-y", 46),
+       PROPERTY_ENTRY_U32("touchscreen-size-x", 1728),
+       PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
+       PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+       PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-rwc-nanote-p8.fw"),
+       PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+       { }
+};
+
+static const struct ts_dmi_data rwc_nanote_p8_data = {
+       .acpi_name = "MSSL1680:00",
+       .properties = rwc_nanote_p8_props,
+};
+
 static const struct property_entry schneider_sct101ctm_props[] = {
        PROPERTY_ENTRY_U32("touchscreen-size-x", 1715),
        PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
@@ -1394,6 +1409,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
                        DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"),
                },
        },
+       {
+               /* RWC NANOTE P8 */
+               .driver_data = (void *)&rwc_nanote_p8_data,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Default string"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "AY07J"),
+                       DMI_MATCH(DMI_PRODUCT_SKU, "0001")
+               },
+       },
        {
                /* Schneider SCT101CTM */
                .driver_data = (void *)&schneider_sct101ctm_data,
index 3ba63ad..9360a8a 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/string.h>
 /* For gpio_get_desc() which is EXPORT_SYMBOL_GPL() */
 #include "../../gpio/gpiolib.h"
+#include "../../gpio/gpiolib-acpi.h"
 
 /*
  * Helper code to get Linux IRQ numbers given a description of the IRQ source
@@ -47,7 +48,7 @@ struct x86_acpi_irq_data {
        int polarity; /* ACPI_ACTIVE_HIGH / ACPI_ACTIVE_LOW / ACPI_ACTIVE_BOTH */
 };
 
-static int x86_acpi_irq_helper_gpiochip_find(struct gpio_chip *gc, void *data)
+static int gpiochip_find_match_label(struct gpio_chip *gc, void *data)
 {
        return gc->label && !strcmp(gc->label, data);
 }
@@ -73,7 +74,7 @@ static int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data)
                return irq;
        case X86_ACPI_IRQ_TYPE_GPIOINT:
                /* Like acpi_dev_gpio_irq_get(), but without parsing ACPI resources */
-               chip = gpiochip_find(data->chip, x86_acpi_irq_helper_gpiochip_find);
+               chip = gpiochip_find(data->chip, gpiochip_find_match_label);
                if (!chip) {
                        pr_err("error cannot find GPIO chip %s\n", data->chip);
                        return -ENODEV;
@@ -143,14 +144,17 @@ struct x86_serdev_info {
 };
 
 struct x86_dev_info {
+       char *invalid_aei_gpiochip;
        const char * const *modules;
-       struct gpiod_lookup_table **gpiod_lookup_tables;
+       struct gpiod_lookup_table * const *gpiod_lookup_tables;
        const struct x86_i2c_client_info *i2c_client_info;
        const struct platform_device_info *pdev_info;
        const struct x86_serdev_info *serdev_info;
        int i2c_client_count;
        int pdev_count;
        int serdev_count;
+       int (*init)(void);
+       void (*exit)(void);
 };
 
 /* Generic / shared bq24190 settings */
@@ -187,8 +191,8 @@ static struct bq24190_platform_data bq24190_pdata = {
 };
 
 static const char * const bq24190_modules[] __initconst = {
-       "crystal_cove_charger", /* For the bq24190 IRQ */
-       "bq24190_charger",      /* For the Vbus regulator for intel-int3496 */
+       "intel_crystal_cove_charger", /* For the bq24190 IRQ */
+       "bq24190_charger",            /* For the Vbus regulator for intel-int3496 */
        NULL
 };
 
@@ -302,7 +306,7 @@ static struct gpiod_lookup_table asus_me176c_goodix_gpios = {
        },
 };
 
-static struct gpiod_lookup_table *asus_me176c_gpios[] = {
+static struct gpiod_lookup_table * const asus_me176c_gpios[] = {
        &int3496_gpo2_pin22_gpios,
        &asus_me176c_goodix_gpios,
        NULL
@@ -317,6 +321,7 @@ static const struct x86_dev_info asus_me176c_info __initconst = {
        .serdev_count = ARRAY_SIZE(asus_me176c_serdevs),
        .gpiod_lookup_tables = asus_me176c_gpios,
        .modules = bq24190_modules,
+       .invalid_aei_gpiochip = "INT33FC:02",
 };
 
 /* Asus TF103C tablets have an Android factory img with everything hardcoded */
@@ -405,7 +410,7 @@ static const struct x86_i2c_client_info asus_tf103c_i2c_clients[] __initconst =
        },
 };
 
-static struct gpiod_lookup_table *asus_tf103c_gpios[] = {
+static struct gpiod_lookup_table * const asus_tf103c_gpios[] = {
        &int3496_gpo2_pin22_gpios,
        NULL
 };
@@ -417,6 +422,7 @@ static const struct x86_dev_info asus_tf103c_info __initconst = {
        .pdev_count = ARRAY_SIZE(int3496_pdevs),
        .gpiod_lookup_tables = asus_tf103c_gpios,
        .modules = bq24190_modules,
+       .invalid_aei_gpiochip = "INT33FC:02",
 };
 
 /*
@@ -490,6 +496,39 @@ static const struct x86_dev_info chuwi_hi8_info __initconst = {
        .i2c_client_count = ARRAY_SIZE(chuwi_hi8_i2c_clients),
 };
 
+#define CZC_EC_EXTRA_PORT      0x68
+#define CZC_EC_ANDROID_KEYS    0x63
+
+static int __init czc_p10t_init(void)
+{
+       /*
+        * The device boots up in "Windows 7" mode, when the home button sends a
+        * Windows specific key sequence (Left Meta + D) and the second button
+        * sends an unknown one while also toggling the Radio Kill Switch.
+        * This is a surprising behavior when the second button is labeled "Back".
+        *
+        * The vendor-supplied Android-x86 build switches the device to a "Android"
+        * mode by writing value 0x63 to the I/O port 0x68. This just seems to just
+        * set bit 6 on address 0x96 in the EC region; switching the bit directly
+        * seems to achieve the same result. It uses a "p10t_switcher" to do the
+        * job. It doesn't seem to be able to do anything else, and no other use
+        * of the port 0x68 is known.
+        *
+        * In the Android mode, the home button sends just a single scancode,
+        * which can be handled in Linux userspace more reasonably and the back
+        * button only sends a scancode without toggling the kill switch.
+        * The scancode can then be mapped either to Back or RF Kill functionality
+        * in userspace, depending on how the button is labeled on that particular
+        * model.
+        */
+       outb(CZC_EC_ANDROID_KEYS, CZC_EC_EXTRA_PORT);
+       return 0;
+}
+
+static const struct x86_dev_info czc_p10t __initconst = {
+       .init = czc_p10t_init,
+};
+
 /*
  * Whitelabel (sold as various brands) TM800A550L tablets.
  * These tablet's DSDT contains a whole bunch of bogus ACPI I2C devices
@@ -559,7 +598,7 @@ static struct gpiod_lookup_table whitelabel_tm800a550l_goodix_gpios = {
        },
 };
 
-static struct gpiod_lookup_table *whitelabel_tm800a550l_gpios[] = {
+static struct gpiod_lookup_table * const whitelabel_tm800a550l_gpios[] = {
        &whitelabel_tm800a550l_goodix_gpios,
        NULL
 };
@@ -641,6 +680,24 @@ static const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
                },
                .driver_data = (void *)&chuwi_hi8_info,
        },
+       {
+               /* CZC P10T */
+               .ident = "CZC ODEON TPC-10 (\"P10T\")",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "CZC"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "ODEON*TPC-10"),
+               },
+               .driver_data = (void *)&czc_p10t,
+       },
+       {
+               /* A variant of CZC P10T */
+               .ident = "ViewSonic ViewPad 10",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ViewSonic"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "VPAD10"),
+               },
+               .driver_data = (void *)&czc_p10t,
+       },
        {
                /* Whitelabel (sold as various brands) TM800A550L */
                .matches = {
@@ -669,7 +726,8 @@ static int serdev_count;
 static struct i2c_client **i2c_clients;
 static struct platform_device **pdevs;
 static struct serdev_device **serdevs;
-static struct gpiod_lookup_table **gpiod_lookup_tables;
+static struct gpiod_lookup_table * const *gpiod_lookup_tables;
+static void (*exit_handler)(void);
 
 static __init int x86_instantiate_i2c_client(const struct x86_dev_info *dev_info,
                                             int idx)
@@ -787,6 +845,9 @@ static void x86_android_tablet_cleanup(void)
 
        kfree(i2c_clients);
 
+       if (exit_handler)
+               exit_handler();
+
        for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++)
                gpiod_remove_lookup_table(gpiod_lookup_tables[i]);
 }
@@ -795,6 +856,7 @@ static __init int x86_android_tablet_init(void)
 {
        const struct x86_dev_info *dev_info;
        const struct dmi_system_id *id;
+       struct gpio_chip *chip;
        int i, ret = 0;
 
        id = dmi_first_match(x86_android_tablet_ids);
@@ -803,6 +865,20 @@ static __init int x86_android_tablet_init(void)
 
        dev_info = id->driver_data;
 
+       /*
+        * The broken DSDTs on these devices often also include broken
+        * _AEI (ACPI Event Interrupt) handlers, disable these.
+        */
+       if (dev_info->invalid_aei_gpiochip) {
+               chip = gpiochip_find(dev_info->invalid_aei_gpiochip,
+                                    gpiochip_find_match_label);
+               if (!chip) {
+                       pr_err("error cannot find GPIO chip %s\n", dev_info->invalid_aei_gpiochip);
+                       return -ENODEV;
+               }
+               acpi_gpiochip_free_interrupts(chip);
+       }
+
        /*
         * Since this runs from module_init() it cannot use -EPROBE_DEFER,
         * instead pre-load any modules which are listed as requirements.
@@ -814,6 +890,15 @@ static __init int x86_android_tablet_init(void)
        for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++)
                gpiod_add_lookup_table(gpiod_lookup_tables[i]);
 
+       if (dev_info->init) {
+               ret = dev_info->init();
+               if (ret < 0) {
+                       x86_android_tablet_cleanup();
+                       return ret;
+               }
+               exit_handler = dev_info->exit;
+       }
+
        i2c_clients = kcalloc(dev_info->i2c_client_count, sizeof(*i2c_clients), GFP_KERNEL);
        if (!i2c_clients) {
                x86_android_tablet_cleanup();
@@ -865,6 +950,6 @@ static __init int x86_android_tablet_init(void)
 module_init(x86_android_tablet_init);
 module_exit(x86_android_tablet_cleanup);
 
-MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 MODULE_DESCRIPTION("X86 Android tablets DSDT fixups driver");
 MODULE_LICENSE("GPL");
index b274942..01ad84f 100644 (file)
@@ -1523,6 +1523,9 @@ static int bq256xx_hw_init(struct bq256xx_device *bq)
                                                BQ256XX_WDT_BIT_SHIFT);
 
        ret = power_supply_get_battery_info(bq->charger, &bat_info);
+       if (ret == -ENOMEM)
+               return ret;
+
        if (ret) {
                dev_warn(bq->dev, "battery info missing, default values will be applied\n");
 
index 0c87ad0..728e2a6 100644 (file)
@@ -689,7 +689,7 @@ static int cw_bat_probe(struct i2c_client *client)
        if (ret) {
                /* Allocate an empty battery */
                cw_bat->battery = devm_kzalloc(&client->dev,
-                                              sizeof(cw_bat->battery),
+                                              sizeof(*cw_bat->battery),
                                               GFP_KERNEL);
                if (!cw_bat->battery)
                        return -ENOMEM;
index 35799e6..2f4b11b 100644 (file)
@@ -169,7 +169,7 @@ static int pps_gpio_probe(struct platform_device *pdev)
        /* GPIO setup */
        ret = pps_gpio_setup(dev);
        if (ret)
-               return -EINVAL;
+               return ret;
 
        /* IRQ setup */
        ret = gpiod_to_irq(data->gpio_pin);
index 86aa414..d255397 100644 (file)
@@ -6014,9 +6014,8 @@ core_initcall(regulator_init);
 static int regulator_late_cleanup(struct device *dev, void *data)
 {
        struct regulator_dev *rdev = dev_to_rdev(dev);
-       const struct regulator_ops *ops = rdev->desc->ops;
        struct regulation_constraints *c = rdev->constraints;
-       int enabled, ret;
+       int ret;
 
        if (c && c->always_on)
                return 0;
@@ -6029,14 +6028,8 @@ static int regulator_late_cleanup(struct device *dev, void *data)
        if (rdev->use_count)
                goto unlock;
 
-       /* If we can't read the status assume it's always on. */
-       if (ops->is_enabled)
-               enabled = ops->is_enabled(rdev);
-       else
-               enabled = 1;
-
-       /* But if reading the status failed, assume that it's off. */
-       if (enabled <= 0)
+       /* If reading the status failed, assume that it's off. */
+       if (_regulator_is_enabled(rdev) <= 0)
                goto unlock;
 
        if (have_full_constraints()) {
index 6f21223..eb9df48 100644 (file)
@@ -87,16 +87,16 @@ static struct da9121_range da9121_3A_1phase_current = {
 };
 
 static struct da9121_range da914x_40A_4phase_current = {
-       .val_min = 14000000,
-       .val_max = 80000000,
-       .val_stp =  2000000,
+       .val_min = 26000000,
+       .val_max = 78000000,
+       .val_stp =  4000000,
        .reg_min = 1,
        .reg_max = 14,
 };
 
 static struct da9121_range da914x_20A_2phase_current = {
-       .val_min =  7000000,
-       .val_max = 40000000,
+       .val_min = 13000000,
+       .val_max = 39000000,
        .val_stp =  2000000,
        .reg_min = 1,
        .reg_max = 14,
@@ -561,7 +561,7 @@ static const struct regulator_desc da9217_reg = {
 };
 
 #define DA914X_MIN_MV          500
-#define DA914X_MAX_MV          1000
+#define DA914X_MAX_MV          1300
 #define DA914X_STEP_MV         10
 #define DA914X_MIN_SEL         (DA914X_MIN_MV / DA914X_STEP_MV)
 #define DA914X_N_VOLTAGES      (((DA914X_MAX_MV - DA914X_MIN_MV) / DA914X_STEP_MV) \
@@ -585,10 +585,6 @@ static const struct regulator_desc da9141_reg = {
        .vsel_mask = DA9121_MASK_BUCK_BUCKx_5_CHx_A_VOUT,
        .enable_reg = DA9121_REG_BUCK_BUCK1_0,
        .enable_mask = DA9121_MASK_BUCK_BUCKx_0_CHx_EN,
-       /* Default value of BUCK_BUCK1_0.CH1_SRC_DVC_UP */
-       .ramp_delay = 20000,
-       /* tBUCK_EN */
-       .enable_time = 20,
 };
 
 static const struct regulator_desc da9142_reg = {
index fbc56b0..b8bf76c 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
@@ -140,7 +141,7 @@ static int max20086_parse_regulators_dt(struct max20086 *chip, bool *boot_on)
        node = of_get_child_by_name(chip->dev->of_node, "regulators");
        if (!node) {
                dev_err(chip->dev, "regulators node not found\n");
-               return PTR_ERR(node);
+               return -ENODEV;
        }
 
        for (i = 0; i < chip->info->num_outputs; ++i)
index 3ddd426..1660197 100644 (file)
@@ -180,6 +180,7 @@ config QCOM_Q6V5_ADSP
        depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
        depends on QCOM_SYSMON || QCOM_SYSMON=n
        depends on RPMSG_QCOM_GLINK || RPMSG_QCOM_GLINK=n
+       depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n
        select MFD_SYSCON
        select QCOM_PIL_INFO
        select QCOM_MDT_LOADER
@@ -199,6 +200,7 @@ config QCOM_Q6V5_MSS
        depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
        depends on QCOM_SYSMON || QCOM_SYSMON=n
        depends on RPMSG_QCOM_GLINK || RPMSG_QCOM_GLINK=n
+       depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n
        select MFD_SYSCON
        select QCOM_MDT_LOADER
        select QCOM_PIL_INFO
@@ -218,6 +220,7 @@ config QCOM_Q6V5_PAS
        depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
        depends on QCOM_SYSMON || QCOM_SYSMON=n
        depends on RPMSG_QCOM_GLINK || RPMSG_QCOM_GLINK=n
+       depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n
        select MFD_SYSCON
        select QCOM_PIL_INFO
        select QCOM_MDT_LOADER
@@ -239,6 +242,7 @@ config QCOM_Q6V5_WCSS
        depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
        depends on QCOM_SYSMON || QCOM_SYSMON=n
        depends on RPMSG_QCOM_GLINK || RPMSG_QCOM_GLINK=n
+       depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n
        select MFD_SYSCON
        select QCOM_MDT_LOADER
        select QCOM_PIL_INFO
index eada7e3..442a388 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/soc/qcom/qcom_aoss.h>
 #include <linux/soc/qcom/smem.h>
 #include <linux/soc/qcom/smem_state.h>
 #include <linux/remoteproc.h>
index 6f8ba0d..b496028 100644 (file)
@@ -256,6 +256,19 @@ config RESET_TI_SYSCON
          you wish to use the reset framework for such memory-mapped devices,
          say Y here. Otherwise, say N.
 
+config RESET_TN48M_CPLD
+       tristate "Delta Networks TN48M switch CPLD reset controller"
+       depends on MFD_TN48M_CPLD || COMPILE_TEST
+       default MFD_TN48M_CPLD
+       help
+         This enables the reset controller driver for the Delta TN48M CPLD.
+         It provides reset signals for Armada 7040 and 385 SoC-s, Alleycat 3X
+         switch MAC-s, Alaska OOB ethernet PHY, Quad Alaska ethernet PHY-s and
+         Microchip PD69200 PoE PSE controller.
+
+         This driver can also be built as a module. If so, the module will be
+         called reset-tn48m.
+
 config RESET_UNIPHIER
        tristate "Reset controller driver for UniPhier SoCs"
        depends on ARCH_UNIPHIER || COMPILE_TEST
index bd0a97b..a80a9c4 100644 (file)
@@ -33,6 +33,7 @@ obj-$(CONFIG_RESET_STARFIVE_JH7100) += reset-starfive-jh7100.o
 obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
 obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o
 obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o
+obj-$(CONFIG_RESET_TN48M_CPLD) += reset-tn48m.o
 obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
 obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
 obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
diff --git a/drivers/reset/reset-tn48m.c b/drivers/reset/reset-tn48m.c
new file mode 100644 (file)
index 0000000..1300272
--- /dev/null
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Delta TN48M CPLD reset driver
+ *
+ * Copyright (C) 2021 Sartura Ltd.
+ *
+ * Author: Robert Marko <robert.marko@sartura.hr>
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include <dt-bindings/reset/delta,tn48m-reset.h>
+
+#define TN48M_RESET_REG                0x10
+
+#define TN48M_RESET_TIMEOUT_US 125000
+#define TN48M_RESET_SLEEP_US   10
+
+struct tn48_reset_map {
+       u8 bit;
+};
+
+struct tn48_reset_data {
+       struct reset_controller_dev rcdev;
+       struct regmap *regmap;
+};
+
+static const struct tn48_reset_map tn48m_resets[] = {
+       [CPU_88F7040_RESET] = {0},
+       [CPU_88F6820_RESET] = {1},
+       [MAC_98DX3265_RESET] = {2},
+       [PHY_88E1680_RESET] = {4},
+       [PHY_88E1512_RESET] = {6},
+       [POE_RESET] = {7},
+};
+
+static inline struct tn48_reset_data *to_tn48_reset_data(
+                       struct reset_controller_dev *rcdev)
+{
+       return container_of(rcdev, struct tn48_reset_data, rcdev);
+}
+
+static int tn48m_control_reset(struct reset_controller_dev *rcdev,
+                              unsigned long id)
+{
+       struct tn48_reset_data *data = to_tn48_reset_data(rcdev);
+       unsigned int val;
+
+       regmap_update_bits(data->regmap, TN48M_RESET_REG,
+                          BIT(tn48m_resets[id].bit), 0);
+
+       return regmap_read_poll_timeout(data->regmap,
+                                       TN48M_RESET_REG,
+                                       val,
+                                       val & BIT(tn48m_resets[id].bit),
+                                       TN48M_RESET_SLEEP_US,
+                                       TN48M_RESET_TIMEOUT_US);
+}
+
+static int tn48m_control_status(struct reset_controller_dev *rcdev,
+                               unsigned long id)
+{
+       struct tn48_reset_data *data = to_tn48_reset_data(rcdev);
+       unsigned int regval;
+       int ret;
+
+       ret = regmap_read(data->regmap, TN48M_RESET_REG, &regval);
+       if (ret < 0)
+               return ret;
+
+       if (BIT(tn48m_resets[id].bit) & regval)
+               return 0;
+       else
+               return 1;
+}
+
+static const struct reset_control_ops tn48_reset_ops = {
+       .reset          = tn48m_control_reset,
+       .status         = tn48m_control_status,
+};
+
+static int tn48m_reset_probe(struct platform_device *pdev)
+{
+       struct tn48_reset_data *data;
+       struct regmap *regmap;
+
+       regmap = dev_get_regmap(pdev->dev.parent, NULL);
+       if (!regmap)
+               return -ENODEV;
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->regmap = regmap;
+
+       data->rcdev.owner = THIS_MODULE;
+       data->rcdev.ops = &tn48_reset_ops;
+       data->rcdev.nr_resets = ARRAY_SIZE(tn48m_resets);
+       data->rcdev.of_node = pdev->dev.of_node;
+
+       return devm_reset_controller_register(&pdev->dev, &data->rcdev);
+}
+
+static const struct of_device_id tn48m_reset_of_match[] = {
+       { .compatible = "delta,tn48m-reset" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, tn48m_reset_of_match);
+
+static struct platform_driver tn48m_reset_driver = {
+       .driver = {
+               .name = "delta-tn48m-reset",
+               .of_match_table = tn48m_reset_of_match,
+       },
+       .probe = tn48m_reset_probe,
+};
+module_platform_driver(tn48m_reset_driver);
+
+MODULE_AUTHOR("Robert Marko <robert.marko@sartura.hr>");
+MODULE_DESCRIPTION("Delta TN48M CPLD reset driver");
+MODULE_LICENSE("GPL");
index d6214cb..5663cf7 100644 (file)
@@ -93,7 +93,7 @@ static int rpmsg_eptdev_destroy(struct device *dev, void *data)
        /* wake up any blocked readers */
        wake_up_interruptible(&eptdev->readq);
 
-       device_del(&eptdev->dev);
+       cdev_device_del(&eptdev->cdev, &eptdev->dev);
        put_device(&eptdev->dev);
 
        return 0;
@@ -336,7 +336,6 @@ static void rpmsg_eptdev_release_device(struct device *dev)
 
        ida_simple_remove(&rpmsg_ept_ida, dev->id);
        ida_simple_remove(&rpmsg_minor_ida, MINOR(eptdev->dev.devt));
-       cdev_del(&eptdev->cdev);
        kfree(eptdev);
 }
 
@@ -381,19 +380,13 @@ static int rpmsg_eptdev_create(struct rpmsg_ctrldev *ctrldev,
        dev->id = ret;
        dev_set_name(dev, "rpmsg%d", ret);
 
-       ret = cdev_add(&eptdev->cdev, dev->devt, 1);
+       ret = cdev_device_add(&eptdev->cdev, &eptdev->dev);
        if (ret)
                goto free_ept_ida;
 
        /* We can now rely on the release function for cleanup */
        dev->release = rpmsg_eptdev_release_device;
 
-       ret = device_add(dev);
-       if (ret) {
-               dev_err(dev, "device_add failed: %d\n", ret);
-               put_device(dev);
-       }
-
        return ret;
 
 free_ept_ida:
@@ -462,7 +455,6 @@ static void rpmsg_ctrldev_release_device(struct device *dev)
 
        ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
        ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
-       cdev_del(&ctrldev->cdev);
        kfree(ctrldev);
 }
 
@@ -497,19 +489,13 @@ static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
        dev->id = ret;
        dev_set_name(&ctrldev->dev, "rpmsg_ctrl%d", ret);
 
-       ret = cdev_add(&ctrldev->cdev, dev->devt, 1);
+       ret = cdev_device_add(&ctrldev->cdev, &ctrldev->dev);
        if (ret)
                goto free_ctrl_ida;
 
        /* We can now rely on the release function for cleanup */
        dev->release = rpmsg_ctrldev_release_device;
 
-       ret = device_add(dev);
-       if (ret) {
-               dev_err(&rpdev->dev, "device_add failed: %d\n", ret);
-               put_device(dev);
-       }
-
        dev_set_drvdata(&rpdev->dev, ctrldev);
 
        return ret;
@@ -535,7 +521,7 @@ static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
        if (ret)
                dev_warn(&rpdev->dev, "failed to nuke endpoints: %d\n", ret);
 
-       device_del(&ctrldev->dev);
+       cdev_device_del(&ctrldev->cdev, &ctrldev->dev);
        put_device(&ctrldev->dev);
 }
 
index cd938a2..3b1cd0c 100644 (file)
@@ -1180,7 +1180,7 @@ static int io_subchannel_chp_event(struct subchannel *sch,
                        else
                                path_event[chpid] = PE_NONE;
                }
-               if (cdev)
+               if (cdev && cdev->drv && cdev->drv->path_event)
                        cdev->drv->path_event(cdev, path_event);
                break;
        }
index d24cafe..511bf8e 100644 (file)
@@ -521,6 +521,8 @@ static void zfcp_fc_adisc_handler(void *data)
                goto out;
        }
 
+       /* re-init to undo drop from zfcp_fc_adisc() */
+       port->d_id = ntoh24(adisc_resp->adisc_port_id);
        /* port is good, unblock rport without going through erp */
        zfcp_scsi_schedule_rport_register(port);
  out:
@@ -534,6 +536,7 @@ static int zfcp_fc_adisc(struct zfcp_port *port)
        struct zfcp_fc_req *fc_req;
        struct zfcp_adapter *adapter = port->adapter;
        struct Scsi_Host *shost = adapter->scsi_host;
+       u32 d_id;
        int ret;
 
        fc_req = kmem_cache_zalloc(zfcp_fc_req_cache, GFP_ATOMIC);
@@ -558,7 +561,15 @@ static int zfcp_fc_adisc(struct zfcp_port *port)
        fc_req->u.adisc.req.adisc_cmd = ELS_ADISC;
        hton24(fc_req->u.adisc.req.adisc_port_id, fc_host_port_id(shost));
 
-       ret = zfcp_fsf_send_els(adapter, port->d_id, &fc_req->ct_els,
+       d_id = port->d_id; /* remember as destination for send els below */
+       /*
+        * Force fresh GID_PN lookup on next port recovery.
+        * Must happen after request setup and before sending request,
+        * to prevent race with port->d_id re-init in zfcp_fc_adisc_handler().
+        */
+       port->d_id = 0;
+
+       ret = zfcp_fsf_send_els(adapter, d_id, &fc_req->ct_els,
                                ZFCP_FC_CTELS_TMO);
        if (ret)
                kmem_cache_free(zfcp_fc_req_cache, fc_req);
index b9482da..3ebe661 100644 (file)
@@ -1567,8 +1567,6 @@ static int twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
        pci_try_set_mwi(pdev);
 
        retval = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
-       if (retval)
-               retval = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
        if (retval) {
                TW_PRINTK(host, TW_DRIVER, 0x18, "Failed to set dma mask");
                retval = -ENODEV;
@@ -1786,8 +1784,6 @@ static int __maybe_unused twl_resume(struct device *dev)
        pci_try_set_mwi(pdev);
 
        retval = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
-       if (retval)
-               retval = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
        if (retval) {
                TW_PRINTK(host, TW_DRIVER, 0x25, "Failed to set dma mask during resume");
                retval = -ENODEV;
index 3ad3eba..ad4972c 100644 (file)
@@ -1507,7 +1507,6 @@ NCR_700_intr(int irq, void *dev_id)
                struct scsi_cmnd *SCp = hostdata->cmd;
 
                handled = 1;
-               SCp = hostdata->cmd;
 
                if(istat & SCSI_INT_PENDING) {
                        udelay(10);
index 440ef32..e5aa982 100644 (file)
@@ -732,9 +732,6 @@ bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad)
        pci_set_master(pdev);
 
        rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
-       if (rc)
-               rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
-
        if (rc) {
                rc = -ENODEV;
                printk(KERN_ERR "dma_set_mask_and_coherent fail %p\n", pdev);
@@ -1559,9 +1556,6 @@ bfad_pci_slot_reset(struct pci_dev *pdev)
        pci_set_master(pdev);
 
        rc = dma_set_mask_and_coherent(&bfad->pcidev->dev, DMA_BIT_MASK(64));
-       if (rc)
-               rc = dma_set_mask_and_coherent(&bfad->pcidev->dev,
-                                              DMA_BIT_MASK(32));
        if (rc)
                goto out_disable_device;
 
index 71fa62b..a826456 100644 (file)
@@ -82,7 +82,7 @@ static int bnx2fc_bind_pcidev(struct bnx2fc_hba *hba);
 static void bnx2fc_unbind_pcidev(struct bnx2fc_hba *hba);
 static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface,
                                  struct device *parent, int npiv);
-static void bnx2fc_destroy_work(struct work_struct *work);
+static void bnx2fc_port_destroy(struct fcoe_port *port);
 
 static struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device *phys_dev);
 static struct bnx2fc_interface *bnx2fc_interface_lookup(struct net_device
@@ -508,7 +508,8 @@ static int bnx2fc_l2_rcv_thread(void *arg)
 
 static void bnx2fc_recv_frame(struct sk_buff *skb)
 {
-       u32 fr_len;
+       u64 crc_err;
+       u32 fr_len, fr_crc;
        struct fc_lport *lport;
        struct fcoe_rcv_info *fr;
        struct fc_stats *stats;
@@ -542,6 +543,11 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
        skb_pull(skb, sizeof(struct fcoe_hdr));
        fr_len = skb->len - sizeof(struct fcoe_crc_eof);
 
+       stats = per_cpu_ptr(lport->stats, get_cpu());
+       stats->RxFrames++;
+       stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
+       put_cpu();
+
        fp = (struct fc_frame *)skb;
        fc_frame_init(fp);
        fr_dev(fp) = lport;
@@ -624,16 +630,15 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
                return;
        }
 
-       stats = per_cpu_ptr(lport->stats, smp_processor_id());
-       stats->RxFrames++;
-       stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
+       fr_crc = le32_to_cpu(fr_crc(fp));
 
-       if (le32_to_cpu(fr_crc(fp)) !=
-                       ~crc32(~0, skb->data, fr_len)) {
-               if (stats->InvalidCRCCount < 5)
+       if (unlikely(fr_crc != ~crc32(~0, skb->data, fr_len))) {
+               stats = per_cpu_ptr(lport->stats, get_cpu());
+               crc_err = (stats->InvalidCRCCount++);
+               put_cpu();
+               if (crc_err < 5)
                        printk(KERN_WARNING PFX "dropping frame with "
                               "CRC error\n");
-               stats->InvalidCRCCount++;
                kfree_skb(skb);
                return;
        }
@@ -907,9 +912,6 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event,
                                __bnx2fc_destroy(interface);
                }
                mutex_unlock(&bnx2fc_dev_lock);
-
-               /* Ensure ALL destroy work has been completed before return */
-               flush_workqueue(bnx2fc_wq);
                return;
 
        default:
@@ -1215,8 +1217,8 @@ static int bnx2fc_vport_destroy(struct fc_vport *vport)
        mutex_unlock(&n_port->lp_mutex);
        bnx2fc_free_vport(interface->hba, port->lport);
        bnx2fc_port_shutdown(port->lport);
+       bnx2fc_port_destroy(port);
        bnx2fc_interface_put(interface);
-       queue_work(bnx2fc_wq, &port->destroy_work);
        return 0;
 }
 
@@ -1525,7 +1527,6 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface,
        port->lport = lport;
        port->priv = interface;
        port->get_netdev = bnx2fc_netdev;
-       INIT_WORK(&port->destroy_work, bnx2fc_destroy_work);
 
        /* Configure fcoe_port */
        rc = bnx2fc_lport_config(lport);
@@ -1653,8 +1654,8 @@ static void __bnx2fc_destroy(struct bnx2fc_interface *interface)
        bnx2fc_interface_cleanup(interface);
        bnx2fc_stop(interface);
        list_del(&interface->list);
+       bnx2fc_port_destroy(port);
        bnx2fc_interface_put(interface);
-       queue_work(bnx2fc_wq, &port->destroy_work);
 }
 
 /**
@@ -1694,15 +1695,12 @@ netdev_err:
        return rc;
 }
 
-static void bnx2fc_destroy_work(struct work_struct *work)
+static void bnx2fc_port_destroy(struct fcoe_port *port)
 {
-       struct fcoe_port *port;
        struct fc_lport *lport;
 
-       port = container_of(work, struct fcoe_port, destroy_work);
        lport = port->lport;
-
-       BNX2FC_HBA_DBG(lport, "Entered bnx2fc_destroy_work\n");
+       BNX2FC_HBA_DBG(lport, "Entered %s, destroying lport %p\n", __func__, lport);
 
        bnx2fc_if_destroy(lport);
 }
@@ -2556,9 +2554,6 @@ static void bnx2fc_ulp_exit(struct cnic_dev *dev)
                        __bnx2fc_destroy(interface);
        mutex_unlock(&bnx2fc_dev_lock);
 
-       /* Ensure ALL destroy work has been completed before return */
-       flush_workqueue(bnx2fc_wq);
-
        bnx2fc_ulp_stop(hba);
        /* unregister cnic device */
        if (test_and_clear_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic))
index 7bb4f9a..84bc81d 100644 (file)
@@ -46,18 +46,14 @@ efc_els_io_alloc_size(struct efc_node *node, u32 reqlen, u32 rsplen)
 
        efc = node->efc;
 
-       spin_lock_irqsave(&node->els_ios_lock, flags);
-
        if (!node->els_io_enabled) {
                efc_log_err(efc, "els io alloc disabled\n");
-               spin_unlock_irqrestore(&node->els_ios_lock, flags);
                return NULL;
        }
 
        els = mempool_alloc(efc->els_io_pool, GFP_ATOMIC);
        if (!els) {
                atomic_add_return(1, &efc->els_io_alloc_failed_count);
-               spin_unlock_irqrestore(&node->els_ios_lock, flags);
                return NULL;
        }
 
@@ -74,7 +70,6 @@ efc_els_io_alloc_size(struct efc_node *node, u32 reqlen, u32 rsplen)
                                              &els->io.req.phys, GFP_KERNEL);
        if (!els->io.req.virt) {
                mempool_free(els, efc->els_io_pool);
-               spin_unlock_irqrestore(&node->els_ios_lock, flags);
                return NULL;
        }
 
@@ -94,10 +89,11 @@ efc_els_io_alloc_size(struct efc_node *node, u32 reqlen, u32 rsplen)
 
                /* add els structure to ELS IO list */
                INIT_LIST_HEAD(&els->list_entry);
+               spin_lock_irqsave(&node->els_ios_lock, flags);
                list_add_tail(&els->list_entry, &node->els_ios_list);
+               spin_unlock_irqrestore(&node->els_ios_lock, flags);
        }
 
-       spin_unlock_irqrestore(&node->els_ios_lock, flags);
        return els;
 }
 
index a05ec7a..ebf5ec3 100644 (file)
@@ -400,8 +400,7 @@ void hisi_sas_task_deliver(struct hisi_hba *hisi_hba,
                           struct hisi_sas_slot *slot,
                           struct hisi_sas_dq *dq,
                           struct hisi_sas_device *sas_dev,
-                          struct hisi_sas_internal_abort *abort,
-                          struct hisi_sas_tmf_task *tmf)
+                          struct hisi_sas_internal_abort *abort)
 {
        struct hisi_sas_cmd_hdr *cmd_hdr_base;
        int dlvry_queue_slot, dlvry_queue;
@@ -427,8 +426,6 @@ void hisi_sas_task_deliver(struct hisi_hba *hisi_hba,
        cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue];
        slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot];
 
-       slot->tmf = tmf;
-       slot->is_internal = tmf;
        task->lldd_task = slot;
 
        memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
@@ -587,7 +584,7 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
        slot->is_internal = tmf;
 
        /* protect task_prep and start_delivery sequence */
-       hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, NULL, tmf);
+       hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, NULL);
 
        return 0;
 
@@ -1380,12 +1377,13 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device)
        struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
        struct device *dev = hisi_hba->dev;
        int s = sizeof(struct host_to_dev_fis);
+       struct hisi_sas_tmf_task tmf = {};
 
        ata_for_each_link(link, ap, EDGE) {
                int pmp = sata_srst_pmp(link);
 
                hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis);
-               rc = hisi_sas_exec_internal_tmf_task(device, fis, s, NULL);
+               rc = hisi_sas_exec_internal_tmf_task(device, fis, s, &tmf);
                if (rc != TMF_RESP_FUNC_COMPLETE)
                        break;
        }
@@ -1396,7 +1394,7 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device)
 
                        hisi_sas_fill_ata_reset_cmd(link->device, 0, pmp, fis);
                        rc = hisi_sas_exec_internal_tmf_task(device, fis,
-                                                            s, NULL);
+                                                            s, &tmf);
                        if (rc != TMF_RESP_FUNC_COMPLETE)
                                dev_err(dev, "ata disk %016llx de-reset failed\n",
                                        SAS_ADDR(device->sas_addr));
@@ -2067,7 +2065,7 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
        slot->port = port;
        slot->is_internal = true;
 
-       hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, abort, NULL);
+       hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, abort);
 
        return 0;
 
@@ -2666,9 +2664,6 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
                goto err_out;
 
        error = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
-       if (error)
-               error = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
-
        if (error) {
                dev_err(dev, "No usable DMA addressing method\n");
                goto err_out;
index a45ef9a..a01a3a7 100644 (file)
@@ -4695,8 +4695,6 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto err_out;
 
        rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
-       if (rc)
-               rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
        if (rc) {
                dev_err(dev, "No usable DMA addressing method\n");
                rc = -ENODEV;
index 4878c94..98cabe0 100644 (file)
@@ -592,6 +592,7 @@ struct lpfc_vport {
 #define FC_VPORT_LOGO_RCVD      0x200    /* LOGO received on vport */
 #define FC_RSCN_DISCOVERY       0x400   /* Auth all devices after RSCN */
 #define FC_LOGO_RCVD_DID_CHNG   0x800    /* FDISC on phys port detect DID chng*/
+#define FC_PT2PT_NO_NVME        0x1000   /* Don't send NVME PRLI */
 #define FC_SCSI_SCAN_TMO        0x4000  /* scsi scan timer running */
 #define FC_ABORT_DISCOVERY      0x8000  /* we want to abort discovery */
 #define FC_NDISC_ACTIVE         0x10000         /* NPort discovery active */
@@ -1161,6 +1162,16 @@ struct lpfc_hba {
        uint32_t cfg_hostmem_hgp;
        uint32_t cfg_log_verbose;
        uint32_t cfg_enable_fc4_type;
+#define LPFC_ENABLE_FCP  1
+#define LPFC_ENABLE_NVME 2
+#define LPFC_ENABLE_BOTH 3
+#if (IS_ENABLED(CONFIG_NVME_FC))
+#define LPFC_MAX_ENBL_FC4_TYPE LPFC_ENABLE_BOTH
+#define LPFC_DEF_ENBL_FC4_TYPE LPFC_ENABLE_BOTH
+#else
+#define LPFC_MAX_ENBL_FC4_TYPE LPFC_ENABLE_FCP
+#define LPFC_DEF_ENBL_FC4_TYPE LPFC_ENABLE_FCP
+#endif
        uint32_t cfg_aer_support;
        uint32_t cfg_sriov_nr_virtfn;
        uint32_t cfg_request_firmware_upgrade;
@@ -1182,9 +1193,6 @@ struct lpfc_hba {
        uint32_t cfg_ras_fwlog_func;
        uint32_t cfg_enable_bbcr;       /* Enable BB Credit Recovery */
        uint32_t cfg_enable_dpp;        /* Enable Direct Packet Push */
-#define LPFC_ENABLE_FCP  1
-#define LPFC_ENABLE_NVME 2
-#define LPFC_ENABLE_BOTH 3
        uint32_t cfg_enable_pbde;
        uint32_t cfg_enable_mi;
        struct nvmet_fc_target_port *targetport;
index 7a7f17d..fa84152 100644 (file)
@@ -1315,6 +1315,9 @@ lpfc_issue_lip(struct Scsi_Host *shost)
        pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK;
        pmboxq->u.mb.mbxOwner = OWN_HOST;
 
+       if ((vport->fc_flag & FC_PT2PT) && (vport->fc_flag & FC_PT2PT_NO_NVME))
+               vport->fc_flag &= ~FC_PT2PT_NO_NVME;
+
        mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO * 2);
 
        if ((mbxstatus == MBX_SUCCESS) &&
@@ -3978,8 +3981,8 @@ LPFC_ATTR_R(nvmet_mrq_post,
  *                    3 - register both FCP and NVME
  * Supported values are [1,3]. Default value is 3
  */
-LPFC_ATTR_R(enable_fc4_type, LPFC_ENABLE_BOTH,
-           LPFC_ENABLE_FCP, LPFC_ENABLE_BOTH,
+LPFC_ATTR_R(enable_fc4_type, LPFC_DEF_ENBL_FC4_TYPE,
+           LPFC_ENABLE_FCP, LPFC_MAX_ENBL_FC4_TYPE,
            "Enable FC4 Protocol support - FCP / NVME");
 
 /*
index db5ccae..f936833 100644 (file)
@@ -1072,7 +1072,8 @@ stop_rr_fcf_flogi:
 
                /* FLOGI failed, so there is no fabric */
                spin_lock_irq(shost->host_lock);
-               vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+               vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP |
+                                   FC_PT2PT_NO_NVME);
                spin_unlock_irq(shost->host_lock);
 
                /* If private loop, then allow max outstanding els to be
@@ -4607,6 +4608,23 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                /* Added for Vendor specifc support
                 * Just keep retrying for these Rsn / Exp codes
                 */
+               if ((vport->fc_flag & FC_PT2PT) &&
+                   cmd == ELS_CMD_NVMEPRLI) {
+                       switch (stat.un.b.lsRjtRsnCode) {
+                       case LSRJT_UNABLE_TPC:
+                       case LSRJT_INVALID_CMD:
+                       case LSRJT_LOGICAL_ERR:
+                       case LSRJT_CMD_UNSUPPORTED:
+                               lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS,
+                                                "0168 NVME PRLI LS_RJT "
+                                                "reason %x port doesn't "
+                                                "support NVME, disabling NVME\n",
+                                                stat.un.b.lsRjtRsnCode);
+                               retry = 0;
+                               vport->fc_flag |= FC_PT2PT_NO_NVME;
+                               goto out_retry;
+                       }
+               }
                switch (stat.un.b.lsRjtRsnCode) {
                case LSRJT_UNABLE_TPC:
                        /* The driver has a VALID PLOGI but the rport has
index a56f01f..558f7d2 100644 (file)
@@ -2104,7 +2104,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
                }
                if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 &&
                    reg_err2 == SLIPORT_ERR2_REG_FW_RESTART) {
-                       lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
+                       lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
                                        "3143 Port Down: Firmware Update "
                                        "Detected\n");
                        en_rn_msg = false;
index 7d717a4..fdf5e77 100644 (file)
@@ -1961,8 +1961,9 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
                         * is configured try it.
                         */
                        ndlp->nlp_fc4_type |= NLP_FC4_FCP;
-                       if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
-                           (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) {
+                       if ((!(vport->fc_flag & FC_PT2PT_NO_NVME)) &&
+                           (vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH ||
+                           vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) {
                                ndlp->nlp_fc4_type |= NLP_FC4_NVME;
                                /* We need to update the localport also */
                                lpfc_nvme_update_localport(vport);
index 1bc0db5..430abeb 100644 (file)
@@ -13363,6 +13363,7 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba)
        uint32_t uerr_sta_hi, uerr_sta_lo;
        uint32_t if_type, portsmphr;
        struct lpfc_register portstat_reg;
+       u32 logmask;
 
        /*
         * For now, use the SLI4 device internal unrecoverable error
@@ -13413,7 +13414,12 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba)
                                readl(phba->sli4_hba.u.if_type2.ERR1regaddr);
                        phba->work_status[1] =
                                readl(phba->sli4_hba.u.if_type2.ERR2regaddr);
-                       lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
+                       logmask = LOG_TRACE_EVENT;
+                       if (phba->work_status[0] ==
+                               SLIPORT_ERR1_REG_ERR_CODE_2 &&
+                           phba->work_status[1] == SLIPORT_ERR2_REG_FW_RESTART)
+                               logmask = LOG_SLI;
+                       lpfc_printf_log(phba, KERN_ERR, logmask,
                                        "2885 Port Status Event: "
                                        "port status reg 0x%x, "
                                        "port smphr reg 0x%x, "
index 253ceca..7eb8c39 100644 (file)
@@ -2267,7 +2267,8 @@ static void myrs_cleanup(struct myrs_hba *cs)
        myrs_unmap(cs);
 
        if (cs->mmio_base) {
-               cs->disable_intr(cs);
+               if (cs->disable_intr)
+                       cs->disable_intr(cs);
                iounmap(cs->mmio_base);
                cs->mmio_base = NULL;
        }
index c814e50..9ec310b 100644 (file)
@@ -2692,7 +2692,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
        u32 tag = le32_to_cpu(psataPayload->tag);
        u32 port_id = le32_to_cpu(psataPayload->port_id);
        u32 dev_id = le32_to_cpu(psataPayload->device_id);
-       unsigned long flags;
 
        if (event)
                pm8001_dbg(pm8001_ha, FAIL, "SATA EVENT 0x%x\n", event);
@@ -2724,8 +2723,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
                ts->resp = SAS_TASK_COMPLETE;
                ts->stat = SAS_DATA_OVERRUN;
                ts->residual = 0;
-               if (pm8001_dev)
-                       atomic_dec(&pm8001_dev->running_req);
                break;
        case IO_XFER_ERROR_BREAK:
                pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
@@ -2767,7 +2764,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
                                IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
                        ts->resp = SAS_TASK_COMPLETE;
                        ts->stat = SAS_QUEUE_FULL;
-                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
                        return;
                }
                break;
@@ -2853,20 +2849,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
                ts->stat = SAS_OPEN_TO;
                break;
        }
-       spin_lock_irqsave(&t->task_state_lock, flags);
-       t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
-       t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
-       t->task_state_flags |= SAS_TASK_STATE_DONE;
-       if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
-               pm8001_dbg(pm8001_ha, FAIL,
-                          "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
-                          t, event, ts->resp, ts->stat);
-               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-       } else {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
-               pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
-       }
 }
 
 /*See the comments for mpi_ssp_completion */
index 160ee8b..32edda3 100644 (file)
@@ -769,8 +769,13 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev,
                res = -TMF_RESP_FUNC_FAILED;
                /* Even TMF timed out, return direct. */
                if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+                       struct pm8001_ccb_info *ccb = task->lldd_task;
+
                        pm8001_dbg(pm8001_ha, FAIL, "TMF task[%x]timeout.\n",
                                   tmf->tmf);
+
+                       if (ccb)
+                               ccb->task = NULL;
                        goto ex_err;
                }
 
index bbf538f..9d20f80 100644 (file)
@@ -2185,9 +2185,9 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
                pm8001_dbg(pm8001_ha, FAIL,
                           "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
                           t, status, ts->resp, ts->stat);
+               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
                if (t->slow_task)
                        complete(&t->slow_task->completion);
-               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
        } else {
                spin_unlock_irqrestore(&t->task_state_lock, flags);
                pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
@@ -2794,9 +2794,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha,
                pm8001_dbg(pm8001_ha, FAIL,
                           "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
                           t, status, ts->resp, ts->stat);
+               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
                if (t->slow_task)
                        complete(&t->slow_task->completion);
-               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
        } else {
                spin_unlock_irqrestore(&t->task_state_lock, flags);
                spin_unlock_irqrestore(&circularQ->oq_lock,
@@ -2821,7 +2821,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha,
        u32 tag = le32_to_cpu(psataPayload->tag);
        u32 port_id = le32_to_cpu(psataPayload->port_id);
        u32 dev_id = le32_to_cpu(psataPayload->device_id);
-       unsigned long flags;
 
        if (event)
                pm8001_dbg(pm8001_ha, FAIL, "SATA EVENT 0x%x\n", event);
@@ -2854,8 +2853,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha,
                ts->resp = SAS_TASK_COMPLETE;
                ts->stat = SAS_DATA_OVERRUN;
                ts->residual = 0;
-               if (pm8001_dev)
-                       atomic_dec(&pm8001_dev->running_req);
                break;
        case IO_XFER_ERROR_BREAK:
                pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
@@ -2904,11 +2901,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha,
                                IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
                        ts->resp = SAS_TASK_COMPLETE;
                        ts->stat = SAS_QUEUE_FULL;
-                       spin_unlock_irqrestore(&circularQ->oq_lock,
-                                       circularQ->lock_flags);
-                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
-                       spin_lock_irqsave(&circularQ->oq_lock,
-                                       circularQ->lock_flags);
                        return;
                }
                break;
@@ -3008,24 +3000,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha,
                ts->stat = SAS_OPEN_TO;
                break;
        }
-       spin_lock_irqsave(&t->task_state_lock, flags);
-       t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
-       t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
-       t->task_state_flags |= SAS_TASK_STATE_DONE;
-       if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
-               pm8001_dbg(pm8001_ha, FAIL,
-                          "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
-                          t, event, ts->resp, ts->stat);
-               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-       } else {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
-               spin_unlock_irqrestore(&circularQ->oq_lock,
-                               circularQ->lock_flags);
-               pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
-               spin_lock_irqsave(&circularQ->oq_lock,
-                               circularQ->lock_flags);
-       }
 }
 
 /*See the comments for mpi_ssp_completion */
@@ -3931,6 +3905,7 @@ static int ssp_coalesced_comp_resp(struct pm8001_hba_info *pm8001_ha,
 /**
  * process_one_iomb - process one outbound Queue memory block
  * @pm8001_ha: our hba card information
+ * @circularQ: outbound circular queue
  * @piomb: IO message buffer
  */
 static void process_one_iomb(struct pm8001_hba_info *pm8001_ha,
@@ -4151,10 +4126,22 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
        u32 ret = MPI_IO_STATUS_FAIL;
        u32 regval;
 
+       /*
+        * Fatal errors are programmed to be signalled in irq vector
+        * pm8001_ha->max_q_num - 1 through pm8001_ha->main_cfg_tbl.pm80xx_tbl.
+        * fatal_err_interrupt
+        */
        if (vec == (pm8001_ha->max_q_num - 1)) {
+               u32 mipsall_ready;
+
+               if (pm8001_ha->chip_id == chip_8008 ||
+                   pm8001_ha->chip_id == chip_8009)
+                       mipsall_ready = SCRATCH_PAD_MIPSALL_READY_8PORT;
+               else
+                       mipsall_ready = SCRATCH_PAD_MIPSALL_READY_16PORT;
+
                regval = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
-               if ((regval & SCRATCH_PAD_MIPSALL_READY) !=
-                                       SCRATCH_PAD_MIPSALL_READY) {
+               if ((regval & mipsall_ready) != mipsall_ready) {
                        pm8001_ha->controller_fatal_error = true;
                        pm8001_dbg(pm8001_ha, FAIL,
                                   "Firmware Fatal error! Regval:0x%x\n",
index c7e5d93..c41ed03 100644 (file)
@@ -1405,8 +1405,12 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t;
 #define SCRATCH_PAD_BOOT_LOAD_SUCCESS  0x0
 #define SCRATCH_PAD_IOP0_READY         0xC00
 #define SCRATCH_PAD_IOP1_READY         0x3000
-#define SCRATCH_PAD_MIPSALL_READY      (SCRATCH_PAD_IOP1_READY | \
+#define SCRATCH_PAD_MIPSALL_READY_16PORT       (SCRATCH_PAD_IOP1_READY | \
                                        SCRATCH_PAD_IOP0_READY | \
+                                       SCRATCH_PAD_ILA_READY | \
+                                       SCRATCH_PAD_RAAE_READY)
+#define SCRATCH_PAD_MIPSALL_READY_8PORT        (SCRATCH_PAD_IOP0_READY | \
+                                       SCRATCH_PAD_ILA_READY | \
                                        SCRATCH_PAD_RAAE_READY)
 
 /* boot loader state */
index 99a56ca..fab43da 100644 (file)
@@ -2250,6 +2250,7 @@ process_els:
            io_req->tm_flags == FCP_TMF_TGT_RESET) {
                clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags);
                io_req->sc_cmd = NULL;
+               kref_put(&io_req->refcount, qedf_release_cmd);
                complete(&io_req->tm_done);
        }
 
index cdc66e2..6ad28bc 100644 (file)
@@ -911,7 +911,7 @@ void qedf_ctx_soft_reset(struct fc_lport *lport)
        struct qed_link_output if_link;
 
        if (lport->vport) {
-               QEDF_ERR(NULL, "Cannot issue host reset on NPIV port.\n");
+               printk_ratelimited("Cannot issue host reset on NPIV port.\n");
                return;
        }
 
@@ -1864,6 +1864,7 @@ static int qedf_vport_create(struct fc_vport *vport, bool disabled)
        vport_qedf->cmd_mgr = base_qedf->cmd_mgr;
        init_completion(&vport_qedf->flogi_compl);
        INIT_LIST_HEAD(&vport_qedf->fcports);
+       INIT_DELAYED_WORK(&vport_qedf->stag_work, qedf_stag_change_work);
 
        rc = qedf_vport_libfc_config(vport, vn_port);
        if (rc) {
@@ -3980,7 +3981,9 @@ void qedf_stag_change_work(struct work_struct *work)
        struct qedf_ctx *qedf =
            container_of(work, struct qedf_ctx, stag_work.work);
 
-       QEDF_ERR(&qedf->dbg_ctx, "Performing software context reset.\n");
+       printk_ratelimited("[%s]:[%s:%d]:%d: Performing software context reset.",
+                       dev_name(&qedf->pdev->dev), __func__, __LINE__,
+                       qedf->dbg_ctx.host_no);
        qedf_ctx_soft_reset(qedf->lport);
 }
 
index 5916ed7..4eb89aa 100644 (file)
@@ -771,11 +771,10 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi,
                        qedi_cmd->list_tmf_work = NULL;
                }
        }
+       spin_unlock_bh(&qedi_conn->tmf_work_lock);
 
-       if (!found) {
-               spin_unlock_bh(&qedi_conn->tmf_work_lock);
+       if (!found)
                goto check_cleanup_reqs;
-       }
 
        QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
                  "TMF work, cqe->tid=0x%x, tmf flags=0x%x, cid=0x%x\n",
@@ -806,7 +805,6 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi,
        qedi_cmd->state = CLEANUP_RECV;
 unlock:
        spin_unlock_bh(&conn->session->back_lock);
-       spin_unlock_bh(&qedi_conn->tmf_work_lock);
        wake_up_interruptible(&qedi_conn->wait_queue);
        return;
 
index 3520b93..f4e6c68 100644 (file)
@@ -214,6 +214,48 @@ static void scsi_unlock_floptical(struct scsi_device *sdev,
                         SCSI_TIMEOUT, 3, NULL);
 }
 
+static int scsi_realloc_sdev_budget_map(struct scsi_device *sdev,
+                                       unsigned int depth)
+{
+       int new_shift = sbitmap_calculate_shift(depth);
+       bool need_alloc = !sdev->budget_map.map;
+       bool need_free = false;
+       int ret;
+       struct sbitmap sb_backup;
+
+       /*
+        * realloc if new shift is calculated, which is caused by setting
+        * up one new default queue depth after calling ->slave_configure
+        */
+       if (!need_alloc && new_shift != sdev->budget_map.shift)
+               need_alloc = need_free = true;
+
+       if (!need_alloc)
+               return 0;
+
+       /*
+        * Request queue has to be frozen for reallocating budget map,
+        * and here disk isn't added yet, so freezing is pretty fast
+        */
+       if (need_free) {
+               blk_mq_freeze_queue(sdev->request_queue);
+               sb_backup = sdev->budget_map;
+       }
+       ret = sbitmap_init_node(&sdev->budget_map,
+                               scsi_device_max_queue_depth(sdev),
+                               new_shift, GFP_KERNEL,
+                               sdev->request_queue->node, false, true);
+       if (need_free) {
+               if (ret)
+                       sdev->budget_map = sb_backup;
+               else
+                       sbitmap_free(&sb_backup);
+               ret = 0;
+               blk_mq_unfreeze_queue(sdev->request_queue);
+       }
+       return ret;
+}
+
 /**
  * scsi_alloc_sdev - allocate and setup a scsi_Device
  * @starget: which target to allocate a &scsi_device for
@@ -306,11 +348,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
         * default device queue depth to figure out sbitmap shift
         * since we use this queue depth most of times.
         */
-       if (sbitmap_init_node(&sdev->budget_map,
-                               scsi_device_max_queue_depth(sdev),
-                               sbitmap_calculate_shift(depth),
-                               GFP_KERNEL, sdev->request_queue->node,
-                               false, true)) {
+       if (scsi_realloc_sdev_budget_map(sdev, depth)) {
                put_device(&starget->dev);
                kfree(sdev);
                goto out;
@@ -1017,6 +1055,13 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
                        }
                        return SCSI_SCAN_NO_RESPONSE;
                }
+
+               /*
+                * The queue_depth is often changed in ->slave_configure.
+                * Set up budget map again since memory consumption of
+                * the map depends on actual queue depth.
+                */
+               scsi_realloc_sdev_budget_map(sdev, sdev->queue_depth);
        }
 
        if (sdev->scsi_level >= SCSI_3)
index 8b16bbb..87975d1 100644 (file)
@@ -92,6 +92,11 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
                clki->min_freq = clkfreq[i];
                clki->max_freq = clkfreq[i+1];
                clki->name = devm_kstrdup(dev, name, GFP_KERNEL);
+               if (!clki->name) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
                if (!strcmp(name, "ref_clk"))
                        clki->keep_link_active = true;
                dev_dbg(dev, "%s: min %u max %u name %s\n", "freq-table-hz",
@@ -127,6 +132,8 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name,
                return -ENOMEM;
 
        vreg->name = devm_kstrdup(dev, name, GFP_KERNEL);
+       if (!vreg->name)
+               return -ENOMEM;
 
        snprintf(prop_name, MAX_PROP_SIZE, "%s-max-microamp", name);
        if (of_property_read_u32(np, prop_name, &vreg->max_uA)) {
index 460d2b4..9349557 100644 (file)
@@ -2681,7 +2681,7 @@ static int ufshcd_map_queues(struct Scsi_Host *shost)
                        break;
                case HCTX_TYPE_READ:
                        map->nr_queues = 0;
-                       break;
+                       continue;
                default:
                        WARN_ON_ONCE(true);
                }
@@ -8613,7 +8613,7 @@ static void ufshcd_hba_exit(struct ufs_hba *hba)
  * @pwr_mode: device power mode to set
  *
  * Returns 0 if requested power mode is set successfully
- * Returns non-zero if failed to set the requested power mode
+ * Returns < 0 if failed to set the requested power mode
  */
 static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
                                     enum ufs_dev_pwr_mode pwr_mode)
@@ -8667,8 +8667,11 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
                sdev_printk(KERN_WARNING, sdp,
                            "START_STOP failed for power mode: %d, result %x\n",
                            pwr_mode, ret);
-               if (ret > 0 && scsi_sense_valid(&sshdr))
-                       scsi_print_sense_hdr(sdp, NULL, &sshdr);
+               if (ret > 0) {
+                       if (scsi_sense_valid(&sshdr))
+                               scsi_print_sense_hdr(sdp, NULL, &sshdr);
+                       ret = -EIO;
+               }
        }
 
        if (!ret)
index 6a295c8..a7ff0e5 100644 (file)
@@ -142,7 +142,8 @@ static inline u32 ufshci_version(u32 major, u32 minor)
 #define INT_FATAL_ERRORS       (DEVICE_FATAL_ERROR |\
                                CONTROLLER_FATAL_ERROR |\
                                SYSTEM_BUS_FATAL_ERROR |\
-                               CRYPTO_ENGINE_FATAL_ERROR)
+                               CRYPTO_ENGINE_FATAL_ERROR |\
+                               UIC_LINK_LOST)
 
 /* HCS - Host Controller Status 30h */
 #define DEVICE_PRESENT                         0x1
index 72771e0..258894e 100644 (file)
@@ -306,10 +306,9 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
        }
 
        lpc_ctrl->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(lpc_ctrl->clk)) {
-               dev_err(dev, "couldn't get clock\n");
-               return PTR_ERR(lpc_ctrl->clk);
-       }
+       if (IS_ERR(lpc_ctrl->clk))
+               return dev_err_probe(dev, PTR_ERR(lpc_ctrl->clk),
+                                    "couldn't get clock\n");
        rc = clk_prepare_enable(lpc_ctrl->clk);
        if (rc) {
                dev_err(dev, "couldn't enable clock\n");
index 670cc82..ca75b14 100644 (file)
@@ -411,17 +411,12 @@ out:
        return ret;
 }
 
-static int init_clks(struct platform_device *pdev, struct clk **clk)
+static void init_clks(struct platform_device *pdev, struct clk **clk)
 {
        int i;
 
-       for (i = CLK_NONE + 1; i < CLK_MAX; i++) {
+       for (i = CLK_NONE + 1; i < CLK_MAX; i++)
                clk[i] = devm_clk_get(&pdev->dev, clk_names[i]);
-               if (IS_ERR(clk[i]))
-                       return PTR_ERR(clk[i]);
-       }
-
-       return 0;
 }
 
 static struct scp *init_scp(struct platform_device *pdev,
@@ -431,7 +426,7 @@ static struct scp *init_scp(struct platform_device *pdev,
 {
        struct genpd_onecell_data *pd_data;
        struct resource *res;
-       int i, j, ret;
+       int i, j;
        struct scp *scp;
        struct clk *clk[CLK_MAX];
 
@@ -486,9 +481,7 @@ static struct scp *init_scp(struct platform_device *pdev,
 
        pd_data->num_domains = num;
 
-       ret = init_clks(pdev, clk);
-       if (ret)
-               return ERR_PTR(ret);
+       init_clks(pdev, clk);
 
        for (i = 0; i < num; i++) {
                struct scp_domain *scpd = &scp->domains[i];
index a9f8b22..02e3195 100644 (file)
@@ -31,7 +31,7 @@ config EXYNOS_USI
        help
          Enable support for USI block. USI (Universal Serial Interface) is an
          IP-core found in modern Samsung Exynos SoCs, like Exynos850 and
-         ExynosAutoV0. USI block can be configured to provide one of the
+         ExynosAutoV9. USI block can be configured to provide one of the
          following serial protocols: UART, SPI or High Speed I2C.
 
          This driver allows one to configure USI for desired protocol, which
index 67369e9..354d3f8 100644 (file)
@@ -1749,8 +1749,11 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
                        continue;
 
                if (status[i] == SDW_SLAVE_UNATTACHED &&
-                   slave->status != SDW_SLAVE_UNATTACHED)
+                   slave->status != SDW_SLAVE_UNATTACHED) {
+                       dev_warn(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n",
+                                i, slave->status);
                        sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED);
+               }
        }
 
        if (status[0] == SDW_SLAVE_ATTACHED) {
@@ -1785,6 +1788,9 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
                        if (slave->status == SDW_SLAVE_UNATTACHED)
                                break;
 
+                       dev_warn(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n",
+                                i, slave->status);
+
                        sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED);
                        break;
 
index 122f7a2..63101f1 100644 (file)
@@ -448,8 +448,8 @@ static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
 
                /* Clear wake status */
                wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS);
-               wake_sts |= (SDW_SHIM_WAKEEN_ENABLE << link_id);
-               intel_writew(shim, SDW_SHIM_WAKESTS_STATUS, wake_sts);
+               wake_sts |= (SDW_SHIM_WAKESTS_STATUS << link_id);
+               intel_writew(shim, SDW_SHIM_WAKESTS, wake_sts);
        }
        mutex_unlock(sdw->link_res->shim_lock);
 }
index d998077..824f4f3 100644 (file)
@@ -180,7 +180,8 @@ static struct sdw_intel_ctx
        if (!res)
                return NULL;
 
-       if (acpi_bus_get_device(res->handle, &adev))
+       adev = acpi_fetch_acpi_dev(res->handle);
+       if (!adev)
                return NULL;
 
        if (!res->count)
@@ -294,13 +295,13 @@ err:
 static int
 sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
 {
-       struct acpi_device *adev;
+       struct acpi_device *adev = acpi_fetch_acpi_dev(ctx->handle);
        struct sdw_intel_link_dev *ldev;
        u32 caps;
        u32 link_mask;
        int i;
 
-       if (acpi_bus_get_device(ctx->handle, &adev))
+       if (!adev)
                return -EINVAL;
 
        /* Check SNDWLCAP.LCOUNT */
index 5481341..da1ad7e 100644 (file)
 #include <linux/of.h>
 #include <linux/of_irq.h>
 #include <linux/of_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
+#include <linux/pm_wakeirq.h>
 #include <linux/slimbus.h>
 #include <linux/soundwire/sdw.h>
 #include <linux/soundwire/sdw_registers.h>
@@ -20,6 +22,9 @@
 #include <sound/soc.h>
 #include "bus.h"
 
+#define SWRM_COMP_SW_RESET                                     0x008
+#define SWRM_COMP_STATUS                                       0x014
+#define SWRM_FRM_GEN_ENABLED                                   BIT(0)
 #define SWRM_COMP_HW_VERSION                                   0x00
 #define SWRM_COMP_CFG_ADDR                                     0x04
 #define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK                   BIT(1)
@@ -29,6 +34,7 @@
 #define SWRM_COMP_PARAMS_RD_FIFO_DEPTH                         GENMASK(19, 15)
 #define SWRM_COMP_PARAMS_DOUT_PORTS_MASK                       GENMASK(4, 0)
 #define SWRM_COMP_PARAMS_DIN_PORTS_MASK                                GENMASK(9, 5)
+#define SWRM_COMP_MASTER_ID                                    0x104
 #define SWRM_INTERRUPT_STATUS                                  0x200
 #define SWRM_INTERRUPT_STATUS_RMSK                             GENMASK(16, 0)
 #define SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ                   BIT(0)
 #define SWR_MAX_CMD_ID 14
 #define MAX_FIFO_RD_RETRY 3
 #define SWR_OVERFLOW_RETRY_COUNT 30
+#define SWRM_LINK_STATUS_RETRY_CNT 100
+
+enum {
+       MASTER_ID_WSA = 1,
+       MASTER_ID_RX,
+       MASTER_ID_TX
+};
 
 struct qcom_swrm_port_config {
        u8 si;
@@ -142,6 +155,7 @@ struct qcom_swrm_ctrl {
        u8 rd_cmd_id;
        int irq;
        unsigned int version;
+       int wake_irq;
        int num_din_ports;
        int num_dout_ports;
        int cols_index;
@@ -159,6 +173,7 @@ struct qcom_swrm_ctrl {
        u32 slave_status;
        u32 wr_fifo_depth;
        u32 rd_fifo_depth;
+       bool clock_stop_not_supported;
 };
 
 struct qcom_swrm_data {
@@ -166,12 +181,12 @@ struct qcom_swrm_data {
        u32 default_rows;
 };
 
-static struct qcom_swrm_data swrm_v1_3_data = {
+static const struct qcom_swrm_data swrm_v1_3_data = {
        .default_rows = 48,
        .default_cols = 16,
 };
 
-static struct qcom_swrm_data swrm_v1_5_data = {
+static const struct qcom_swrm_data swrm_v1_5_data = {
        .default_rows = 50,
        .default_cols = 16,
 };
@@ -490,6 +505,30 @@ static int qcom_swrm_enumerate(struct sdw_bus *bus)
        return 0;
 }
 
+static irqreturn_t qcom_swrm_wake_irq_handler(int irq, void *dev_id)
+{
+       struct qcom_swrm_ctrl *swrm = dev_id;
+       int ret;
+
+       ret = pm_runtime_get_sync(swrm->dev);
+       if (ret < 0 && ret != -EACCES) {
+               dev_err_ratelimited(swrm->dev,
+                                   "pm_runtime_get_sync failed in %s, ret %d\n",
+                                   __func__, ret);
+               pm_runtime_put_noidle(swrm->dev);
+       }
+
+       if (swrm->wake_irq > 0) {
+               if (!irqd_irq_disabled(irq_get_irq_data(swrm->wake_irq)))
+                       disable_irq_nosync(swrm->wake_irq);
+       }
+
+       pm_runtime_mark_last_busy(swrm->dev);
+       pm_runtime_put_autosuspend(swrm->dev);
+
+       return IRQ_HANDLED;
+}
+
 static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id)
 {
        struct qcom_swrm_ctrl *swrm = dev_id;
@@ -497,6 +536,7 @@ static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id)
        u32 i;
        int devnum;
        int ret = IRQ_HANDLED;
+       clk_prepare_enable(swrm->hclk);
 
        swrm->reg_read(swrm, SWRM_INTERRUPT_STATUS, &intr_sts);
        intr_sts_masked = intr_sts & swrm->intr_mask;
@@ -604,6 +644,7 @@ static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id)
                intr_sts_masked = intr_sts & swrm->intr_mask;
        } while (intr_sts_masked);
 
+       clk_disable_unprepare(swrm->hclk);
        return ret;
 }
 
@@ -1017,6 +1058,15 @@ static int qcom_swrm_startup(struct snd_pcm_substream *substream,
        struct snd_soc_dai *codec_dai;
        int ret, i;
 
+       ret = pm_runtime_get_sync(ctrl->dev);
+       if (ret < 0 && ret != -EACCES) {
+               dev_err_ratelimited(ctrl->dev,
+                                   "pm_runtime_get_sync failed in %s, ret %d\n",
+                                   __func__, ret);
+               pm_runtime_put_noidle(ctrl->dev);
+               return ret;
+       }
+
        sruntime = sdw_alloc_stream(dai->name);
        if (!sruntime)
                return -ENOMEM;
@@ -1044,6 +1094,9 @@ static void qcom_swrm_shutdown(struct snd_pcm_substream *substream,
 
        sdw_release_stream(ctrl->sruntime[dai->id]);
        ctrl->sruntime[dai->id] = NULL;
+       pm_runtime_mark_last_busy(ctrl->dev);
+       pm_runtime_put_autosuspend(ctrl->dev);
+
 }
 
 static const struct snd_soc_dai_ops qcom_swrm_pdm_dai_ops = {
@@ -1197,12 +1250,23 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
 static int swrm_reg_show(struct seq_file *s_file, void *data)
 {
        struct qcom_swrm_ctrl *swrm = s_file->private;
-       int reg, reg_val;
+       int reg, reg_val, ret;
+
+       ret = pm_runtime_get_sync(swrm->dev);
+       if (ret < 0 && ret != -EACCES) {
+               dev_err_ratelimited(swrm->dev,
+                                   "pm_runtime_get_sync failed in %s, ret %d\n",
+                                   __func__, ret);
+               pm_runtime_put_noidle(swrm->dev);
+       }
 
        for (reg = 0; reg <= SWR_MSTR_MAX_REG_ADDR; reg += 4) {
                swrm->reg_read(swrm, reg, &reg_val);
                seq_printf(s_file, "0x%.3x: 0x%.2x\n", reg, reg_val);
        }
+       pm_runtime_mark_last_busy(swrm->dev);
+       pm_runtime_put_autosuspend(swrm->dev);
+
 
        return 0;
 }
@@ -1267,6 +1331,7 @@ static int qcom_swrm_probe(struct platform_device *pdev)
        ctrl->bus.ops = &qcom_swrm_ops;
        ctrl->bus.port_ops = &qcom_swrm_port_ops;
        ctrl->bus.compute_params = &qcom_swrm_compute_params;
+       ctrl->bus.clk_stop_timeout = 300;
 
        ret = qcom_swrm_get_port_config(ctrl);
        if (ret)
@@ -1301,6 +1366,18 @@ static int qcom_swrm_probe(struct platform_device *pdev)
                goto err_clk;
        }
 
+       ctrl->wake_irq = of_irq_get(dev->of_node, 1);
+       if (ctrl->wake_irq > 0) {
+               ret = devm_request_threaded_irq(dev, ctrl->wake_irq, NULL,
+                                               qcom_swrm_wake_irq_handler,
+                                               IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+                                               "swr_wake_irq", ctrl);
+               if (ret) {
+                       dev_err(dev, "Failed to request soundwire wake irq\n");
+                       goto err_init;
+               }
+       }
+
        ret = sdw_bus_master_add(&ctrl->bus, dev, dev->fwnode);
        if (ret) {
                dev_err(dev, "Failed to register Soundwire controller (%d)\n",
@@ -1319,6 +1396,21 @@ static int qcom_swrm_probe(struct platform_device *pdev)
                 (ctrl->version >> 24) & 0xff, (ctrl->version >> 16) & 0xff,
                 ctrl->version & 0xffff);
 
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
+       /* Clk stop is not supported on WSA Soundwire masters */
+       if (ctrl->version <= 0x01030000) {
+               ctrl->clock_stop_not_supported = true;
+       } else {
+               ctrl->reg_read(ctrl, SWRM_COMP_MASTER_ID, &val);
+               if (val == MASTER_ID_WSA)
+                       ctrl->clock_stop_not_supported = true;
+       }
+
 #ifdef CONFIG_DEBUG_FS
        ctrl->debugfs = debugfs_create_dir("qualcomm-sdw", ctrl->bus.debugfs);
        debugfs_create_file("qualcomm-registers", 0400, ctrl->debugfs, ctrl,
@@ -1345,6 +1437,115 @@ static int qcom_swrm_remove(struct platform_device *pdev)
        return 0;
 }
 
+static bool swrm_wait_for_frame_gen_enabled(struct qcom_swrm_ctrl *swrm)
+{
+       int retry = SWRM_LINK_STATUS_RETRY_CNT;
+       int comp_sts;
+
+       do {
+               swrm->reg_read(swrm, SWRM_COMP_STATUS, &comp_sts);
+
+               if (comp_sts & SWRM_FRM_GEN_ENABLED)
+                       return true;
+
+               usleep_range(500, 510);
+       } while (retry--);
+
+       dev_err(swrm->dev, "%s: link status not %s\n", __func__,
+               comp_sts && SWRM_FRM_GEN_ENABLED ? "connected" : "disconnected");
+
+       return false;
+}
+
+static int __maybe_unused swrm_runtime_resume(struct device *dev)
+{
+       struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dev);
+       int ret;
+
+       if (ctrl->wake_irq > 0) {
+               if (!irqd_irq_disabled(irq_get_irq_data(ctrl->wake_irq)))
+                       disable_irq_nosync(ctrl->wake_irq);
+       }
+
+       clk_prepare_enable(ctrl->hclk);
+
+       if (ctrl->clock_stop_not_supported) {
+               reinit_completion(&ctrl->enumeration);
+               ctrl->reg_write(ctrl, SWRM_COMP_SW_RESET, 0x01);
+               usleep_range(100, 105);
+
+               qcom_swrm_init(ctrl);
+
+               usleep_range(100, 105);
+               if (!swrm_wait_for_frame_gen_enabled(ctrl))
+                       dev_err(ctrl->dev, "link failed to connect\n");
+
+               /* wait for hw enumeration to complete */
+               wait_for_completion_timeout(&ctrl->enumeration,
+                                           msecs_to_jiffies(TIMEOUT_MS));
+               qcom_swrm_get_device_status(ctrl);
+               sdw_handle_slave_status(&ctrl->bus, ctrl->status);
+       } else {
+               ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, SWRM_MCP_BUS_CLK_START);
+               ctrl->reg_write(ctrl, SWRM_INTERRUPT_CLEAR,
+                       SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET);
+
+               ctrl->intr_mask |= SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET;
+               ctrl->reg_write(ctrl, SWRM_INTERRUPT_MASK_ADDR, ctrl->intr_mask);
+               ctrl->reg_write(ctrl, SWRM_INTERRUPT_CPU_EN, ctrl->intr_mask);
+
+               usleep_range(100, 105);
+               if (!swrm_wait_for_frame_gen_enabled(ctrl))
+                       dev_err(ctrl->dev, "link failed to connect\n");
+
+               ret = sdw_bus_exit_clk_stop(&ctrl->bus);
+               if (ret < 0)
+                       dev_err(ctrl->dev, "bus failed to exit clock stop %d\n", ret);
+       }
+
+       return 0;
+}
+
+static int __maybe_unused swrm_runtime_suspend(struct device *dev)
+{
+       struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dev);
+       int ret;
+
+       if (!ctrl->clock_stop_not_supported) {
+               /* Mask bus clash interrupt */
+               ctrl->intr_mask &= ~SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET;
+               ctrl->reg_write(ctrl, SWRM_INTERRUPT_MASK_ADDR, ctrl->intr_mask);
+               ctrl->reg_write(ctrl, SWRM_INTERRUPT_CPU_EN, ctrl->intr_mask);
+               /* Prepare slaves for clock stop */
+               ret = sdw_bus_prep_clk_stop(&ctrl->bus);
+               if (ret < 0 && ret != -ENODATA) {
+                       dev_err(dev, "prepare clock stop failed %d", ret);
+                       return ret;
+               }
+
+               ret = sdw_bus_clk_stop(&ctrl->bus);
+               if (ret < 0 && ret != -ENODATA) {
+                       dev_err(dev, "bus clock stop failed %d", ret);
+                       return ret;
+               }
+       }
+
+       clk_disable_unprepare(ctrl->hclk);
+
+       usleep_range(300, 305);
+
+       if (ctrl->wake_irq > 0) {
+               if (irqd_irq_disabled(irq_get_irq_data(ctrl->wake_irq)))
+                       enable_irq(ctrl->wake_irq);
+       }
+
+       return 0;
+}
+
+static const struct dev_pm_ops swrm_dev_pm_ops = {
+       SET_RUNTIME_PM_OPS(swrm_runtime_suspend, swrm_runtime_resume, NULL)
+};
+
 static const struct of_device_id qcom_swrm_of_match[] = {
        { .compatible = "qcom,soundwire-v1.3.0", .data = &swrm_v1_3_data },
        { .compatible = "qcom,soundwire-v1.5.1", .data = &swrm_v1_5_data },
@@ -1359,6 +1560,7 @@ static struct platform_driver qcom_swrm_driver = {
        .driver = {
                .name   = "qcom-soundwire",
                .of_match_table = qcom_swrm_of_match,
+               .pm = &swrm_dev_pm_ops,
        }
 };
 module_platform_driver(qcom_swrm_driver);
index 980f26d..f273459 100644 (file)
@@ -865,117 +865,177 @@ msg_unlock:
        return ret;
 }
 
-/**
- * sdw_release_stream() - Free the assigned stream runtime
- *
- * @stream: SoundWire stream runtime
- *
- * sdw_release_stream should be called only once per stream
- */
-void sdw_release_stream(struct sdw_stream_runtime *stream)
+static struct sdw_port_runtime *sdw_port_alloc(struct list_head *port_list)
 {
-       kfree(stream);
+       struct sdw_port_runtime *p_rt;
+
+       p_rt = kzalloc(sizeof(*p_rt), GFP_KERNEL);
+       if (!p_rt)
+               return NULL;
+
+       list_add_tail(&p_rt->port_node, port_list);
+
+       return p_rt;
 }
-EXPORT_SYMBOL(sdw_release_stream);
 
-/**
- * sdw_alloc_stream() - Allocate and return stream runtime
- *
- * @stream_name: SoundWire stream name
- *
- * Allocates a SoundWire stream runtime instance.
- * sdw_alloc_stream should be called only once per stream. Typically
- * invoked from ALSA/ASoC machine/platform driver.
- */
-struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name)
+static int sdw_port_config(struct sdw_port_runtime *p_rt,
+                          struct sdw_port_config *port_config,
+                          int port_index)
 {
-       struct sdw_stream_runtime *stream;
+       p_rt->ch_mask = port_config[port_index].ch_mask;
+       p_rt->num = port_config[port_index].num;
 
-       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
-       if (!stream)
-               return NULL;
+       /*
+        * TODO: Check port capabilities for requested configuration
+        */
 
-       stream->name = stream_name;
-       INIT_LIST_HEAD(&stream->master_list);
-       stream->state = SDW_STREAM_ALLOCATED;
-       stream->m_rt_count = 0;
+       return 0;
+}
 
-       return stream;
+static void sdw_port_free(struct sdw_port_runtime *p_rt)
+{
+       list_del(&p_rt->port_node);
+       kfree(p_rt);
 }
-EXPORT_SYMBOL(sdw_alloc_stream);
 
-static struct sdw_master_runtime
-*sdw_find_master_rt(struct sdw_bus *bus,
-                   struct sdw_stream_runtime *stream)
+static bool sdw_slave_port_allocated(struct sdw_slave_runtime *s_rt)
 {
+       return !list_empty(&s_rt->port_list);
+}
+
+static void sdw_slave_port_free(struct sdw_slave *slave,
+                               struct sdw_stream_runtime *stream)
+{
+       struct sdw_port_runtime *p_rt, *_p_rt;
        struct sdw_master_runtime *m_rt;
+       struct sdw_slave_runtime *s_rt;
 
-       /* Retrieve Bus handle if already available */
        list_for_each_entry(m_rt, &stream->master_list, stream_node) {
-               if (m_rt->bus == bus)
-                       return m_rt;
+               list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
+                       if (s_rt->slave != slave)
+                               continue;
+
+                       list_for_each_entry_safe(p_rt, _p_rt,
+                                                &s_rt->port_list, port_node) {
+                               sdw_port_free(p_rt);
+                       }
+               }
        }
+}
 
-       return NULL;
+static int sdw_slave_port_alloc(struct sdw_slave *slave,
+                               struct sdw_slave_runtime *s_rt,
+                               unsigned int num_config)
+{
+       struct sdw_port_runtime *p_rt;
+       int i;
+
+       /* Iterate for number of ports to perform initialization */
+       for (i = 0; i < num_config; i++) {
+               p_rt = sdw_port_alloc(&s_rt->port_list);
+               if (!p_rt)
+                       return -ENOMEM;
+       }
+
+       return 0;
 }
 
-/**
- * sdw_alloc_master_rt() - Allocates and initialize Master runtime handle
- *
- * @bus: SDW bus instance
- * @stream_config: Stream configuration
- * @stream: Stream runtime handle.
- *
- * This function is to be called with bus_lock held.
- */
-static struct sdw_master_runtime
-*sdw_alloc_master_rt(struct sdw_bus *bus,
-                    struct sdw_stream_config *stream_config,
-                    struct sdw_stream_runtime *stream)
+static int sdw_slave_port_is_valid_range(struct device *dev, int num)
 {
-       struct sdw_master_runtime *m_rt;
+       if (!SDW_VALID_PORT_RANGE(num)) {
+               dev_err(dev, "SoundWire: Invalid port number :%d\n", num);
+               return -EINVAL;
+       }
 
-       /*
-        * check if Master is already allocated (as a result of Slave adding
-        * it first), if so skip allocation and go to configure
-        */
-       m_rt = sdw_find_master_rt(bus, stream);
-       if (m_rt)
-               goto stream_config;
+       return 0;
+}
 
-       m_rt = kzalloc(sizeof(*m_rt), GFP_KERNEL);
-       if (!m_rt)
-               return NULL;
+static int sdw_slave_port_config(struct sdw_slave *slave,
+                                struct sdw_slave_runtime *s_rt,
+                                struct sdw_port_config *port_config)
+{
+       struct sdw_port_runtime *p_rt;
+       int ret;
+       int i;
 
-       /* Initialization of Master runtime handle */
-       INIT_LIST_HEAD(&m_rt->port_list);
-       INIT_LIST_HEAD(&m_rt->slave_rt_list);
-       list_add_tail(&m_rt->stream_node, &stream->master_list);
+       i = 0;
+       list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
+               /*
+                * TODO: Check valid port range as defined by DisCo/
+                * slave
+                */
+               ret = sdw_slave_port_is_valid_range(&slave->dev, port_config[i].num);
+               if (ret < 0)
+                       return ret;
 
-       list_add_tail(&m_rt->bus_node, &bus->m_rt_list);
+               ret = sdw_port_config(p_rt, port_config, i);
+               if (ret < 0)
+                       return ret;
+               i++;
+       }
 
-stream_config:
-       m_rt->ch_count = stream_config->ch_count;
-       m_rt->bus = bus;
-       m_rt->stream = stream;
-       m_rt->direction = stream_config->direction;
+       return 0;
+}
 
-       return m_rt;
+static bool sdw_master_port_allocated(struct sdw_master_runtime *m_rt)
+{
+       return !list_empty(&m_rt->port_list);
+}
+
+static void sdw_master_port_free(struct sdw_master_runtime *m_rt)
+{
+       struct sdw_port_runtime *p_rt, *_p_rt;
+
+       list_for_each_entry_safe(p_rt, _p_rt, &m_rt->port_list, port_node) {
+               sdw_port_free(p_rt);
+       }
+}
+
+static int sdw_master_port_alloc(struct sdw_master_runtime *m_rt,
+                                unsigned int num_ports)
+{
+       struct sdw_port_runtime *p_rt;
+       int i;
+
+       /* Iterate for number of ports to perform initialization */
+       for (i = 0; i < num_ports; i++) {
+               p_rt = sdw_port_alloc(&m_rt->port_list);
+               if (!p_rt)
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int sdw_master_port_config(struct sdw_master_runtime *m_rt,
+                                 struct sdw_port_config *port_config)
+{
+       struct sdw_port_runtime *p_rt;
+       int ret;
+       int i;
+
+       i = 0;
+       list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
+               ret = sdw_port_config(p_rt, port_config, i);
+               if (ret < 0)
+                       return ret;
+               i++;
+       }
+
+       return 0;
 }
 
 /**
- * sdw_alloc_slave_rt() - Allocate and initialize Slave runtime handle.
+ * sdw_slave_rt_alloc() - Allocate a Slave runtime handle.
  *
  * @slave: Slave handle
- * @stream_config: Stream configuration
- * @stream: Stream runtime handle
+ * @m_rt: Master runtime handle
  *
  * This function is to be called with bus_lock held.
  */
 static struct sdw_slave_runtime
-*sdw_alloc_slave_rt(struct sdw_slave *slave,
-                   struct sdw_stream_config *stream_config,
-                   struct sdw_stream_runtime *stream)
+*sdw_slave_rt_alloc(struct sdw_slave *slave,
+                   struct sdw_master_runtime *m_rt)
 {
        struct sdw_slave_runtime *s_rt;
 
@@ -984,154 +1044,156 @@ static struct sdw_slave_runtime
                return NULL;
 
        INIT_LIST_HEAD(&s_rt->port_list);
-       s_rt->ch_count = stream_config->ch_count;
-       s_rt->direction = stream_config->direction;
        s_rt->slave = slave;
 
+       list_add_tail(&s_rt->m_rt_node, &m_rt->slave_rt_list);
+
        return s_rt;
 }
 
-static void sdw_master_port_release(struct sdw_bus *bus,
-                                   struct sdw_master_runtime *m_rt)
+/**
+ * sdw_slave_rt_config() - Configure a Slave runtime handle.
+ *
+ * @s_rt: Slave runtime handle
+ * @stream_config: Stream configuration
+ *
+ * This function is to be called with bus_lock held.
+ */
+static int sdw_slave_rt_config(struct sdw_slave_runtime *s_rt,
+                              struct sdw_stream_config *stream_config)
 {
-       struct sdw_port_runtime *p_rt, *_p_rt;
+       s_rt->ch_count = stream_config->ch_count;
+       s_rt->direction = stream_config->direction;
 
-       list_for_each_entry_safe(p_rt, _p_rt, &m_rt->port_list, port_node) {
-               list_del(&p_rt->port_node);
-               kfree(p_rt);
-       }
+       return 0;
 }
 
-static void sdw_slave_port_release(struct sdw_bus *bus,
-                                  struct sdw_slave *slave,
-                                  struct sdw_stream_runtime *stream)
+static struct sdw_slave_runtime *sdw_slave_rt_find(struct sdw_slave *slave,
+                                                  struct sdw_stream_runtime *stream)
 {
-       struct sdw_port_runtime *p_rt, *_p_rt;
+       struct sdw_slave_runtime *s_rt, *_s_rt;
        struct sdw_master_runtime *m_rt;
-       struct sdw_slave_runtime *s_rt;
 
        list_for_each_entry(m_rt, &stream->master_list, stream_node) {
-               list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
-                       if (s_rt->slave != slave)
-                               continue;
-
-                       list_for_each_entry_safe(p_rt, _p_rt,
-                                                &s_rt->port_list, port_node) {
-                               list_del(&p_rt->port_node);
-                               kfree(p_rt);
-                       }
+               /* Retrieve Slave runtime handle */
+               list_for_each_entry_safe(s_rt, _s_rt,
+                                        &m_rt->slave_rt_list, m_rt_node) {
+                       if (s_rt->slave == slave)
+                               return s_rt;
                }
        }
+       return NULL;
 }
 
 /**
- * sdw_release_slave_stream() - Free Slave(s) runtime handle
+ * sdw_slave_rt_free() - Free Slave(s) runtime handle
  *
  * @slave: Slave handle.
  * @stream: Stream runtime handle.
  *
  * This function is to be called with bus_lock held.
  */
-static void sdw_release_slave_stream(struct sdw_slave *slave,
-                                    struct sdw_stream_runtime *stream)
+static void sdw_slave_rt_free(struct sdw_slave *slave,
+                             struct sdw_stream_runtime *stream)
+{
+       struct sdw_slave_runtime *s_rt;
+
+       s_rt = sdw_slave_rt_find(slave, stream);
+       if (s_rt) {
+               list_del(&s_rt->m_rt_node);
+               kfree(s_rt);
+       }
+}
+
+static struct sdw_master_runtime
+*sdw_master_rt_find(struct sdw_bus *bus,
+                   struct sdw_stream_runtime *stream)
 {
-       struct sdw_slave_runtime *s_rt, *_s_rt;
        struct sdw_master_runtime *m_rt;
 
+       /* Retrieve Bus handle if already available */
        list_for_each_entry(m_rt, &stream->master_list, stream_node) {
-               /* Retrieve Slave runtime handle */
-               list_for_each_entry_safe(s_rt, _s_rt,
-                                        &m_rt->slave_rt_list, m_rt_node) {
-                       if (s_rt->slave == slave) {
-                               list_del(&s_rt->m_rt_node);
-                               kfree(s_rt);
-                               return;
-                       }
-               }
+               if (m_rt->bus == bus)
+                       return m_rt;
        }
+
+       return NULL;
 }
 
 /**
- * sdw_release_master_stream() - Free Master runtime handle
+ * sdw_master_rt_alloc() - Allocates a Master runtime handle
  *
- * @m_rt: Master runtime node
+ * @bus: SDW bus instance
  * @stream: Stream runtime handle.
  *
- * This function is to be called with bus_lock held
- * It frees the Master runtime handle and associated Slave(s) runtime
- * handle. If this is called first then sdw_release_slave_stream() will have
- * no effect as Slave(s) runtime handle would already be freed up.
+ * This function is to be called with bus_lock held.
  */
-static void sdw_release_master_stream(struct sdw_master_runtime *m_rt,
-                                     struct sdw_stream_runtime *stream)
+static struct sdw_master_runtime
+*sdw_master_rt_alloc(struct sdw_bus *bus,
+                    struct sdw_stream_runtime *stream)
 {
-       struct sdw_slave_runtime *s_rt, *_s_rt;
+       struct sdw_master_runtime *m_rt;
 
-       list_for_each_entry_safe(s_rt, _s_rt, &m_rt->slave_rt_list, m_rt_node) {
-               sdw_slave_port_release(s_rt->slave->bus, s_rt->slave, stream);
-               sdw_release_slave_stream(s_rt->slave, stream);
-       }
+       m_rt = kzalloc(sizeof(*m_rt), GFP_KERNEL);
+       if (!m_rt)
+               return NULL;
 
-       list_del(&m_rt->stream_node);
-       list_del(&m_rt->bus_node);
-       kfree(m_rt);
+       /* Initialization of Master runtime handle */
+       INIT_LIST_HEAD(&m_rt->port_list);
+       INIT_LIST_HEAD(&m_rt->slave_rt_list);
+       list_add_tail(&m_rt->stream_node, &stream->master_list);
+
+       list_add_tail(&m_rt->bus_node, &bus->m_rt_list);
+
+       m_rt->bus = bus;
+       m_rt->stream = stream;
+
+       return m_rt;
 }
 
 /**
- * sdw_stream_remove_master() - Remove master from sdw_stream
+ * sdw_master_rt_config() - Configure Master runtime handle
  *
- * @bus: SDW Bus instance
- * @stream: SoundWire stream
+ * @m_rt: Master runtime handle
+ * @stream_config: Stream configuration
  *
- * This removes and frees port_rt and master_rt from a stream
+ * This function is to be called with bus_lock held.
  */
-int sdw_stream_remove_master(struct sdw_bus *bus,
-                            struct sdw_stream_runtime *stream)
-{
-       struct sdw_master_runtime *m_rt, *_m_rt;
 
-       mutex_lock(&bus->bus_lock);
-
-       list_for_each_entry_safe(m_rt, _m_rt,
-                                &stream->master_list, stream_node) {
-               if (m_rt->bus != bus)
-                       continue;
-
-               sdw_master_port_release(bus, m_rt);
-               sdw_release_master_stream(m_rt, stream);
-               stream->m_rt_count--;
-       }
-
-       if (list_empty(&stream->master_list))
-               stream->state = SDW_STREAM_RELEASED;
-
-       mutex_unlock(&bus->bus_lock);
+static int sdw_master_rt_config(struct sdw_master_runtime *m_rt,
+                               struct sdw_stream_config *stream_config)
+{
+       m_rt->ch_count = stream_config->ch_count;
+       m_rt->direction = stream_config->direction;
 
        return 0;
 }
-EXPORT_SYMBOL(sdw_stream_remove_master);
 
 /**
- * sdw_stream_remove_slave() - Remove slave from sdw_stream
+ * sdw_master_rt_free() - Free Master runtime handle
  *
- * @slave: SDW Slave instance
- * @stream: SoundWire stream
+ * @m_rt: Master runtime node
+ * @stream: Stream runtime handle.
  *
- * This removes and frees port_rt and slave_rt from a stream
+ * This function is to be called with bus_lock held
+ * It frees the Master runtime handle and associated Slave(s) runtime
+ * handle. If this is called first then sdw_slave_rt_free() will have
+ * no effect as Slave(s) runtime handle would already be freed up.
  */
-int sdw_stream_remove_slave(struct sdw_slave *slave,
-                           struct sdw_stream_runtime *stream)
+static void sdw_master_rt_free(struct sdw_master_runtime *m_rt,
+                              struct sdw_stream_runtime *stream)
 {
-       mutex_lock(&slave->bus->bus_lock);
-
-       sdw_slave_port_release(slave->bus, slave, stream);
-       sdw_release_slave_stream(slave, stream);
+       struct sdw_slave_runtime *s_rt, *_s_rt;
 
-       mutex_unlock(&slave->bus->bus_lock);
+       list_for_each_entry_safe(s_rt, _s_rt, &m_rt->slave_rt_list, m_rt_node) {
+               sdw_slave_port_free(s_rt->slave, stream);
+               sdw_slave_rt_free(s_rt->slave, stream);
+       }
 
-       return 0;
+       list_del(&m_rt->stream_node);
+       list_del(&m_rt->bus_node);
+       kfree(m_rt);
 }
-EXPORT_SYMBOL(sdw_stream_remove_slave);
 
 /**
  * sdw_config_stream() - Configure the allocated stream
@@ -1172,248 +1234,12 @@ static int sdw_config_stream(struct device *dev,
        stream->params.rate = stream_config->frame_rate;
        stream->params.bps = stream_config->bps;
 
-       /* TODO: Update this check during Device-device support */
-       if (is_slave)
-               stream->params.ch_count += stream_config->ch_count;
-
-       return 0;
-}
-
-static int sdw_is_valid_port_range(struct device *dev,
-                                  struct sdw_port_runtime *p_rt)
-{
-       if (!SDW_VALID_PORT_RANGE(p_rt->num)) {
-               dev_err(dev,
-                       "SoundWire: Invalid port number :%d\n", p_rt->num);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static struct sdw_port_runtime
-*sdw_port_alloc(struct device *dev,
-               struct sdw_port_config *port_config,
-               int port_index)
-{
-       struct sdw_port_runtime *p_rt;
-
-       p_rt = kzalloc(sizeof(*p_rt), GFP_KERNEL);
-       if (!p_rt)
-               return NULL;
-
-       p_rt->ch_mask = port_config[port_index].ch_mask;
-       p_rt->num = port_config[port_index].num;
-
-       return p_rt;
-}
-
-static int sdw_master_port_config(struct sdw_bus *bus,
-                                 struct sdw_master_runtime *m_rt,
-                                 struct sdw_port_config *port_config,
-                                 unsigned int num_ports)
-{
-       struct sdw_port_runtime *p_rt;
-       int i;
-
-       /* Iterate for number of ports to perform initialization */
-       for (i = 0; i < num_ports; i++) {
-               p_rt = sdw_port_alloc(bus->dev, port_config, i);
-               if (!p_rt)
-                       return -ENOMEM;
-
-               /*
-                * TODO: Check port capabilities for requested
-                * configuration (audio mode support)
-                */
-
-               list_add_tail(&p_rt->port_node, &m_rt->port_list);
-       }
-
-       return 0;
-}
-
-static int sdw_slave_port_config(struct sdw_slave *slave,
-                                struct sdw_slave_runtime *s_rt,
-                                struct sdw_port_config *port_config,
-                                unsigned int num_config)
-{
-       struct sdw_port_runtime *p_rt;
-       int i, ret;
-
-       /* Iterate for number of ports to perform initialization */
-       for (i = 0; i < num_config; i++) {
-               p_rt = sdw_port_alloc(&slave->dev, port_config, i);
-               if (!p_rt)
-                       return -ENOMEM;
-
-               /*
-                * TODO: Check valid port range as defined by DisCo/
-                * slave
-                */
-               ret = sdw_is_valid_port_range(&slave->dev, p_rt);
-               if (ret < 0) {
-                       kfree(p_rt);
-                       return ret;
-               }
-
-               /*
-                * TODO: Check port capabilities for requested
-                * configuration (audio mode support)
-                */
-
-               list_add_tail(&p_rt->port_node, &s_rt->port_list);
-       }
-
-       return 0;
-}
-
-/**
- * sdw_stream_add_master() - Allocate and add master runtime to a stream
- *
- * @bus: SDW Bus instance
- * @stream_config: Stream configuration for audio stream
- * @port_config: Port configuration for audio stream
- * @num_ports: Number of ports
- * @stream: SoundWire stream
- */
-int sdw_stream_add_master(struct sdw_bus *bus,
-                         struct sdw_stream_config *stream_config,
-                         struct sdw_port_config *port_config,
-                         unsigned int num_ports,
-                         struct sdw_stream_runtime *stream)
-{
-       struct sdw_master_runtime *m_rt;
-       int ret;
-
-       mutex_lock(&bus->bus_lock);
-
-       /*
-        * For multi link streams, add the second master only if
-        * the bus supports it.
-        * Check if bus->multi_link is set
-        */
-       if (!bus->multi_link && stream->m_rt_count > 0) {
-               dev_err(bus->dev,
-                       "Multilink not supported, link %d\n", bus->link_id);
-               ret = -EINVAL;
-               goto unlock;
-       }
-
-       m_rt = sdw_alloc_master_rt(bus, stream_config, stream);
-       if (!m_rt) {
-               dev_err(bus->dev,
-                       "Master runtime config failed for stream:%s\n",
-                       stream->name);
-               ret = -ENOMEM;
-               goto unlock;
-       }
-
-       ret = sdw_config_stream(bus->dev, stream, stream_config, false);
-       if (ret)
-               goto stream_error;
-
-       ret = sdw_master_port_config(bus, m_rt, port_config, num_ports);
-       if (ret)
-               goto stream_error;
-
-       stream->m_rt_count++;
-
-       goto unlock;
-
-stream_error:
-       sdw_release_master_stream(m_rt, stream);
-unlock:
-       mutex_unlock(&bus->bus_lock);
-       return ret;
-}
-EXPORT_SYMBOL(sdw_stream_add_master);
-
-/**
- * sdw_stream_add_slave() - Allocate and add master/slave runtime to a stream
- *
- * @slave: SDW Slave instance
- * @stream_config: Stream configuration for audio stream
- * @stream: SoundWire stream
- * @port_config: Port configuration for audio stream
- * @num_ports: Number of ports
- *
- * It is expected that Slave is added before adding Master
- * to the Stream.
- *
- */
-int sdw_stream_add_slave(struct sdw_slave *slave,
-                        struct sdw_stream_config *stream_config,
-                        struct sdw_port_config *port_config,
-                        unsigned int num_ports,
-                        struct sdw_stream_runtime *stream)
-{
-       struct sdw_slave_runtime *s_rt;
-       struct sdw_master_runtime *m_rt;
-       int ret;
-
-       mutex_lock(&slave->bus->bus_lock);
-
-       /*
-        * If this API is invoked by Slave first then m_rt is not valid.
-        * So, allocate m_rt and add Slave to it.
-        */
-       m_rt = sdw_alloc_master_rt(slave->bus, stream_config, stream);
-       if (!m_rt) {
-               dev_err(&slave->dev,
-                       "alloc master runtime failed for stream:%s\n",
-                       stream->name);
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       s_rt = sdw_alloc_slave_rt(slave, stream_config, stream);
-       if (!s_rt) {
-               dev_err(&slave->dev,
-                       "Slave runtime config failed for stream:%s\n",
-                       stream->name);
-               ret = -ENOMEM;
-               goto stream_error;
-       }
-
-       ret = sdw_config_stream(&slave->dev, stream, stream_config, true);
-       if (ret) {
-               /*
-                * sdw_release_master_stream will release s_rt in slave_rt_list in
-                * stream_error case, but s_rt is only added to slave_rt_list
-                * when sdw_config_stream is successful, so free s_rt explicitly
-                * when sdw_config_stream is failed.
-                */
-               kfree(s_rt);
-               goto stream_error;
-       }
-
-       list_add_tail(&s_rt->m_rt_node, &m_rt->slave_rt_list);
-
-       ret = sdw_slave_port_config(slave, s_rt, port_config, num_ports);
-       if (ret)
-               goto stream_error;
-
-       /*
-        * Change stream state to CONFIGURED on first Slave add.
-        * Bus is not aware of number of Slave(s) in a stream at this
-        * point so cannot depend on all Slave(s) to be added in order to
-        * change stream state to CONFIGURED.
-        */
-       stream->state = SDW_STREAM_CONFIGURED;
-       goto error;
-
-stream_error:
-       /*
-        * we hit error so cleanup the stream, release all Slave(s) and
-        * Master runtime
-        */
-       sdw_release_master_stream(m_rt, stream);
-error:
-       mutex_unlock(&slave->bus->bus_lock);
-       return ret;
+       /* TODO: Update this check during Device-device support */
+       if (is_slave)
+               stream->params.ch_count += stream_config->ch_count;
+
+       return 0;
 }
-EXPORT_SYMBOL(sdw_stream_add_slave);
 
 /**
  * sdw_get_slave_dpn_prop() - Get Slave port capabilities
@@ -1679,6 +1505,11 @@ int sdw_enable_stream(struct sdw_stream_runtime *stream)
 
        sdw_acquire_bus_lock(stream);
 
+       if (stream->state == SDW_STREAM_ENABLED) {
+               ret = 0;
+               goto state_err;
+       }
+
        if (stream->state != SDW_STREAM_PREPARED &&
            stream->state != SDW_STREAM_DISABLED) {
                pr_err("%s: %s: inconsistent state state %d\n",
@@ -1762,6 +1593,11 @@ int sdw_disable_stream(struct sdw_stream_runtime *stream)
 
        sdw_acquire_bus_lock(stream);
 
+       if (stream->state == SDW_STREAM_DISABLED) {
+               ret = 0;
+               goto state_err;
+       }
+
        if (stream->state != SDW_STREAM_ENABLED) {
                pr_err("%s: %s: inconsistent state state %d\n",
                       __func__, stream->name, stream->state);
@@ -1837,6 +1673,11 @@ int sdw_deprepare_stream(struct sdw_stream_runtime *stream)
 
        sdw_acquire_bus_lock(stream);
 
+       if (stream->state == SDW_STREAM_DEPREPARED) {
+               ret = 0;
+               goto state_err;
+       }
+
        if (stream->state != SDW_STREAM_PREPARED &&
            stream->state != SDW_STREAM_DISABLED) {
                pr_err("%s: %s: inconsistent state state %d\n",
@@ -1873,6 +1714,32 @@ static int set_stream(struct snd_pcm_substream *substream,
        return ret;
 }
 
+/**
+ * sdw_alloc_stream() - Allocate and return stream runtime
+ *
+ * @stream_name: SoundWire stream name
+ *
+ * Allocates a SoundWire stream runtime instance.
+ * sdw_alloc_stream should be called only once per stream. Typically
+ * invoked from ALSA/ASoC machine/platform driver.
+ */
+struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name)
+{
+       struct sdw_stream_runtime *stream;
+
+       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+       if (!stream)
+               return NULL;
+
+       stream->name = stream_name;
+       INIT_LIST_HEAD(&stream->master_list);
+       stream->state = SDW_STREAM_ALLOCATED;
+       stream->m_rt_count = 0;
+
+       return stream;
+}
+EXPORT_SYMBOL(sdw_alloc_stream);
+
 /**
  * sdw_startup_stream() - Startup SoundWire stream
  *
@@ -1949,3 +1816,270 @@ void sdw_shutdown_stream(void *sdw_substream)
        set_stream(substream, NULL);
 }
 EXPORT_SYMBOL(sdw_shutdown_stream);
+
+/**
+ * sdw_release_stream() - Free the assigned stream runtime
+ *
+ * @stream: SoundWire stream runtime
+ *
+ * sdw_release_stream should be called only once per stream
+ */
+void sdw_release_stream(struct sdw_stream_runtime *stream)
+{
+       kfree(stream);
+}
+EXPORT_SYMBOL(sdw_release_stream);
+
+/**
+ * sdw_stream_add_master() - Allocate and add master runtime to a stream
+ *
+ * @bus: SDW Bus instance
+ * @stream_config: Stream configuration for audio stream
+ * @port_config: Port configuration for audio stream
+ * @num_ports: Number of ports
+ * @stream: SoundWire stream
+ */
+int sdw_stream_add_master(struct sdw_bus *bus,
+                         struct sdw_stream_config *stream_config,
+                         struct sdw_port_config *port_config,
+                         unsigned int num_ports,
+                         struct sdw_stream_runtime *stream)
+{
+       struct sdw_master_runtime *m_rt;
+       bool alloc_master_rt = true;
+       int ret;
+
+       mutex_lock(&bus->bus_lock);
+
+       /*
+        * For multi link streams, add the second master only if
+        * the bus supports it.
+        * Check if bus->multi_link is set
+        */
+       if (!bus->multi_link && stream->m_rt_count > 0) {
+               dev_err(bus->dev,
+                       "Multilink not supported, link %d\n", bus->link_id);
+               ret = -EINVAL;
+               goto unlock;
+       }
+
+       /*
+        * check if Master is already allocated (e.g. as a result of Slave adding
+        * it first), if so skip allocation and go to configuration
+        */
+       m_rt = sdw_master_rt_find(bus, stream);
+       if (m_rt) {
+               alloc_master_rt = false;
+               goto skip_alloc_master_rt;
+       }
+
+       m_rt = sdw_master_rt_alloc(bus, stream);
+       if (!m_rt) {
+               dev_err(bus->dev, "Master runtime alloc failed for stream:%s\n", stream->name);
+               ret = -ENOMEM;
+               goto unlock;
+       }
+skip_alloc_master_rt:
+
+       if (sdw_master_port_allocated(m_rt))
+               goto skip_alloc_master_port;
+
+       ret = sdw_master_port_alloc(m_rt, num_ports);
+       if (ret)
+               goto alloc_error;
+
+       stream->m_rt_count++;
+
+skip_alloc_master_port:
+
+       ret = sdw_master_rt_config(m_rt, stream_config);
+       if (ret < 0)
+               goto unlock;
+
+       ret = sdw_config_stream(bus->dev, stream, stream_config, false);
+       if (ret)
+               goto unlock;
+
+       ret = sdw_master_port_config(m_rt, port_config);
+
+       goto unlock;
+
+alloc_error:
+       /*
+        * we only cleanup what was allocated in this routine
+        */
+       if (alloc_master_rt)
+               sdw_master_rt_free(m_rt, stream);
+unlock:
+       mutex_unlock(&bus->bus_lock);
+       return ret;
+}
+EXPORT_SYMBOL(sdw_stream_add_master);
+
+/**
+ * sdw_stream_remove_master() - Remove master from sdw_stream
+ *
+ * @bus: SDW Bus instance
+ * @stream: SoundWire stream
+ *
+ * This removes and frees port_rt and master_rt from a stream
+ */
+int sdw_stream_remove_master(struct sdw_bus *bus,
+                            struct sdw_stream_runtime *stream)
+{
+       struct sdw_master_runtime *m_rt, *_m_rt;
+
+       mutex_lock(&bus->bus_lock);
+
+       list_for_each_entry_safe(m_rt, _m_rt,
+                                &stream->master_list, stream_node) {
+               if (m_rt->bus != bus)
+                       continue;
+
+               sdw_master_port_free(m_rt);
+               sdw_master_rt_free(m_rt, stream);
+               stream->m_rt_count--;
+       }
+
+       if (list_empty(&stream->master_list))
+               stream->state = SDW_STREAM_RELEASED;
+
+       mutex_unlock(&bus->bus_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(sdw_stream_remove_master);
+
+/**
+ * sdw_stream_add_slave() - Allocate and add master/slave runtime to a stream
+ *
+ * @slave: SDW Slave instance
+ * @stream_config: Stream configuration for audio stream
+ * @stream: SoundWire stream
+ * @port_config: Port configuration for audio stream
+ * @num_ports: Number of ports
+ *
+ * It is expected that Slave is added before adding Master
+ * to the Stream.
+ *
+ */
+int sdw_stream_add_slave(struct sdw_slave *slave,
+                        struct sdw_stream_config *stream_config,
+                        struct sdw_port_config *port_config,
+                        unsigned int num_ports,
+                        struct sdw_stream_runtime *stream)
+{
+       struct sdw_slave_runtime *s_rt;
+       struct sdw_master_runtime *m_rt;
+       bool alloc_master_rt = true;
+       bool alloc_slave_rt = true;
+
+       int ret;
+
+       mutex_lock(&slave->bus->bus_lock);
+
+       /*
+        * check if Master is already allocated, if so skip allocation
+        * and go to configuration
+        */
+       m_rt = sdw_master_rt_find(slave->bus, stream);
+       if (m_rt) {
+               alloc_master_rt = false;
+               goto skip_alloc_master_rt;
+       }
+
+       /*
+        * If this API is invoked by Slave first then m_rt is not valid.
+        * So, allocate m_rt and add Slave to it.
+        */
+       m_rt = sdw_master_rt_alloc(slave->bus, stream);
+       if (!m_rt) {
+               dev_err(&slave->dev, "Master runtime alloc failed for stream:%s\n", stream->name);
+               ret = -ENOMEM;
+               goto unlock;
+       }
+
+skip_alloc_master_rt:
+       s_rt = sdw_slave_rt_find(slave, stream);
+       if (s_rt)
+               goto skip_alloc_slave_rt;
+
+       s_rt = sdw_slave_rt_alloc(slave, m_rt);
+       if (!s_rt) {
+               dev_err(&slave->dev, "Slave runtime alloc failed for stream:%s\n", stream->name);
+               alloc_slave_rt = false;
+               ret = -ENOMEM;
+               goto alloc_error;
+       }
+
+skip_alloc_slave_rt:
+       if (sdw_slave_port_allocated(s_rt))
+               goto skip_port_alloc;
+
+       ret = sdw_slave_port_alloc(slave, s_rt, num_ports);
+       if (ret)
+               goto alloc_error;
+
+skip_port_alloc:
+       ret =  sdw_master_rt_config(m_rt, stream_config);
+       if (ret)
+               goto unlock;
+
+       ret = sdw_slave_rt_config(s_rt, stream_config);
+       if (ret)
+               goto unlock;
+
+       ret = sdw_config_stream(&slave->dev, stream, stream_config, true);
+       if (ret)
+               goto unlock;
+
+       ret = sdw_slave_port_config(slave, s_rt, port_config);
+       if (ret)
+               goto unlock;
+
+       /*
+        * Change stream state to CONFIGURED on first Slave add.
+        * Bus is not aware of number of Slave(s) in a stream at this
+        * point so cannot depend on all Slave(s) to be added in order to
+        * change stream state to CONFIGURED.
+        */
+       stream->state = SDW_STREAM_CONFIGURED;
+       goto unlock;
+
+alloc_error:
+       /*
+        * we only cleanup what was allocated in this routine. The 'else if'
+        * is intentional, the 'master_rt_free' will call sdw_slave_rt_free()
+        * internally.
+        */
+       if (alloc_master_rt)
+               sdw_master_rt_free(m_rt, stream);
+       else if (alloc_slave_rt)
+               sdw_slave_rt_free(slave, stream);
+unlock:
+       mutex_unlock(&slave->bus->bus_lock);
+       return ret;
+}
+EXPORT_SYMBOL(sdw_stream_add_slave);
+
+/**
+ * sdw_stream_remove_slave() - Remove slave from sdw_stream
+ *
+ * @slave: SDW Slave instance
+ * @stream: SoundWire stream
+ *
+ * This removes and frees port_rt and slave_rt from a stream
+ */
+int sdw_stream_remove_slave(struct sdw_slave *slave,
+                           struct sdw_stream_runtime *stream)
+{
+       mutex_lock(&slave->bus->bus_lock);
+
+       sdw_slave_port_free(slave, stream);
+       sdw_slave_rt_free(slave, stream);
+
+       mutex_unlock(&slave->bus->bus_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(sdw_stream_remove_slave);
index c9a769b..86c7621 100644 (file)
@@ -585,7 +585,7 @@ static void bcm_qspi_chip_select(struct bcm_qspi *qspi, int cs)
        u32 rd = 0;
        u32 wr = 0;
 
-       if (qspi->base[CHIP_SELECT]) {
+       if (cs >= 0 && qspi->base[CHIP_SELECT]) {
                rd = bcm_qspi_read(qspi, CHIP_SELECT, 0);
                wr = (rd & ~0xff) | (1 << cs);
                if (rd == wr)
index c208efe..0bc7daa 100644 (file)
@@ -693,6 +693,11 @@ static int meson_spicc_probe(struct platform_device *pdev)
        writel_relaxed(0, spicc->base + SPICC_INTREG);
 
        irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               ret = irq;
+               goto out_master;
+       }
+
        ret = devm_request_irq(&pdev->dev, irq, meson_spicc_irq,
                               0, NULL, spicc);
        if (ret) {
index a15de10..753bd31 100644 (file)
@@ -624,7 +624,7 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
        else
                mdata->state = MTK_SPI_IDLE;
 
-       if (!master->can_dma(master, master->cur_msg->spi, trans)) {
+       if (!master->can_dma(master, NULL, trans)) {
                if (trans->rx_buf) {
                        cnt = mdata->xfer_len / 4;
                        ioread32_rep(mdata->base + SPI_RX_DATA_REG,
index 553b6b9..c6a1bb0 100644 (file)
@@ -585,6 +585,12 @@ static int rockchip_spi_slave_abort(struct spi_controller *ctlr)
 {
        struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
 
+       if (atomic_read(&rs->state) & RXDMA)
+               dmaengine_terminate_sync(ctlr->dma_rx);
+       if (atomic_read(&rs->state) & TXDMA)
+               dmaengine_terminate_sync(ctlr->dma_tx);
+       atomic_set(&rs->state, 0);
+       spi_enable_chip(rs, false);
        rs->slave_abort = true;
        spi_finalize_current_transfer(ctlr);
 
@@ -654,7 +660,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
        struct spi_controller *ctlr;
        struct resource *mem;
        struct device_node *np = pdev->dev.of_node;
-       u32 rsd_nsecs;
+       u32 rsd_nsecs, num_cs;
        bool slave_mode;
 
        slave_mode = of_property_read_bool(np, "spi-slave");
@@ -764,8 +770,9 @@ static int rockchip_spi_probe(struct platform_device *pdev)
                 * rk spi0 has two native cs, spi1..5 one cs only
                 * if num-cs is missing in the dts, default to 1
                 */
-               if (of_property_read_u16(np, "num-cs", &ctlr->num_chipselect))
-                       ctlr->num_chipselect = 1;
+               if (of_property_read_u32(np, "num-cs", &num_cs))
+                       num_cs = 1;
+               ctlr->num_chipselect = num_cs;
                ctlr->use_gpio_descriptors = true;
        }
        ctlr->dev.of_node = pdev->dev.of_node;
index 514337c..ffdc55f 100644 (file)
@@ -688,7 +688,7 @@ static int stm32_qspi_probe(struct platform_device *pdev)
        struct resource *res;
        int ret, irq;
 
-       ctrl = spi_alloc_master(dev, sizeof(*qspi));
+       ctrl = devm_spi_alloc_master(dev, sizeof(*qspi));
        if (!ctrl)
                return -ENOMEM;
 
@@ -697,58 +697,46 @@ static int stm32_qspi_probe(struct platform_device *pdev)
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi");
        qspi->io_base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(qspi->io_base)) {
-               ret = PTR_ERR(qspi->io_base);
-               goto err_master_put;
-       }
+       if (IS_ERR(qspi->io_base))
+               return PTR_ERR(qspi->io_base);
 
        qspi->phys_base = res->start;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm");
        qspi->mm_base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(qspi->mm_base)) {
-               ret = PTR_ERR(qspi->mm_base);
-               goto err_master_put;
-       }
+       if (IS_ERR(qspi->mm_base))
+               return PTR_ERR(qspi->mm_base);
 
        qspi->mm_size = resource_size(res);
-       if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) {
-               ret = -EINVAL;
-               goto err_master_put;
-       }
+       if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ)
+               return -EINVAL;
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               ret = irq;
-               goto err_master_put;
-       }
+       if (irq < 0)
+               return irq;
 
        ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0,
                               dev_name(dev), qspi);
        if (ret) {
                dev_err(dev, "failed to request irq\n");
-               goto err_master_put;
+               return ret;
        }
 
        init_completion(&qspi->data_completion);
        init_completion(&qspi->match_completion);
 
        qspi->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(qspi->clk)) {
-               ret = PTR_ERR(qspi->clk);
-               goto err_master_put;
-       }
+       if (IS_ERR(qspi->clk))
+               return PTR_ERR(qspi->clk);
 
        qspi->clk_rate = clk_get_rate(qspi->clk);
-       if (!qspi->clk_rate) {
-               ret = -EINVAL;
-               goto err_master_put;
-       }
+       if (!qspi->clk_rate)
+               return -EINVAL;
 
        ret = clk_prepare_enable(qspi->clk);
        if (ret) {
                dev_err(dev, "can not enable the clock\n");
-               goto err_master_put;
+               return ret;
        }
 
        rstc = devm_reset_control_get_exclusive(dev, NULL);
@@ -784,7 +772,7 @@ static int stm32_qspi_probe(struct platform_device *pdev)
        pm_runtime_enable(dev);
        pm_runtime_get_noresume(dev);
 
-       ret = devm_spi_register_master(dev, ctrl);
+       ret = spi_register_master(ctrl);
        if (ret)
                goto err_pm_runtime_free;
 
@@ -806,8 +794,6 @@ err_dma_free:
        stm32_qspi_dma_free(qspi);
 err_clk_disable:
        clk_disable_unprepare(qspi->clk);
-err_master_put:
-       spi_master_put(qspi->ctrl);
 
        return ret;
 }
@@ -817,6 +803,7 @@ static int stm32_qspi_remove(struct platform_device *pdev)
        struct stm32_qspi *qspi = platform_get_drvdata(pdev);
 
        pm_runtime_get_sync(qspi->dev);
+       spi_unregister_master(qspi->ctrl);
        /* disable qspi */
        writel_relaxed(0, qspi->io_base + QSPI_CR);
        stm32_qspi_dma_free(qspi);
index 9bd3fd1..7fc2450 100644 (file)
@@ -221,7 +221,6 @@ struct stm32_spi;
  * time between frames (if driver has this functionality)
  * @set_number_of_data: optional routine to configure registers to desired
  * number of data (if driver has this functionality)
- * @can_dma: routine to determine if the transfer is eligible for DMA use
  * @transfer_one_dma_start: routine to start transfer a single spi_transfer
  * using DMA
  * @dma_rx_cb: routine to call after DMA RX channel operation is complete
@@ -232,7 +231,7 @@ struct stm32_spi;
  * @baud_rate_div_min: minimum baud rate divisor
  * @baud_rate_div_max: maximum baud rate divisor
  * @has_fifo: boolean to know if fifo is used for driver
- * @has_startbit: boolean to know if start bit is used to start transfer
+ * @flags: compatible specific SPI controller flags used at registration time
  */
 struct stm32_spi_cfg {
        const struct stm32_spi_regspec *regs;
@@ -253,6 +252,7 @@ struct stm32_spi_cfg {
        unsigned int baud_rate_div_min;
        unsigned int baud_rate_div_max;
        bool has_fifo;
+       u16 flags;
 };
 
 /**
@@ -1722,6 +1722,7 @@ static const struct stm32_spi_cfg stm32f4_spi_cfg = {
        .baud_rate_div_min = STM32F4_SPI_BR_DIV_MIN,
        .baud_rate_div_max = STM32F4_SPI_BR_DIV_MAX,
        .has_fifo = false,
+       .flags = SPI_MASTER_MUST_TX,
 };
 
 static const struct stm32_spi_cfg stm32h7_spi_cfg = {
@@ -1854,7 +1855,7 @@ static int stm32_spi_probe(struct platform_device *pdev)
        master->prepare_message = stm32_spi_prepare_msg;
        master->transfer_one = stm32_spi_transfer_one;
        master->unprepare_message = stm32_spi_unprepare_msg;
-       master->flags = SPI_MASTER_MUST_TX;
+       master->flags = spi->cfg->flags;
 
        spi->dma_tx = dma_request_chan(spi->dev, "tx");
        if (IS_ERR(spi->dma_tx)) {
index 342ee8d..cc0da48 100644 (file)
@@ -726,7 +726,7 @@ static int uniphier_spi_probe(struct platform_device *pdev)
                if (ret) {
                        dev_err(&pdev->dev, "failed to get TX DMA capacities: %d\n",
                                ret);
-                       goto out_disable_clk;
+                       goto out_release_dma;
                }
                dma_tx_burst = caps.max_burst;
        }
@@ -735,7 +735,7 @@ static int uniphier_spi_probe(struct platform_device *pdev)
        if (IS_ERR_OR_NULL(master->dma_rx)) {
                if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) {
                        ret = -EPROBE_DEFER;
-                       goto out_disable_clk;
+                       goto out_release_dma;
                }
                master->dma_rx = NULL;
                dma_rx_burst = INT_MAX;
@@ -744,7 +744,7 @@ static int uniphier_spi_probe(struct platform_device *pdev)
                if (ret) {
                        dev_err(&pdev->dev, "failed to get RX DMA capacities: %d\n",
                                ret);
-                       goto out_disable_clk;
+                       goto out_release_dma;
                }
                dma_rx_burst = caps.max_burst;
        }
@@ -753,10 +753,20 @@ static int uniphier_spi_probe(struct platform_device *pdev)
 
        ret = devm_spi_register_master(&pdev->dev, master);
        if (ret)
-               goto out_disable_clk;
+               goto out_release_dma;
 
        return 0;
 
+out_release_dma:
+       if (!IS_ERR_OR_NULL(master->dma_rx)) {
+               dma_release_channel(master->dma_rx);
+               master->dma_rx = NULL;
+       }
+       if (!IS_ERR_OR_NULL(master->dma_tx)) {
+               dma_release_channel(master->dma_tx);
+               master->dma_tx = NULL;
+       }
+
 out_disable_clk:
        clk_disable_unprepare(priv->clk);
 
index cfa222c..78f31b6 100644 (file)
@@ -570,6 +570,9 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem,
 
        if (op->dummy.nbytes) {
                tmpbuf = kzalloc(op->dummy.nbytes, GFP_KERNEL);
+               if (!tmpbuf)
+                       return -ENOMEM;
+
                memset(tmpbuf, 0xff, op->dummy.nbytes);
                reinit_completion(&xqspi->data_completion);
                xqspi->txbuf = tmpbuf;
index abe9395..861a154 100644 (file)
@@ -144,6 +144,8 @@ static int init_display(struct fbtft_par *par)
 {
        int rc;
 
+       par->fbtftops.reset(par);
+
        rc = init_tearing_effect_line(par);
        if (rc)
                return rc;
index 4cdec34..55677ef 100644 (file)
@@ -334,7 +334,10 @@ static int __init fbtft_driver_module_init(void)                           \
        ret = spi_register_driver(&fbtft_driver_spi_driver);               \
        if (ret < 0)                                                       \
                return ret;                                                \
-       return platform_driver_register(&fbtft_driver_platform_driver);    \
+       ret = platform_driver_register(&fbtft_driver_platform_driver);     \
+       if (ret < 0)                                                       \
+               spi_unregister_driver(&fbtft_driver_spi_driver);           \
+       return ret;                                                        \
 }                                                                          \
                                                                           \
 static void __exit fbtft_driver_module_exit(void)                          \
index 6759a62..3a2e458 100644 (file)
@@ -1058,15 +1058,27 @@ service_callback(enum vchiq_reason reason, struct vchiq_header *header,
 
        DEBUG_TRACE(SERVICE_CALLBACK_LINE);
 
+       rcu_read_lock();
        service = handle_to_service(handle);
-       if (WARN_ON(!service))
+       if (WARN_ON(!service)) {
+               rcu_read_unlock();
                return VCHIQ_SUCCESS;
+       }
 
        user_service = (struct user_service *)service->base.userdata;
        instance = user_service->instance;
 
-       if (!instance || instance->closing)
+       if (!instance || instance->closing) {
+               rcu_read_unlock();
                return VCHIQ_SUCCESS;
+       }
+
+       /*
+        * As hopping around different synchronization mechanism,
+        * taking an extra reference results in simpler implementation.
+        */
+       vchiq_service_get(service);
+       rcu_read_unlock();
 
        vchiq_log_trace(vchiq_arm_log_level,
                        "%s - service %lx(%d,%p), reason %d, header %lx, instance %lx, bulk_userdata %lx",
@@ -1097,6 +1109,7 @@ service_callback(enum vchiq_reason reason, struct vchiq_header *header,
                                                        bulk_userdata);
                                if (status != VCHIQ_SUCCESS) {
                                        DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+                                       vchiq_service_put(service);
                                        return status;
                                }
                        }
@@ -1105,10 +1118,12 @@ service_callback(enum vchiq_reason reason, struct vchiq_header *header,
                        if (wait_for_completion_interruptible(&user_service->remove_event)) {
                                vchiq_log_info(vchiq_arm_log_level, "%s interrupted", __func__);
                                DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+                               vchiq_service_put(service);
                                return VCHIQ_RETRY;
                        } else if (instance->closing) {
                                vchiq_log_info(vchiq_arm_log_level, "%s closing", __func__);
                                DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+                               vchiq_service_put(service);
                                return VCHIQ_ERROR;
                        }
                        DEBUG_TRACE(SERVICE_CALLBACK_LINE);
@@ -1137,6 +1152,7 @@ service_callback(enum vchiq_reason reason, struct vchiq_header *header,
                header = NULL;
        }
        DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+       vchiq_service_put(service);
 
        if (skip_completion)
                return VCHIQ_SUCCESS;
index 8075f60..2d5cf17 100644 (file)
@@ -443,6 +443,9 @@ static bool iscsit_tpg_check_network_portal(
                                break;
                }
                spin_unlock(&tpg->tpg_np_lock);
+
+               if (match)
+                       break;
        }
        spin_unlock(&tiqn->tiqn_tpg_lock);
 
index 1ca3208..17a6f51 100644 (file)
@@ -158,6 +158,7 @@ void optee_remove_common(struct optee *optee)
        optee_unregister_devices();
 
        optee_notif_uninit(optee);
+       teedev_close_context(optee->ctx);
        /*
         * The two devices have to be unregistered before we can free the
         * other resources.
index 20a1b1a..f2bf6c6 100644 (file)
@@ -424,6 +424,7 @@ static struct tee_shm_pool_mgr *optee_ffa_shm_pool_alloc_pages(void)
  */
 
 static void handle_ffa_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
+                                             struct optee *optee,
                                              struct optee_msg_arg *arg)
 {
        struct tee_shm *shm;
@@ -439,7 +440,7 @@ static void handle_ffa_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
                shm = optee_rpc_cmd_alloc_suppl(ctx, arg->params[0].u.value.b);
                break;
        case OPTEE_RPC_SHM_TYPE_KERNEL:
-               shm = tee_shm_alloc(ctx, arg->params[0].u.value.b,
+               shm = tee_shm_alloc(optee->ctx, arg->params[0].u.value.b,
                                    TEE_SHM_MAPPED | TEE_SHM_PRIV);
                break;
        default:
@@ -493,14 +494,13 @@ err_bad_param:
 }
 
 static void handle_ffa_rpc_func_cmd(struct tee_context *ctx,
+                                   struct optee *optee,
                                    struct optee_msg_arg *arg)
 {
-       struct optee *optee = tee_get_drvdata(ctx->teedev);
-
        arg->ret_origin = TEEC_ORIGIN_COMMS;
        switch (arg->cmd) {
        case OPTEE_RPC_CMD_SHM_ALLOC:
-               handle_ffa_rpc_func_cmd_shm_alloc(ctx, arg);
+               handle_ffa_rpc_func_cmd_shm_alloc(ctx, optee, arg);
                break;
        case OPTEE_RPC_CMD_SHM_FREE:
                handle_ffa_rpc_func_cmd_shm_free(ctx, optee, arg);
@@ -510,12 +510,12 @@ static void handle_ffa_rpc_func_cmd(struct tee_context *ctx,
        }
 }
 
-static void optee_handle_ffa_rpc(struct tee_context *ctx, u32 cmd,
-                                struct optee_msg_arg *arg)
+static void optee_handle_ffa_rpc(struct tee_context *ctx, struct optee *optee,
+                                u32 cmd, struct optee_msg_arg *arg)
 {
        switch (cmd) {
        case OPTEE_FFA_YIELDING_CALL_RETURN_RPC_CMD:
-               handle_ffa_rpc_func_cmd(ctx, arg);
+               handle_ffa_rpc_func_cmd(ctx, optee, arg);
                break;
        case OPTEE_FFA_YIELDING_CALL_RETURN_INTERRUPT:
                /* Interrupt delivered by now */
@@ -582,7 +582,7 @@ static int optee_ffa_yielding_call(struct tee_context *ctx,
                 * above.
                 */
                cond_resched();
-               optee_handle_ffa_rpc(ctx, data->data1, rpc_arg);
+               optee_handle_ffa_rpc(ctx, optee, data->data1, rpc_arg);
                cmd = OPTEE_FFA_YIELDING_CALL_RESUME;
                data->data0 = cmd;
                data->data1 = 0;
@@ -619,9 +619,18 @@ static int optee_ffa_do_call_with_arg(struct tee_context *ctx,
                .data2 = (u32)(shm->sec_world_id >> 32),
                .data3 = shm->offset,
        };
-       struct optee_msg_arg *arg = tee_shm_get_va(shm, 0);
-       unsigned int rpc_arg_offs = OPTEE_MSG_GET_ARG_SIZE(arg->num_params);
-       struct optee_msg_arg *rpc_arg = tee_shm_get_va(shm, rpc_arg_offs);
+       struct optee_msg_arg *arg;
+       unsigned int rpc_arg_offs;
+       struct optee_msg_arg *rpc_arg;
+
+       arg = tee_shm_get_va(shm, 0);
+       if (IS_ERR(arg))
+               return PTR_ERR(arg);
+
+       rpc_arg_offs = OPTEE_MSG_GET_ARG_SIZE(arg->num_params);
+       rpc_arg = tee_shm_get_va(shm, rpc_arg_offs);
+       if (IS_ERR(rpc_arg))
+               return PTR_ERR(rpc_arg);
 
        return optee_ffa_yielding_call(ctx, &data, rpc_arg);
 }
@@ -793,7 +802,9 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 {
        const struct ffa_dev_ops *ffa_ops;
        unsigned int rpc_arg_count;
+       struct tee_shm_pool *pool;
        struct tee_device *teedev;
+       struct tee_context *ctx;
        struct optee *optee;
        int rc;
 
@@ -813,12 +824,12 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
        if (!optee)
                return -ENOMEM;
 
-       optee->pool = optee_ffa_config_dyn_shm();
-       if (IS_ERR(optee->pool)) {
-               rc = PTR_ERR(optee->pool);
-               optee->pool = NULL;
-               goto err;
+       pool = optee_ffa_config_dyn_shm();
+       if (IS_ERR(pool)) {
+               rc = PTR_ERR(pool);
+               goto err_free_optee;
        }
+       optee->pool = pool;
 
        optee->ops = &optee_ffa_ops;
        optee->ffa.ffa_dev = ffa_dev;
@@ -829,7 +840,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
                                  optee);
        if (IS_ERR(teedev)) {
                rc = PTR_ERR(teedev);
-               goto err;
+               goto err_free_pool;
        }
        optee->teedev = teedev;
 
@@ -837,50 +848,57 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
                                  optee);
        if (IS_ERR(teedev)) {
                rc = PTR_ERR(teedev);
-               goto err;
+               goto err_unreg_teedev;
        }
        optee->supp_teedev = teedev;
 
        rc = tee_device_register(optee->teedev);
        if (rc)
-               goto err;
+               goto err_unreg_supp_teedev;
 
        rc = tee_device_register(optee->supp_teedev);
        if (rc)
-               goto err;
+               goto err_unreg_supp_teedev;
 
        rc = rhashtable_init(&optee->ffa.global_ids, &shm_rhash_params);
        if (rc)
-               goto err;
+               goto err_unreg_supp_teedev;
        mutex_init(&optee->ffa.mutex);
        mutex_init(&optee->call_queue.mutex);
        INIT_LIST_HEAD(&optee->call_queue.waiters);
        optee_supp_init(&optee->supp);
        ffa_dev_set_drvdata(ffa_dev, optee);
+       ctx = teedev_open(optee->teedev);
+       if (IS_ERR(ctx))
+               goto err_rhashtable_free;
+       optee->ctx = ctx;
        rc = optee_notif_init(optee, OPTEE_DEFAULT_MAX_NOTIF_VALUE);
-       if (rc) {
-               optee_ffa_remove(ffa_dev);
-               return rc;
-       }
+       if (rc)
+               goto err_close_ctx;
 
        rc = optee_enumerate_devices(PTA_CMD_GET_DEVICES);
-       if (rc) {
-               optee_ffa_remove(ffa_dev);
-               return rc;
-       }
+       if (rc)
+               goto err_unregister_devices;
 
        pr_info("initialized driver\n");
        return 0;
-err:
-       /*
-        * tee_device_unregister() is safe to call even if the
-        * devices hasn't been registered with
-        * tee_device_register() yet.
-        */
+
+err_unregister_devices:
+       optee_unregister_devices();
+       optee_notif_uninit(optee);
+err_close_ctx:
+       teedev_close_context(ctx);
+err_rhashtable_free:
+       rhashtable_free_and_destroy(&optee->ffa.global_ids, rh_free_fn, NULL);
+       optee_supp_uninit(&optee->supp);
+       mutex_destroy(&optee->call_queue.mutex);
+err_unreg_supp_teedev:
        tee_device_unregister(optee->supp_teedev);
+err_unreg_teedev:
        tee_device_unregister(optee->teedev);
-       if (optee->pool)
-               tee_shm_pool_free(optee->pool);
+err_free_pool:
+       tee_shm_pool_free(pool);
+err_free_optee:
        kfree(optee);
        return rc;
 }
index a28fa03..0521284 100644 (file)
@@ -121,5 +121,5 @@ int optee_notif_init(struct optee *optee, u_int max_key)
 
 void optee_notif_uninit(struct optee *optee)
 {
-       kfree(optee->notif.bitmap);
+       bitmap_free(optee->notif.bitmap);
 }
index 46f74ab..92bc47b 100644 (file)
@@ -53,7 +53,6 @@ struct optee_call_queue {
 
 struct optee_notif {
        u_int max_key;
-       struct tee_context *ctx;
        /* Serializes access to the elements below in this struct */
        spinlock_t lock;
        struct list_head db;
@@ -134,9 +133,10 @@ struct optee_ops {
 /**
  * struct optee - main service struct
  * @supp_teedev:       supplicant device
+ * @teedev:            client device
  * @ops:               internal callbacks for different ways to reach secure
  *                     world
- * @teedev:            client device
+ * @ctx:               driver internal TEE context
  * @smc:               specific to SMC ABI
  * @ffa:               specific to FF-A ABI
  * @call_queue:                queue of threads waiting to call @invoke_fn
@@ -152,6 +152,7 @@ struct optee {
        struct tee_device *supp_teedev;
        struct tee_device *teedev;
        const struct optee_ops *ops;
+       struct tee_context *ctx;
        union {
                struct optee_smc smc;
                struct optee_ffa ffa;
index 449d6a7..1a55339 100644 (file)
@@ -75,16 +75,6 @@ static int from_msg_param_tmp_mem(struct tee_param *p, u32 attr,
        p->u.memref.shm_offs = mp->u.tmem.buf_ptr - pa;
        p->u.memref.shm = shm;
 
-       /* Check that the memref is covered by the shm object */
-       if (p->u.memref.size) {
-               size_t o = p->u.memref.shm_offs +
-                          p->u.memref.size - 1;
-
-               rc = tee_shm_get_pa(shm, o, NULL);
-               if (rc)
-                       return rc;
-       }
-
        return 0;
 }
 
@@ -622,6 +612,7 @@ static void handle_rpc_func_cmd_shm_free(struct tee_context *ctx,
 }
 
 static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
+                                         struct optee *optee,
                                          struct optee_msg_arg *arg,
                                          struct optee_call_ctx *call_ctx)
 {
@@ -651,7 +642,8 @@ static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
                shm = optee_rpc_cmd_alloc_suppl(ctx, sz);
                break;
        case OPTEE_RPC_SHM_TYPE_KERNEL:
-               shm = tee_shm_alloc(ctx, sz, TEE_SHM_MAPPED | TEE_SHM_PRIV);
+               shm = tee_shm_alloc(optee->ctx, sz,
+                                   TEE_SHM_MAPPED | TEE_SHM_PRIV);
                break;
        default:
                arg->ret = TEEC_ERROR_BAD_PARAMETERS;
@@ -747,7 +739,7 @@ static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
        switch (arg->cmd) {
        case OPTEE_RPC_CMD_SHM_ALLOC:
                free_pages_list(call_ctx);
-               handle_rpc_func_cmd_shm_alloc(ctx, arg, call_ctx);
+               handle_rpc_func_cmd_shm_alloc(ctx, optee, arg, call_ctx);
                break;
        case OPTEE_RPC_CMD_SHM_FREE:
                handle_rpc_func_cmd_shm_free(ctx, arg);
@@ -776,7 +768,7 @@ static void optee_handle_rpc(struct tee_context *ctx,
 
        switch (OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0)) {
        case OPTEE_SMC_RPC_FUNC_ALLOC:
-               shm = tee_shm_alloc(ctx, param->a1,
+               shm = tee_shm_alloc(optee->ctx, param->a1,
                                    TEE_SHM_MAPPED | TEE_SHM_PRIV);
                if (!IS_ERR(shm) && !tee_shm_get_pa(shm, 0, &pa)) {
                        reg_pair_from_64(&param->a1, &param->a2, pa);
@@ -954,57 +946,34 @@ static irqreturn_t notif_irq_thread_fn(int irq, void *dev_id)
 {
        struct optee *optee = dev_id;
 
-       optee_smc_do_bottom_half(optee->notif.ctx);
+       optee_smc_do_bottom_half(optee->ctx);
 
        return IRQ_HANDLED;
 }
 
 static int optee_smc_notif_init_irq(struct optee *optee, u_int irq)
 {
-       struct tee_context *ctx;
        int rc;
 
-       ctx = teedev_open(optee->teedev);
-       if (IS_ERR(ctx))
-               return PTR_ERR(ctx);
-
-       optee->notif.ctx = ctx;
        rc = request_threaded_irq(irq, notif_irq_handler,
                                  notif_irq_thread_fn,
                                  0, "optee_notification", optee);
        if (rc)
-               goto err_close_ctx;
+               return rc;
 
        optee->smc.notif_irq = irq;
 
        return 0;
-
-err_close_ctx:
-       teedev_close_context(optee->notif.ctx);
-       optee->notif.ctx = NULL;
-
-       return rc;
 }
 
 static void optee_smc_notif_uninit_irq(struct optee *optee)
 {
-       if (optee->notif.ctx) {
-               optee_smc_stop_async_notif(optee->notif.ctx);
+       if (optee->smc.sec_caps & OPTEE_SMC_SEC_CAP_ASYNC_NOTIF) {
+               optee_smc_stop_async_notif(optee->ctx);
                if (optee->smc.notif_irq) {
                        free_irq(optee->smc.notif_irq, optee);
                        irq_dispose_mapping(optee->smc.notif_irq);
                }
-
-               /*
-                * The thread normally working with optee->notif.ctx was
-                * stopped with free_irq() above.
-                *
-                * Note we're not using teedev_close_context() or
-                * tee_client_close_context() since we have already called
-                * tee_device_put() while initializing to avoid a circular
-                * reference counting.
-                */
-               teedev_close_context(optee->notif.ctx);
        }
 }
 
@@ -1366,6 +1335,7 @@ static int optee_probe(struct platform_device *pdev)
        struct optee *optee = NULL;
        void *memremaped_shm = NULL;
        struct tee_device *teedev;
+       struct tee_context *ctx;
        u32 max_notif_value;
        u32 sec_caps;
        int rc;
@@ -1446,9 +1416,13 @@ static int optee_probe(struct platform_device *pdev)
        optee->pool = pool;
 
        platform_set_drvdata(pdev, optee);
+       ctx = teedev_open(optee->teedev);
+       if (IS_ERR(ctx))
+               goto err_supp_uninit;
+       optee->ctx = ctx;
        rc = optee_notif_init(optee, max_notif_value);
        if (rc)
-               goto err_supp_uninit;
+               goto err_close_ctx;
 
        if (sec_caps & OPTEE_SMC_SEC_CAP_ASYNC_NOTIF) {
                unsigned int irq;
@@ -1496,6 +1470,8 @@ err_disable_shm_cache:
        optee_unregister_devices();
 err_notif_uninit:
        optee_notif_uninit(optee);
+err_close_ctx:
+       teedev_close_context(ctx);
 err_supp_uninit:
        optee_supp_uninit(&optee->supp);
        mutex_destroy(&optee->call_queue.mutex);
index 72acb1f..4f47881 100644 (file)
@@ -404,6 +404,10 @@ static void int3400_notify(acpi_handle handle,
        thermal_prop[3] = kasprintf(GFP_KERNEL, "EVENT=%d", therm_event);
        thermal_prop[4] = NULL;
        kobject_uevent_env(&priv->thermal->device.kobj, KOBJ_CHANGE, thermal_prop);
+       kfree(thermal_prop[0]);
+       kfree(thermal_prop[1]);
+       kfree(thermal_prop[2]);
+       kfree(thermal_prop[3]);
 }
 
 static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
index 3a53369..b3f3103 100644 (file)
@@ -154,10 +154,8 @@ int tb_nvm_add_non_active(struct tb_nvm *nvm, size_t size,
 void tb_nvm_free(struct tb_nvm *nvm)
 {
        if (nvm) {
-               if (nvm->non_active)
-                       nvmem_unregister(nvm->non_active);
-               if (nvm->active)
-                       nvmem_unregister(nvm->active);
+               nvmem_unregister(nvm->non_active);
+               nvmem_unregister(nvm->active);
                vfree(nvm->buf);
                ida_simple_remove(&nvm_ida, nvm->id);
        }
index ba27b27..fa92f72 100644 (file)
@@ -322,6 +322,7 @@ static int addr_cnt;
 #define GSM1_ESCAPE_BITS       0x20
 #define XON                    0x11
 #define XOFF                   0x13
+#define ISO_IEC_646_MASK       0x7F
 
 static const struct tty_port_operations gsm_port_ops;
 
@@ -438,7 +439,7 @@ static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
                modembits |= MDM_RTR;
        if (dlci->modem_tx & TIOCM_RI)
                modembits |= MDM_IC;
-       if (dlci->modem_tx & TIOCM_CD)
+       if (dlci->modem_tx & TIOCM_CD || dlci->gsm->initiator)
                modembits |= MDM_DV;
        return modembits;
 }
@@ -447,7 +448,7 @@ static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
  *     gsm_print_packet        -       display a frame for debug
  *     @hdr: header to print before decode
  *     @addr: address EA from the frame
- *     @cr: C/R bit from the frame
+ *     @cr: C/R bit seen as initiator
  *     @control: control including PF bit
  *     @data: following data bytes
  *     @dlen: length of data
@@ -531,7 +532,8 @@ static int gsm_stuff_frame(const u8 *input, u8 *output, int len)
        int olen = 0;
        while (len--) {
                if (*input == GSM1_SOF || *input == GSM1_ESCAPE
-                   || *input == XON || *input == XOFF) {
+                   || (*input & ISO_IEC_646_MASK) == XON
+                   || (*input & ISO_IEC_646_MASK) == XOFF) {
                        *output++ = GSM1_ESCAPE;
                        *output++ = *input++ ^ GSM1_ESCAPE_BITS;
                        olen++;
@@ -546,7 +548,7 @@ static int gsm_stuff_frame(const u8 *input, u8 *output, int len)
  *     gsm_send        -       send a control frame
  *     @gsm: our GSM mux
  *     @addr: address for control frame
- *     @cr: command/response bit
+ *     @cr: command/response bit seen as initiator
  *     @control:  control byte including PF bit
  *
  *     Format up and transmit a control frame. These do not go via the
@@ -561,11 +563,15 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
        int len;
        u8 cbuf[10];
        u8 ibuf[3];
+       int ocr;
+
+       /* toggle C/R coding if not initiator */
+       ocr = cr ^ (gsm->initiator ? 0 : 1);
 
        switch (gsm->encoding) {
        case 0:
                cbuf[0] = GSM0_SOF;
-               cbuf[1] = (addr << 2) | (cr << 1) | EA;
+               cbuf[1] = (addr << 2) | (ocr << 1) | EA;
                cbuf[2] = control;
                cbuf[3] = EA;   /* Length of data = 0 */
                cbuf[4] = 0xFF - gsm_fcs_add_block(INIT_FCS, cbuf + 1, 3);
@@ -575,7 +581,7 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
        case 1:
        case 2:
                /* Control frame + packing (but not frame stuffing) in mode 1 */
-               ibuf[0] = (addr << 2) | (cr << 1) | EA;
+               ibuf[0] = (addr << 2) | (ocr << 1) | EA;
                ibuf[1] = control;
                ibuf[2] = 0xFF - gsm_fcs_add_block(INIT_FCS, ibuf, 2);
                /* Stuffing may double the size worst case */
@@ -609,7 +615,7 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
 
 static inline void gsm_response(struct gsm_mux *gsm, int addr, int control)
 {
-       gsm_send(gsm, addr, 1, control);
+       gsm_send(gsm, addr, 0, control);
 }
 
 /**
@@ -1015,25 +1021,25 @@ static void gsm_control_reply(struct gsm_mux *gsm, int cmd, const u8 *data,
  *     @tty: virtual tty bound to the DLCI
  *     @dlci: DLCI to affect
  *     @modem: modem bits (full EA)
- *     @clen: command length
+ *     @slen: number of signal octets
  *
  *     Used when a modem control message or line state inline in adaption
  *     layer 2 is processed. Sort out the local modem state and throttles
  */
 
 static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
-                                                       u32 modem, int clen)
+                                                       u32 modem, int slen)
 {
        int  mlines = 0;
        u8 brk = 0;
        int fc;
 
-       /* The modem status command can either contain one octet (v.24 signals)
-          or two octets (v.24 signals + break signals). The length field will
-          either be 2 or 3 respectively. This is specified in section
-          5.4.6.3.7 of the  27.010 mux spec. */
+       /* The modem status command can either contain one octet (V.24 signals)
+        * or two octets (V.24 signals + break signals). This is specified in
+        * section 5.4.6.3.7 of the 07.10 mux spec.
+        */
 
-       if (clen == 2)
+       if (slen == 1)
                modem = modem & 0x7f;
        else {
                brk = modem & 0x7f;
@@ -1090,6 +1096,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
        unsigned int brk = 0;
        struct gsm_dlci *dlci;
        int len = clen;
+       int slen;
        const u8 *dp = data;
        struct tty_struct *tty;
 
@@ -1109,6 +1116,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
                return;
        dlci = gsm->dlci[addr];
 
+       slen = len;
        while (gsm_read_ea(&modem, *dp++) == 0) {
                len--;
                if (len == 0)
@@ -1125,7 +1133,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
                modem |= (brk & 0x7f);
        }
        tty = tty_port_tty_get(&dlci->port);
-       gsm_process_modem(tty, dlci, modem, clen);
+       gsm_process_modem(tty, dlci, modem, slen);
        if (tty) {
                tty_wakeup(tty);
                tty_kref_put(tty);
@@ -1449,6 +1457,9 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
        if (dlci->addr != 0) {
                tty_port_tty_hangup(&dlci->port, false);
                kfifo_reset(&dlci->fifo);
+               /* Ensure that gsmtty_open() can return. */
+               tty_port_set_initialized(&dlci->port, 0);
+               wake_up_interruptible(&dlci->port.open_wait);
        } else
                dlci->gsm->dead = true;
        /* Unregister gsmtty driver,report gsmtty dev remove uevent for user */
@@ -1512,7 +1523,7 @@ static void gsm_dlci_t1(struct timer_list *t)
                        dlci->mode = DLCI_MODE_ADM;
                        gsm_dlci_open(dlci);
                } else {
-                       gsm_dlci_close(dlci);
+                       gsm_dlci_begin_close(dlci); /* prevent half open link */
                }
 
                break;
@@ -1591,6 +1602,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen)
        struct tty_struct *tty;
        unsigned int modem = 0;
        int len = clen;
+       int slen = 0;
 
        if (debug & 16)
                pr_debug("%d bytes for tty\n", len);
@@ -1603,12 +1615,14 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen)
        case 2:         /* Asynchronous serial with line state in each frame */
                while (gsm_read_ea(&modem, *data++) == 0) {
                        len--;
+                       slen++;
                        if (len == 0)
                                return;
                }
+               slen++;
                tty = tty_port_tty_get(port);
                if (tty) {
-                       gsm_process_modem(tty, dlci, modem, clen);
+                       gsm_process_modem(tty, dlci, modem, slen);
                        tty_kref_put(tty);
                }
                fallthrough;
@@ -1746,7 +1760,12 @@ static void gsm_dlci_release(struct gsm_dlci *dlci)
                gsm_destroy_network(dlci);
                mutex_unlock(&dlci->mutex);
 
-               tty_hangup(tty);
+               /* We cannot use tty_hangup() because in tty_kref_put() the tty
+                * driver assumes that the hangup queue is free and reuses it to
+                * queue release_one_tty() -> NULL pointer panic in
+                * process_one_work().
+                */
+               tty_vhangup(tty);
 
                tty_port_tty_set(&dlci->port, NULL);
                tty_kref_put(tty);
@@ -1798,10 +1817,10 @@ static void gsm_queue(struct gsm_mux *gsm)
                goto invalid;
 
        cr = gsm->address & 1;          /* C/R bit */
+       cr ^= gsm->initiator ? 0 : 1;   /* Flip so 1 always means command */
 
        gsm_print_packet("<--", address, cr, gsm->control, gsm->buf, gsm->len);
 
-       cr ^= 1 - gsm->initiator;       /* Flip so 1 always means command */
        dlci = gsm->dlci[address];
 
        switch (gsm->control) {
@@ -3232,9 +3251,9 @@ static void gsmtty_throttle(struct tty_struct *tty)
        if (dlci->state == DLCI_CLOSED)
                return;
        if (C_CRTSCTS(tty))
-               dlci->modem_tx &= ~TIOCM_DTR;
+               dlci->modem_tx &= ~TIOCM_RTS;
        dlci->throttled = true;
-       /* Send an MSC with DTR cleared */
+       /* Send an MSC with RTS cleared */
        gsmtty_modem_update(dlci, 0);
 }
 
@@ -3244,9 +3263,9 @@ static void gsmtty_unthrottle(struct tty_struct *tty)
        if (dlci->state == DLCI_CLOSED)
                return;
        if (C_CRTSCTS(tty))
-               dlci->modem_tx |= TIOCM_DTR;
+               dlci->modem_tx |= TIOCM_RTS;
        dlci->throttled = false;
-       /* Send an MSC with DTR set */
+       /* Send an MSC with RTS set */
        gsmtty_modem_update(dlci, 0);
 }
 
index 8933ef1..efc7210 100644 (file)
@@ -1329,7 +1329,7 @@ handle_newline:
                        put_tty_queue(c, ldata);
                        smp_store_release(&ldata->canon_head, ldata->read_head);
                        kill_fasync(&tty->fasync, SIGIO, POLL_IN);
-                       wake_up_interruptible_poll(&tty->read_wait, EPOLLIN);
+                       wake_up_interruptible_poll(&tty->read_wait, EPOLLIN | EPOLLRDNORM);
                        return;
                }
        }
@@ -1561,7 +1561,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
 
        if (read_cnt(ldata)) {
                kill_fasync(&tty->fasync, SIGIO, POLL_IN);
-               wake_up_interruptible_poll(&tty->read_wait, EPOLLIN);
+               wake_up_interruptible_poll(&tty->read_wait, EPOLLIN | EPOLLRDNORM);
        }
 }
 
@@ -1926,7 +1926,7 @@ static bool canon_copy_from_read_buf(struct tty_struct *tty,
                return false;
 
        canon_head = smp_load_acquire(&ldata->canon_head);
-       n = min(*nr + 1, canon_head - ldata->read_tail);
+       n = min(*nr, canon_head - ldata->read_tail);
 
        tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
        size = min_t(size_t, tail + n, N_TTY_BUF_SIZE);
@@ -1948,10 +1948,8 @@ static bool canon_copy_from_read_buf(struct tty_struct *tty,
                n += N_TTY_BUF_SIZE;
        c = n + found;
 
-       if (!found || read_buf(ldata, eol) != __DISABLED_CHAR) {
-               c = min(*nr, c);
+       if (!found || read_buf(ldata, eol) != __DISABLED_CHAR)
                n = c;
-       }
 
        n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu tail:%zu more:%zu\n",
                    __func__, eol, found, n, c, tail, more);
index dae2a4e..29db413 100644 (file)
@@ -50,10 +50,17 @@ static int rpmsg_tty_cb(struct rpmsg_device *rpdev, void *data, int len, void *p
 static int rpmsg_tty_install(struct tty_driver *driver, struct tty_struct *tty)
 {
        struct rpmsg_tty_port *cport = idr_find(&tty_idr, tty->index);
+       struct tty_port *port;
 
        tty->driver_data = cport;
 
-       return tty_port_install(&cport->port, driver, tty);
+       port = tty_port_get(&cport->port);
+       return tty_port_install(port, driver, tty);
+}
+
+static void rpmsg_tty_cleanup(struct tty_struct *tty)
+{
+       tty_port_put(tty->port);
 }
 
 static int rpmsg_tty_open(struct tty_struct *tty, struct file *filp)
@@ -106,12 +113,19 @@ static unsigned int rpmsg_tty_write_room(struct tty_struct *tty)
        return size;
 }
 
+static void rpmsg_tty_hangup(struct tty_struct *tty)
+{
+       tty_port_hangup(tty->port);
+}
+
 static const struct tty_operations rpmsg_tty_ops = {
        .install        = rpmsg_tty_install,
        .open           = rpmsg_tty_open,
        .close          = rpmsg_tty_close,
        .write          = rpmsg_tty_write,
        .write_room     = rpmsg_tty_write_room,
+       .hangup         = rpmsg_tty_hangup,
+       .cleanup        = rpmsg_tty_cleanup,
 };
 
 static struct rpmsg_tty_port *rpmsg_tty_alloc_cport(void)
@@ -137,8 +151,10 @@ static struct rpmsg_tty_port *rpmsg_tty_alloc_cport(void)
        return cport;
 }
 
-static void rpmsg_tty_release_cport(struct rpmsg_tty_port *cport)
+static void rpmsg_tty_destruct_port(struct tty_port *port)
 {
+       struct rpmsg_tty_port *cport = container_of(port, struct rpmsg_tty_port, port);
+
        mutex_lock(&idr_lock);
        idr_remove(&tty_idr, cport->id);
        mutex_unlock(&idr_lock);
@@ -146,7 +162,10 @@ static void rpmsg_tty_release_cport(struct rpmsg_tty_port *cport)
        kfree(cport);
 }
 
-static const struct tty_port_operations rpmsg_tty_port_ops = { };
+static const struct tty_port_operations rpmsg_tty_port_ops = {
+       .destruct = rpmsg_tty_destruct_port,
+};
+
 
 static int rpmsg_tty_probe(struct rpmsg_device *rpdev)
 {
@@ -166,7 +185,8 @@ static int rpmsg_tty_probe(struct rpmsg_device *rpdev)
                                           cport->id, dev);
        if (IS_ERR(tty_dev)) {
                ret = dev_err_probe(dev, PTR_ERR(tty_dev), "Failed to register tty port\n");
-               goto err_destroy;
+               tty_port_put(&cport->port);
+               return ret;
        }
 
        cport->rpdev = rpdev;
@@ -177,12 +197,6 @@ static int rpmsg_tty_probe(struct rpmsg_device *rpdev)
                rpdev->src, rpdev->dst, cport->id);
 
        return 0;
-
-err_destroy:
-       tty_port_destroy(&cport->port);
-       rpmsg_tty_release_cport(cport);
-
-       return ret;
 }
 
 static void rpmsg_tty_remove(struct rpmsg_device *rpdev)
@@ -192,13 +206,11 @@ static void rpmsg_tty_remove(struct rpmsg_device *rpdev)
        dev_dbg(&rpdev->dev, "Removing rpmsg tty device %d\n", cport->id);
 
        /* User hang up to release the tty */
-       if (tty_port_initialized(&cport->port))
-               tty_port_tty_hangup(&cport->port, false);
+       tty_port_tty_hangup(&cport->port, false);
 
        tty_unregister_device(rpmsg_tty_driver, cport->id);
 
-       tty_port_destroy(&cport->port);
-       rpmsg_tty_release_cport(cport);
+       tty_port_put(&cport->port);
 }
 
 static struct rpmsg_device_id rpmsg_driver_tty_id_table[] = {
index 673cda3..948d0a1 100644 (file)
@@ -26,7 +26,7 @@ static int __init serial_init_chip(struct parisc_device *dev)
        unsigned long address;
        int err;
 
-#ifdef CONFIG_64BIT
+#if defined(CONFIG_64BIT) && defined(CONFIG_IOSAPIC)
        if (!dev->irq && (dev->id.sversion == 0xad))
                dev->irq = iosapic_serial_irq(dev);
 #endif
index bce2872..be86262 100644 (file)
@@ -83,8 +83,17 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
                port->mapsize = resource_size(&resource);
 
                /* Check for shifted address mapping */
-               if (of_property_read_u32(np, "reg-offset", &prop) == 0)
+               if (of_property_read_u32(np, "reg-offset", &prop) == 0) {
+                       if (prop >= port->mapsize) {
+                               dev_warn(&ofdev->dev, "reg-offset %u exceeds region size %pa\n",
+                                        prop, &port->mapsize);
+                               ret = -EINVAL;
+                               goto err_unprepare;
+                       }
+
                        port->mapbase += prop;
+                       port->mapsize -= prop;
+               }
 
                port->iotype = UPIO_MEM;
                if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
index e8b5469..e17e97e 100644 (file)
@@ -4779,8 +4779,30 @@ static const struct pci_device_id serial_pci_tbl[] = {
        {       PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400,
                PCI_ANY_ID, PCI_ANY_ID, 0, 0,    /* 135a.0dc0 */
                pbn_b2_4_115200 },
+       /* Brainboxes Devices */
        /*
-        * BrainBoxes UC-260
+       * Brainboxes UC-101
+       */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0BA1,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_2_115200 },
+       /*
+        * Brainboxes UC-235/246
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0AA1,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_1_115200 },
+       /*
+        * Brainboxes UC-257
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0861,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_2_115200 },
+       /*
+        * Brainboxes UC-260/271/701/756
         */
        {       PCI_VENDOR_ID_INTASHIELD, 0x0D21,
                PCI_ANY_ID, PCI_ANY_ID,
@@ -4788,7 +4810,81 @@ static const struct pci_device_id serial_pci_tbl[] = {
                pbn_b2_4_115200 },
        {       PCI_VENDOR_ID_INTASHIELD, 0x0E34,
                PCI_ANY_ID, PCI_ANY_ID,
-                PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
+               PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
+               pbn_b2_4_115200 },
+       /*
+        * Brainboxes UC-268
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0841,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_4_115200 },
+       /*
+        * Brainboxes UC-275/279
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0881,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_8_115200 },
+       /*
+        * Brainboxes UC-302
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x08E1,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_2_115200 },
+       /*
+        * Brainboxes UC-310
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x08C1,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_2_115200 },
+       /*
+        * Brainboxes UC-313
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x08A3,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_2_115200 },
+       /*
+        * Brainboxes UC-320/324
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0A61,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_1_115200 },
+       /*
+        * Brainboxes UC-346
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0B02,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_4_115200 },
+       /*
+        * Brainboxes UC-357
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0A81,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_2_115200 },
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0A83,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_2_115200 },
+       /*
+        * Brainboxes UC-368
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0C41,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
+               pbn_b2_4_115200 },
+       /*
+        * Brainboxes UC-420/431
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0921,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0,
                pbn_b2_4_115200 },
        /*
         * Perle PCI-RAS cards
index 025b055..95ff10f 100644 (file)
@@ -117,7 +117,7 @@ static int pericom8250_probe(struct pci_dev *pdev, const struct pci_device_id *i
        uart.port.private_data = pericom;
        uart.port.iotype = UPIO_PORT;
        uart.port.uartclk = 921600 * 16;
-       uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ | UPF_MAGIC_MULTIPLIER;
+       uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
        uart.port.set_divisor = pericom_do_set_divisor;
        for (i = 0; i < nr && i < maxnr; i++) {
                unsigned int offset = (i == 3 && nr == 4) ? 0x38 : i * 0x8;
index 2abb3de..3b12bfc 100644 (file)
@@ -2056,7 +2056,10 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
        serial8250_rpm_put(up);
 }
 
-static void wait_for_lsr(struct uart_8250_port *up, int bits)
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static void wait_for_xmitr(struct uart_8250_port *up, int bits)
 {
        unsigned int status, tmout = 10000;
 
@@ -2073,16 +2076,6 @@ static void wait_for_lsr(struct uart_8250_port *up, int bits)
                udelay(1);
                touch_nmi_watchdog();
        }
-}
-
-/*
- *     Wait for transmitter & holding register to empty
- */
-static void wait_for_xmitr(struct uart_8250_port *up, int bits)
-{
-       unsigned int tmout;
-
-       wait_for_lsr(up, bits);
 
        /* Wait up to 1s for flow control if necessary */
        if (up->port.flags & UPF_CONS_FLOW) {
@@ -3332,35 +3325,6 @@ static void serial8250_console_restore(struct uart_8250_port *up)
        serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS);
 }
 
-/*
- * Print a string to the serial port using the device FIFO
- *
- * It sends fifosize bytes and then waits for the fifo
- * to get empty.
- */
-static void serial8250_console_fifo_write(struct uart_8250_port *up,
-                                         const char *s, unsigned int count)
-{
-       int i;
-       const char *end = s + count;
-       unsigned int fifosize = up->port.fifosize;
-       bool cr_sent = false;
-
-       while (s != end) {
-               wait_for_lsr(up, UART_LSR_THRE);
-
-               for (i = 0; i < fifosize && s != end; ++i) {
-                       if (*s == '\n' && !cr_sent) {
-                               serial_out(up, UART_TX, '\r');
-                               cr_sent = true;
-                       } else {
-                               serial_out(up, UART_TX, *s++);
-                               cr_sent = false;
-                       }
-               }
-       }
-}
-
 /*
  *     Print a string to the serial port trying not to disturb
  *     any possible real use of the port...
@@ -3376,7 +3340,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
        struct uart_8250_em485 *em485 = up->em485;
        struct uart_port *port = &up->port;
        unsigned long flags;
-       unsigned int ier, use_fifo;
+       unsigned int ier;
        int locked = 1;
 
        touch_nmi_watchdog();
@@ -3408,20 +3372,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
                mdelay(port->rs485.delay_rts_before_send);
        }
 
-       use_fifo = (up->capabilities & UART_CAP_FIFO) &&
-               port->fifosize > 1 &&
-               (serial_port_in(port, UART_FCR) & UART_FCR_ENABLE_FIFO) &&
-               /*
-                * After we put a data in the fifo, the controller will send
-                * it regardless of the CTS state. Therefore, only use fifo
-                * if we don't use control flow.
-                */
-               !(up->port.flags & UPF_CONS_FLOW);
-
-       if (likely(use_fifo))
-               serial8250_console_fifo_write(up, s, count);
-       else
-               uart_console_write(port, s, count, serial8250_console_putchar);
+       uart_console_write(port, s, count, serial8250_console_putchar);
 
        /*
         *      Finally, wait for transmitter to become empty
index 1f1df46..ba053a6 100644 (file)
@@ -1582,9 +1582,6 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
            container_of(port, struct uart_amba_port, port);
        unsigned int cr;
 
-       if (port->rs485.flags & SER_RS485_ENABLED)
-               mctrl &= ~TIOCM_RTS;
-
        cr = pl011_read(uap, REG_CR);
 
 #define        TIOCMBIT(tiocmbit, uartbit)             \
@@ -1808,14 +1805,8 @@ static int pl011_startup(struct uart_port *port)
        cr &= UART011_CR_RTS | UART011_CR_DTR;
        cr |= UART01x_CR_UARTEN | UART011_CR_RXE;
 
-       if (port->rs485.flags & SER_RS485_ENABLED) {
-               if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
-                       cr &= ~UART011_CR_RTS;
-               else
-                       cr |= UART011_CR_RTS;
-       } else {
+       if (!(port->rs485.flags & SER_RS485_ENABLED))
                cr |= UART011_CR_TXE;
-       }
 
        pl011_write(cr, uap, REG_CR);
 
index 64e7e6c..38d1c07 100644 (file)
@@ -734,12 +734,15 @@ static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
 static void sc16is7xx_tx_proc(struct kthread_work *ws)
 {
        struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port);
+       struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
 
        if ((port->rs485.flags & SER_RS485_ENABLED) &&
            (port->rs485.delay_rts_before_send > 0))
                msleep(port->rs485.delay_rts_before_send);
 
+       mutex_lock(&s->efr_lock);
        sc16is7xx_handle_tx(port);
+       mutex_unlock(&s->efr_lock);
 }
 
 static void sc16is7xx_reconf_rs485(struct uart_port *port)
index dc40c41..0db90be 100644 (file)
@@ -144,6 +144,11 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
        unsigned long flags;
        unsigned int old;
 
+       if (port->rs485.flags & SER_RS485_ENABLED) {
+               set &= ~TIOCM_RTS;
+               clear &= ~TIOCM_RTS;
+       }
+
        spin_lock_irqsave(&port->lock, flags);
        old = port->mctrl;
        port->mctrl = (old & ~clear) | set;
@@ -157,23 +162,10 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
 
 static void uart_port_dtr_rts(struct uart_port *uport, int raise)
 {
-       int rs485_on = uport->rs485_config &&
-               (uport->rs485.flags & SER_RS485_ENABLED);
-       int RTS_after_send = !!(uport->rs485.flags & SER_RS485_RTS_AFTER_SEND);
-
-       if (raise) {
-               if (rs485_on && RTS_after_send) {
-                       uart_set_mctrl(uport, TIOCM_DTR);
-                       uart_clear_mctrl(uport, TIOCM_RTS);
-               } else {
-                       uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
-               }
-       } else {
-               unsigned int clear = TIOCM_DTR;
-
-               clear |= (!rs485_on || RTS_after_send) ? TIOCM_RTS : 0;
-               uart_clear_mctrl(uport, clear);
-       }
+       if (raise)
+               uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
+       else
+               uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
 }
 
 /*
@@ -1075,11 +1067,6 @@ uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
                goto out;
 
        if (!tty_io_error(tty)) {
-               if (uport->rs485.flags & SER_RS485_ENABLED) {
-                       set &= ~TIOCM_RTS;
-                       clear &= ~TIOCM_RTS;
-               }
-
                uart_update_mctrl(uport, set, clear);
                ret = 0;
        }
@@ -2390,6 +2377,9 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
                 */
                spin_lock_irqsave(&port->lock, flags);
                port->mctrl &= TIOCM_DTR;
+               if (port->rs485.flags & SER_RS485_ENABLED &&
+                   !(port->rs485.flags & SER_RS485_RTS_AFTER_SEND))
+                       port->mctrl |= TIOCM_RTS;
                port->ops->set_mctrl(port, port->mctrl);
                spin_unlock_irqrestore(&port->lock, flags);
 
index 1f89ab0..9570002 100644 (file)
@@ -550,11 +550,23 @@ static void stm32_usart_transmit_chars(struct uart_port *port)
        struct stm32_port *stm32_port = to_stm32_port(port);
        const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
        struct circ_buf *xmit = &port->state->xmit;
+       u32 isr;
+       int ret;
 
        if (port->x_char) {
                if (stm32_usart_tx_dma_started(stm32_port) &&
                    stm32_usart_tx_dma_enabled(stm32_port))
                        stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
+
+               /* Check that TDR is empty before filling FIFO */
+               ret =
+               readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
+                                                 isr,
+                                                 (isr & USART_SR_TXE),
+                                                 10, 1000);
+               if (ret)
+                       dev_warn(port->dev, "1 character may be erased\n");
+
                writel_relaxed(port->x_char, port->membase + ofs->tdr);
                port->x_char = 0;
                port->icount.tx++;
@@ -730,7 +742,7 @@ static void stm32_usart_start_tx(struct uart_port *port)
        struct serial_rs485 *rs485conf = &port->rs485;
        struct circ_buf *xmit = &port->state->xmit;
 
-       if (uart_circ_empty(xmit))
+       if (uart_circ_empty(xmit) && !port->x_char)
                return;
 
        if (rs485conf->flags & SER_RS485_ENABLED) {
index 3639bb6..5801369 100644 (file)
@@ -599,8 +599,8 @@ static int vt_setactivate(struct vt_setactivate __user *sa)
        if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES)
                return -ENXIO;
 
-       vsa.console = array_index_nospec(vsa.console, MAX_NR_CONSOLES + 1);
        vsa.console--;
+       vsa.console = array_index_nospec(vsa.console, MAX_NR_CONSOLES);
        console_lock();
        ret = vc_allocate(vsa.console);
        if (ret) {
@@ -845,6 +845,7 @@ int vt_ioctl(struct tty_struct *tty,
                        return -ENXIO;
 
                arg--;
+               arg = array_index_nospec(arg, MAX_NR_CONSOLES);
                console_lock();
                ret = vc_allocate(arg);
                console_unlock();
index 55c73b1..d00ff98 100644 (file)
@@ -483,11 +483,11 @@ int cdns_drd_exit(struct cdns *cdns)
 /* Indicate the cdns3 core was power lost before */
 bool cdns_power_is_lost(struct cdns *cdns)
 {
-       if (cdns->version == CDNS3_CONTROLLER_V1) {
-               if (!(readl(&cdns->otg_v1_regs->simulate) & BIT(0)))
+       if (cdns->version == CDNS3_CONTROLLER_V0) {
+               if (!(readl(&cdns->otg_v0_regs->simulate) & BIT(0)))
                        return true;
        } else {
-               if (!(readl(&cdns->otg_v0_regs->simulate) & BIT(0)))
+               if (!(readl(&cdns->otg_v1_regs->simulate) & BIT(0)))
                        return true;
        }
        return false;
index 4169cf4..5509d38 100644 (file)
@@ -39,8 +39,11 @@ static int ulpi_match(struct device *dev, struct device_driver *driver)
        struct ulpi *ulpi = to_ulpi_dev(dev);
        const struct ulpi_device_id *id;
 
-       /* Some ULPI devices don't have a vendor id so rely on OF match */
-       if (ulpi->id.vendor == 0)
+       /*
+        * Some ULPI devices don't have a vendor id
+        * or provide an id_table so rely on OF match.
+        */
+       if (ulpi->id.vendor == 0 || !drv->id_table)
                return of_driver_match_device(dev, driver);
 
        for (id = drv->id_table; id->vendor; id++)
@@ -127,6 +130,7 @@ static const struct attribute_group *ulpi_dev_attr_groups[] = {
 
 static void ulpi_dev_release(struct device *dev)
 {
+       of_node_put(dev->of_node);
        kfree(to_ulpi_dev(dev));
 }
 
@@ -244,12 +248,16 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi)
                return ret;
 
        ret = ulpi_read_id(ulpi);
-       if (ret)
+       if (ret) {
+               of_node_put(ulpi->dev.of_node);
                return ret;
+       }
 
        ret = device_register(&ulpi->dev);
-       if (ret)
+       if (ret) {
+               put_device(&ulpi->dev);
                return ret;
+       }
 
        dev_dbg(&ulpi->dev, "registered ULPI PHY: vendor %04x, product %04x\n",
                ulpi->id.vendor, ulpi->id.product);
@@ -296,7 +304,6 @@ EXPORT_SYMBOL_GPL(ulpi_register_interface);
  */
 void ulpi_unregister_interface(struct ulpi *ulpi)
 {
-       of_node_put(ulpi->dev.of_node);
        device_unregister(&ulpi->dev);
 }
 EXPORT_SYMBOL_GPL(ulpi_unregister_interface);
index 3e01dd6..d9712c2 100644 (file)
@@ -1563,6 +1563,13 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
                urb->hcpriv = NULL;
                INIT_LIST_HEAD(&urb->urb_list);
                atomic_dec(&urb->use_count);
+               /*
+                * Order the write of urb->use_count above before the read
+                * of urb->reject below.  Pairs with the memory barriers in
+                * usb_kill_urb() and usb_poison_urb().
+                */
+               smp_mb__after_atomic();
+
                atomic_dec(&urb->dev->urbnum);
                if (atomic_read(&urb->reject))
                        wake_up(&usb_kill_urb_queue);
@@ -1665,6 +1672,13 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
 
        usb_anchor_resume_wakeups(anchor);
        atomic_dec(&urb->use_count);
+       /*
+        * Order the write of urb->use_count above before the read
+        * of urb->reject below.  Pairs with the memory barriers in
+        * usb_kill_urb() and usb_poison_urb().
+        */
+       smp_mb__after_atomic();
+
        if (unlikely(atomic_read(&urb->reject)))
                wake_up(&usb_kill_urb_queue);
        usb_put_urb(urb);
index c2bbf97..d5bc36c 100644 (file)
@@ -602,11 +602,14 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
                return retval;
        }
 
-       find_and_link_peer(hub, port1);
-
        retval = component_add(&port_dev->dev, &connector_ops);
-       if (retval)
+       if (retval) {
                dev_warn(&port_dev->dev, "failed to add component\n");
+               device_unregister(&port_dev->dev);
+               return retval;
+       }
+
+       find_and_link_peer(hub, port1);
 
        /*
         * Enable runtime pm and hold a refernce that hub_configure()
index 3072772..33d62d7 100644 (file)
@@ -715,6 +715,12 @@ void usb_kill_urb(struct urb *urb)
        if (!(urb && urb->dev && urb->ep))
                return;
        atomic_inc(&urb->reject);
+       /*
+        * Order the write of urb->reject above before the read
+        * of urb->use_count below.  Pairs with the barriers in
+        * __usb_hcd_giveback_urb() and usb_hcd_submit_urb().
+        */
+       smp_mb__after_atomic();
 
        usb_hcd_unlink_urb(urb, -ENOENT);
        wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
@@ -756,6 +762,12 @@ void usb_poison_urb(struct urb *urb)
        if (!urb)
                return;
        atomic_inc(&urb->reject);
+       /*
+        * Order the write of urb->reject above before the read
+        * of urb->use_count below.  Pairs with the barriers in
+        * __usb_hcd_giveback_urb() and usb_hcd_submit_urb().
+        */
+       smp_mb__after_atomic();
 
        if (!urb->dev || !urb->ep)
                return;
index 8a63da3..88c337b 100644 (file)
@@ -1418,6 +1418,7 @@ void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg);
 void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2);
 int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode);
 #define dwc2_is_device_connected(hsotg) (hsotg->connected)
+#define dwc2_is_device_enabled(hsotg) (hsotg->enabled)
 int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg);
 int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup);
 int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg);
@@ -1454,6 +1455,7 @@ static inline int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
                                           int testmode)
 { return 0; }
 #define dwc2_is_device_connected(hsotg) (0)
+#define dwc2_is_device_enabled(hsotg) (0)
 static inline int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
 { return 0; }
 static inline int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg,
index 1b39c47..d8d6493 100644 (file)
@@ -130,8 +130,10 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role)
                already = dwc2_ovr_avalid(hsotg, true);
        } else if (role == USB_ROLE_DEVICE) {
                already = dwc2_ovr_bvalid(hsotg, true);
-               /* This clear DCTL.SFTDISCON bit */
-               dwc2_hsotg_core_connect(hsotg);
+               if (dwc2_is_device_enabled(hsotg)) {
+                       /* This clear DCTL.SFTDISCON bit */
+                       dwc2_hsotg_core_connect(hsotg);
+               }
        } else {
                if (dwc2_is_device_mode(hsotg)) {
                        if (!dwc2_ovr_bvalid(hsotg, false))
index 2bc03f4..eee3504 100644 (file)
@@ -5097,7 +5097,7 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg)
                hsotg->gadget.speed = USB_SPEED_UNKNOWN;
                spin_unlock_irqrestore(&hsotg->lock, flags);
 
-               for (ep = 0; ep < hsotg->num_of_eps; ep++) {
+               for (ep = 1; ep < hsotg->num_of_eps; ep++) {
                        if (hsotg->eps_in[ep])
                                dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep);
                        if (hsotg->eps_out[ep])
index 7ff8fc8..06d0e88 100644 (file)
@@ -43,6 +43,7 @@
 #define PCI_DEVICE_ID_INTEL_ADLP               0x51ee
 #define PCI_DEVICE_ID_INTEL_ADLM               0x54ee
 #define PCI_DEVICE_ID_INTEL_ADLS               0x7ae1
+#define PCI_DEVICE_ID_INTEL_RPLS               0x7a61
 #define PCI_DEVICE_ID_INTEL_TGL                        0x9a15
 #define PCI_DEVICE_ID_AMD_MR                   0x163a
 
@@ -85,8 +86,8 @@ static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
 static struct gpiod_lookup_table platform_bytcr_gpios = {
        .dev_id         = "0000:00:16.0",
        .table          = {
-               GPIO_LOOKUP("INT33FC:00", 54, "reset", GPIO_ACTIVE_HIGH),
-               GPIO_LOOKUP("INT33FC:02", 14, "cs", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("INT33FC:00", 54, "cs", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("INT33FC:02", 14, "reset", GPIO_ACTIVE_HIGH),
                {}
        },
 };
@@ -119,6 +120,13 @@ static const struct property_entry dwc3_pci_intel_properties[] = {
        {}
 };
 
+static const struct property_entry dwc3_pci_intel_byt_properties[] = {
+       PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
+       PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
+       PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
+       {}
+};
+
 static const struct property_entry dwc3_pci_mrfld_properties[] = {
        PROPERTY_ENTRY_STRING("dr_mode", "otg"),
        PROPERTY_ENTRY_STRING("linux,extcon-name", "mrfld_bcove_pwrsrc"),
@@ -161,6 +169,10 @@ static const struct software_node dwc3_pci_intel_swnode = {
        .properties = dwc3_pci_intel_properties,
 };
 
+static const struct software_node dwc3_pci_intel_byt_swnode = {
+       .properties = dwc3_pci_intel_byt_properties,
+};
+
 static const struct software_node dwc3_pci_intel_mrfld_swnode = {
        .properties = dwc3_pci_mrfld_properties,
 };
@@ -344,7 +356,7 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
          (kernel_ulong_t) &dwc3_pci_intel_swnode, },
 
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BYT),
-         (kernel_ulong_t) &dwc3_pci_intel_swnode, },
+         (kernel_ulong_t) &dwc3_pci_intel_byt_swnode, },
 
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD),
          (kernel_ulong_t) &dwc3_pci_intel_mrfld_swnode, },
@@ -409,6 +421,9 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLS),
          (kernel_ulong_t) &dwc3_pci_intel_swnode, },
 
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPLS),
+         (kernel_ulong_t) &dwc3_pci_intel_swnode, },
+
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL),
          (kernel_ulong_t) &dwc3_pci_intel_swnode, },
 
index 9cc3ad7..a6f3a9b 100644 (file)
@@ -99,17 +99,29 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
        struct device           *dev = priv_data->dev;
        struct reset_control    *crst, *hibrst, *apbrst;
        struct phy              *usb3_phy;
-       int                     ret;
+       int                     ret = 0;
        u32                     reg;
 
-       usb3_phy = devm_phy_get(dev, "usb3-phy");
-       if (PTR_ERR(usb3_phy) == -EPROBE_DEFER) {
-               ret = -EPROBE_DEFER;
+       usb3_phy = devm_phy_optional_get(dev, "usb3-phy");
+       if (IS_ERR(usb3_phy)) {
+               ret = PTR_ERR(usb3_phy);
+               dev_err_probe(dev, ret,
+                             "failed to get USB3 PHY\n");
                goto err;
-       } else if (IS_ERR(usb3_phy)) {
-               usb3_phy = NULL;
        }
 
+       /*
+        * The following core resets are not required unless a USB3 PHY
+        * is used, and the subsequent register settings are not required
+        * unless a core reset is performed (they should be set properly
+        * by the first-stage boot loader, but may be reverted by a core
+        * reset). They may also break the configuration if USB3 is actually
+        * in use but the usb3-phy entry is missing from the device tree.
+        * Therefore, skip these operations in this case.
+        */
+       if (!usb3_phy)
+               goto skip_usb3_phy;
+
        crst = devm_reset_control_get_exclusive(dev, "usb_crst");
        if (IS_ERR(crst)) {
                ret = PTR_ERR(crst);
@@ -188,6 +200,7 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
                goto err;
        }
 
+skip_usb3_phy:
        /*
         * This routes the USB DMA traffic to go through FPD path instead
         * of reaching DDR directly. This traffic routing is needed to
index 520031b..a0c883f 100644 (file)
@@ -1291,6 +1291,19 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb,
        if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable)
                trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(stream_id);
 
+       /*
+        * As per data book 4.2.3.2TRB Control Bit Rules section
+        *
+        * The controller autonomously checks the HWO field of a TRB to determine if the
+        * entire TRB is valid. Therefore, software must ensure that the rest of the TRB
+        * is valid before setting the HWO field to '1'. In most systems, this means that
+        * software must update the fourth DWORD of a TRB last.
+        *
+        * However there is a possibility of CPU re-ordering here which can cause
+        * controller to observe the HWO bit set prematurely.
+        * Add a write memory barrier to prevent CPU re-ordering.
+        */
+       wmb();
        trb->ctrl |= DWC3_TRB_CTRL_HWO;
 
        dwc3_ep_inc_enq(dep);
@@ -4147,9 +4160,11 @@ static irqreturn_t dwc3_thread_interrupt(int irq, void *_evt)
        unsigned long flags;
        irqreturn_t ret = IRQ_NONE;
 
+       local_bh_disable();
        spin_lock_irqsave(&dwc->lock, flags);
        ret = dwc3_process_event_buf(evt);
        spin_unlock_irqrestore(&dwc->lock, flags);
+       local_bh_enable();
 
        return ret;
 }
index 16f9e34..9315313 100644 (file)
@@ -1988,6 +1988,9 @@ unknown:
                                if (w_index != 0x5 || (w_value >> 8))
                                        break;
                                interface = w_value & 0xFF;
+                               if (interface >= MAX_CONFIG_INTERFACES ||
+                                   !os_desc_cfg->interface[interface])
+                                       break;
                                buf[6] = w_index;
                                count = count_ext_prop(os_desc_cfg,
                                        interface);
index 25ad1e9..1922fd0 100644 (file)
@@ -1711,16 +1711,24 @@ static void ffs_data_put(struct ffs_data *ffs)
 
 static void ffs_data_closed(struct ffs_data *ffs)
 {
+       struct ffs_epfile *epfiles;
+       unsigned long flags;
+
        ENTER();
 
        if (atomic_dec_and_test(&ffs->opened)) {
                if (ffs->no_disconnect) {
                        ffs->state = FFS_DEACTIVATED;
-                       if (ffs->epfiles) {
-                               ffs_epfiles_destroy(ffs->epfiles,
-                                                  ffs->eps_count);
-                               ffs->epfiles = NULL;
-                       }
+                       spin_lock_irqsave(&ffs->eps_lock, flags);
+                       epfiles = ffs->epfiles;
+                       ffs->epfiles = NULL;
+                       spin_unlock_irqrestore(&ffs->eps_lock,
+                                                       flags);
+
+                       if (epfiles)
+                               ffs_epfiles_destroy(epfiles,
+                                                ffs->eps_count);
+
                        if (ffs->setup_state == FFS_SETUP_PENDING)
                                __ffs_ep0_stall(ffs);
                } else {
@@ -1767,14 +1775,27 @@ static struct ffs_data *ffs_data_new(const char *dev_name)
 
 static void ffs_data_clear(struct ffs_data *ffs)
 {
+       struct ffs_epfile *epfiles;
+       unsigned long flags;
+
        ENTER();
 
        ffs_closed(ffs);
 
        BUG_ON(ffs->gadget);
 
-       if (ffs->epfiles) {
-               ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
+       spin_lock_irqsave(&ffs->eps_lock, flags);
+       epfiles = ffs->epfiles;
+       ffs->epfiles = NULL;
+       spin_unlock_irqrestore(&ffs->eps_lock, flags);
+
+       /*
+        * potential race possible between ffs_func_eps_disable
+        * & ffs_epfile_release therefore maintaining a local
+        * copy of epfile will save us from use-after-free.
+        */
+       if (epfiles) {
+               ffs_epfiles_destroy(epfiles, ffs->eps_count);
                ffs->epfiles = NULL;
        }
 
@@ -1922,12 +1943,15 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
 
 static void ffs_func_eps_disable(struct ffs_function *func)
 {
-       struct ffs_ep *ep         = func->eps;
-       struct ffs_epfile *epfile = func->ffs->epfiles;
-       unsigned count            = func->ffs->eps_count;
+       struct ffs_ep *ep;
+       struct ffs_epfile *epfile;
+       unsigned short count;
        unsigned long flags;
 
        spin_lock_irqsave(&func->ffs->eps_lock, flags);
+       count = func->ffs->eps_count;
+       epfile = func->ffs->epfiles;
+       ep = func->eps;
        while (count--) {
                /* pending requests get nuked */
                if (ep->ep)
@@ -1945,14 +1969,18 @@ static void ffs_func_eps_disable(struct ffs_function *func)
 
 static int ffs_func_eps_enable(struct ffs_function *func)
 {
-       struct ffs_data *ffs      = func->ffs;
-       struct ffs_ep *ep         = func->eps;
-       struct ffs_epfile *epfile = ffs->epfiles;
-       unsigned count            = ffs->eps_count;
+       struct ffs_data *ffs;
+       struct ffs_ep *ep;
+       struct ffs_epfile *epfile;
+       unsigned short count;
        unsigned long flags;
        int ret = 0;
 
        spin_lock_irqsave(&func->ffs->eps_lock, flags);
+       ffs = func->ffs;
+       ep = func->eps;
+       epfile = ffs->epfiles;
+       count = ffs->eps_count;
        while(count--) {
                ep->ep->driver_data = ep;
 
index 1abf08e..6803cd6 100644 (file)
@@ -584,6 +584,7 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
 
        if (is_iso) {
                switch (speed) {
+               case USB_SPEED_SUPER_PLUS:
                case USB_SPEED_SUPER:
                        size = ss->isoc_maxpacket *
                                        (ss->isoc_mult + 1) *
index 36fa6ef..097a709 100644 (file)
@@ -203,7 +203,7 @@ static struct uac2_input_terminal_descriptor io_in_it_desc = {
 
        .bDescriptorSubtype = UAC_INPUT_TERMINAL,
        /* .bTerminalID = DYNAMIC */
-       .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_UNDEFINED),
+       .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_MICROPHONE),
        .bAssocTerminal = 0,
        /* .bCSourceID = DYNAMIC */
        .iChannelNames = 0,
@@ -231,7 +231,7 @@ static struct uac2_output_terminal_descriptor io_out_ot_desc = {
 
        .bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
        /* .bTerminalID = DYNAMIC */
-       .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_UNDEFINED),
+       .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_SPEAKER),
        .bAssocTerminal = 0,
        /* .bSourceID = DYNAMIC */
        /* .bCSourceID = DYNAMIC */
index 431d5a7..00b3f6b 100644 (file)
@@ -637,14 +637,17 @@ static int rndis_set_response(struct rndis_params *params,
        rndis_set_cmplt_type *resp;
        rndis_resp_t *r;
 
+       BufLength = le32_to_cpu(buf->InformationBufferLength);
+       BufOffset = le32_to_cpu(buf->InformationBufferOffset);
+       if ((BufLength > RNDIS_MAX_TOTAL_SIZE) ||
+           (BufOffset + 8 >= RNDIS_MAX_TOTAL_SIZE))
+                   return -EINVAL;
+
        r = rndis_add_response(params, sizeof(rndis_set_cmplt_type));
        if (!r)
                return -ENOMEM;
        resp = (rndis_set_cmplt_type *)r->buf;
 
-       BufLength = le32_to_cpu(buf->InformationBufferLength);
-       BufOffset = le32_to_cpu(buf->InformationBufferOffset);
-
 #ifdef VERBOSE_DEBUG
        pr_debug("%s: Length: %d\n", __func__, BufLength);
        pr_debug("%s: Offset: %d\n", __func__, BufOffset);
@@ -919,6 +922,7 @@ struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v)
        params->resp_avail = resp_avail;
        params->v = v;
        INIT_LIST_HEAD(&params->resp_queue);
+       spin_lock_init(&params->resp_lock);
        pr_debug("%s: configNr = %d\n", __func__, i);
 
        return params;
@@ -1012,12 +1016,14 @@ void rndis_free_response(struct rndis_params *params, u8 *buf)
 {
        rndis_resp_t *r, *n;
 
+       spin_lock(&params->resp_lock);
        list_for_each_entry_safe(r, n, &params->resp_queue, list) {
                if (r->buf == buf) {
                        list_del(&r->list);
                        kfree(r);
                }
        }
+       spin_unlock(&params->resp_lock);
 }
 EXPORT_SYMBOL_GPL(rndis_free_response);
 
@@ -1027,14 +1033,17 @@ u8 *rndis_get_next_response(struct rndis_params *params, u32 *length)
 
        if (!length) return NULL;
 
+       spin_lock(&params->resp_lock);
        list_for_each_entry_safe(r, n, &params->resp_queue, list) {
                if (!r->send) {
                        r->send = 1;
                        *length = r->length;
+                       spin_unlock(&params->resp_lock);
                        return r->buf;
                }
        }
 
+       spin_unlock(&params->resp_lock);
        return NULL;
 }
 EXPORT_SYMBOL_GPL(rndis_get_next_response);
@@ -1051,7 +1060,9 @@ static rndis_resp_t *rndis_add_response(struct rndis_params *params, u32 length)
        r->length = length;
        r->send = 0;
 
+       spin_lock(&params->resp_lock);
        list_add_tail(&r->list, &params->resp_queue);
+       spin_unlock(&params->resp_lock);
        return r;
 }
 
index f6167f7..6206b8b 100644 (file)
@@ -174,6 +174,7 @@ typedef struct rndis_params {
        void                    (*resp_avail)(void *v);
        void                    *v;
        struct list_head        resp_queue;
+       spinlock_t              resp_lock;
 } rndis_params;
 
 /* RNDIS Message parser and other useless functions */
index c5a2c73..d86c3a3 100644 (file)
@@ -1004,7 +1004,7 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
                ret = -EBUSY;
                goto out_unlock;
        }
-       if ((in && !ep->ep->caps.dir_in) || (!in && ep->ep->caps.dir_in)) {
+       if (in != usb_endpoint_dir_in(ep->ep->desc)) {
                dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
                ret = -EINVAL;
                goto out_unlock;
index dd0819d..9040a05 100644 (file)
@@ -1895,7 +1895,7 @@ static int at91udc_probe(struct platform_device *pdev)
                                        at91_vbus_irq, 0, driver_name, udc);
                        if (retval) {
                                DBG("request vbus irq %d failed\n",
-                                   udc->board.vbus_pin);
+                                   desc_to_gpio(udc->board.vbus_pin));
                                goto err_unprepare_iclk;
                        }
                }
index 57d417a..601829a 100644 (file)
@@ -2378,6 +2378,8 @@ static void handle_ext_role_switch_states(struct device *dev,
        switch (role) {
        case USB_ROLE_NONE:
                usb3->connection_state = USB_ROLE_NONE;
+               if (cur_role == USB_ROLE_HOST)
+                       device_release_driver(host);
                if (usb3->driver)
                        usb3_disconnect(usb3);
                usb3_vbus_out(usb3, false);
index 6ce886f..2907fad 100644 (file)
@@ -1615,6 +1615,8 @@ static void xudc_getstatus(struct xusb_udc *udc)
                break;
        case USB_RECIP_ENDPOINT:
                epnum = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK;
+               if (epnum >= XUSB_MAX_ENDPOINTS)
+                       goto stall;
                target_ep = &udc->ep[epnum];
                epcfgreg = udc->read_fn(udc->addr + target_ep->offset);
                halt = epcfgreg & XUSB_EP_CFG_STALL_MASK;
@@ -1682,6 +1684,10 @@ static void xudc_set_clear_feature(struct xusb_udc *udc)
        case USB_RECIP_ENDPOINT:
                if (!udc->setup.wValue) {
                        endpoint = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK;
+                       if (endpoint >= XUSB_MAX_ENDPOINTS) {
+                               xudc_ep0_stall(udc);
+                               return;
+                       }
                        target_ep = &udc->ep[endpoint];
                        outinbit = udc->setup.wIndex & USB_ENDPOINT_DIR_MASK;
                        outinbit = outinbit >> 7;
index 4d34f60..5810036 100644 (file)
@@ -419,6 +419,9 @@ static int __maybe_unused xhci_plat_suspend(struct device *dev)
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        int ret;
 
+       if (pm_runtime_suspended(dev))
+               pm_runtime_resume(dev);
+
        ret = xhci_priv_suspend_quirk(hcd);
        if (ret)
                return ret;
index dc357ca..2d37854 100644 (file)
@@ -1091,6 +1091,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
        int                     retval = 0;
        bool                    comp_timer_running = false;
        bool                    pending_portevent = false;
+       bool                    reinit_xhc = false;
 
        if (!hcd->state)
                return 0;
@@ -1107,10 +1108,11 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
        set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
 
        spin_lock_irq(&xhci->lock);
-       if ((xhci->quirks & XHCI_RESET_ON_RESUME) || xhci->broken_suspend)
-               hibernated = true;
 
-       if (!hibernated) {
+       if (hibernated || xhci->quirks & XHCI_RESET_ON_RESUME || xhci->broken_suspend)
+               reinit_xhc = true;
+
+       if (!reinit_xhc) {
                /*
                 * Some controllers might lose power during suspend, so wait
                 * for controller not ready bit to clear, just as in xHC init.
@@ -1143,12 +1145,17 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
                        spin_unlock_irq(&xhci->lock);
                        return -ETIMEDOUT;
                }
-               temp = readl(&xhci->op_regs->status);
        }
 
-       /* If restore operation fails, re-initialize the HC during resume */
-       if ((temp & STS_SRE) || hibernated) {
+       temp = readl(&xhci->op_regs->status);
 
+       /* re-initialize the HC on Restore Error, or Host Controller Error */
+       if (temp & (STS_SRE | STS_HCE)) {
+               reinit_xhc = true;
+               xhci_warn(xhci, "xHC error in resume, USBSTS 0x%x, Reinit\n", temp);
+       }
+
+       if (reinit_xhc) {
                if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
                                !(xhci_all_ports_seen_u0(xhci))) {
                        del_timer_sync(&xhci->comp_mode_recovery_timer);
@@ -1604,9 +1611,12 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
        struct urb_priv *urb_priv;
        int num_tds;
 
-       if (!urb || xhci_check_args(hcd, urb->dev, urb->ep,
-                                       true, true, __func__) <= 0)
+       if (!urb)
                return -EINVAL;
+       ret = xhci_check_args(hcd, urb->dev, urb->ep,
+                                       true, true, __func__);
+       if (ret <= 0)
+               return ret ? ret : -EINVAL;
 
        slot_id = urb->dev->slot_id;
        ep_index = xhci_get_endpoint_index(&urb->ep->desc);
@@ -3323,7 +3333,7 @@ static int xhci_check_streams_endpoint(struct xhci_hcd *xhci,
                return -EINVAL;
        ret = xhci_check_args(xhci_to_hcd(xhci), udev, ep, 1, true, __func__);
        if (ret <= 0)
-               return -EINVAL;
+               return ret ? ret : -EINVAL;
        if (usb_ss_max_streams(&ep->ss_ep_comp) == 0) {
                xhci_warn(xhci, "WARN: SuperSpeed Endpoint Companion"
                                " descriptor for ep 0x%x does not support streams\n",
index 507deef..04c4e3f 100644 (file)
@@ -543,6 +543,9 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
        if (of_property_read_u16_array(np, "language-id", &hub->lang_id, 1))
                hub->lang_id = USB251XB_DEF_LANGUAGE_ID;
 
+       if (of_property_read_u8(np, "boost-up", &hub->boost_up))
+               hub->boost_up = USB251XB_DEF_BOOST_UP;
+
        cproperty_char = of_get_property(np, "manufacturer", NULL);
        strlcpy(str, cproperty_char ? : USB251XB_DEF_MANUFACTURER_STRING,
                sizeof(str));
@@ -584,7 +587,6 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
         * may be as soon as needed.
         */
        hub->bat_charge_en = USB251XB_DEF_BATTERY_CHARGING_ENABLE;
-       hub->boost_up = USB251XB_DEF_BOOST_UP;
        hub->boost_57 = USB251XB_DEF_BOOST_57;
        hub->boost_14 = USB251XB_DEF_BOOST_14;
        hub->port_map12 = USB251XB_DEF_PORT_MAP_12;
index 29f4b87..2798fca 100644 (file)
 #define CH341_QUIRK_SIMULATE_BREAK     BIT(1)
 
 static const struct usb_device_id id_table[] = {
-       { USB_DEVICE(0x1a86, 0x5512) },
        { USB_DEVICE(0x1a86, 0x5523) },
        { USB_DEVICE(0x1a86, 0x7522) },
        { USB_DEVICE(0x1a86, 0x7523) },
+       { USB_DEVICE(0x2184, 0x0057) },
        { USB_DEVICE(0x4348, 0x5523) },
        { USB_DEVICE(0x9986, 0x7523) },
        { },
index 8a60c0d..a27f7ef 100644 (file)
@@ -51,6 +51,7 @@ static void cp210x_enable_event_mode(struct usb_serial_port *port);
 static void cp210x_disable_event_mode(struct usb_serial_port *port);
 
 static const struct usb_device_id id_table[] = {
+       { USB_DEVICE(0x0404, 0x034C) }, /* NCR Retail IO Box */
        { USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */
        { USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */
        { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
@@ -68,6 +69,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */
        { USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */
        { USB_DEVICE(0x0FDE, 0xCA05) }, /* OWL Wireless Electricity Monitor CM-160 */
+       { USB_DEVICE(0x106F, 0x0003) }, /* CPI / Money Controls Bulk Coin Recycler */
        { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
        { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
        { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
index 4edebd1..49c08f0 100644 (file)
@@ -969,6 +969,7 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_023_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_034_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_101_PID) },
+       { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_159_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_1_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_2_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_3_PID) },
@@ -977,12 +978,14 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_6_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_7_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_8_PID) },
+       { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_235_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_257_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_1_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_2_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_3_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_4_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_313_PID) },
+       { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_320_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_324_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_346_1_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_346_2_PID) },
index 755858c..d1a9564 100644 (file)
 #define BRAINBOXES_VX_023_PID          0x1003 /* VX-023 ExpressCard 1 Port RS422/485 */
 #define BRAINBOXES_VX_034_PID          0x1004 /* VX-034 ExpressCard 2 Port RS422/485 */
 #define BRAINBOXES_US_101_PID          0x1011 /* US-101 1xRS232 */
+#define BRAINBOXES_US_159_PID          0x1021 /* US-159 1xRS232 */
+#define BRAINBOXES_US_235_PID          0x1017 /* US-235 1xRS232 */
+#define BRAINBOXES_US_320_PID          0x1019 /* US-320 1xRS422/485 */
 #define BRAINBOXES_US_324_PID          0x1013 /* US-324 1xRS422/485 1Mbaud */
 #define BRAINBOXES_US_606_1_PID                0x2001 /* US-606 6 Port RS232 Serial Port 1 and 2 */
 #define BRAINBOXES_US_606_2_PID                0x2002 /* US-606 6 Port RS232 Serial Port 3 and 4 */
index 42420bf..e7755d9 100644 (file)
@@ -198,6 +198,8 @@ static void option_instat_callback(struct urb *urb);
 
 #define DELL_PRODUCT_5821E                     0x81d7
 #define DELL_PRODUCT_5821E_ESIM                        0x81e0
+#define DELL_PRODUCT_5829E_ESIM                        0x81e4
+#define DELL_PRODUCT_5829E                     0x81e6
 
 #define KYOCERA_VENDOR_ID                      0x0c88
 #define KYOCERA_PRODUCT_KPC650                 0x17da
@@ -1063,6 +1065,10 @@ static const struct usb_device_id option_ids[] = {
          .driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
        { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5821E_ESIM),
          .driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
+       { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5829E),
+         .driver_info = RSVD(0) | RSVD(6) },
+       { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5829E_ESIM),
+         .driver_info = RSVD(0) | RSVD(6) },
        { 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) },
@@ -1273,10 +1279,16 @@ static const struct usb_device_id option_ids[] = {
          .driver_info = NCTRL(2) },
        { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x7011, 0xff),    /* Telit LE910-S1 (ECM) */
          .driver_info = NCTRL(2) },
+       { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x701a, 0xff),    /* Telit LE910R1 (RNDIS) */
+         .driver_info = NCTRL(2) },
+       { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x701b, 0xff),    /* Telit LE910R1 (ECM) */
+         .driver_info = NCTRL(2) },
        { USB_DEVICE(TELIT_VENDOR_ID, 0x9010),                          /* Telit SBL FN980 flashing device */
          .driver_info = NCTRL(0) | ZLP },
        { USB_DEVICE(TELIT_VENDOR_ID, 0x9200),                          /* Telit LE910S1 flashing device */
          .driver_info = NCTRL(0) | ZLP },
+       { USB_DEVICE(TELIT_VENDOR_ID, 0x9201),                          /* Telit LE910R1 flashing device */
+         .driver_info = NCTRL(0) | ZLP },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff),
          .driver_info = RSVD(1) },
@@ -1649,6 +1661,8 @@ static const struct usb_device_id option_ids[] = {
          .driver_info = RSVD(2) },
        { USB_DEVICE_INTERFACE_CLASS(ZTE_VENDOR_ID, 0x1476, 0xff) },    /* GosunCn ZTE WeLink ME3630 (ECM/NCM mode) */
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1481, 0xff, 0x00, 0x00) }, /* ZTE MF871A */
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1485, 0xff, 0xff, 0xff),  /* ZTE MF286D */
+         .driver_info = RSVD(5) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1533, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1534, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1535, 0xff, 0xff, 0xff) },
index 29191d3..1a05e3d 100644 (file)
@@ -2301,6 +2301,16 @@ UNUSUAL_DEV(  0x2027, 0xa001, 0x0000, 0x9999,
                USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
                US_FL_SCM_MULT_TARG ),
 
+/*
+ * Reported by DocMAX <mail@vacharakis.de>
+ * and Thomas Weißschuh <linux@weissschuh.net>
+ */
+UNUSUAL_DEV( 0x2109, 0x0715, 0x9999, 0x9999,
+               "VIA Labs, Inc.",
+               "VL817 SATA Bridge",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_IGNORE_UAS),
+
 UNUSUAL_DEV( 0x2116, 0x0320, 0x0001, 0x0001,
                "ST",
                "2A",
index 07d3074..a7d5078 100644 (file)
@@ -56,7 +56,12 @@ int typec_link_ports(struct typec_port *con)
 {
        struct each_port_arg arg = { .port = con, .match = NULL };
 
+       if (!has_acpi_companion(&con->dev))
+               return 0;
+
        bus_for_each_dev(&acpi_bus_type, NULL, &arg, typec_port_match);
+       if (!arg.match)
+               return 0;
 
        /*
         * REVISIT: Now each connector can have only a single component master.
@@ -74,5 +79,6 @@ int typec_link_ports(struct typec_port *con)
 
 void typec_unlink_ports(struct typec_port *con)
 {
-       component_master_del(&con->dev, &typec_aggregate_ops);
+       if (has_acpi_companion(&con->dev))
+               component_master_del(&con->dev, &typec_aggregate_ops);
 }
index 35a1307..e07d26a 100644 (file)
@@ -75,9 +75,25 @@ static int tcpci_write16(struct tcpci *tcpci, unsigned int reg, u16 val)
 static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
 {
        struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+       bool vconn_pres;
+       enum typec_cc_polarity polarity = TYPEC_POLARITY_CC1;
        unsigned int reg;
        int ret;
 
+       ret = regmap_read(tcpci->regmap, TCPC_POWER_STATUS, &reg);
+       if (ret < 0)
+               return ret;
+
+       vconn_pres = !!(reg & TCPC_POWER_STATUS_VCONN_PRES);
+       if (vconn_pres) {
+               ret = regmap_read(tcpci->regmap, TCPC_TCPC_CTRL, &reg);
+               if (ret < 0)
+                       return ret;
+
+               if (reg & TCPC_TCPC_CTRL_ORIENTATION)
+                       polarity = TYPEC_POLARITY_CC2;
+       }
+
        switch (cc) {
        case TYPEC_CC_RA:
                reg = (TCPC_ROLE_CTRL_CC_RA << TCPC_ROLE_CTRL_CC1_SHIFT) |
@@ -112,6 +128,16 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
                break;
        }
 
+       if (vconn_pres) {
+               if (polarity == TYPEC_POLARITY_CC2) {
+                       reg &= ~(TCPC_ROLE_CTRL_CC1_MASK << TCPC_ROLE_CTRL_CC1_SHIFT);
+                       reg |= (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC1_SHIFT);
+               } else {
+                       reg &= ~(TCPC_ROLE_CTRL_CC2_MASK << TCPC_ROLE_CTRL_CC2_SHIFT);
+                       reg |= (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC2_SHIFT);
+               }
+       }
+
        ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
        if (ret < 0)
                return ret;
index 2be7a77..b2edd45 100644 (file)
@@ -98,6 +98,7 @@
 #define TCPC_POWER_STATUS_SOURCING_VBUS        BIT(4)
 #define TCPC_POWER_STATUS_VBUS_DET     BIT(3)
 #define TCPC_POWER_STATUS_VBUS_PRES    BIT(2)
+#define TCPC_POWER_STATUS_VCONN_PRES   BIT(1)
 #define TCPC_POWER_STATUS_SINKING_VBUS BIT(0)
 
 #define TCPC_FAULT_STATUS              0x1f
index 59d4fa2..5fce795 100644 (file)
@@ -5156,7 +5156,8 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
        case SNK_TRYWAIT_DEBOUNCE:
                break;
        case SNK_ATTACH_WAIT:
-               tcpm_set_state(port, SNK_UNATTACHED, 0);
+       case SNK_DEBOUNCED:
+               /* Do nothing, as TCPM is still waiting for vbus to reaach VSAFE5V to connect */
                break;
 
        case SNK_NEGOTIATE_CAPABILITIES:
@@ -5263,6 +5264,10 @@ static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port)
        case PR_SWAP_SNK_SRC_SOURCE_ON:
                /* Do nothing, vsafe0v is expected during transition */
                break;
+       case SNK_ATTACH_WAIT:
+       case SNK_DEBOUNCED:
+               /*Do nothing, still waiting for VSAFE5V for connect */
+               break;
        default:
                if (port->pwr_role == TYPEC_SINK && port->auto_vbus_discharge_enabled)
                        tcpm_set_state(port, SNK_UNATTACHED, 0);
index 6d27a5b..7ffcda9 100644 (file)
@@ -761,12 +761,12 @@ static int tps6598x_probe(struct i2c_client *client)
 
        ret = tps6598x_read32(tps, TPS_REG_STATUS, &status);
        if (ret < 0)
-               return ret;
+               goto err_clear_mask;
        trace_tps6598x_status(status);
 
        ret = tps6598x_read32(tps, TPS_REG_SYSTEM_CONF, &conf);
        if (ret < 0)
-               return ret;
+               goto err_clear_mask;
 
        /*
         * This fwnode has a "compatible" property, but is never populated as a
@@ -855,7 +855,8 @@ err_role_put:
        usb_role_switch_put(tps->role_sw);
 err_fwnode_put:
        fwnode_handle_put(fwnode);
-
+err_clear_mask:
+       tps6598x_write64(tps, TPS_REG_INT_MASK1, 0);
        return ret;
 }
 
index bff96d6..6db7c8d 100644 (file)
@@ -325,7 +325,7 @@ static int ucsi_ccg_init(struct ucsi_ccg *uc)
                if (status < 0)
                        return status;
 
-               if (!data)
+               if (!(data & DEV_INT))
                        return 0;
 
                status = ccg_write(uc, CCGX_RAB_INTR_REG, &data, sizeof(data));
index d6ca1c7..37f0b42 100644 (file)
@@ -629,16 +629,18 @@ err:
        return ret;
 }
 
-static int vhost_vsock_stop(struct vhost_vsock *vsock)
+static int vhost_vsock_stop(struct vhost_vsock *vsock, bool check_owner)
 {
        size_t i;
-       int ret;
+       int ret = 0;
 
        mutex_lock(&vsock->dev.mutex);
 
-       ret = vhost_dev_check_owner(&vsock->dev);
-       if (ret)
-               goto err;
+       if (check_owner) {
+               ret = vhost_dev_check_owner(&vsock->dev);
+               if (ret)
+                       goto err;
+       }
 
        for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) {
                struct vhost_virtqueue *vq = &vsock->vqs[i];
@@ -753,7 +755,12 @@ static int vhost_vsock_dev_release(struct inode *inode, struct file *file)
         * inefficient.  Room for improvement here. */
        vsock_for_each_connected_socket(vhost_vsock_reset_orphans);
 
-       vhost_vsock_stop(vsock);
+       /* Don't check the owner, because we are in the release path, so we
+        * need to stop the vsock device in any case.
+        * vhost_vsock_stop() can not fail in this case, so we don't need to
+        * check the return code.
+        */
+       vhost_vsock_stop(vsock, false);
        vhost_vsock_flush(vsock);
        vhost_dev_stop(&vsock->dev);
 
@@ -868,7 +875,7 @@ static long vhost_vsock_dev_ioctl(struct file *f, unsigned int ioctl,
                if (start)
                        return vhost_vsock_start(vsock);
                else
-                       return vhost_vsock_stop(vsock);
+                       return vhost_vsock_stop(vsock, true);
        case VHOST_GET_FEATURES:
                features = VHOST_VSOCK_FEATURES;
                if (copy_to_user(argp, &features, sizeof(features)))
index 840d981..fcc4638 100644 (file)
@@ -78,6 +78,26 @@ config FRAMEBUFFER_CONSOLE
        help
          Low-level framebuffer-based console driver.
 
+config FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+       bool "Enable legacy fbcon hardware acceleration code"
+       depends on FRAMEBUFFER_CONSOLE
+       default y if PARISC
+       default n
+       help
+         This option enables the fbcon (framebuffer text-based) hardware
+         acceleration for graphics drivers which were written for the fbdev
+         graphics interface.
+
+         On modern machines, on mainstream machines (like x86-64) or when
+         using a modern Linux distribution those fbdev drivers usually aren't used.
+         So enabling this option wouldn't have any effect, which is why you want
+         to disable this option on such newer machines.
+
+         If you compile this kernel for older machines which still require the
+         fbdev drivers, you may want to say Y.
+
+         If unsure, select n.
+
 config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
        bool "Map the console to the primary display device"
        depends on FRAMEBUFFER_CONSOLE
index 01fae2c..f98e8f2 100644 (file)
@@ -43,6 +43,21 @@ static void update_attr(u8 *dst, u8 *src, int attribute,
        }
 }
 
+static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                     int sx, int dy, int dx, int height, int width)
+{
+       struct fb_copyarea area;
+
+       area.sx = sx * vc->vc_font.width;
+       area.sy = sy * vc->vc_font.height;
+       area.dx = dx * vc->vc_font.width;
+       area.dy = dy * vc->vc_font.height;
+       area.height = height * vc->vc_font.height;
+       area.width = width * vc->vc_font.width;
+
+       info->fbops->fb_copyarea(info, &area);
+}
+
 static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy,
                      int sx, int height, int width)
 {
@@ -378,6 +393,7 @@ static int bit_update_start(struct fb_info *info)
 
 void fbcon_set_bitops(struct fbcon_ops *ops)
 {
+       ops->bmove = bit_bmove;
        ops->clear = bit_clear;
        ops->putcs = bit_putcs;
        ops->clear_margins = bit_clear_margins;
index 99ecd9a..2fc1b80 100644 (file)
@@ -173,6 +173,8 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
                        int count, int ypos, int xpos);
 static void fbcon_clear_margins(struct vc_data *vc, int bottom_only);
 static void fbcon_cursor(struct vc_data *vc, int mode);
+static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
+                       int height, int width);
 static int fbcon_switch(struct vc_data *vc);
 static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch);
 static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table);
@@ -180,8 +182,16 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table);
 /*
  *  Internal routines
  */
+static __inline__ void ywrap_up(struct vc_data *vc, int count);
+static __inline__ void ywrap_down(struct vc_data *vc, int count);
+static __inline__ void ypan_up(struct vc_data *vc, int count);
+static __inline__ void ypan_down(struct vc_data *vc, int count);
+static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx,
+                           int dy, int dx, int height, int width, u_int y_break);
 static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
                           int unit);
+static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
+                             int line, int count, int dy);
 static void fbcon_modechanged(struct fb_info *info);
 static void fbcon_set_all_vcs(struct fb_info *info);
 static void fbcon_start(void);
@@ -1125,6 +1135,14 @@ static void fbcon_init(struct vc_data *vc, int init)
 
        ops->graphics = 0;
 
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+       if ((info->flags & FBINFO_HWACCEL_COPYAREA) &&
+           !(info->flags & FBINFO_HWACCEL_DISABLED))
+               p->scrollmode = SCROLL_MOVE;
+       else /* default to something safe */
+               p->scrollmode = SCROLL_REDRAW;
+#endif
+
        /*
         *  ++guenther: console.c:vc_allocate() relies on initializing
         *  vc_{cols,rows}, but we must not set those if we are only
@@ -1211,13 +1229,14 @@ finished:
  *  This system is now divided into two levels because of complications
  *  caused by hardware scrolling. Top level functions:
  *
- *     fbcon_clear(), fbcon_putc(), fbcon_clear_margins()
+ *     fbcon_bmove(), fbcon_clear(), fbcon_putc(), fbcon_clear_margins()
  *
  *  handles y values in range [0, scr_height-1] that correspond to real
  *  screen positions. y_wrap shift means that first line of bitmap may be
  *  anywhere on this display. These functions convert lineoffsets to
  *  bitmap offsets and deal with the wrap-around case by splitting blits.
  *
+ *     fbcon_bmove_physical_8()    -- These functions fast implementations
  *     fbcon_clear_physical_8()    -- of original fbcon_XXX fns.
  *     fbcon_putc_physical_8()     -- (font width != 8) may be added later
  *
@@ -1390,6 +1409,224 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
        }
 }
 
+static __inline__ void ywrap_up(struct vc_data *vc, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+
+       p->yscroll += count;
+       if (p->yscroll >= p->vrows)     /* Deal with wrap */
+               p->yscroll -= p->vrows;
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode |= FB_VMODE_YWRAP;
+       ops->update_start(info);
+       scrollback_max += count;
+       if (scrollback_max > scrollback_phys_max)
+               scrollback_max = scrollback_phys_max;
+       scrollback_current = 0;
+}
+
+static __inline__ void ywrap_down(struct vc_data *vc, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+
+       p->yscroll -= count;
+       if (p->yscroll < 0)     /* Deal with wrap */
+               p->yscroll += p->vrows;
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode |= FB_VMODE_YWRAP;
+       ops->update_start(info);
+       scrollback_max -= count;
+       if (scrollback_max < 0)
+               scrollback_max = 0;
+       scrollback_current = 0;
+}
+
+static __inline__ void ypan_up(struct vc_data *vc, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+       struct fbcon_ops *ops = info->fbcon_par;
+
+       p->yscroll += count;
+       if (p->yscroll > p->vrows - vc->vc_rows) {
+               ops->bmove(vc, info, p->vrows - vc->vc_rows,
+                           0, 0, 0, vc->vc_rows, vc->vc_cols);
+               p->yscroll -= p->vrows - vc->vc_rows;
+       }
+
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode &= ~FB_VMODE_YWRAP;
+       ops->update_start(info);
+       fbcon_clear_margins(vc, 1);
+       scrollback_max += count;
+       if (scrollback_max > scrollback_phys_max)
+               scrollback_max = scrollback_phys_max;
+       scrollback_current = 0;
+}
+
+static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+
+       p->yscroll += count;
+
+       if (p->yscroll > p->vrows - vc->vc_rows) {
+               p->yscroll -= p->vrows - vc->vc_rows;
+               fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t);
+       }
+
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode &= ~FB_VMODE_YWRAP;
+       ops->update_start(info);
+       fbcon_clear_margins(vc, 1);
+       scrollback_max += count;
+       if (scrollback_max > scrollback_phys_max)
+               scrollback_max = scrollback_phys_max;
+       scrollback_current = 0;
+}
+
+static __inline__ void ypan_down(struct vc_data *vc, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+       struct fbcon_ops *ops = info->fbcon_par;
+
+       p->yscroll -= count;
+       if (p->yscroll < 0) {
+               ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows,
+                           0, vc->vc_rows, vc->vc_cols);
+               p->yscroll += p->vrows - vc->vc_rows;
+       }
+
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode &= ~FB_VMODE_YWRAP;
+       ops->update_start(info);
+       fbcon_clear_margins(vc, 1);
+       scrollback_max -= count;
+       if (scrollback_max < 0)
+               scrollback_max = 0;
+       scrollback_current = 0;
+}
+
+static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+
+       p->yscroll -= count;
+
+       if (p->yscroll < 0) {
+               p->yscroll += p->vrows - vc->vc_rows;
+               fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count);
+       }
+
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode &= ~FB_VMODE_YWRAP;
+       ops->update_start(info);
+       fbcon_clear_margins(vc, 1);
+       scrollback_max -= count;
+       if (scrollback_max < 0)
+               scrollback_max = 0;
+       scrollback_current = 0;
+}
+
+static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
+                             int line, int count, int dy)
+{
+       unsigned short *s = (unsigned short *)
+               (vc->vc_origin + vc->vc_size_row * line);
+
+       while (count--) {
+               unsigned short *start = s;
+               unsigned short *le = advance_row(s, 1);
+               unsigned short c;
+               int x = 0;
+               unsigned short attr = 1;
+
+               do {
+                       c = scr_readw(s);
+                       if (attr != (c & 0xff00)) {
+                               attr = c & 0xff00;
+                               if (s > start) {
+                                       fbcon_putcs(vc, start, s - start,
+                                                   dy, x);
+                                       x += s - start;
+                                       start = s;
+                               }
+                       }
+                       console_conditional_schedule();
+                       s++;
+               } while (s < le);
+               if (s > start)
+                       fbcon_putcs(vc, start, s - start, dy, x);
+               console_conditional_schedule();
+               dy++;
+       }
+}
+
+static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
+                       struct fbcon_display *p, int line, int count, int ycount)
+{
+       int offset = ycount * vc->vc_cols;
+       unsigned short *d = (unsigned short *)
+           (vc->vc_origin + vc->vc_size_row * line);
+       unsigned short *s = d + offset;
+       struct fbcon_ops *ops = info->fbcon_par;
+
+       while (count--) {
+               unsigned short *start = s;
+               unsigned short *le = advance_row(s, 1);
+               unsigned short c;
+               int x = 0;
+
+               do {
+                       c = scr_readw(s);
+
+                       if (c == scr_readw(d)) {
+                               if (s > start) {
+                                       ops->bmove(vc, info, line + ycount, x,
+                                                  line, x, 1, s-start);
+                                       x += s - start + 1;
+                                       start = s + 1;
+                               } else {
+                                       x++;
+                                       start++;
+                               }
+                       }
+
+                       scr_writew(c, d);
+                       console_conditional_schedule();
+                       s++;
+                       d++;
+               } while (s < le);
+               if (s > start)
+                       ops->bmove(vc, info, line + ycount, x, line, x, 1,
+                                  s-start);
+               console_conditional_schedule();
+               if (ycount > 0)
+                       line++;
+               else {
+                       line--;
+                       /* NOTE: We subtract two lines from these pointers */
+                       s -= vc->vc_size_row;
+                       d -= vc->vc_size_row;
+               }
+       }
+}
+
 static void fbcon_redraw(struct vc_data *vc, struct fbcon_display *p,
                         int line, int count, int offset)
 {
@@ -1450,6 +1687,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
 {
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
        struct fbcon_display *p = &fb_display[vc->vc_num];
+       int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
 
        if (fbcon_is_inactive(vc, info))
                return true;
@@ -1466,32 +1704,291 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
        case SM_UP:
                if (count > vc->vc_rows)        /* Maximum realistic size */
                        count = vc->vc_rows;
-               fbcon_redraw(vc, p, t, b - t - count,
-                            count * vc->vc_cols);
-               fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
-               scr_memsetw((unsigned short *) (vc->vc_origin +
-                                               vc->vc_size_row *
-                                               (b - count)),
-                           vc->vc_video_erase_char,
-                           vc->vc_size_row * count);
-               return true;
+               if (logo_shown >= 0)
+                       goto redraw_up;
+               switch (fb_scrollmode(p)) {
+               case SCROLL_MOVE:
+                       fbcon_redraw_blit(vc, info, p, t, b - t - count,
+                                    count);
+                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       scr_memsetw((unsigned short *) (vc->vc_origin +
+                                                       vc->vc_size_row *
+                                                       (b - count)),
+                                   vc->vc_video_erase_char,
+                                   vc->vc_size_row * count);
+                       return true;
+
+               case SCROLL_WRAP_MOVE:
+                       if (b - t - count > 3 * vc->vc_rows >> 2) {
+                               if (t > 0)
+                                       fbcon_bmove(vc, 0, 0, count, 0, t,
+                                                   vc->vc_cols);
+                               ywrap_up(vc, count);
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_bmove(vc, b - count, 0, b, 0,
+                                                   vc->vc_rows - b,
+                                                   vc->vc_cols);
+                       } else if (info->flags & FBINFO_READS_FAST)
+                               fbcon_bmove(vc, t + count, 0, t, 0,
+                                           b - t - count, vc->vc_cols);
+                       else
+                               goto redraw_up;
+                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_PAN_REDRAW:
+                       if ((p->yscroll + count <=
+                            2 * (p->vrows - vc->vc_rows))
+                           && ((!scroll_partial && (b - t == vc->vc_rows))
+                               || (scroll_partial
+                                   && (b - t - count >
+                                       3 * vc->vc_rows >> 2)))) {
+                               if (t > 0)
+                                       fbcon_redraw_move(vc, p, 0, t, count);
+                               ypan_up_redraw(vc, t, count);
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_redraw_move(vc, p, b,
+                                                         vc->vc_rows - b, b);
+                       } else
+                               fbcon_redraw_move(vc, p, t + count, b - t - count, t);
+                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_PAN_MOVE:
+                       if ((p->yscroll + count <=
+                            2 * (p->vrows - vc->vc_rows))
+                           && ((!scroll_partial && (b - t == vc->vc_rows))
+                               || (scroll_partial
+                                   && (b - t - count >
+                                       3 * vc->vc_rows >> 2)))) {
+                               if (t > 0)
+                                       fbcon_bmove(vc, 0, 0, count, 0, t,
+                                                   vc->vc_cols);
+                               ypan_up(vc, count);
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_bmove(vc, b - count, 0, b, 0,
+                                                   vc->vc_rows - b,
+                                                   vc->vc_cols);
+                       } else if (info->flags & FBINFO_READS_FAST)
+                               fbcon_bmove(vc, t + count, 0, t, 0,
+                                           b - t - count, vc->vc_cols);
+                       else
+                               goto redraw_up;
+                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_REDRAW:
+                     redraw_up:
+                       fbcon_redraw(vc, p, t, b - t - count,
+                                    count * vc->vc_cols);
+                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       scr_memsetw((unsigned short *) (vc->vc_origin +
+                                                       vc->vc_size_row *
+                                                       (b - count)),
+                                   vc->vc_video_erase_char,
+                                   vc->vc_size_row * count);
+                       return true;
+               }
+               break;
 
        case SM_DOWN:
                if (count > vc->vc_rows)        /* Maximum realistic size */
                        count = vc->vc_rows;
-               fbcon_redraw(vc, p, b - 1, b - t - count,
-                            -count * vc->vc_cols);
-               fbcon_clear(vc, t, 0, count, vc->vc_cols);
-               scr_memsetw((unsigned short *) (vc->vc_origin +
-                                               vc->vc_size_row *
-                                               t),
-                           vc->vc_video_erase_char,
-                           vc->vc_size_row * count);
-               return true;
+               if (logo_shown >= 0)
+                       goto redraw_down;
+               switch (fb_scrollmode(p)) {
+               case SCROLL_MOVE:
+                       fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
+                                    -count);
+                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       scr_memsetw((unsigned short *) (vc->vc_origin +
+                                                       vc->vc_size_row *
+                                                       t),
+                                   vc->vc_video_erase_char,
+                                   vc->vc_size_row * count);
+                       return true;
+
+               case SCROLL_WRAP_MOVE:
+                       if (b - t - count > 3 * vc->vc_rows >> 2) {
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_bmove(vc, b, 0, b - count, 0,
+                                                   vc->vc_rows - b,
+                                                   vc->vc_cols);
+                               ywrap_down(vc, count);
+                               if (t > 0)
+                                       fbcon_bmove(vc, count, 0, 0, 0, t,
+                                                   vc->vc_cols);
+                       } else if (info->flags & FBINFO_READS_FAST)
+                               fbcon_bmove(vc, t, 0, t + count, 0,
+                                           b - t - count, vc->vc_cols);
+                       else
+                               goto redraw_down;
+                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_PAN_MOVE:
+                       if ((count - p->yscroll <= p->vrows - vc->vc_rows)
+                           && ((!scroll_partial && (b - t == vc->vc_rows))
+                               || (scroll_partial
+                                   && (b - t - count >
+                                       3 * vc->vc_rows >> 2)))) {
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_bmove(vc, b, 0, b - count, 0,
+                                                   vc->vc_rows - b,
+                                                   vc->vc_cols);
+                               ypan_down(vc, count);
+                               if (t > 0)
+                                       fbcon_bmove(vc, count, 0, 0, 0, t,
+                                                   vc->vc_cols);
+                       } else if (info->flags & FBINFO_READS_FAST)
+                               fbcon_bmove(vc, t, 0, t + count, 0,
+                                           b - t - count, vc->vc_cols);
+                       else
+                               goto redraw_down;
+                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_PAN_REDRAW:
+                       if ((count - p->yscroll <= p->vrows - vc->vc_rows)
+                           && ((!scroll_partial && (b - t == vc->vc_rows))
+                               || (scroll_partial
+                                   && (b - t - count >
+                                       3 * vc->vc_rows >> 2)))) {
+                               if (vc->vc_rows - b > 0)
+                                       fbcon_redraw_move(vc, p, b, vc->vc_rows - b,
+                                                         b - count);
+                               ypan_down_redraw(vc, t, count);
+                               if (t > 0)
+                                       fbcon_redraw_move(vc, p, count, t, 0);
+                       } else
+                               fbcon_redraw_move(vc, p, t, b - t - count, t + count);
+                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       break;
+
+               case SCROLL_REDRAW:
+                     redraw_down:
+                       fbcon_redraw(vc, p, b - 1, b - t - count,
+                                    -count * vc->vc_cols);
+                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       scr_memsetw((unsigned short *) (vc->vc_origin +
+                                                       vc->vc_size_row *
+                                                       t),
+                                   vc->vc_video_erase_char,
+                                   vc->vc_size_row * count);
+                       return true;
+               }
        }
        return false;
 }
 
+
+static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
+                       int height, int width)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_display *p = &fb_display[vc->vc_num];
+
+       if (fbcon_is_inactive(vc, info))
+               return;
+
+       if (!width || !height)
+               return;
+
+       /*  Split blits that cross physical y_wrap case.
+        *  Pathological case involves 4 blits, better to use recursive
+        *  code rather than unrolled case
+        *
+        *  Recursive invocations don't need to erase the cursor over and
+        *  over again, so we use fbcon_bmove_rec()
+        */
+       fbcon_bmove_rec(vc, p, sy, sx, dy, dx, height, width,
+                       p->vrows - p->yscroll);
+}
+
+static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx,
+                           int dy, int dx, int height, int width, u_int y_break)
+{
+       struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
+       u_int b;
+
+       if (sy < y_break && sy + height > y_break) {
+               b = y_break - sy;
+               if (dy < sy) {  /* Avoid trashing self */
+                       fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+                                       y_break);
+                       fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+                                       height - b, width, y_break);
+               } else {
+                       fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+                                       height - b, width, y_break);
+                       fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+                                       y_break);
+               }
+               return;
+       }
+
+       if (dy < y_break && dy + height > y_break) {
+               b = y_break - dy;
+               if (dy < sy) {  /* Avoid trashing self */
+                       fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+                                       y_break);
+                       fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+                                       height - b, width, y_break);
+               } else {
+                       fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+                                       height - b, width, y_break);
+                       fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+                                       y_break);
+               }
+               return;
+       }
+       ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx,
+                  height, width);
+}
+
+static void updatescrollmode_accel(struct fbcon_display *p,
+                                       struct fb_info *info,
+                                       struct vc_data *vc)
+{
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+       struct fbcon_ops *ops = info->fbcon_par;
+       int cap = info->flags;
+       u16 t = 0;
+       int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
+                                 info->fix.xpanstep);
+       int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t);
+       int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+       int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
+                                  info->var.xres_virtual);
+       int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&
+               divides(ypan, vc->vc_font.height) && vyres > yres;
+       int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
+               divides(ywrap, vc->vc_font.height) &&
+               divides(vc->vc_font.height, vyres) &&
+               divides(vc->vc_font.height, yres);
+       int reading_fast = cap & FBINFO_READS_FAST;
+       int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) &&
+               !(cap & FBINFO_HWACCEL_DISABLED);
+       int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) &&
+               !(cap & FBINFO_HWACCEL_DISABLED);
+
+       if (good_wrap || good_pan) {
+               if (reading_fast || fast_copyarea)
+                       p->scrollmode = good_wrap ?
+                               SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
+               else
+                       p->scrollmode = good_wrap ? SCROLL_REDRAW :
+                               SCROLL_PAN_REDRAW;
+       } else {
+               if (reading_fast || (fast_copyarea && !fast_imageblit))
+                       p->scrollmode = SCROLL_MOVE;
+               else
+                       p->scrollmode = SCROLL_REDRAW;
+       }
+#endif
+}
+
 static void updatescrollmode(struct fbcon_display *p,
                                        struct fb_info *info,
                                        struct vc_data *vc)
@@ -1507,6 +2004,9 @@ static void updatescrollmode(struct fbcon_display *p,
                p->vrows -= (yres - (fh * vc->vc_rows)) / fh;
        if ((yres % fh) && (vyres % fh < yres % fh))
                p->vrows--;
+
+       /* update scrollmode in case hardware acceleration is used */
+       updatescrollmode_accel(p, info, vc);
 }
 
 #define PITCH(w) (((w) + 7) >> 3)
@@ -1664,7 +2164,21 @@ static int fbcon_switch(struct vc_data *vc)
 
        updatescrollmode(p, info, vc);
 
-       scrollback_phys_max = 0;
+       switch (fb_scrollmode(p)) {
+       case SCROLL_WRAP_MOVE:
+               scrollback_phys_max = p->vrows - vc->vc_rows;
+               break;
+       case SCROLL_PAN_MOVE:
+       case SCROLL_PAN_REDRAW:
+               scrollback_phys_max = p->vrows - 2 * vc->vc_rows;
+               if (scrollback_phys_max < 0)
+                       scrollback_phys_max = 0;
+               break;
+       default:
+               scrollback_phys_max = 0;
+               break;
+       }
+
        scrollback_max = 0;
        scrollback_current = 0;
 
index a00603b..969d41e 100644 (file)
@@ -29,6 +29,9 @@ struct fbcon_display {
     /* Filled in by the low-level console driver */
     const u_char *fontdata;
     int userfont;                   /* != 0 if fontdata kmalloc()ed */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+    u_short scrollmode;             /* Scroll Method, use fb_scrollmode() */
+#endif
     u_short inverse;                /* != 0 text black on white as default */
     short yscroll;                  /* Hardware scrolling */
     int vrows;                      /* number of virtual rows */
@@ -51,6 +54,8 @@ struct fbcon_display {
 };
 
 struct fbcon_ops {
+       void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy,
+                     int sx, int dy, int dx, int height, int width);
        void (*clear)(struct vc_data *vc, struct fb_info *info, int sy,
                      int sx, int height, int width);
        void (*putcs)(struct vc_data *vc, struct fb_info *info,
@@ -149,6 +154,73 @@ static inline int attr_col_ec(int shift, struct vc_data *vc,
 #define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0)
 #define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1)
 
+    /*
+     *  Scroll Method
+     */
+
+/* There are several methods fbcon can use to move text around the screen:
+ *
+ *                     Operation   Pan    Wrap
+ *---------------------------------------------
+ * SCROLL_MOVE         copyarea    No     No
+ * SCROLL_PAN_MOVE     copyarea    Yes    No
+ * SCROLL_WRAP_MOVE    copyarea    No     Yes
+ * SCROLL_REDRAW       imageblit   No     No
+ * SCROLL_PAN_REDRAW   imageblit   Yes    No
+ * SCROLL_WRAP_REDRAW  imageblit   No     Yes
+ *
+ * (SCROLL_WRAP_REDRAW is not implemented yet)
+ *
+ * In general, fbcon will choose the best scrolling
+ * method based on the rule below:
+ *
+ * Pan/Wrap > accel imageblit > accel copyarea >
+ * soft imageblit > (soft copyarea)
+ *
+ * Exception to the rule: Pan + accel copyarea is
+ * preferred over Pan + accel imageblit.
+ *
+ * The above is typical for PCI/AGP cards. Unless
+ * overridden, fbcon will never use soft copyarea.
+ *
+ * If you need to override the above rule, set the
+ * appropriate flags in fb_info->flags.  For example,
+ * to prefer copyarea over imageblit, set
+ * FBINFO_READS_FAST.
+ *
+ * Other notes:
+ * + use the hardware engine to move the text
+ *    (hw-accelerated copyarea() and fillrect())
+ * + use hardware-supported panning on a large virtual screen
+ * + amifb can not only pan, but also wrap the display by N lines
+ *    (i.e. visible line i = physical line (i+N) % yres).
+ * + read what's already rendered on the screen and
+ *     write it in a different place (this is cfb_copyarea())
+ * + re-render the text to the screen
+ *
+ * Whether to use wrapping or panning can only be figured out at
+ * runtime (when we know whether our font height is a multiple
+ * of the pan/wrap step)
+ *
+ */
+
+#define SCROLL_MOVE       0x001
+#define SCROLL_PAN_MOVE           0x002
+#define SCROLL_WRAP_MOVE   0x003
+#define SCROLL_REDRAW     0x004
+#define SCROLL_PAN_REDRAW  0x005
+
+static inline u_short fb_scrollmode(struct fbcon_display *fb)
+{
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+       return fb->scrollmode;
+#else
+       /* hardcoded to SCROLL_REDRAW if acceleration was disabled. */
+       return SCROLL_REDRAW;
+#endif
+}
+
+
 #ifdef CONFIG_FB_TILEBLITTING
 extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
 #endif
index ffa7893..2789ace 100644 (file)
@@ -59,12 +59,31 @@ static void ccw_update_attr(u8 *dst, u8 *src, int attribute,
        }
 }
 
+
+static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                    int sx, int dy, int dx, int height, int width)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fb_copyarea area;
+       u32 vyres = GETVYRES(ops->p, info);
+
+       area.sx = sy * vc->vc_font.height;
+       area.sy = vyres - ((sx + width) * vc->vc_font.width);
+       area.dx = dy * vc->vc_font.height;
+       area.dy = vyres - ((dx + width) * vc->vc_font.width);
+       area.width = height * vc->vc_font.height;
+       area.height  = width * vc->vc_font.width;
+
+       info->fbops->fb_copyarea(info, &area);
+}
+
 static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
                     int sx, int height, int width)
 {
+       struct fbcon_ops *ops = info->fbcon_par;
        struct fb_fillrect region;
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
-       u32 vyres = info->var.yres;
+       u32 vyres = GETVYRES(ops->p, info);
 
        region.color = attr_bgcol_ec(bgshift,vc,info);
        region.dx = sy * vc->vc_font.height;
@@ -121,7 +140,7 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
        u32 cnt, pitch, size;
        u32 attribute = get_attribute(info, scr_readw(s));
        u8 *dst, *buf = NULL;
-       u32 vyres = info->var.yres;
+       u32 vyres = GETVYRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -210,7 +229,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
        int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
        int err = 1, dx, dy;
        char *src;
-       u32 vyres = info->var.yres;
+       u32 vyres = GETVYRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -368,7 +387,7 @@ static int ccw_update_start(struct fb_info *info)
 {
        struct fbcon_ops *ops = info->fbcon_par;
        u32 yoffset;
-       u32 vyres = info->var.yres;
+       u32 vyres = GETVYRES(ops->p, info);
        int err;
 
        yoffset = (vyres - info->var.yres) - ops->var.xoffset;
@@ -383,6 +402,7 @@ static int ccw_update_start(struct fb_info *info)
 
 void fbcon_rotate_ccw(struct fbcon_ops *ops)
 {
+       ops->bmove = ccw_bmove;
        ops->clear = ccw_clear;
        ops->putcs = ccw_putcs;
        ops->clear_margins = ccw_clear_margins;
index 92e5b7f..86a254c 100644 (file)
@@ -44,12 +44,31 @@ static void cw_update_attr(u8 *dst, u8 *src, int attribute,
        }
 }
 
+
+static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                    int sx, int dy, int dx, int height, int width)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fb_copyarea area;
+       u32 vxres = GETVXRES(ops->p, info);
+
+       area.sx = vxres - ((sy + height) * vc->vc_font.height);
+       area.sy = sx * vc->vc_font.width;
+       area.dx = vxres - ((dy + height) * vc->vc_font.height);
+       area.dy = dx * vc->vc_font.width;
+       area.width = height * vc->vc_font.height;
+       area.height  = width * vc->vc_font.width;
+
+       info->fbops->fb_copyarea(info, &area);
+}
+
 static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
                     int sx, int height, int width)
 {
+       struct fbcon_ops *ops = info->fbcon_par;
        struct fb_fillrect region;
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
-       u32 vxres = info->var.xres;
+       u32 vxres = GETVXRES(ops->p, info);
 
        region.color = attr_bgcol_ec(bgshift,vc,info);
        region.dx = vxres - ((sy + height) * vc->vc_font.height);
@@ -106,7 +125,7 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
        u32 cnt, pitch, size;
        u32 attribute = get_attribute(info, scr_readw(s));
        u8 *dst, *buf = NULL;
-       u32 vxres = info->var.xres;
+       u32 vxres = GETVXRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -193,7 +212,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
        int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
        int err = 1, dx, dy;
        char *src;
-       u32 vxres = info->var.xres;
+       u32 vxres = GETVXRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -350,7 +369,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
 static int cw_update_start(struct fb_info *info)
 {
        struct fbcon_ops *ops = info->fbcon_par;
-       u32 vxres = info->var.xres;
+       u32 vxres = GETVXRES(ops->p, info);
        u32 xoffset;
        int err;
 
@@ -366,6 +385,7 @@ static int cw_update_start(struct fb_info *info)
 
 void fbcon_rotate_cw(struct fbcon_ops *ops)
 {
+       ops->bmove = cw_bmove;
        ops->clear = cw_clear;
        ops->putcs = cw_putcs;
        ops->clear_margins = cw_clear_margins;
index b528b2e..01cbe30 100644 (file)
 #ifndef _FBCON_ROTATE_H
 #define _FBCON_ROTATE_H
 
+#define GETVYRES(s,i) ({                           \
+        (fb_scrollmode(s) == SCROLL_REDRAW || fb_scrollmode(s) == SCROLL_MOVE) ? \
+        (i)->var.yres : (i)->var.yres_virtual; })
+
+#define GETVXRES(s,i) ({                           \
+        (fb_scrollmode(s) == SCROLL_REDRAW || fb_scrollmode(s) == SCROLL_MOVE || !(i)->fix.xpanstep) ? \
+        (i)->var.xres : (i)->var.xres_virtual; })
+
+
 static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat)
 {
        u32 tmp = (y * pitch) + x, index = tmp / 8,  bit = tmp % 8;
index 09619bd..23bc045 100644 (file)
@@ -44,13 +44,33 @@ static void ud_update_attr(u8 *dst, u8 *src, int attribute,
        }
 }
 
+
+static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                    int sx, int dy, int dx, int height, int width)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct fb_copyarea area;
+       u32 vyres = GETVYRES(ops->p, info);
+       u32 vxres = GETVXRES(ops->p, info);
+
+       area.sy = vyres - ((sy + height) * vc->vc_font.height);
+       area.sx = vxres - ((sx + width) * vc->vc_font.width);
+       area.dy = vyres - ((dy + height) * vc->vc_font.height);
+       area.dx = vxres - ((dx + width) * vc->vc_font.width);
+       area.height = height * vc->vc_font.height;
+       area.width  = width * vc->vc_font.width;
+
+       info->fbops->fb_copyarea(info, &area);
+}
+
 static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
                     int sx, int height, int width)
 {
+       struct fbcon_ops *ops = info->fbcon_par;
        struct fb_fillrect region;
        int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
-       u32 vyres = info->var.yres;
-       u32 vxres = info->var.xres;
+       u32 vyres = GETVYRES(ops->p, info);
+       u32 vxres = GETVXRES(ops->p, info);
 
        region.color = attr_bgcol_ec(bgshift,vc,info);
        region.dy = vyres - ((sy + height) * vc->vc_font.height);
@@ -142,8 +162,8 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
        u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
        u32 attribute = get_attribute(info, scr_readw(s));
        u8 *dst, *buf = NULL;
-       u32 vyres = info->var.yres;
-       u32 vxres = info->var.xres;
+       u32 vyres = GETVYRES(ops->p, info);
+       u32 vxres = GETVXRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -239,8 +259,8 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
        int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
        int err = 1, dx, dy;
        char *src;
-       u32 vyres = info->var.yres;
-       u32 vxres = info->var.xres;
+       u32 vyres = GETVYRES(ops->p, info);
+       u32 vxres = GETVXRES(ops->p, info);
 
        if (!ops->fontbuffer)
                return;
@@ -390,8 +410,8 @@ static int ud_update_start(struct fb_info *info)
 {
        struct fbcon_ops *ops = info->fbcon_par;
        int xoffset, yoffset;
-       u32 vyres = info->var.yres;
-       u32 vxres = info->var.xres;
+       u32 vyres = GETVYRES(ops->p, info);
+       u32 vxres = GETVXRES(ops->p, info);
        int err;
 
        xoffset = vxres - info->var.xres - ops->var.xoffset;
@@ -409,6 +429,7 @@ static int ud_update_start(struct fb_info *info)
 
 void fbcon_rotate_ud(struct fbcon_ops *ops)
 {
+       ops->bmove = ud_bmove;
        ops->clear = ud_clear;
        ops->putcs = ud_putcs;
        ops->clear_margins = ud_clear_margins;
index 0fa7ede..13083ad 100644 (file)
@@ -1160,6 +1160,8 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
                ret = fbcon_set_con2fb_map_ioctl(argp);
                break;
        case FBIOBLANK:
+               if (arg > FB_BLANK_POWERDOWN)
+                       return -EINVAL;
                console_lock();
                lock_fb_info(info);
                ret = fb_blank(info, arg);
index 72af950..2768eff 100644 (file)
 #include <asm/types.h>
 #include "fbcon.h"
 
+static void tile_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                      int sx, int dy, int dx, int height, int width)
+{
+       struct fb_tilearea area;
+
+       area.sx = sx;
+       area.sy = sy;
+       area.dx = dx;
+       area.dy = dy;
+       area.height = height;
+       area.width = width;
+
+       info->tileops->fb_tilecopy(info, &area);
+}
+
 static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy,
                       int sx, int height, int width)
 {
@@ -118,6 +133,7 @@ void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info)
        struct fb_tilemap map;
        struct fbcon_ops *ops = info->fbcon_par;
 
+       ops->bmove = tile_bmove;
        ops->clear = tile_clear;
        ops->putcs = tile_putcs;
        ops->clear_margins = tile_clear_margins;
index 23999df..c8e0ea2 100644 (file)
@@ -287,8 +287,6 @@ struct hvfb_par {
 
 static uint screen_width = HVFB_WIDTH;
 static uint screen_height = HVFB_HEIGHT;
-static uint screen_width_max = HVFB_WIDTH;
-static uint screen_height_max = HVFB_HEIGHT;
 static uint screen_depth;
 static uint screen_fb_size;
 static uint dio_fb_size; /* FB size for deferred IO */
@@ -582,7 +580,6 @@ static int synthvid_get_supported_resolution(struct hv_device *hdev)
        int ret = 0;
        unsigned long t;
        u8 index;
-       int i;
 
        memset(msg, 0, sizeof(struct synthvid_msg));
        msg->vid_hdr.type = SYNTHVID_RESOLUTION_REQUEST;
@@ -613,13 +610,6 @@ static int synthvid_get_supported_resolution(struct hv_device *hdev)
                goto out;
        }
 
-       for (i = 0; i < msg->resolution_resp.resolution_count; i++) {
-               screen_width_max = max_t(unsigned int, screen_width_max,
-                   msg->resolution_resp.supported_resolution[i].width);
-               screen_height_max = max_t(unsigned int, screen_height_max,
-                   msg->resolution_resp.supported_resolution[i].height);
-       }
-
        screen_width =
                msg->resolution_resp.supported_resolution[index].width;
        screen_height =
@@ -941,7 +931,7 @@ static void hvfb_get_option(struct fb_info *info)
 
        if (x < HVFB_WIDTH_MIN || y < HVFB_HEIGHT_MIN ||
            (synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10) &&
-           (x > screen_width_max || y > screen_height_max)) ||
+           (x * y * screen_depth / 8 > screen_fb_size)) ||
            (par->synthvid_version == SYNTHVID_VERSION_WIN8 &&
             x * y * screen_depth / 8 > SYNTHVID_FB_SIZE_WIN8) ||
            (par->synthvid_version == SYNTHVID_VERSION_WIN7 &&
@@ -1194,8 +1184,8 @@ static int hvfb_probe(struct hv_device *hdev,
        }
 
        hvfb_get_option(info);
-       pr_info("Screen resolution: %dx%d, Color depth: %d\n",
-               screen_width, screen_height, screen_depth);
+       pr_info("Screen resolution: %dx%d, Color depth: %d, Frame buffer size: %d\n",
+               screen_width, screen_height, screen_depth, screen_fb_size);
 
        ret = hvfb_getmem(hdev, info);
        if (ret) {
index 0fe922f..bcacfb6 100644 (file)
@@ -505,15 +505,15 @@ void xxxfb_fillrect(struct fb_info *p, const struct fb_fillrect *region)
 }
 
 /**
- *      xxxfb_copyarea - OBSOLETE function.
+ *      xxxfb_copyarea - REQUIRED function. Can use generic routines if
+ *                       non acclerated hardware and packed pixel based.
  *                       Copies one area of the screen to another area.
- *                       Will be deleted in a future version
  *
  *      @info: frame buffer structure that represents a single frame buffer
  *      @area: Structure providing the data to copy the framebuffer contents
  *            from one region to another.
  *
- *      This drawing operation copied a rectangular area from one area of the
+ *      This drawing operation copies a rectangular area from one area of the
  *     screen to another area.
  */
 void xxxfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) 
@@ -645,9 +645,9 @@ static const struct fb_ops xxxfb_ops = {
        .fb_setcolreg   = xxxfb_setcolreg,
        .fb_blank       = xxxfb_blank,
        .fb_pan_display = xxxfb_pan_display,
-       .fb_fillrect    = xxxfb_fillrect,       /* Needed !!!   */
-       .fb_copyarea    = xxxfb_copyarea,       /* Obsolete     */
-       .fb_imageblit   = xxxfb_imageblit,      /* Needed !!!   */
+       .fb_fillrect    = xxxfb_fillrect,       /* Needed !!! */
+       .fb_copyarea    = xxxfb_copyarea,       /* Needed !!! */
+       .fb_imageblit   = xxxfb_imageblit,      /* Needed !!! */
        .fb_cursor      = xxxfb_cursor,         /* Optional !!! */
        .fb_sync        = xxxfb_sync,
        .fb_ioctl       = xxxfb_ioctl,
index 5655780..c7b8a8e 100644 (file)
@@ -2089,16 +2089,20 @@ static ssize_t w1_seq_show(struct device *device,
                if (sl->reg_num.id == reg_num->id)
                        seq = i;
 
+               if (w1_reset_bus(sl->master))
+                       goto error;
+
+               /* Put the device into chain DONE state */
+               w1_write_8(sl->master, W1_MATCH_ROM);
+               w1_write_block(sl->master, (u8 *)&rn, 8);
                w1_write_8(sl->master, W1_42_CHAIN);
                w1_write_8(sl->master, W1_42_CHAIN_DONE);
                w1_write_8(sl->master, W1_42_CHAIN_DONE_INV);
-               w1_read_block(sl->master, &ack, sizeof(ack));
 
                /* check for acknowledgment */
                ack = w1_read_8(sl->master);
                if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
                        goto error;
-
        }
 
        /* Exit from CHAIN state */
index 2c890f4..72d4e3f 100644 (file)
@@ -264,7 +264,7 @@ struct xen_device_domain_owner {
 };
 
 static DEFINE_SPINLOCK(dev_domain_list_spinlock);
-static struct list_head dev_domain_list = LIST_HEAD_INIT(dev_domain_list);
+static LIST_HEAD(dev_domain_list);
 
 static struct xen_device_domain_owner *find_device(struct pci_dev *dev)
 {
index 6aab046..79df61f 100644 (file)
@@ -96,12 +96,8 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)
                 dentry, dentry, from_kuid(&init_user_ns, uid),
                 any);
        ret = NULL;
-
-       if (d_inode(dentry))
-               ret = v9fs_fid_find_inode(d_inode(dentry), uid);
-
        /* we'll recheck under lock if there's anything to look in */
-       if (!ret && dentry->d_fsdata) {
+       if (dentry->d_fsdata) {
                struct hlist_head *h = (struct hlist_head *)&dentry->d_fsdata;
 
                spin_lock(&dentry->d_lock);
@@ -113,6 +109,9 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)
                        }
                }
                spin_unlock(&dentry->d_lock);
+       } else {
+               if (dentry->d_inode)
+                       ret = v9fs_fid_find_inode(dentry->d_inode, uid);
        }
 
        return ret;
index 7a2b11c..6c7dc13 100644 (file)
@@ -369,8 +369,8 @@ source "fs/ksmbd/Kconfig"
 
 config SMBFS_COMMON
        tristate
-       default y if CIFS=y
-       default m if CIFS=m
+       default y if CIFS=y || SMB_SERVER=y
+       default m if CIFS=m || SMB_SERVER=m
 
 source "fs/coda/Kconfig"
 source "fs/afs/Kconfig"
index dab324a..208a74e 100644 (file)
@@ -96,7 +96,7 @@ obj-$(CONFIG_EXPORTFS)                += exportfs/
 obj-$(CONFIG_NFSD)             += nfsd/
 obj-$(CONFIG_LOCKD)            += lockd/
 obj-$(CONFIG_NLS)              += nls/
-obj-$(CONFIG_UNICODE)          += unicode/
+obj-y                          += unicode/
 obj-$(CONFIG_SYSV_FS)          += sysv/
 obj-$(CONFIG_SMBFS_COMMON)     += smbfs_common/
 obj-$(CONFIG_CIFS)             += cifs/
index 605017e..9e11e6f 100644 (file)
@@ -1117,7 +1117,7 @@ out_free_interp:
                         * without MAP_FIXED nor MAP_FIXED_NOREPLACE).
                         */
                        alignment = maximum_alignment(elf_phdata, elf_ex->e_phnum);
-                       if (alignment > ELF_MIN_ALIGN) {
+                       if (interpreter || alignment > ELF_MIN_ALIGN) {
                                load_bias = ELF_ET_DYN_BASE;
                                if (current->flags & PF_RANDOMIZE)
                                        load_bias += arch_mmap_rnd();
index ddea6ac..e1eae7e 100644 (file)
@@ -822,11 +822,7 @@ static int __init init_misc_binfmt(void)
        int err = register_filesystem(&bm_fs_type);
        if (!err)
                insert_binfmt(&misc_format);
-       if (!register_sysctl_mount_point("fs/binfmt_misc")) {
-               pr_warn("Failed to create fs/binfmt_misc sysctl mount point");
-               return -ENOMEM;
-       }
-       return 0;
+       return err;
 }
 
 static void __exit exit_misc_binfmt(void)
index 1db24e6..8202ad6 100644 (file)
@@ -124,7 +124,16 @@ void btrfs_put_block_group(struct btrfs_block_group *cache)
 {
        if (refcount_dec_and_test(&cache->refs)) {
                WARN_ON(cache->pinned > 0);
-               WARN_ON(cache->reserved > 0);
+               /*
+                * If there was a failure to cleanup a log tree, very likely due
+                * to an IO failure on a writeback attempt of one or more of its
+                * extent buffers, we could not do proper (and cheap) unaccounting
+                * of their reserved space, so don't warn on reserved > 0 in that
+                * case.
+                */
+               if (!(cache->flags & BTRFS_BLOCK_GROUP_METADATA) ||
+                   !BTRFS_FS_LOG_CLEANUP_ERROR(cache->fs_info))
+                       WARN_ON(cache->reserved > 0);
 
                /*
                 * A block_group shouldn't be on the discard_list anymore.
@@ -2544,6 +2553,19 @@ int btrfs_inc_block_group_ro(struct btrfs_block_group *cache,
        int ret;
        bool dirty_bg_running;
 
+       /*
+        * This can only happen when we are doing read-only scrub on read-only
+        * mount.
+        * In that case we should not start a new transaction on read-only fs.
+        * Thus here we skip all chunk allocations.
+        */
+       if (sb_rdonly(fs_info->sb)) {
+               mutex_lock(&fs_info->ro_block_group_mutex);
+               ret = inc_block_group_ro(cache, 0);
+               mutex_unlock(&fs_info->ro_block_group_mutex);
+               return ret;
+       }
+
        do {
                trans = btrfs_join_transaction(root);
                if (IS_ERR(trans))
@@ -3974,9 +3996,22 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
                 * important and indicates a real bug if this happens.
                 */
                if (WARN_ON(space_info->bytes_pinned > 0 ||
-                           space_info->bytes_reserved > 0 ||
                            space_info->bytes_may_use > 0))
                        btrfs_dump_space_info(info, space_info, 0, 0);
+
+               /*
+                * If there was a failure to cleanup a log tree, very likely due
+                * to an IO failure on a writeback attempt of one or more of its
+                * extent buffers, we could not do proper (and cheap) unaccounting
+                * of their reserved space, so don't warn on bytes_reserved > 0 in
+                * that case.
+                */
+               if (!(space_info->flags & BTRFS_BLOCK_GROUP_METADATA) ||
+                   !BTRFS_FS_LOG_CLEANUP_ERROR(info)) {
+                       if (WARN_ON(space_info->bytes_reserved > 0))
+                               btrfs_dump_space_info(info, space_info, 0, 0);
+               }
+
                WARN_ON(space_info->reclaim_size > 0);
                list_del(&space_info->list);
                btrfs_sysfs_remove_space_info(space_info);
index b4a9b1c..947f047 100644 (file)
@@ -145,6 +145,9 @@ enum {
        BTRFS_FS_STATE_DUMMY_FS_INFO,
 
        BTRFS_FS_STATE_NO_CSUMS,
+
+       /* Indicates there was an error cleaning up a log tree. */
+       BTRFS_FS_STATE_LOG_CLEANUP_ERROR,
 };
 
 #define BTRFS_BACKREF_REV_MAX          256
@@ -3288,7 +3291,7 @@ void btrfs_exclop_balance(struct btrfs_fs_info *fs_info,
 int __init btrfs_auto_defrag_init(void);
 void __cold btrfs_auto_defrag_exit(void);
 int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
-                          struct btrfs_inode *inode);
+                          struct btrfs_inode *inode, u32 extent_thresh);
 int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info);
 void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info);
 int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync);
@@ -3593,6 +3596,9 @@ do {                                                              \
 
 #define BTRFS_FS_ERROR(fs_info)        (unlikely(test_bit(BTRFS_FS_STATE_ERROR, \
                                                   &(fs_info)->fs_state)))
+#define BTRFS_FS_LOG_CLEANUP_ERROR(fs_info)                            \
+       (unlikely(test_bit(BTRFS_FS_STATE_LOG_CLEANUP_ERROR,            \
+                          &(fs_info)->fs_state)))
 
 __printf(5, 6)
 __cold
index 5a36add..c28cedd 100644 (file)
@@ -261,6 +261,7 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
                        em->mod_len = (em->mod_len + em->mod_start) - merge->mod_start;
                        em->mod_start = merge->mod_start;
                        em->generation = max(em->generation, merge->generation);
+                       set_bit(EXTENT_FLAG_MERGED, &em->flags);
 
                        rb_erase_cached(&merge->rb_node, &tree->map);
                        RB_CLEAR_NODE(&merge->rb_node);
@@ -278,6 +279,7 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
                RB_CLEAR_NODE(&merge->rb_node);
                em->mod_len = (merge->mod_start + merge->mod_len) - em->mod_start;
                em->generation = max(em->generation, merge->generation);
+               set_bit(EXTENT_FLAG_MERGED, &em->flags);
                free_extent_map(merge);
        }
 }
index 8e21733..d2fa32f 100644 (file)
@@ -25,6 +25,8 @@ enum {
        EXTENT_FLAG_FILLING,
        /* filesystem extent mapping type */
        EXTENT_FLAG_FS_MAPPING,
+       /* This em is merged from two or more physically adjacent ems */
+       EXTENT_FLAG_MERGED,
 };
 
 struct extent_map {
@@ -40,6 +42,12 @@ struct extent_map {
        u64 ram_bytes;
        u64 block_start;
        u64 block_len;
+
+       /*
+        * Generation of the extent map, for merged em it's the highest
+        * generation of all merged ems.
+        * For non-merged extents, it's from btrfs_file_extent_item::generation.
+        */
        u64 generation;
        unsigned long flags;
        /* Used for chunk mappings, flag EXTENT_FLAG_FS_MAPPING must be set */
index 11204db..a0179cc 100644 (file)
@@ -50,11 +50,14 @@ struct inode_defrag {
        /* root objectid */
        u64 root;
 
-       /* last offset we were able to defrag */
-       u64 last_offset;
-
-       /* if we've wrapped around back to zero once already */
-       int cycled;
+       /*
+        * The extent size threshold for autodefrag.
+        *
+        * This value is different for compressed/non-compressed extents,
+        * thus needs to be passed from higher layer.
+        * (aka, inode_should_defrag())
+        */
+       u32 extent_thresh;
 };
 
 static int __compare_inode_defrag(struct inode_defrag *defrag1,
@@ -107,8 +110,8 @@ static int __btrfs_add_inode_defrag(struct btrfs_inode *inode,
                         */
                        if (defrag->transid < entry->transid)
                                entry->transid = defrag->transid;
-                       if (defrag->last_offset > entry->last_offset)
-                               entry->last_offset = defrag->last_offset;
+                       entry->extent_thresh = min(defrag->extent_thresh,
+                                                  entry->extent_thresh);
                        return -EEXIST;
                }
        }
@@ -134,7 +137,7 @@ static inline int __need_auto_defrag(struct btrfs_fs_info *fs_info)
  * enabled
  */
 int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
-                          struct btrfs_inode *inode)
+                          struct btrfs_inode *inode, u32 extent_thresh)
 {
        struct btrfs_root *root = inode->root;
        struct btrfs_fs_info *fs_info = root->fs_info;
@@ -160,6 +163,7 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
        defrag->ino = btrfs_ino(inode);
        defrag->transid = transid;
        defrag->root = root->root_key.objectid;
+       defrag->extent_thresh = extent_thresh;
 
        spin_lock(&fs_info->defrag_inodes_lock);
        if (!test_bit(BTRFS_INODE_IN_DEFRAG, &inode->runtime_flags)) {
@@ -178,34 +182,6 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
        return 0;
 }
 
-/*
- * Requeue the defrag object. If there is a defrag object that points to
- * the same inode in the tree, we will merge them together (by
- * __btrfs_add_inode_defrag()) and free the one that we want to requeue.
- */
-static void btrfs_requeue_inode_defrag(struct btrfs_inode *inode,
-                                      struct inode_defrag *defrag)
-{
-       struct btrfs_fs_info *fs_info = inode->root->fs_info;
-       int ret;
-
-       if (!__need_auto_defrag(fs_info))
-               goto out;
-
-       /*
-        * Here we don't check the IN_DEFRAG flag, because we need merge
-        * them together.
-        */
-       spin_lock(&fs_info->defrag_inodes_lock);
-       ret = __btrfs_add_inode_defrag(inode, defrag);
-       spin_unlock(&fs_info->defrag_inodes_lock);
-       if (ret)
-               goto out;
-       return;
-out:
-       kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
-}
-
 /*
  * pick the defragable inode that we want, if it doesn't exist, we will get
  * the next one.
@@ -278,8 +254,14 @@ static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info,
        struct btrfs_root *inode_root;
        struct inode *inode;
        struct btrfs_ioctl_defrag_range_args range;
-       int num_defrag;
-       int ret;
+       int ret = 0;
+       u64 cur = 0;
+
+again:
+       if (test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state))
+               goto cleanup;
+       if (!__need_auto_defrag(fs_info))
+               goto cleanup;
 
        /* get the inode */
        inode_root = btrfs_get_fs_root(fs_info, defrag->root, true);
@@ -295,39 +277,30 @@ static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info,
                goto cleanup;
        }
 
+       if (cur >= i_size_read(inode)) {
+               iput(inode);
+               goto cleanup;
+       }
+
        /* do a chunk of defrag */
        clear_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags);
        memset(&range, 0, sizeof(range));
        range.len = (u64)-1;
-       range.start = defrag->last_offset;
+       range.start = cur;
+       range.extent_thresh = defrag->extent_thresh;
 
        sb_start_write(fs_info->sb);
-       num_defrag = btrfs_defrag_file(inode, NULL, &range, defrag->transid,
+       ret = btrfs_defrag_file(inode, NULL, &range, defrag->transid,
                                       BTRFS_DEFRAG_BATCH);
        sb_end_write(fs_info->sb);
-       /*
-        * if we filled the whole defrag batch, there
-        * must be more work to do.  Queue this defrag
-        * again
-        */
-       if (num_defrag == BTRFS_DEFRAG_BATCH) {
-               defrag->last_offset = range.start;
-               btrfs_requeue_inode_defrag(BTRFS_I(inode), defrag);
-       } else if (defrag->last_offset && !defrag->cycled) {
-               /*
-                * we didn't fill our defrag batch, but
-                * we didn't start at zero.  Make sure we loop
-                * around to the start of the file.
-                */
-               defrag->last_offset = 0;
-               defrag->cycled = 1;
-               btrfs_requeue_inode_defrag(BTRFS_I(inode), defrag);
-       } else {
-               kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
-       }
-
        iput(inode);
-       return 0;
+
+       if (ret < 0)
+               goto cleanup;
+
+       cur = max(cur + fs_info->sectorsize, range.start);
+       goto again;
+
 cleanup:
        kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
        return ret;
index 3b2403b..76e530f 100644 (file)
@@ -560,12 +560,12 @@ static inline int inode_need_compress(struct btrfs_inode *inode, u64 start,
 }
 
 static inline void inode_should_defrag(struct btrfs_inode *inode,
-               u64 start, u64 end, u64 num_bytes, u64 small_write)
+               u64 start, u64 end, u64 num_bytes, u32 small_write)
 {
        /* If this is a small write inside eof, kick off a defrag */
        if (num_bytes < small_write &&
            (start > 0 || end + 1 < inode->disk_i_size))
-               btrfs_add_inode_defrag(NULL, inode);
+               btrfs_add_inode_defrag(NULL, inode, small_write);
 }
 
 /*
index a5bd692..8d47ec5 100644 (file)
@@ -805,10 +805,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
                goto fail;
        }
 
-       spin_lock(&fs_info->trans_lock);
-       list_add(&pending_snapshot->list,
-                &trans->transaction->pending_snapshots);
-       spin_unlock(&fs_info->trans_lock);
+       trans->pending_snapshot = pending_snapshot;
 
        ret = btrfs_commit_transaction(trans);
        if (ret)
@@ -1015,8 +1012,155 @@ out:
        return ret;
 }
 
+/*
+ * Defrag specific helper to get an extent map.
+ *
+ * Differences between this and btrfs_get_extent() are:
+ *
+ * - No extent_map will be added to inode->extent_tree
+ *   To reduce memory usage in the long run.
+ *
+ * - Extra optimization to skip file extents older than @newer_than
+ *   By using btrfs_search_forward() we can skip entire file ranges that
+ *   have extents created in past transactions, because btrfs_search_forward()
+ *   will not visit leaves and nodes with a generation smaller than given
+ *   minimal generation threshold (@newer_than).
+ *
+ * Return valid em if we find a file extent matching the requirement.
+ * Return NULL if we can not find a file extent matching the requirement.
+ *
+ * Return ERR_PTR() for error.
+ */
+static struct extent_map *defrag_get_extent(struct btrfs_inode *inode,
+                                           u64 start, u64 newer_than)
+{
+       struct btrfs_root *root = inode->root;
+       struct btrfs_file_extent_item *fi;
+       struct btrfs_path path = { 0 };
+       struct extent_map *em;
+       struct btrfs_key key;
+       u64 ino = btrfs_ino(inode);
+       int ret;
+
+       em = alloc_extent_map();
+       if (!em) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       key.objectid = ino;
+       key.type = BTRFS_EXTENT_DATA_KEY;
+       key.offset = start;
+
+       if (newer_than) {
+               ret = btrfs_search_forward(root, &key, &path, newer_than);
+               if (ret < 0)
+                       goto err;
+               /* Can't find anything newer */
+               if (ret > 0)
+                       goto not_found;
+       } else {
+               ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
+               if (ret < 0)
+                       goto err;
+       }
+       if (path.slots[0] >= btrfs_header_nritems(path.nodes[0])) {
+               /*
+                * If btrfs_search_slot() makes path to point beyond nritems,
+                * we should not have an empty leaf, as this inode must at
+                * least have its INODE_ITEM.
+                */
+               ASSERT(btrfs_header_nritems(path.nodes[0]));
+               path.slots[0] = btrfs_header_nritems(path.nodes[0]) - 1;
+       }
+       btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
+       /* Perfect match, no need to go one slot back */
+       if (key.objectid == ino && key.type == BTRFS_EXTENT_DATA_KEY &&
+           key.offset == start)
+               goto iterate;
+
+       /* We didn't find a perfect match, needs to go one slot back */
+       if (path.slots[0] > 0) {
+               btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
+               if (key.objectid == ino && key.type == BTRFS_EXTENT_DATA_KEY)
+                       path.slots[0]--;
+       }
+
+iterate:
+       /* Iterate through the path to find a file extent covering @start */
+       while (true) {
+               u64 extent_end;
+
+               if (path.slots[0] >= btrfs_header_nritems(path.nodes[0]))
+                       goto next;
+
+               btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
+
+               /*
+                * We may go one slot back to INODE_REF/XATTR item, then
+                * need to go forward until we reach an EXTENT_DATA.
+                * But we should still has the correct ino as key.objectid.
+                */
+               if (WARN_ON(key.objectid < ino) || key.type < BTRFS_EXTENT_DATA_KEY)
+                       goto next;
+
+               /* It's beyond our target range, definitely not extent found */
+               if (key.objectid > ino || key.type > BTRFS_EXTENT_DATA_KEY)
+                       goto not_found;
+
+               /*
+                *      |       |<- File extent ->|
+                *      \- start
+                *
+                * This means there is a hole between start and key.offset.
+                */
+               if (key.offset > start) {
+                       em->start = start;
+                       em->orig_start = start;
+                       em->block_start = EXTENT_MAP_HOLE;
+                       em->len = key.offset - start;
+                       break;
+               }
+
+               fi = btrfs_item_ptr(path.nodes[0], path.slots[0],
+                                   struct btrfs_file_extent_item);
+               extent_end = btrfs_file_extent_end(&path);
+
+               /*
+                *      |<- file extent ->|     |
+                *                              \- start
+                *
+                * We haven't reached start, search next slot.
+                */
+               if (extent_end <= start)
+                       goto next;
+
+               /* Now this extent covers @start, convert it to em */
+               btrfs_extent_item_to_extent_map(inode, &path, fi, false, em);
+               break;
+next:
+               ret = btrfs_next_item(root, &path);
+               if (ret < 0)
+                       goto err;
+               if (ret > 0)
+                       goto not_found;
+       }
+       btrfs_release_path(&path);
+       return em;
+
+not_found:
+       btrfs_release_path(&path);
+       free_extent_map(em);
+       return NULL;
+
+err:
+       btrfs_release_path(&path);
+       free_extent_map(em);
+       return ERR_PTR(ret);
+}
+
 static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start,
-                                              bool locked)
+                                              u64 newer_than, bool locked)
 {
        struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
@@ -1031,6 +1175,20 @@ static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start,
        em = lookup_extent_mapping(em_tree, start, sectorsize);
        read_unlock(&em_tree->lock);
 
+       /*
+        * We can get a merged extent, in that case, we need to re-search
+        * tree to get the original em for defrag.
+        *
+        * If @newer_than is 0 or em::generation < newer_than, we can trust
+        * this em, as either we don't care about the generation, or the
+        * merged extent map will be rejected anyway.
+        */
+       if (em && test_bit(EXTENT_FLAG_MERGED, &em->flags) &&
+           newer_than && em->generation >= newer_than) {
+               free_extent_map(em);
+               em = NULL;
+       }
+
        if (!em) {
                struct extent_state *cached = NULL;
                u64 end = start + sectorsize - 1;
@@ -1038,7 +1196,7 @@ static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start,
                /* get the big lock and read metadata off disk */
                if (!locked)
                        lock_extent_bits(io_tree, start, end, &cached);
-               em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, start, sectorsize);
+               em = defrag_get_extent(BTRFS_I(inode), start, newer_than);
                if (!locked)
                        unlock_extent_cached(io_tree, start, end, &cached);
 
@@ -1049,23 +1207,42 @@ static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start,
        return em;
 }
 
+static u32 get_extent_max_capacity(const struct extent_map *em)
+{
+       if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
+               return BTRFS_MAX_COMPRESSED;
+       return BTRFS_MAX_EXTENT_SIZE;
+}
+
 static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em,
                                     bool locked)
 {
        struct extent_map *next;
-       bool ret = true;
+       bool ret = false;
 
        /* this is the last extent */
        if (em->start + em->len >= i_size_read(inode))
                return false;
 
-       next = defrag_lookup_extent(inode, em->start + em->len, locked);
+       /*
+        * We want to check if the next extent can be merged with the current
+        * one, which can be an extent created in a past generation, so we pass
+        * a minimum generation of 0 to defrag_lookup_extent().
+        */
+       next = defrag_lookup_extent(inode, em->start + em->len, 0, locked);
+       /* No more em or hole */
        if (!next || next->block_start >= EXTENT_MAP_LAST_BYTE)
-               ret = false;
-       else if ((em->block_start + em->block_len == next->block_start) &&
-                (em->block_len > SZ_128K && next->block_len > SZ_128K))
-               ret = false;
-
+               goto out;
+       if (test_bit(EXTENT_FLAG_PREALLOC, &next->flags))
+               goto out;
+       /*
+        * If the next extent is at its max capacity, defragging current extent
+        * makes no sense, as the total number of extents won't change.
+        */
+       if (next->len >= get_extent_max_capacity(em))
+               goto out;
+       ret = true;
+out:
        free_extent_map(next);
        return ret;
 }
@@ -1189,8 +1366,10 @@ struct defrag_target_range {
 static int defrag_collect_targets(struct btrfs_inode *inode,
                                  u64 start, u64 len, u32 extent_thresh,
                                  u64 newer_than, bool do_compress,
-                                 bool locked, struct list_head *target_list)
+                                 bool locked, struct list_head *target_list,
+                                 u64 *last_scanned_ret)
 {
+       bool last_is_target = false;
        u64 cur = start;
        int ret = 0;
 
@@ -1200,7 +1379,9 @@ static int defrag_collect_targets(struct btrfs_inode *inode,
                bool next_mergeable = true;
                u64 range_len;
 
-               em = defrag_lookup_extent(&inode->vfs_inode, cur, locked);
+               last_is_target = false;
+               em = defrag_lookup_extent(&inode->vfs_inode, cur,
+                                         newer_than, locked);
                if (!em)
                        break;
 
@@ -1213,6 +1394,39 @@ static int defrag_collect_targets(struct btrfs_inode *inode,
                if (em->generation < newer_than)
                        goto next;
 
+               /* This em is under writeback, no need to defrag */
+               if (em->generation == (u64)-1)
+                       goto next;
+
+               /*
+                * Our start offset might be in the middle of an existing extent
+                * map, so take that into account.
+                */
+               range_len = em->len - (cur - em->start);
+               /*
+                * If this range of the extent map is already flagged for delalloc,
+                * skip it, because:
+                *
+                * 1) We could deadlock later, when trying to reserve space for
+                *    delalloc, because in case we can't immediately reserve space
+                *    the flusher can start delalloc and wait for the respective
+                *    ordered extents to complete. The deadlock would happen
+                *    because we do the space reservation while holding the range
+                *    locked, and starting writeback, or finishing an ordered
+                *    extent, requires locking the range;
+                *
+                * 2) If there's delalloc there, it means there's dirty pages for
+                *    which writeback has not started yet (we clean the delalloc
+                *    flag when starting writeback and after creating an ordered
+                *    extent). If we mark pages in an adjacent range for defrag,
+                *    then we will have a larger contiguous range for delalloc,
+                *    very likely resulting in a larger extent after writeback is
+                *    triggered (except in a case of free space fragmentation).
+                */
+               if (test_range_bit(&inode->io_tree, cur, cur + range_len - 1,
+                                  EXTENT_DELALLOC, 0, NULL))
+                       goto next;
+
                /*
                 * For do_compress case, we want to compress all valid file
                 * extents, thus no @extent_thresh or mergeable check.
@@ -1221,7 +1435,14 @@ static int defrag_collect_targets(struct btrfs_inode *inode,
                        goto add;
 
                /* Skip too large extent */
-               if (em->len >= extent_thresh)
+               if (range_len >= extent_thresh)
+                       goto next;
+
+               /*
+                * Skip extents already at its max capacity, this is mostly for
+                * compressed extents, which max cap is only 128K.
+                */
+               if (em->len >= get_extent_max_capacity(em))
                        goto next;
 
                next_mergeable = defrag_check_next_extent(&inode->vfs_inode, em,
@@ -1242,6 +1463,7 @@ static int defrag_collect_targets(struct btrfs_inode *inode,
                }
 
 add:
+               last_is_target = true;
                range_len = min(extent_map_end(em), start + len) - cur;
                /*
                 * This one is a good target, check if it can be merged into
@@ -1285,6 +1507,17 @@ next:
                        kfree(entry);
                }
        }
+       if (!ret && last_scanned_ret) {
+               /*
+                * If the last extent is not a target, the caller can skip to
+                * the end of that extent.
+                * Otherwise, we can only go the end of the specified range.
+                */
+               if (!last_is_target)
+                       *last_scanned_ret = max(cur, *last_scanned_ret);
+               else
+                       *last_scanned_ret = max(start + len, *last_scanned_ret);
+       }
        return ret;
 }
 
@@ -1343,7 +1576,8 @@ static int defrag_one_locked_target(struct btrfs_inode *inode,
 }
 
 static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len,
-                           u32 extent_thresh, u64 newer_than, bool do_compress)
+                           u32 extent_thresh, u64 newer_than, bool do_compress,
+                           u64 *last_scanned_ret)
 {
        struct extent_state *cached_state = NULL;
        struct defrag_target_range *entry;
@@ -1389,7 +1623,7 @@ static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len,
         */
        ret = defrag_collect_targets(inode, start, len, extent_thresh,
                                     newer_than, do_compress, true,
-                                    &target_list);
+                                    &target_list, last_scanned_ret);
        if (ret < 0)
                goto unlock_extent;
 
@@ -1424,7 +1658,8 @@ static int defrag_one_cluster(struct btrfs_inode *inode,
                              u64 start, u32 len, u32 extent_thresh,
                              u64 newer_than, bool do_compress,
                              unsigned long *sectors_defragged,
-                             unsigned long max_sectors)
+                             unsigned long max_sectors,
+                             u64 *last_scanned_ret)
 {
        const u32 sectorsize = inode->root->fs_info->sectorsize;
        struct defrag_target_range *entry;
@@ -1435,21 +1670,32 @@ static int defrag_one_cluster(struct btrfs_inode *inode,
        BUILD_BUG_ON(!IS_ALIGNED(CLUSTER_SIZE, PAGE_SIZE));
        ret = defrag_collect_targets(inode, start, len, extent_thresh,
                                     newer_than, do_compress, false,
-                                    &target_list);
+                                    &target_list, NULL);
        if (ret < 0)
                goto out;
 
        list_for_each_entry(entry, &target_list, list) {
                u32 range_len = entry->len;
 
-               /* Reached the limit */
-               if (max_sectors && max_sectors == *sectors_defragged)
+               /* Reached or beyond the limit */
+               if (max_sectors && *sectors_defragged >= max_sectors) {
+                       ret = 1;
                        break;
+               }
 
                if (max_sectors)
                        range_len = min_t(u32, range_len,
                                (max_sectors - *sectors_defragged) * sectorsize);
 
+               /*
+                * If defrag_one_range() has updated last_scanned_ret,
+                * our range may already be invalid (e.g. hole punched).
+                * Skip if our range is before last_scanned_ret, as there is
+                * no need to defrag the range anymore.
+                */
+               if (entry->start + range_len <= *last_scanned_ret)
+                       continue;
+
                if (ra)
                        page_cache_sync_readahead(inode->vfs_inode.i_mapping,
                                ra, NULL, entry->start >> PAGE_SHIFT,
@@ -1462,16 +1708,20 @@ static int defrag_one_cluster(struct btrfs_inode *inode,
                 * accounting.
                 */
                ret = defrag_one_range(inode, entry->start, range_len,
-                                      extent_thresh, newer_than, do_compress);
+                                      extent_thresh, newer_than, do_compress,
+                                      last_scanned_ret);
                if (ret < 0)
                        break;
-               *sectors_defragged += range_len;
+               *sectors_defragged += range_len >>
+                                     inode->root->fs_info->sectorsize_bits;
        }
 out:
        list_for_each_entry_safe(entry, tmp, &target_list, list) {
                list_del_init(&entry->list);
                kfree(entry);
        }
+       if (ret >= 0)
+               *last_scanned_ret = max(*last_scanned_ret, start + len);
        return ret;
 }
 
@@ -1484,6 +1734,12 @@ out:
  * @newer_than:           minimum transid to defrag
  * @max_to_defrag: max number of sectors to be defragged, if 0, the whole inode
  *                will be defragged.
+ *
+ * Return <0 for error.
+ * Return >=0 for the number of sectors defragged, and range->start will be updated
+ * to indicate the file offset where next defrag should be started at.
+ * (Mostly for autodefrag, which sets @max_to_defrag thus we may exit early without
+ *  defragging all the range).
  */
 int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
                      struct btrfs_ioctl_defrag_range_args *range,
@@ -1499,6 +1755,7 @@ int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
        int compress_type = BTRFS_COMPRESS_ZLIB;
        int ret = 0;
        u32 extent_thresh = range->extent_thresh;
+       pgoff_t start_index;
 
        if (isize == 0)
                return 0;
@@ -1518,12 +1775,16 @@ int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
 
        if (range->start + range->len > range->start) {
                /* Got a specific range */
-               last_byte = min(isize, range->start + range->len) - 1;
+               last_byte = min(isize, range->start + range->len);
        } else {
                /* Defrag until file end */
-               last_byte = isize - 1;
+               last_byte = isize;
        }
 
+       /* Align the range */
+       cur = round_down(range->start, fs_info->sectorsize);
+       last_byte = round_up(last_byte, fs_info->sectorsize) - 1;
+
        /*
         * If we were not given a ra, allocate a readahead context. As
         * readahead is just an optimization, defrag will work without it so
@@ -1536,16 +1797,27 @@ int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
                        file_ra_state_init(ra, inode->i_mapping);
        }
 
-       /* Align the range */
-       cur = round_down(range->start, fs_info->sectorsize);
-       last_byte = round_up(last_byte, fs_info->sectorsize) - 1;
+       /*
+        * Make writeback start from the beginning of the range, so that the
+        * defrag range can be written sequentially.
+        */
+       start_index = cur >> PAGE_SHIFT;
+       if (start_index < inode->i_mapping->writeback_index)
+               inode->i_mapping->writeback_index = start_index;
 
        while (cur < last_byte) {
+               const unsigned long prev_sectors_defragged = sectors_defragged;
+               u64 last_scanned = cur;
                u64 cluster_end;
 
                /* The cluster size 256K should always be page aligned */
                BUILD_BUG_ON(!IS_ALIGNED(CLUSTER_SIZE, PAGE_SIZE));
 
+               if (btrfs_defrag_cancelled(fs_info)) {
+                       ret = -EAGAIN;
+                       break;
+               }
+
                /* We want the cluster end at page boundary when possible */
                cluster_end = (((cur >> PAGE_SHIFT) +
                               (SZ_256K >> PAGE_SHIFT)) << PAGE_SHIFT) - 1;
@@ -1565,16 +1837,30 @@ int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
                        BTRFS_I(inode)->defrag_compress = compress_type;
                ret = defrag_one_cluster(BTRFS_I(inode), ra, cur,
                                cluster_end + 1 - cur, extent_thresh,
-                               newer_than, do_compress,
-                               &sectors_defragged, max_to_defrag);
+                               newer_than, do_compress, &sectors_defragged,
+                               max_to_defrag, &last_scanned);
+
+               if (sectors_defragged > prev_sectors_defragged)
+                       balance_dirty_pages_ratelimited(inode->i_mapping);
+
                btrfs_inode_unlock(inode, 0);
                if (ret < 0)
                        break;
-               cur = cluster_end + 1;
+               cur = max(cluster_end + 1, last_scanned);
+               if (ret > 0) {
+                       ret = 0;
+                       break;
+               }
+               cond_resched();
        }
 
        if (ra_allocated)
                kfree(ra);
+       /*
+        * Update range.start for autodefrag, this will indicate where to start
+        * in next run.
+        */
+       range->start = cur;
        if (sectors_defragged) {
                /*
                 * We have defragged some sectors, for compression case they
@@ -3086,10 +3372,8 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
        btrfs_inode_lock(inode, 0);
        err = btrfs_delete_subvolume(dir, dentry);
        btrfs_inode_unlock(inode, 0);
-       if (!err) {
-               fsnotify_rmdir(dir, dentry);
-               d_delete(dentry);
-       }
+       if (!err)
+               d_delete_notify(dir, dentry);
 
 out_dput:
        dput(dentry);
@@ -3290,7 +3574,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
        struct block_device *bdev = NULL;
        fmode_t mode;
        int ret;
-       bool cancel;
+       bool cancel = false;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
index 0fb90cb..e6e28a9 100644 (file)
@@ -380,6 +380,17 @@ int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
                kunmap(cur_page);
                cur_in += LZO_LEN;
 
+               if (seg_len > lzo1x_worst_compress(PAGE_SIZE)) {
+                       /*
+                        * seg_len shouldn't be larger than we have allocated
+                        * for workspace->cbuf
+                        */
+                       btrfs_err(fs_info, "unexpectedly large lzo segment len %u",
+                                       seg_len);
+                       ret = -EIO;
+                       goto out;
+               }
+
                /* Copy the compressed segment payload into workspace */
                copy_compressed_segment(cb, workspace->cbuf, seg_len, &cur_in);
 
index 8928275..f12dc68 100644 (file)
@@ -1185,9 +1185,24 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
        struct btrfs_trans_handle *trans = NULL;
        int ret = 0;
 
+       /*
+        * We need to have subvol_sem write locked, to prevent races between
+        * concurrent tasks trying to disable quotas, because we will unlock
+        * and relock qgroup_ioctl_lock across BTRFS_FS_QUOTA_ENABLED changes.
+        */
+       lockdep_assert_held_write(&fs_info->subvol_sem);
+
        mutex_lock(&fs_info->qgroup_ioctl_lock);
        if (!fs_info->quota_root)
                goto out;
+
+       /*
+        * Request qgroup rescan worker to complete and wait for it. This wait
+        * must be done before transaction start for quota disable since it may
+        * deadlock with transaction by the qgroup rescan worker.
+        */
+       clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
+       btrfs_qgroup_wait_for_completion(fs_info, false);
        mutex_unlock(&fs_info->qgroup_ioctl_lock);
 
        /*
@@ -1205,14 +1220,13 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
        if (IS_ERR(trans)) {
                ret = PTR_ERR(trans);
                trans = NULL;
+               set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
                goto out;
        }
 
        if (!fs_info->quota_root)
                goto out;
 
-       clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
-       btrfs_qgroup_wait_for_completion(fs_info, false);
        spin_lock(&fs_info->qgroup_lock);
        quota_root = fs_info->quota_root;
        fs_info->quota_root = NULL;
@@ -3383,6 +3397,9 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
                        btrfs_warn(fs_info,
                        "qgroup rescan init failed, qgroup is not enabled");
                        ret = -EINVAL;
+               } else if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) {
+                       /* Quota disable is in progress */
+                       ret = -EBUSY;
                }
 
                if (ret) {
index d8ccb62..201eb26 100644 (file)
@@ -4999,6 +4999,10 @@ static int put_file_data(struct send_ctx *sctx, u64 offset, u32 len)
                        lock_page(page);
                        if (!PageUptodate(page)) {
                                unlock_page(page);
+                               btrfs_err(fs_info,
+                       "send: IO error at offset %llu for inode %llu root %llu",
+                                       page_offset(page), sctx->cur_ino,
+                                       sctx->send_root->root_key.objectid);
                                put_page(page);
                                ret = -EIO;
                                break;
index 03de89b..c3cfdfd 100644 (file)
@@ -1981,16 +1981,24 @@ static void btrfs_cleanup_pending_block_groups(struct btrfs_trans_handle *trans)
 static inline int btrfs_start_delalloc_flush(struct btrfs_fs_info *fs_info)
 {
        /*
-        * We use writeback_inodes_sb here because if we used
+        * We use try_to_writeback_inodes_sb() here because if we used
         * btrfs_start_delalloc_roots we would deadlock with fs freeze.
         * Currently are holding the fs freeze lock, if we do an async flush
         * we'll do btrfs_join_transaction() and deadlock because we need to
         * wait for the fs freeze lock.  Using the direct flushing we benefit
         * from already being in a transaction and our join_transaction doesn't
         * have to re-take the fs freeze lock.
+        *
+        * Note that try_to_writeback_inodes_sb() will only trigger writeback
+        * if it can read lock sb->s_umount. It will always be able to lock it,
+        * except when the filesystem is being unmounted or being frozen, but in
+        * those cases sync_filesystem() is called, which results in calling
+        * writeback_inodes_sb() while holding a write lock on sb->s_umount.
+        * Note that we don't call writeback_inodes_sb() directly, because it
+        * will emit a warning if sb->s_umount is not locked.
         */
        if (btrfs_test_opt(fs_info, FLUSHONCOMMIT))
-               writeback_inodes_sb(fs_info->sb, WB_REASON_SYNC);
+               try_to_writeback_inodes_sb(fs_info->sb, WB_REASON_SYNC);
        return 0;
 }
 
@@ -2000,6 +2008,27 @@ static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info)
                btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1);
 }
 
+/*
+ * Add a pending snapshot associated with the given transaction handle to the
+ * respective handle. This must be called after the transaction commit started
+ * and while holding fs_info->trans_lock.
+ * This serves to guarantee a caller of btrfs_commit_transaction() that it can
+ * safely free the pending snapshot pointer in case btrfs_commit_transaction()
+ * returns an error.
+ */
+static void add_pending_snapshot(struct btrfs_trans_handle *trans)
+{
+       struct btrfs_transaction *cur_trans = trans->transaction;
+
+       if (!trans->pending_snapshot)
+               return;
+
+       lockdep_assert_held(&trans->fs_info->trans_lock);
+       ASSERT(cur_trans->state >= TRANS_STATE_COMMIT_START);
+
+       list_add(&trans->pending_snapshot->list, &cur_trans->pending_snapshots);
+}
+
 int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
 {
        struct btrfs_fs_info *fs_info = trans->fs_info;
@@ -2073,6 +2102,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
        if (cur_trans->state >= TRANS_STATE_COMMIT_START) {
                enum btrfs_trans_state want_state = TRANS_STATE_COMPLETED;
 
+               add_pending_snapshot(trans);
+
                spin_unlock(&fs_info->trans_lock);
                refcount_inc(&cur_trans->use_count);
 
@@ -2163,6 +2194,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
         * COMMIT_DOING so make sure to wait for num_writers to == 1 again.
         */
        spin_lock(&fs_info->trans_lock);
+       add_pending_snapshot(trans);
        cur_trans->state = TRANS_STATE_COMMIT_DOING;
        spin_unlock(&fs_info->trans_lock);
        wait_event(cur_trans->writer_wait,
index 1852ed9..9402d8d 100644 (file)
@@ -123,6 +123,8 @@ struct btrfs_trans_handle {
        struct btrfs_transaction *transaction;
        struct btrfs_block_rsv *block_rsv;
        struct btrfs_block_rsv *orig_rsv;
+       /* Set by a task that wants to create a snapshot. */
+       struct btrfs_pending_snapshot *pending_snapshot;
        refcount_t use_count;
        unsigned int type;
        /*
index 72e1c94..9fd145f 100644 (file)
@@ -965,6 +965,7 @@ static int check_dev_item(struct extent_buffer *leaf,
                          struct btrfs_key *key, int slot)
 {
        struct btrfs_dev_item *ditem;
+       const u32 item_size = btrfs_item_size(leaf, slot);
 
        if (unlikely(key->objectid != BTRFS_DEV_ITEMS_OBJECTID)) {
                dev_item_err(leaf, slot,
@@ -972,6 +973,13 @@ static int check_dev_item(struct extent_buffer *leaf,
                             key->objectid, BTRFS_DEV_ITEMS_OBJECTID);
                return -EUCLEAN;
        }
+
+       if (unlikely(item_size != sizeof(*ditem))) {
+               dev_item_err(leaf, slot, "invalid item size: has %u expect %zu",
+                            item_size, sizeof(*ditem));
+               return -EUCLEAN;
+       }
+
        ditem = btrfs_item_ptr(leaf, slot, struct btrfs_dev_item);
        if (unlikely(btrfs_device_id(leaf, ditem) != key->offset)) {
                dev_item_err(leaf, slot,
@@ -1007,6 +1015,7 @@ static int check_inode_item(struct extent_buffer *leaf,
        struct btrfs_inode_item *iitem;
        u64 super_gen = btrfs_super_generation(fs_info->super_copy);
        u32 valid_mask = (S_IFMT | S_ISUID | S_ISGID | S_ISVTX | 0777);
+       const u32 item_size = btrfs_item_size(leaf, slot);
        u32 mode;
        int ret;
        u32 flags;
@@ -1016,6 +1025,12 @@ static int check_inode_item(struct extent_buffer *leaf,
        if (unlikely(ret < 0))
                return ret;
 
+       if (unlikely(item_size != sizeof(*iitem))) {
+               generic_err(leaf, slot, "invalid item size: has %u expect %zu",
+                           item_size, sizeof(*iitem));
+               return -EUCLEAN;
+       }
+
        iitem = btrfs_item_ptr(leaf, slot, struct btrfs_inode_item);
 
        /* Here we use super block generation + 1 to handle log tree */
index c1ddbe8..3ee014c 100644 (file)
@@ -3414,6 +3414,29 @@ static void free_log_tree(struct btrfs_trans_handle *trans,
        if (log->node) {
                ret = walk_log_tree(trans, log, &wc);
                if (ret) {
+                       /*
+                        * We weren't able to traverse the entire log tree, the
+                        * typical scenario is getting an -EIO when reading an
+                        * extent buffer of the tree, due to a previous writeback
+                        * failure of it.
+                        */
+                       set_bit(BTRFS_FS_STATE_LOG_CLEANUP_ERROR,
+                               &log->fs_info->fs_state);
+
+                       /*
+                        * Some extent buffers of the log tree may still be dirty
+                        * and not yet written back to storage, because we may
+                        * have updates to a log tree without syncing a log tree,
+                        * such as during rename and link operations. So flush
+                        * them out and wait for their writeback to complete, so
+                        * that we properly cleanup their state and pages.
+                        */
+                       btrfs_write_marked_extents(log->fs_info,
+                                                  &log->dirty_log_pages,
+                                                  EXTENT_DIRTY | EXTENT_NEW);
+                       btrfs_wait_tree_log_extents(log,
+                                                   EXTENT_DIRTY | EXTENT_NEW);
+
                        if (trans)
                                btrfs_abort_transaction(trans, ret);
                        else
index 04eb527..753986e 100644 (file)
@@ -191,6 +191,64 @@ presubmission_error:
        return ret;
 }
 
+/*
+ * Query the occupancy of the cache in a region, returning where the next chunk
+ * of data starts and how long it is.
+ */
+static int cachefiles_query_occupancy(struct netfs_cache_resources *cres,
+                                     loff_t start, size_t len, size_t granularity,
+                                     loff_t *_data_start, size_t *_data_len)
+{
+       struct cachefiles_object *object;
+       struct file *file;
+       loff_t off, off2;
+
+       *_data_start = -1;
+       *_data_len = 0;
+
+       if (!fscache_wait_for_operation(cres, FSCACHE_WANT_READ))
+               return -ENOBUFS;
+
+       object = cachefiles_cres_object(cres);
+       file = cachefiles_cres_file(cres);
+       granularity = max_t(size_t, object->volume->cache->bsize, granularity);
+
+       _enter("%pD,%li,%llx,%zx/%llx",
+              file, file_inode(file)->i_ino, start, len,
+              i_size_read(file_inode(file)));
+
+       off = cachefiles_inject_read_error();
+       if (off == 0)
+               off = vfs_llseek(file, start, SEEK_DATA);
+       if (off == -ENXIO)
+               return -ENODATA; /* Beyond EOF */
+       if (off < 0 && off >= (loff_t)-MAX_ERRNO)
+               return -ENOBUFS; /* Error. */
+       if (round_up(off, granularity) >= start + len)
+               return -ENODATA; /* No data in range */
+
+       off2 = cachefiles_inject_read_error();
+       if (off2 == 0)
+               off2 = vfs_llseek(file, off, SEEK_HOLE);
+       if (off2 == -ENXIO)
+               return -ENODATA; /* Beyond EOF */
+       if (off2 < 0 && off2 >= (loff_t)-MAX_ERRNO)
+               return -ENOBUFS; /* Error. */
+
+       /* Round away partial blocks */
+       off = round_up(off, granularity);
+       off2 = round_down(off2, granularity);
+       if (off2 <= off)
+               return -ENODATA;
+
+       *_data_start = off;
+       if (off2 > start + len)
+               *_data_len = len;
+       else
+               *_data_len = off2 - off;
+       return 0;
+}
+
 /*
  * Handle completion of a write to the cache.
  */
@@ -545,6 +603,7 @@ static const struct netfs_cache_ops cachefiles_netfs_cache_ops = {
        .write                  = cachefiles_write,
        .prepare_read           = cachefiles_prepare_read,
        .prepare_write          = cachefiles_prepare_write,
+       .query_occupancy        = cachefiles_query_occupancy,
 };
 
 /*
index 7d305b9..b472cd0 100644 (file)
@@ -2218,6 +2218,7 @@ static int unsafe_request_wait(struct inode *inode)
        struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_mds_request *req1 = NULL, *req2 = NULL;
+       unsigned int max_sessions;
        int ret, err = 0;
 
        spin_lock(&ci->i_unsafe_lock);
@@ -2235,37 +2236,45 @@ static int unsafe_request_wait(struct inode *inode)
        }
        spin_unlock(&ci->i_unsafe_lock);
 
+       /*
+        * The mdsc->max_sessions is unlikely to be changed
+        * mostly, here we will retry it by reallocating the
+        * sessions array memory to get rid of the mdsc->mutex
+        * lock.
+        */
+retry:
+       max_sessions = mdsc->max_sessions;
+
        /*
         * Trigger to flush the journal logs in all the relevant MDSes
         * manually, or in the worst case we must wait at most 5 seconds
         * to wait the journal logs to be flushed by the MDSes periodically.
         */
-       if (req1 || req2) {
+       if ((req1 || req2) && likely(max_sessions)) {
                struct ceph_mds_session **sessions = NULL;
                struct ceph_mds_session *s;
                struct ceph_mds_request *req;
-               unsigned int max;
                int i;
 
-               /*
-                * The mdsc->max_sessions is unlikely to be changed
-                * mostly, here we will retry it by reallocating the
-                * sessions arrary memory to get rid of the mdsc->mutex
-                * lock.
-                */
-retry:
-               max = mdsc->max_sessions;
-               sessions = krealloc(sessions, max * sizeof(s), __GFP_ZERO);
-               if (!sessions)
-                       return -ENOMEM;
+               sessions = kzalloc(max_sessions * sizeof(s), GFP_KERNEL);
+               if (!sessions) {
+                       err = -ENOMEM;
+                       goto out;
+               }
 
                spin_lock(&ci->i_unsafe_lock);
                if (req1) {
                        list_for_each_entry(req, &ci->i_unsafe_dirops,
                                            r_unsafe_dir_item) {
                                s = req->r_session;
-                               if (unlikely(s->s_mds >= max)) {
+                               if (unlikely(s->s_mds >= max_sessions)) {
                                        spin_unlock(&ci->i_unsafe_lock);
+                                       for (i = 0; i < max_sessions; i++) {
+                                               s = sessions[i];
+                                               if (s)
+                                                       ceph_put_mds_session(s);
+                                       }
+                                       kfree(sessions);
                                        goto retry;
                                }
                                if (!sessions[s->s_mds]) {
@@ -2278,8 +2287,14 @@ retry:
                        list_for_each_entry(req, &ci->i_unsafe_iops,
                                            r_unsafe_target_item) {
                                s = req->r_session;
-                               if (unlikely(s->s_mds >= max)) {
+                               if (unlikely(s->s_mds >= max_sessions)) {
                                        spin_unlock(&ci->i_unsafe_lock);
+                                       for (i = 0; i < max_sessions; i++) {
+                                               s = sessions[i];
+                                               if (s)
+                                                       ceph_put_mds_session(s);
+                                       }
+                                       kfree(sessions);
                                        goto retry;
                                }
                                if (!sessions[s->s_mds]) {
@@ -2300,7 +2315,7 @@ retry:
                spin_unlock(&ci->i_ceph_lock);
 
                /* send flush mdlog request to MDSes */
-               for (i = 0; i < max; i++) {
+               for (i = 0; i < max_sessions; i++) {
                        s = sessions[i];
                        if (s) {
                                send_flush_mdlog(s);
@@ -2317,15 +2332,19 @@ retry:
                                        ceph_timeout_jiffies(req1->r_timeout));
                if (ret)
                        err = -EIO;
-               ceph_mdsc_put_request(req1);
        }
        if (req2) {
                ret = !wait_for_completion_timeout(&req2->r_safe_completion,
                                        ceph_timeout_jiffies(req2->r_timeout));
                if (ret)
                        err = -EIO;
-               ceph_mdsc_put_request(req2);
        }
+
+out:
+       if (req1)
+               ceph_mdsc_put_request(req1);
+       if (req2)
+               ceph_mdsc_put_request(req2);
        return err;
 }
 
index 5b9104b..bbed322 100644 (file)
@@ -583,6 +583,7 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry,
        struct ceph_inode_info *ci = ceph_inode(dir);
        struct inode *inode;
        struct timespec64 now;
+       struct ceph_string *pool_ns;
        struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(dir->i_sb);
        struct ceph_vino vino = { .ino = req->r_deleg_ino,
                                  .snap = CEPH_NOSNAP };
@@ -632,6 +633,12 @@ static int ceph_finish_async_create(struct inode *dir, struct dentry *dentry,
        in.max_size = cpu_to_le64(lo->stripe_unit);
 
        ceph_file_layout_to_legacy(lo, &in.layout);
+       /* lo is private, so pool_ns can't change */
+       pool_ns = rcu_dereference_raw(lo->pool_ns);
+       if (pool_ns) {
+               iinfo.pool_ns_len = pool_ns->len;
+               iinfo.pool_ns_data = pool_ns->str;
+       }
 
        down_read(&mdsc->snap_rwsem);
        ret = ceph_fill_inode(inode, NULL, &iinfo, NULL, req->r_session,
@@ -750,8 +757,10 @@ retry:
                                restore_deleg_ino(dir, req->r_deleg_ino);
                                ceph_mdsc_put_request(req);
                                try_async = false;
+                               ceph_put_string(rcu_dereference_raw(lo.pool_ns));
                                goto retry;
                        }
+                       ceph_put_string(rcu_dereference_raw(lo.pool_ns));
                        goto out_req;
                }
        }
index 463ebe3..cdce160 100644 (file)
@@ -396,11 +396,11 @@ static int cifs_swn_resource_state_changed(struct cifs_swn_reg *swnreg, const ch
        switch (state) {
        case CIFS_SWN_RESOURCE_STATE_UNAVAILABLE:
                cifs_dbg(FYI, "%s: resource name '%s' become unavailable\n", __func__, name);
-               cifs_reconnect(swnreg->tcon->ses->server, true);
+               cifs_mark_tcp_ses_conns_for_reconnect(swnreg->tcon->ses->server, true);
                break;
        case CIFS_SWN_RESOURCE_STATE_AVAILABLE:
                cifs_dbg(FYI, "%s: resource name '%s' become available\n", __func__, name);
-               cifs_reconnect(swnreg->tcon->ses->server, true);
+               cifs_mark_tcp_ses_conns_for_reconnect(swnreg->tcon->ses->server, true);
                break;
        case CIFS_SWN_RESOURCE_STATE_UNKNOWN:
                cifs_dbg(FYI, "%s: resource name '%s' changed to unknown state\n", __func__, name);
@@ -498,7 +498,7 @@ static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *a
                goto unlock;
        }
 
-       cifs_reconnect(tcon->ses->server, false);
+       cifs_mark_tcp_ses_conns_for_reconnect(tcon->ses->server, false);
 
 unlock:
        mutex_unlock(&tcon->ses->server->srv_mutex);
index ee3aab3..bf861fe 100644 (file)
@@ -949,6 +949,9 @@ static void populate_new_aces(char *nacl_base,
                pnntace = (struct cifs_ace *) (nacl_base + nsize);
                nsize += setup_special_mode_ACE(pnntace, nmode);
                num_aces++;
+               pnntace = (struct cifs_ace *) (nacl_base + nsize);
+               nsize += setup_authusers_ACE(pnntace);
+               num_aces++;
                goto set_size;
        }
 
@@ -1297,7 +1300,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
 
                if (uid_valid(uid)) { /* chown */
                        uid_t id;
-                       nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
+                       nowner_sid_ptr = kzalloc(sizeof(struct cifs_sid),
                                                                GFP_KERNEL);
                        if (!nowner_sid_ptr) {
                                rc = -ENOMEM;
@@ -1326,7 +1329,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
                }
                if (gid_valid(gid)) { /* chgrp */
                        gid_t id;
-                       ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
+                       ngroup_sid_ptr = kzalloc(sizeof(struct cifs_sid),
                                                                GFP_KERNEL);
                        if (!ngroup_sid_ptr) {
                                rc = -ENOMEM;
@@ -1613,7 +1616,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
        nsecdesclen = secdesclen;
        if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */
                if (mode_from_sid)
-                       nsecdesclen += sizeof(struct cifs_ace);
+                       nsecdesclen += 2 * sizeof(struct cifs_ace);
                else /* cifsacl */
                        nsecdesclen += 5 * sizeof(struct cifs_ace);
        } else { /* chown */
index 199edac..082c214 100644 (file)
@@ -919,6 +919,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
 
 out_super:
        deactivate_locked_super(sb);
+       return root;
 out:
        if (cifs_sb) {
                kfree(cifs_sb->prepath);
index 11a22a3..053cb44 100644 (file)
@@ -162,7 +162,7 @@ static void cifs_resolve_server(struct work_struct *work)
        mutex_unlock(&server->srv_mutex);
 }
 
-/**
+/*
  * Mark all sessions and tcons for reconnect.
  *
  * @server needs to be previously set to CifsNeedReconnect.
@@ -175,11 +175,6 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
        struct TCP_Server_Info *pserver;
        struct cifs_ses *ses;
        struct cifs_tcon *tcon;
-       struct mid_q_entry *mid, *nmid;
-       struct list_head retry_list;
-
-       server->maxBuf = 0;
-       server->max_read = 0;
 
        /*
         * before reconnecting the tcp session, mark the smb session (uid) and the tid bad so they
@@ -219,6 +214,16 @@ next_session:
                spin_unlock(&ses->chan_lock);
        }
        spin_unlock(&cifs_tcp_ses_lock);
+}
+
+static void
+cifs_abort_connection(struct TCP_Server_Info *server)
+{
+       struct mid_q_entry *mid, *nmid;
+       struct list_head retry_list;
+
+       server->maxBuf = 0;
+       server->max_read = 0;
 
        /* do not want to be sending data on a socket we are freeing */
        cifs_dbg(FYI, "%s: tearing down socket\n", __func__);
@@ -310,6 +315,8 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
 
        cifs_mark_tcp_ses_conns_for_reconnect(server, mark_smb_session);
 
+       cifs_abort_connection(server);
+
        do {
                try_to_freeze();
                mutex_lock(&server->srv_mutex);
@@ -434,6 +441,8 @@ reconnect_dfs_server(struct TCP_Server_Info *server,
 
        cifs_mark_tcp_ses_conns_for_reconnect(server, mark_smb_session);
 
+       cifs_abort_connection(server);
+
        do {
                try_to_freeze();
                mutex_lock(&server->srv_mutex);
@@ -639,6 +648,7 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
 
                if (server->tcpStatus == CifsNeedReconnect) {
                        spin_unlock(&cifs_tcp_ses_lock);
+                       cifs_reconnect(server, false);
                        return -ECONNABORTED;
                }
                spin_unlock(&cifs_tcp_ses_lock);
@@ -1831,13 +1841,9 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
                int i;
 
                for (i = 1; i < chan_count; i++) {
-                       /*
-                        * note: for now, we're okay accessing ses->chans
-                        * without chan_lock. But when chans can go away, we'll
-                        * need to introduce ref counting to make sure that chan
-                        * is not freed from under us.
-                        */
+                       spin_unlock(&ses->chan_lock);
                        cifs_put_tcp_session(ses->chans[i].server, 0);
+                       spin_lock(&ses->chan_lock);
                        ses->chans[i].server = NULL;
                }
        }
@@ -1981,6 +1987,19 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
                }
        }
 
+       ctx->workstation_name = kstrdup(ses->workstation_name, GFP_KERNEL);
+       if (!ctx->workstation_name) {
+               cifs_dbg(FYI, "Unable to allocate memory for workstation_name\n");
+               rc = -ENOMEM;
+               kfree(ctx->username);
+               ctx->username = NULL;
+               kfree_sensitive(ctx->password);
+               ctx->password = NULL;
+               kfree(ctx->domainname);
+               ctx->domainname = NULL;
+               goto out_key_put;
+       }
+
 out_key_put:
        up_read(&key->sem);
        key_put(key);
@@ -2331,10 +2350,19 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
                if (ses->server->posix_ext_supported) {
                        tcon->posix_extensions = true;
                        pr_warn_once("SMB3.11 POSIX Extensions are experimental\n");
-               } else {
+               } else if ((ses->server->vals->protocol_id == SMB311_PROT_ID) ||
+                   (strcmp(ses->server->vals->version_string,
+                    SMB3ANY_VERSION_STRING) == 0) ||
+                   (strcmp(ses->server->vals->version_string,
+                    SMBDEFAULT_VERSION_STRING) == 0)) {
                        cifs_dbg(VFS, "Server does not support mounting with posix SMB3.11 extensions\n");
                        rc = -EOPNOTSUPP;
                        goto out_fail;
+               } else {
+                       cifs_dbg(VFS, "Check vers= mount option. SMB3.11 "
+                               "disabled but required for POSIX extensions\n");
+                       rc = -EOPNOTSUPP;
+                       goto out_fail;
                }
        }
 
index dd96437..831f424 100644 (file)
@@ -1355,7 +1355,7 @@ static void mark_for_reconnect_if_needed(struct cifs_tcon *tcon, struct dfs_cach
        }
 
        cifs_dbg(FYI, "%s: no cached or matched targets. mark dfs share for reconnect.\n", __func__);
-       cifs_reconnect(tcon->ses->server, true);
+       cifs_mark_tcp_ses_conns_for_reconnect(tcon->ses->server, true);
 }
 
 /* Refresh dfs referral of tcon and mark it for reconnect if needed */
index 59334be..e7af802 100644 (file)
@@ -4269,8 +4269,6 @@ cifs_readv_complete(struct work_struct *work)
        for (i = 0; i < rdata->nr_pages; i++) {
                struct page *page = rdata->pages[i];
 
-               lru_cache_add(page);
-
                if (rdata->result == 0 ||
                    (rdata->result == -EAGAIN && got_bytes)) {
                        flush_dcache_page(page);
@@ -4278,12 +4276,12 @@ cifs_readv_complete(struct work_struct *work)
                } else
                        SetPageError(page);
 
-               unlock_page(page);
-
                if (rdata->result == 0 ||
                    (rdata->result == -EAGAIN && got_bytes))
                        cifs_readpage_to_fscache(rdata->mapping->host, page);
 
+               unlock_page(page);
+
                got_bytes -= min_t(unsigned int, PAGE_SIZE, got_bytes);
 
                put_page(page);
@@ -4340,7 +4338,6 @@ readpages_fill_pages(struct TCP_Server_Info *server,
                         * fill them until the writes are flushed.
                         */
                        zero_user(page, 0, PAGE_SIZE);
-                       lru_cache_add(page);
                        flush_dcache_page(page);
                        SetPageUptodate(page);
                        unlock_page(page);
@@ -4350,7 +4347,6 @@ readpages_fill_pages(struct TCP_Server_Info *server,
                        continue;
                } else {
                        /* no need to hold page hostage */
-                       lru_cache_add(page);
                        unlock_page(page);
                        put_page(page);
                        rdata->pages[i] = NULL;
@@ -4393,92 +4389,20 @@ cifs_readpages_copy_into_pages(struct TCP_Server_Info *server,
        return readpages_fill_pages(server, rdata, iter, iter->count);
 }
 
-static int
-readpages_get_pages(struct address_space *mapping, struct list_head *page_list,
-                   unsigned int rsize, struct list_head *tmplist,
-                   unsigned int *nr_pages, loff_t *offset, unsigned int *bytes)
-{
-       struct page *page, *tpage;
-       unsigned int expected_index;
-       int rc;
-       gfp_t gfp = readahead_gfp_mask(mapping);
-
-       INIT_LIST_HEAD(tmplist);
-
-       page = lru_to_page(page_list);
-
-       /*
-        * Lock the page and put it in the cache. Since no one else
-        * should have access to this page, we're safe to simply set
-        * PG_locked without checking it first.
-        */
-       __SetPageLocked(page);
-       rc = add_to_page_cache_locked(page, mapping,
-                                     page->index, gfp);
-
-       /* give up if we can't stick it in the cache */
-       if (rc) {
-               __ClearPageLocked(page);
-               return rc;
-       }
-
-       /* move first page to the tmplist */
-       *offset = (loff_t)page->index << PAGE_SHIFT;
-       *bytes = PAGE_SIZE;
-       *nr_pages = 1;
-       list_move_tail(&page->lru, tmplist);
-
-       /* now try and add more pages onto the request */
-       expected_index = page->index + 1;
-       list_for_each_entry_safe_reverse(page, tpage, page_list, lru) {
-               /* discontinuity ? */
-               if (page->index != expected_index)
-                       break;
-
-               /* would this page push the read over the rsize? */
-               if (*bytes + PAGE_SIZE > rsize)
-                       break;
-
-               __SetPageLocked(page);
-               rc = add_to_page_cache_locked(page, mapping, page->index, gfp);
-               if (rc) {
-                       __ClearPageLocked(page);
-                       break;
-               }
-               list_move_tail(&page->lru, tmplist);
-               (*bytes) += PAGE_SIZE;
-               expected_index++;
-               (*nr_pages)++;
-       }
-       return rc;
-}
-
-static int cifs_readpages(struct file *file, struct address_space *mapping,
-       struct list_head *page_list, unsigned num_pages)
+static void cifs_readahead(struct readahead_control *ractl)
 {
        int rc;
-       int err = 0;
-       struct list_head tmplist;
-       struct cifsFileInfo *open_file = file->private_data;
-       struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
+       struct cifsFileInfo *open_file = ractl->file->private_data;
+       struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(ractl->file);
        struct TCP_Server_Info *server;
        pid_t pid;
-       unsigned int xid;
+       unsigned int xid, nr_pages, last_batch_size = 0, cache_nr_pages = 0;
+       pgoff_t next_cached = ULONG_MAX;
+       bool caching = fscache_cookie_enabled(cifs_inode_cookie(ractl->mapping->host)) &&
+               cifs_inode_cookie(ractl->mapping->host)->cache_priv;
+       bool check_cache = caching;
 
        xid = get_xid();
-       /*
-        * Reads as many pages as possible from fscache. Returns -ENOBUFS
-        * immediately if the cookie is negative
-        *
-        * After this point, every page in the list might have PG_fscache set,
-        * so we will need to clean that up off of every page we don't use.
-        */
-       rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
-                                        &num_pages);
-       if (rc == 0) {
-               free_xid(xid);
-               return rc;
-       }
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
                pid = open_file->pid;
@@ -4489,39 +4413,73 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
        server = cifs_pick_channel(tlink_tcon(open_file->tlink)->ses);
 
        cifs_dbg(FYI, "%s: file=%p mapping=%p num_pages=%u\n",
-                __func__, file, mapping, num_pages);
+                __func__, ractl->file, ractl->mapping, readahead_count(ractl));
 
        /*
-        * Start with the page at end of list and move it to private
-        * list. Do the same with any following pages until we hit
-        * the rsize limit, hit an index discontinuity, or run out of
-        * pages. Issue the async read and then start the loop again
-        * until the list is empty.
-        *
-        * Note that list order is important. The page_list is in
-        * the order of declining indexes. When we put the pages in
-        * the rdata->pages, then we want them in increasing order.
+        * Chop the readahead request up into rsize-sized read requests.
         */
-       while (!list_empty(page_list) && !err) {
-               unsigned int i, nr_pages, bytes, rsize;
-               loff_t offset;
-               struct page *page, *tpage;
+       while ((nr_pages = readahead_count(ractl) - last_batch_size)) {
+               unsigned int i, got, rsize;
+               struct page *page;
                struct cifs_readdata *rdata;
                struct cifs_credits credits_on_stack;
                struct cifs_credits *credits = &credits_on_stack;
+               pgoff_t index = readahead_index(ractl) + last_batch_size;
+
+               /*
+                * Find out if we have anything cached in the range of
+                * interest, and if so, where the next chunk of cached data is.
+                */
+               if (caching) {
+                       if (check_cache) {
+                               rc = cifs_fscache_query_occupancy(
+                                       ractl->mapping->host, index, nr_pages,
+                                       &next_cached, &cache_nr_pages);
+                               if (rc < 0)
+                                       caching = false;
+                               check_cache = false;
+                       }
+
+                       if (index == next_cached) {
+                               /*
+                                * TODO: Send a whole batch of pages to be read
+                                * by the cache.
+                                */
+                               page = readahead_page(ractl);
+                               last_batch_size = 1 << thp_order(page);
+                               if (cifs_readpage_from_fscache(ractl->mapping->host,
+                                                              page) < 0) {
+                                       /*
+                                        * TODO: Deal with cache read failure
+                                        * here, but for the moment, delegate
+                                        * that to readpage.
+                                        */
+                                       caching = false;
+                               }
+                               unlock_page(page);
+                               next_cached++;
+                               cache_nr_pages--;
+                               if (cache_nr_pages == 0)
+                                       check_cache = true;
+                               continue;
+                       }
+               }
 
                if (open_file->invalidHandle) {
                        rc = cifs_reopen_file(open_file, true);
-                       if (rc == -EAGAIN)
-                               continue;
-                       else if (rc)
+                       if (rc) {
+                               if (rc == -EAGAIN)
+                                       continue;
                                break;
+                       }
                }
 
                rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize,
                                                   &rsize, credits);
                if (rc)
                        break;
+               nr_pages = min_t(size_t, rsize / PAGE_SIZE, readahead_count(ractl));
+               nr_pages = min_t(size_t, nr_pages, next_cached - index);
 
                /*
                 * Give up immediately if rsize is too small to read an entire
@@ -4529,16 +4487,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                 * reach this point however since we set ra_pages to 0 when the
                 * rsize is smaller than a cache page.
                 */
-               if (unlikely(rsize < PAGE_SIZE)) {
-                       add_credits_and_wake_if(server, credits, 0);
-                       free_xid(xid);
-                       return 0;
-               }
-
-               nr_pages = 0;
-               err = readpages_get_pages(mapping, page_list, rsize, &tmplist,
-                                        &nr_pages, &offset, &bytes);
-               if (!nr_pages) {
+               if (unlikely(!nr_pages)) {
                        add_credits_and_wake_if(server, credits, 0);
                        break;
                }
@@ -4546,36 +4495,31 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                rdata = cifs_readdata_alloc(nr_pages, cifs_readv_complete);
                if (!rdata) {
                        /* best to give up if we're out of mem */
-                       list_for_each_entry_safe(page, tpage, &tmplist, lru) {
-                               list_del(&page->lru);
-                               lru_cache_add(page);
-                               unlock_page(page);
-                               put_page(page);
-                       }
-                       rc = -ENOMEM;
                        add_credits_and_wake_if(server, credits, 0);
                        break;
                }
 
-               rdata->cfile = cifsFileInfo_get(open_file);
-               rdata->server = server;
-               rdata->mapping = mapping;
-               rdata->offset = offset;
-               rdata->bytes = bytes;
-               rdata->pid = pid;
-               rdata->pagesz = PAGE_SIZE;
-               rdata->tailsz = PAGE_SIZE;
+               got = __readahead_batch(ractl, rdata->pages, nr_pages);
+               if (got != nr_pages) {
+                       pr_warn("__readahead_batch() returned %u/%u\n",
+                               got, nr_pages);
+                       nr_pages = got;
+               }
+
+               rdata->nr_pages = nr_pages;
+               rdata->bytes    = readahead_batch_length(ractl);
+               rdata->cfile    = cifsFileInfo_get(open_file);
+               rdata->server   = server;
+               rdata->mapping  = ractl->mapping;
+               rdata->offset   = readahead_pos(ractl);
+               rdata->pid      = pid;
+               rdata->pagesz   = PAGE_SIZE;
+               rdata->tailsz   = PAGE_SIZE;
                rdata->read_into_pages = cifs_readpages_read_into_pages;
                rdata->copy_into_pages = cifs_readpages_copy_into_pages;
-               rdata->credits = credits_on_stack;
-
-               list_for_each_entry_safe(page, tpage, &tmplist, lru) {
-                       list_del(&page->lru);
-                       rdata->pages[rdata->nr_pages++] = page;
-               }
+               rdata->credits  = credits_on_stack;
 
                rc = adjust_credits(server, &rdata->credits, rdata->bytes);
-
                if (!rc) {
                        if (rdata->cfile->invalidHandle)
                                rc = -EAGAIN;
@@ -4587,7 +4531,6 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                        add_credits_and_wake_if(server, &rdata->credits, 0);
                        for (i = 0; i < rdata->nr_pages; i++) {
                                page = rdata->pages[i];
-                               lru_cache_add(page);
                                unlock_page(page);
                                put_page(page);
                        }
@@ -4597,10 +4540,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                }
 
                kref_put(&rdata->refcount, cifs_readdata_release);
+               last_batch_size = nr_pages;
        }
 
        free_xid(xid);
-       return rc;
 }
 
 /*
@@ -4924,7 +4867,7 @@ oplock_break_done:
  * In the non-cached mode (mount with cache=none), we shunt off direct read and write requests
  * so this method should never be called.
  *
- * Direct IO is not yet supported in the cached mode. 
+ * Direct IO is not yet supported in the cached mode.
  */
 static ssize_t
 cifs_direct_io(struct kiocb *iocb, struct iov_iter *iter)
@@ -5006,7 +4949,7 @@ static int cifs_set_page_dirty(struct page *page)
 
 const struct address_space_operations cifs_addr_ops = {
        .readpage = cifs_readpage,
-       .readpages = cifs_readpages,
+       .readahead = cifs_readahead,
        .writepage = cifs_writepage,
        .writepages = cifs_writepages,
        .write_begin = cifs_write_begin,
index 7ec35f3..a92e9ee 100644 (file)
@@ -149,7 +149,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
        fsparam_u32("echo_interval", Opt_echo_interval),
        fsparam_u32("max_credits", Opt_max_credits),
        fsparam_u32("handletimeout", Opt_handletimeout),
-       fsparam_u32("snapshot", Opt_snapshot),
+       fsparam_u64("snapshot", Opt_snapshot),
        fsparam_u32("max_channels", Opt_max_channels),
 
        /* Mount options which take string value */
@@ -1078,7 +1078,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
                ctx->echo_interval = result.uint_32;
                break;
        case Opt_snapshot:
-               ctx->snapshot_time = result.uint_32;
+               ctx->snapshot_time = result.uint_64;
                break;
        case Opt_max_credits:
                if (result.uint_32 < 20 || result.uint_32 > 60000) {
index efaac4d..33af72e 100644 (file)
@@ -134,37 +134,127 @@ void cifs_fscache_release_inode_cookie(struct inode *inode)
        }
 }
 
+static inline void fscache_end_operation(struct netfs_cache_resources *cres)
+{
+       const struct netfs_cache_ops *ops = fscache_operation_valid(cres);
+
+       if (ops)
+               ops->end_operation(cres);
+}
+
 /*
- * Retrieve a page from FS-Cache
+ * Fallback page reading interface.
  */
-int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
+static int fscache_fallback_read_page(struct inode *inode, struct page *page)
 {
-       cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n",
-                __func__, CIFS_I(inode)->fscache, page, inode);
-       return -ENOBUFS; // Needs conversion to using netfslib
+       struct netfs_cache_resources cres;
+       struct fscache_cookie *cookie = cifs_inode_cookie(inode);
+       struct iov_iter iter;
+       struct bio_vec bvec[1];
+       int ret;
+
+       memset(&cres, 0, sizeof(cres));
+       bvec[0].bv_page         = page;
+       bvec[0].bv_offset       = 0;
+       bvec[0].bv_len          = PAGE_SIZE;
+       iov_iter_bvec(&iter, READ, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
+
+       ret = fscache_begin_read_operation(&cres, cookie);
+       if (ret < 0)
+               return ret;
+
+       ret = fscache_read(&cres, page_offset(page), &iter, NETFS_READ_HOLE_FAIL,
+                          NULL, NULL);
+       fscache_end_operation(&cres);
+       return ret;
 }
 
 /*
- * Retrieve a set of pages from FS-Cache
+ * Fallback page writing interface.
  */
-int __cifs_readpages_from_fscache(struct inode *inode,
-                               struct address_space *mapping,
-                               struct list_head *pages,
-                               unsigned *nr_pages)
+static int fscache_fallback_write_page(struct inode *inode, struct page *page,
+                                      bool no_space_allocated_yet)
 {
-       cifs_dbg(FYI, "%s: (0x%p/%u/0x%p)\n",
-                __func__, CIFS_I(inode)->fscache, *nr_pages, inode);
-       return -ENOBUFS; // Needs conversion to using netfslib
+       struct netfs_cache_resources cres;
+       struct fscache_cookie *cookie = cifs_inode_cookie(inode);
+       struct iov_iter iter;
+       struct bio_vec bvec[1];
+       loff_t start = page_offset(page);
+       size_t len = PAGE_SIZE;
+       int ret;
+
+       memset(&cres, 0, sizeof(cres));
+       bvec[0].bv_page         = page;
+       bvec[0].bv_offset       = 0;
+       bvec[0].bv_len          = PAGE_SIZE;
+       iov_iter_bvec(&iter, WRITE, bvec, ARRAY_SIZE(bvec), PAGE_SIZE);
+
+       ret = fscache_begin_write_operation(&cres, cookie);
+       if (ret < 0)
+               return ret;
+
+       ret = cres.ops->prepare_write(&cres, &start, &len, i_size_read(inode),
+                                     no_space_allocated_yet);
+       if (ret == 0)
+               ret = fscache_write(&cres, page_offset(page), &iter, NULL, NULL);
+       fscache_end_operation(&cres);
+       return ret;
 }
 
-void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
+/*
+ * Retrieve a page from FS-Cache
+ */
+int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
 {
-       struct cifsInodeInfo *cifsi = CIFS_I(inode);
+       int ret;
 
-       WARN_ON(!cifsi->fscache);
+       cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n",
+                __func__, cifs_inode_cookie(inode), page, inode);
 
+       ret = fscache_fallback_read_page(inode, page);
+       if (ret < 0)
+               return ret;
+
+       /* Read completed synchronously */
+       SetPageUptodate(page);
+       return 0;
+}
+
+void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
+{
        cifs_dbg(FYI, "%s: (fsc: %p, p: %p, i: %p)\n",
-                __func__, cifsi->fscache, page, inode);
+                __func__, cifs_inode_cookie(inode), page, inode);
+
+       fscache_fallback_write_page(inode, page, true);
+}
+
+/*
+ * Query the cache occupancy.
+ */
+int __cifs_fscache_query_occupancy(struct inode *inode,
+                                  pgoff_t first, unsigned int nr_pages,
+                                  pgoff_t *_data_first,
+                                  unsigned int *_data_nr_pages)
+{
+       struct netfs_cache_resources cres;
+       struct fscache_cookie *cookie = cifs_inode_cookie(inode);
+       loff_t start, data_start;
+       size_t len, data_len;
+       int ret;
 
-       // Needs conversion to using netfslib
+       ret = fscache_begin_read_operation(&cres, cookie);
+       if (ret < 0)
+               return ret;
+
+       start = first * PAGE_SIZE;
+       len = nr_pages * PAGE_SIZE;
+       ret = cres.ops->query_occupancy(&cres, start, len, PAGE_SIZE,
+                                       &data_start, &data_len);
+       if (ret == 0) {
+               *_data_first = data_start / PAGE_SIZE;
+               *_data_nr_pages = len / PAGE_SIZE;
+       }
+
+       fscache_end_operation(&cres);
+       return ret;
 }
index c6ca49a..5512990 100644 (file)
@@ -9,6 +9,7 @@
 #ifndef _CIFS_FSCACHE_H
 #define _CIFS_FSCACHE_H
 
+#include <linux/swap.h>
 #include <linux/fscache.h>
 
 #include "cifsglob.h"
@@ -58,14 +59,6 @@ void cifs_fscache_fill_coherency(struct inode *inode,
 }
 
 
-extern int cifs_fscache_release_page(struct page *page, gfp_t gfp);
-extern int __cifs_readpage_from_fscache(struct inode *, struct page *);
-extern int __cifs_readpages_from_fscache(struct inode *,
-                                        struct address_space *,
-                                        struct list_head *,
-                                        unsigned *);
-extern void __cifs_readpage_to_fscache(struct inode *, struct page *);
-
 static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode)
 {
        return CIFS_I(inode)->fscache;
@@ -80,33 +73,52 @@ static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags
                           i_size_read(inode), flags);
 }
 
-static inline int cifs_readpage_from_fscache(struct inode *inode,
-                                            struct page *page)
-{
-       if (CIFS_I(inode)->fscache)
-               return __cifs_readpage_from_fscache(inode, page);
+extern int __cifs_fscache_query_occupancy(struct inode *inode,
+                                         pgoff_t first, unsigned int nr_pages,
+                                         pgoff_t *_data_first,
+                                         unsigned int *_data_nr_pages);
 
-       return -ENOBUFS;
+static inline int cifs_fscache_query_occupancy(struct inode *inode,
+                                              pgoff_t first, unsigned int nr_pages,
+                                              pgoff_t *_data_first,
+                                              unsigned int *_data_nr_pages)
+{
+       if (!cifs_inode_cookie(inode))
+               return -ENOBUFS;
+       return __cifs_fscache_query_occupancy(inode, first, nr_pages,
+                                             _data_first, _data_nr_pages);
 }
 
-static inline int cifs_readpages_from_fscache(struct inode *inode,
-                                             struct address_space *mapping,
-                                             struct list_head *pages,
-                                             unsigned *nr_pages)
+extern int __cifs_readpage_from_fscache(struct inode *pinode, struct page *ppage);
+extern void __cifs_readpage_to_fscache(struct inode *pinode, struct page *ppage);
+
+
+static inline int cifs_readpage_from_fscache(struct inode *inode,
+                                            struct page *page)
 {
-       if (CIFS_I(inode)->fscache)
-               return __cifs_readpages_from_fscache(inode, mapping, pages,
-                                                    nr_pages);
+       if (cifs_inode_cookie(inode))
+               return __cifs_readpage_from_fscache(inode, page);
        return -ENOBUFS;
 }
 
 static inline void cifs_readpage_to_fscache(struct inode *inode,
                                            struct page *page)
 {
-       if (PageFsCache(page))
+       if (cifs_inode_cookie(inode))
                __cifs_readpage_to_fscache(inode, page);
 }
 
+static inline int cifs_fscache_release_page(struct page *page, gfp_t gfp)
+{
+       if (PageFsCache(page)) {
+               if (current_is_kswapd() || !(gfp & __GFP_FS))
+                       return false;
+               wait_on_page_fscache(page);
+               fscache_note_page_release(cifs_inode_cookie(page->mapping->host));
+       }
+       return true;
+}
+
 #else /* CONFIG_CIFS_FSCACHE */
 static inline
 void cifs_fscache_fill_coherency(struct inode *inode,
@@ -123,22 +135,29 @@ static inline void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool upd
 static inline struct fscache_cookie *cifs_inode_cookie(struct inode *inode) { return NULL; }
 static inline void cifs_invalidate_cache(struct inode *inode, unsigned int flags) {}
 
-static inline int
-cifs_readpage_from_fscache(struct inode *inode, struct page *page)
+static inline int cifs_fscache_query_occupancy(struct inode *inode,
+                                              pgoff_t first, unsigned int nr_pages,
+                                              pgoff_t *_data_first,
+                                              unsigned int *_data_nr_pages)
 {
+       *_data_first = ULONG_MAX;
+       *_data_nr_pages = 0;
        return -ENOBUFS;
 }
 
-static inline int cifs_readpages_from_fscache(struct inode *inode,
-                                             struct address_space *mapping,
-                                             struct list_head *pages,
-                                             unsigned *nr_pages)
+static inline int
+cifs_readpage_from_fscache(struct inode *inode, struct page *page)
 {
        return -ENOBUFS;
 }
 
-static inline void cifs_readpage_to_fscache(struct inode *inode,
-                       struct page *page) {}
+static inline
+void cifs_readpage_to_fscache(struct inode *inode, struct page *page) {}
+
+static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp)
+{
+       return true; /* May release page */
+}
 
 #endif /* CONFIG_CIFS_FSCACHE */
 
index 7d8b3ce..60d853c 100644 (file)
@@ -83,6 +83,7 @@ static void cifs_set_ops(struct inode *inode)
 static void
 cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
 {
+       struct cifs_fscache_inode_coherency_data cd;
        struct cifsInodeInfo *cifs_i = CIFS_I(inode);
 
        cifs_dbg(FYI, "%s: revalidating inode %llu\n",
@@ -113,6 +114,9 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
        cifs_dbg(FYI, "%s: invalidating inode %llu mapping\n",
                 __func__, cifs_i->uniqueid);
        set_bit(CIFS_INO_INVALID_MAPPING, &cifs_i->flags);
+       /* Invalidate fscache cookie */
+       cifs_fscache_fill_coherency(&cifs_i->vfs_inode, &cd);
+       fscache_invalidate(cifs_inode_cookie(inode), &cd, i_size_read(inode), 0);
 }
 
 /*
@@ -2261,8 +2265,6 @@ cifs_dentry_needs_reval(struct dentry *dentry)
 int
 cifs_invalidate_mapping(struct inode *inode)
 {
-       struct cifs_fscache_inode_coherency_data cd;
-       struct cifsInodeInfo *cifsi = CIFS_I(inode);
        int rc = 0;
 
        if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
@@ -2272,8 +2274,6 @@ cifs_invalidate_mapping(struct inode *inode)
                                 __func__, inode);
        }
 
-       cifs_fscache_fill_coherency(&cifsi->vfs_inode, &cd);
-       fscache_invalidate(cifs_inode_cookie(inode), &cd, i_size_read(inode), 0);
        return rc;
 }
 
index dc3b16d..32f478c 100644 (file)
@@ -127,11 +127,6 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
        struct cifs_server_iface *ifaces = NULL;
        size_t iface_count;
 
-       if (ses->server->dialect < SMB30_PROT_ID) {
-               cifs_dbg(VFS, "multichannel is not supported on this protocol version, use 3.0 or above\n");
-               return 0;
-       }
-
        spin_lock(&ses->chan_lock);
 
        new_chan_count = old_chan_count = ses->chan_count;
@@ -145,6 +140,12 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
                return 0;
        }
 
+       if (ses->server->dialect < SMB30_PROT_ID) {
+               spin_unlock(&ses->chan_lock);
+               cifs_dbg(VFS, "multichannel is not supported on this protocol version, use 3.0 or above\n");
+               return 0;
+       }
+
        if (!(ses->server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
                ses->chan_max = 1;
                spin_unlock(&ses->chan_lock);
@@ -713,7 +714,11 @@ static int size_of_ntlmssp_blob(struct cifs_ses *ses, int base_size)
        else
                sz += sizeof(__le16);
 
-       sz += sizeof(__le16) * strnlen(ses->workstation_name, CIFS_MAX_WORKSTATION_LEN);
+       if (ses->workstation_name)
+               sz += sizeof(__le16) * strnlen(ses->workstation_name,
+                       CIFS_MAX_WORKSTATION_LEN);
+       else
+               sz += sizeof(__le16);
 
        return sz;
 }
index 8272c91..b2fb7bd 100644 (file)
@@ -228,9 +228,7 @@ cifs_get_next_mid(struct TCP_Server_Info *server)
        spin_unlock(&GlobalMid_Lock);
 
        if (reconnect) {
-               spin_lock(&cifs_tcp_ses_lock);
-               server->tcpStatus = CifsNeedReconnect;
-               spin_unlock(&cifs_tcp_ses_lock);
+               cifs_mark_tcp_ses_conns_for_reconnect(server, false);
        }
 
        return mid;
index 8540f7c..a4c3e02 100644 (file)
@@ -430,10 +430,7 @@ unmask:
                 * be taken as the remainder of this one. We need to kill the
                 * socket so the server throws away the partial SMB
                 */
-               spin_lock(&cifs_tcp_ses_lock);
-               if (server->tcpStatus != CifsExiting)
-                       server->tcpStatus = CifsNeedReconnect;
-               spin_unlock(&cifs_tcp_ses_lock);
+               cifs_mark_tcp_ses_conns_for_reconnect(server, false);
                trace_smb3_partial_send_reconnect(server->CurrentMid,
                                                  server->conn_id, server->hostname);
        }
index 7d8b72d..9d486fb 100644 (file)
@@ -175,11 +175,13 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
                                switch (handler->flags) {
                                case XATTR_CIFS_NTSD_FULL:
                                        aclflags = (CIFS_ACL_OWNER |
+                                                   CIFS_ACL_GROUP |
                                                    CIFS_ACL_DACL |
                                                    CIFS_ACL_SACL);
                                        break;
                                case XATTR_CIFS_NTSD:
                                        aclflags = (CIFS_ACL_OWNER |
+                                                   CIFS_ACL_GROUP |
                                                    CIFS_ACL_DACL);
                                        break;
                                case XATTR_CIFS_ACL:
index 1466b5d..d1f9d26 100644 (file)
  */
 DEFINE_SPINLOCK(configfs_dirent_lock);
 
+/*
+ * All of link_obj/unlink_obj/link_group/unlink_group require that
+ * subsys->su_mutex is held.
+ * But parent configfs_subsystem is NULL when config_item is root.
+ * Use this mutex when config_item is root.
+ */
+static DEFINE_MUTEX(configfs_subsystem_mutex);
+
 static void configfs_d_iput(struct dentry * dentry,
                            struct inode * inode)
 {
@@ -1780,8 +1788,8 @@ void configfs_unregister_group(struct config_group *group)
        configfs_detach_group(&group->cg_item);
        d_inode(dentry)->i_flags |= S_DEAD;
        dont_mount(dentry);
+       d_drop(dentry);
        fsnotify_rmdir(d_inode(parent), dentry);
-       d_delete(dentry);
        inode_unlock(d_inode(parent));
 
        dput(dentry);
@@ -1859,7 +1867,9 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
                group->cg_item.ci_name = group->cg_item.ci_namebuf;
 
        sd = root->d_fsdata;
+       mutex_lock(&configfs_subsystem_mutex);
        link_group(to_config_group(sd->s_element), group);
+       mutex_unlock(&configfs_subsystem_mutex);
 
        inode_lock_nested(d_inode(root), I_MUTEX_PARENT);
 
@@ -1884,7 +1894,9 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
        inode_unlock(d_inode(root));
 
        if (err) {
+               mutex_lock(&configfs_subsystem_mutex);
                unlink_group(group);
+               mutex_unlock(&configfs_subsystem_mutex);
                configfs_release_fs();
        }
        put_fragment(frag);
@@ -1922,16 +1934,18 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
        configfs_detach_group(&group->cg_item);
        d_inode(dentry)->i_flags |= S_DEAD;
        dont_mount(dentry);
-       fsnotify_rmdir(d_inode(root), dentry);
        inode_unlock(d_inode(dentry));
 
-       d_delete(dentry);
+       d_drop(dentry);
+       fsnotify_rmdir(d_inode(root), dentry);
 
        inode_unlock(d_inode(root));
 
        dput(dentry);
 
+       mutex_lock(&configfs_subsystem_mutex);
        unlink_group(group);
+       mutex_unlock(&configfs_subsystem_mutex);
        configfs_release_fs();
 }
 
index 42e5a76..4f25015 100644 (file)
@@ -621,8 +621,8 @@ void devpts_pty_kill(struct dentry *dentry)
 
        dentry->d_fsdata = NULL;
        drop_nlink(dentry->d_inode);
-       fsnotify_unlink(d_inode(dentry->d_parent), dentry);
        d_drop(dentry);
+       fsnotify_unlink(d_inode(dentry->d_parent), dentry);
        dput(dentry);   /* d_alloc_name() in devpts_pty_new() */
 }
 
index fa7ddb7..226a57c 100644 (file)
@@ -252,12 +252,10 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
                return ret;
 
        iomap->offset = map.m_la;
-       if (flags & IOMAP_DAX) {
+       if (flags & IOMAP_DAX)
                iomap->dax_dev = mdev.m_daxdev;
-               iomap->offset += mdev.m_dax_part_off;
-       } else {
+       else
                iomap->bdev = mdev.m_bdev;
-       }
        iomap->length = map.m_llen;
        iomap->flags = 0;
        iomap->private = NULL;
@@ -284,6 +282,8 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
        } else {
                iomap->type = IOMAP_MAPPED;
                iomap->addr = mdev.m_pa;
+               if (flags & IOMAP_DAX)
+                       iomap->addr += mdev.m_dax_part_off;
        }
        return 0;
 }
index 498b766..423bc1a 100644 (file)
@@ -810,68 +810,11 @@ static bool z_erofs_get_sync_decompress_policy(struct erofs_sb_info *sbi,
        return false;
 }
 
-static void z_erofs_decompressqueue_work(struct work_struct *work);
-static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
-                                      bool sync, int bios)
-{
-       struct erofs_sb_info *const sbi = EROFS_SB(io->sb);
-
-       /* wake up the caller thread for sync decompression */
-       if (sync) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&io->u.wait.lock, flags);
-               if (!atomic_add_return(bios, &io->pending_bios))
-                       wake_up_locked(&io->u.wait);
-               spin_unlock_irqrestore(&io->u.wait.lock, flags);
-               return;
-       }
-
-       if (atomic_add_return(bios, &io->pending_bios))
-               return;
-       /* Use workqueue and sync decompression for atomic contexts only */
-       if (in_atomic() || irqs_disabled()) {
-               queue_work(z_erofs_workqueue, &io->u.work);
-               /* enable sync decompression for readahead */
-               if (sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO)
-                       sbi->opt.sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON;
-               return;
-       }
-       z_erofs_decompressqueue_work(&io->u.work);
-}
-
 static bool z_erofs_page_is_invalidated(struct page *page)
 {
        return !page->mapping && !z_erofs_is_shortlived_page(page);
 }
 
-static void z_erofs_decompressqueue_endio(struct bio *bio)
-{
-       tagptr1_t t = tagptr_init(tagptr1_t, bio->bi_private);
-       struct z_erofs_decompressqueue *q = tagptr_unfold_ptr(t);
-       blk_status_t err = bio->bi_status;
-       struct bio_vec *bvec;
-       struct bvec_iter_all iter_all;
-
-       bio_for_each_segment_all(bvec, bio, iter_all) {
-               struct page *page = bvec->bv_page;
-
-               DBG_BUGON(PageUptodate(page));
-               DBG_BUGON(z_erofs_page_is_invalidated(page));
-
-               if (err)
-                       SetPageError(page);
-
-               if (erofs_page_is_managed(EROFS_SB(q->sb), page)) {
-                       if (!err)
-                               SetPageUptodate(page);
-                       unlock_page(page);
-               }
-       }
-       z_erofs_decompress_kickoff(q, tagptr_unfold_tags(t), -1);
-       bio_put(bio);
-}
-
 static int z_erofs_decompress_pcluster(struct super_block *sb,
                                       struct z_erofs_pcluster *pcl,
                                       struct page **pagepool)
@@ -1123,6 +1066,35 @@ static void z_erofs_decompressqueue_work(struct work_struct *work)
        kvfree(bgq);
 }
 
+static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
+                                      bool sync, int bios)
+{
+       struct erofs_sb_info *const sbi = EROFS_SB(io->sb);
+
+       /* wake up the caller thread for sync decompression */
+       if (sync) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&io->u.wait.lock, flags);
+               if (!atomic_add_return(bios, &io->pending_bios))
+                       wake_up_locked(&io->u.wait);
+               spin_unlock_irqrestore(&io->u.wait.lock, flags);
+               return;
+       }
+
+       if (atomic_add_return(bios, &io->pending_bios))
+               return;
+       /* Use workqueue and sync decompression for atomic contexts only */
+       if (in_atomic() || irqs_disabled()) {
+               queue_work(z_erofs_workqueue, &io->u.work);
+               /* enable sync decompression for readahead */
+               if (sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO)
+                       sbi->opt.sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON;
+               return;
+       }
+       z_erofs_decompressqueue_work(&io->u.work);
+}
+
 static struct page *pickup_page_for_submission(struct z_erofs_pcluster *pcl,
                                               unsigned int nr,
                                               struct page **pagepool,
@@ -1300,6 +1272,33 @@ static void move_to_bypass_jobqueue(struct z_erofs_pcluster *pcl,
        qtail[JQ_BYPASS] = &pcl->next;
 }
 
+static void z_erofs_decompressqueue_endio(struct bio *bio)
+{
+       tagptr1_t t = tagptr_init(tagptr1_t, bio->bi_private);
+       struct z_erofs_decompressqueue *q = tagptr_unfold_ptr(t);
+       blk_status_t err = bio->bi_status;
+       struct bio_vec *bvec;
+       struct bvec_iter_all iter_all;
+
+       bio_for_each_segment_all(bvec, bio, iter_all) {
+               struct page *page = bvec->bv_page;
+
+               DBG_BUGON(PageUptodate(page));
+               DBG_BUGON(z_erofs_page_is_invalidated(page));
+
+               if (err)
+                       SetPageError(page);
+
+               if (erofs_page_is_managed(EROFS_SB(q->sb), page)) {
+                       if (!err)
+                               SetPageUptodate(page);
+                       unlock_page(page);
+               }
+       }
+       z_erofs_decompress_kickoff(q, tagptr_unfold_tags(t), -1);
+       bio_put(bio);
+}
+
 static void z_erofs_submit_queue(struct super_block *sb,
                                 struct z_erofs_decompress_frontend *f,
                                 struct page **pagepool,
index 18d7fd1..361b1d6 100644 (file)
@@ -630,6 +630,13 @@ static int z_erofs_do_map_blocks(struct inode *inode,
                if (endoff >= m.clusterofs) {
                        m.headtype = m.type;
                        map->m_la = (m.lcn << lclusterbits) | m.clusterofs;
+                       /*
+                        * For ztailpacking files, in order to inline data more
+                        * effectively, special EOF lclusters are now supported
+                        * which can have three parts at most.
+                        */
+                       if (ztailpacking && end > inode->i_size)
+                               end = inode->i_size;
                        break;
                }
                /* m.lcn should be >= 1 if endoff < m.clusterofs */
index 5a35768..57e82e2 100644 (file)
@@ -139,7 +139,7 @@ fail:
 /*
  * Inode operation get_posix_acl().
  *
- * inode->i_mutex: don't care
+ * inode->i_rwsem: don't care
  */
 struct posix_acl *
 ext4_get_acl(struct inode *inode, int type, bool rcu)
@@ -183,7 +183,7 @@ ext4_get_acl(struct inode *inode, int type, bool rcu)
 /*
  * Set the access or default ACL of an inode.
  *
- * inode->i_mutex: down unless called from ext4_new_inode
+ * inode->i_rwsem: down unless called from ext4_new_inode
  */
 static int
 __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
@@ -271,8 +271,8 @@ out_stop:
 /*
  * Initialize the ACLs of a new inode. Called from ext4_new_inode.
  *
- * dir->i_mutex: down
- * inode->i_mutex: up (access to inode is still exclusive)
+ * dir->i_rwsem: down
+ * inode->i_rwsem: up (access to inode is still exclusive)
  */
 int
 ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
index 71a3cdc..bcd3b9b 100644 (file)
@@ -1028,7 +1028,7 @@ struct ext4_inode_info {
 
        /*
         * Extended attributes can be read independently of the main file
-        * data. Taking i_mutex even when reading would cause contention
+        * data. Taking i_rwsem even when reading would cause contention
         * between readers of EAs and writers of regular file data, so
         * instead we synchronize on xattr_sem when reading or changing
         * EAs.
@@ -1750,6 +1750,7 @@ struct ext4_sb_info {
        spinlock_t s_fc_lock;
        struct buffer_head *s_fc_bh;
        struct ext4_fc_stats s_fc_stats;
+       tid_t s_fc_ineligible_tid;
 #ifdef CONFIG_EXT4_DEBUG
        int s_fc_debug_max_replay;
 #endif
@@ -1795,10 +1796,7 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
 enum {
        EXT4_MF_MNTDIR_SAMPLED,
        EXT4_MF_FS_ABORTED,     /* Fatal error detected */
-       EXT4_MF_FC_INELIGIBLE,  /* Fast commit ineligible */
-       EXT4_MF_FC_COMMITTING   /* File system underoing a fast
-                                * commit.
-                                */
+       EXT4_MF_FC_INELIGIBLE   /* Fast commit ineligible */
 };
 
 static inline void ext4_set_mount_flag(struct super_block *sb, int bit)
@@ -2485,7 +2483,7 @@ struct ext4_filename {
 #ifdef CONFIG_FS_ENCRYPTION
        struct fscrypt_str crypto_buf;
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        struct fscrypt_str cf_name;
 #endif
 };
@@ -2721,7 +2719,7 @@ extern unsigned ext4_free_clusters_after_init(struct super_block *sb,
                                              struct ext4_group_desc *gdp);
 ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 extern int ext4_fname_setup_ci_filename(struct inode *dir,
                                         const struct qstr *iname,
                                         struct ext4_filename *fname);
@@ -2754,7 +2752,7 @@ static inline int ext4_fname_setup_filename(struct inode *dir,
 
        ext4_fname_from_fscrypt_name(fname, &name);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        err = ext4_fname_setup_ci_filename(dir, iname, fname);
 #endif
        return err;
@@ -2773,7 +2771,7 @@ static inline int ext4_fname_prepare_lookup(struct inode *dir,
 
        ext4_fname_from_fscrypt_name(fname, &name);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        err = ext4_fname_setup_ci_filename(dir, &dentry->d_name, fname);
 #endif
        return err;
@@ -2790,7 +2788,7 @@ static inline void ext4_fname_free_filename(struct ext4_filename *fname)
        fname->usr_fname = NULL;
        fname->disk_name.name = NULL;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        kfree(fname->cf_name.name);
        fname->cf_name.name = NULL;
 #endif
@@ -2806,7 +2804,7 @@ static inline int ext4_fname_setup_filename(struct inode *dir,
        fname->disk_name.name = (unsigned char *) iname->name;
        fname->disk_name.len = iname->len;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        err = ext4_fname_setup_ci_filename(dir, iname, fname);
 #endif
 
@@ -2822,7 +2820,7 @@ static inline int ext4_fname_prepare_lookup(struct inode *dir,
 
 static inline void ext4_fname_free_filename(struct ext4_filename *fname)
 {
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        kfree(fname->cf_name.name);
        fname->cf_name.name = NULL;
 #endif
@@ -2926,7 +2924,7 @@ void __ext4_fc_track_create(handle_t *handle, struct inode *inode,
                            struct dentry *dentry);
 void ext4_fc_track_create(handle_t *handle, struct dentry *dentry);
 void ext4_fc_track_inode(handle_t *handle, struct inode *inode);
-void ext4_fc_mark_ineligible(struct super_block *sb, int reason);
+void ext4_fc_mark_ineligible(struct super_block *sb, int reason, handle_t *handle);
 void ext4_fc_start_update(struct inode *inode);
 void ext4_fc_stop_update(struct inode *inode);
 void ext4_fc_del(struct inode *inode);
@@ -2935,6 +2933,9 @@ void ext4_fc_replay_cleanup(struct super_block *sb);
 int ext4_fc_commit(journal_t *journal, tid_t commit_tid);
 int __init ext4_fc_init_dentry_cache(void);
 void ext4_fc_destroy_dentry_cache(void);
+int ext4_fc_record_regions(struct super_block *sb, int ino,
+                          ext4_lblk_t lblk, ext4_fsblk_t pblk,
+                          int len, int replay);
 
 /* mballoc.c */
 extern const struct seq_operations ext4_mb_seq_groups_ops;
@@ -3407,7 +3408,7 @@ do {                                                              \
 #define EXT4_FREECLUSTERS_WATERMARK 0
 #endif
 
-/* Update i_disksize. Requires i_mutex to avoid races with truncate */
+/* Update i_disksize. Requires i_rwsem to avoid races with truncate */
 static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize)
 {
        WARN_ON_ONCE(S_ISREG(inode->i_mode) &&
@@ -3418,7 +3419,7 @@ static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize)
        up_write(&EXT4_I(inode)->i_data_sem);
 }
 
-/* Update i_size, i_disksize. Requires i_mutex to avoid races with truncate */
+/* Update i_size, i_disksize. Requires i_rwsem to avoid races with truncate */
 static inline int ext4_update_inode_size(struct inode *inode, loff_t newsize)
 {
        int changed = 0;
index 0e4fa64..db2ae4a 100644 (file)
@@ -491,7 +491,7 @@ static inline int ext4_free_data_revoke_credits(struct inode *inode, int blocks)
 /*
  * This function controls whether or not we should try to go down the
  * dioread_nolock code paths, which makes it safe to avoid taking
- * i_mutex for direct I/O reads.  This only works for extent-based
+ * i_rwsem for direct I/O reads.  This only works for extent-based
  * files, and it doesn't work if data journaling is enabled, since the
  * dioread_nolock code uses b_private to pass information back to the
  * I/O completion handler, and this conflicts with the jbd's use of
index 74c91da..c0f3f83 100644 (file)
@@ -97,7 +97,7 @@ static int ext4_ext_trunc_restart_fn(struct inode *inode, int *dropped)
         * Drop i_data_sem to avoid deadlock with ext4_map_blocks.  At this
         * moment, get_block can be called only for blocks inside i_size since
         * page cache has been already dropped and writes are blocked by
-        * i_mutex. So we can safely drop the i_data_sem here.
+        * i_rwsem. So we can safely drop the i_data_sem here.
         */
        BUG_ON(EXT4_JOURNAL(inode) == NULL);
        ext4_discard_preallocations(inode, 0);
@@ -4572,7 +4572,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
 
        flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
 
-       /* Wait all existing dio workers, newcomers will block on i_mutex */
+       /* Wait all existing dio workers, newcomers will block on i_rwsem */
        inode_dio_wait(inode);
 
        /* Preallocate the range including the unaligned edges */
@@ -4738,7 +4738,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
                        goto out;
        }
 
-       /* Wait all existing dio workers, newcomers will block on i_mutex */
+       /* Wait all existing dio workers, newcomers will block on i_rwsem */
        inode_dio_wait(inode);
 
        ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, flags);
@@ -5334,7 +5334,7 @@ static int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
                ret = PTR_ERR(handle);
                goto out_mmap;
        }
-       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE);
+       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE, handle);
 
        down_write(&EXT4_I(inode)->i_data_sem);
        ext4_discard_preallocations(inode, 0);
@@ -5474,7 +5474,7 @@ static int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
                ret = PTR_ERR(handle);
                goto out_mmap;
        }
-       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE);
+       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE, handle);
 
        /* Expand file to avoid data loss if there is error while shifting */
        inode->i_size += len;
@@ -5571,7 +5571,7 @@ out_mutex:
  * stuff such as page-cache locking consistency, bh mapping consistency or
  * extent's data copying must be performed by caller.
  * Locking:
- *             i_mutex is held for both inodes
+ *             i_rwsem is held for both inodes
  *             i_data_sem is locked for write for both inodes
  * Assumptions:
  *             All pages from requested range are locked for both inodes
@@ -6091,11 +6091,15 @@ int ext4_ext_clear_bb(struct inode *inode)
 
                                        ext4_mb_mark_bb(inode->i_sb,
                                                        path[j].p_block, 1, 0);
+                                       ext4_fc_record_regions(inode->i_sb, inode->i_ino,
+                                                       0, path[j].p_block, 1, 1);
                                }
                                ext4_ext_drop_refs(path);
                                kfree(path);
                        }
                        ext4_mb_mark_bb(inode->i_sb, map.m_pblk, map.m_len, 0);
+                       ext4_fc_record_regions(inode->i_sb, inode->i_ino,
+                                       map.m_lblk, map.m_pblk, map.m_len, 1);
                }
                cur = cur + map.m_len;
        }
index 5ae8026..7964ee3 100644 (file)
@@ -300,18 +300,32 @@ restart:
 }
 
 /*
- * Mark file system as fast commit ineligible. This means that next commit
- * operation would result in a full jbd2 commit.
+ * Mark file system as fast commit ineligible, and record latest
+ * ineligible transaction tid. This means until the recorded
+ * transaction, commit operation would result in a full jbd2 commit.
  */
-void ext4_fc_mark_ineligible(struct super_block *sb, int reason)
+void ext4_fc_mark_ineligible(struct super_block *sb, int reason, handle_t *handle)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
+       tid_t tid;
 
        if (!test_opt2(sb, JOURNAL_FAST_COMMIT) ||
            (EXT4_SB(sb)->s_mount_state & EXT4_FC_REPLAY))
                return;
 
        ext4_set_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
+       if (handle && !IS_ERR(handle))
+               tid = handle->h_transaction->t_tid;
+       else {
+               read_lock(&sbi->s_journal->j_state_lock);
+               tid = sbi->s_journal->j_running_transaction ?
+                               sbi->s_journal->j_running_transaction->t_tid : 0;
+               read_unlock(&sbi->s_journal->j_state_lock);
+       }
+       spin_lock(&sbi->s_fc_lock);
+       if (sbi->s_fc_ineligible_tid < tid)
+               sbi->s_fc_ineligible_tid = tid;
+       spin_unlock(&sbi->s_fc_lock);
        WARN_ON(reason >= EXT4_FC_REASON_MAX);
        sbi->s_fc_stats.fc_ineligible_reason_count[reason]++;
 }
@@ -361,7 +375,8 @@ static int ext4_fc_track_template(
        spin_lock(&sbi->s_fc_lock);
        if (list_empty(&EXT4_I(inode)->i_fc_list))
                list_add_tail(&EXT4_I(inode)->i_fc_list,
-                               (ext4_test_mount_flag(inode->i_sb, EXT4_MF_FC_COMMITTING)) ?
+                               (sbi->s_journal->j_flags & JBD2_FULL_COMMIT_ONGOING ||
+                                sbi->s_journal->j_flags & JBD2_FAST_COMMIT_ONGOING) ?
                                &sbi->s_fc_q[FC_Q_STAGING] :
                                &sbi->s_fc_q[FC_Q_MAIN]);
        spin_unlock(&sbi->s_fc_lock);
@@ -387,7 +402,7 @@ static int __track_dentry_update(struct inode *inode, void *arg, bool update)
        mutex_unlock(&ei->i_fc_lock);
        node = kmem_cache_alloc(ext4_fc_dentry_cachep, GFP_NOFS);
        if (!node) {
-               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_NOMEM);
+               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_NOMEM, NULL);
                mutex_lock(&ei->i_fc_lock);
                return -ENOMEM;
        }
@@ -400,7 +415,7 @@ static int __track_dentry_update(struct inode *inode, void *arg, bool update)
                if (!node->fcd_name.name) {
                        kmem_cache_free(ext4_fc_dentry_cachep, node);
                        ext4_fc_mark_ineligible(inode->i_sb,
-                               EXT4_FC_REASON_NOMEM);
+                               EXT4_FC_REASON_NOMEM, NULL);
                        mutex_lock(&ei->i_fc_lock);
                        return -ENOMEM;
                }
@@ -414,7 +429,8 @@ static int __track_dentry_update(struct inode *inode, void *arg, bool update)
        node->fcd_name.len = dentry->d_name.len;
 
        spin_lock(&sbi->s_fc_lock);
-       if (ext4_test_mount_flag(inode->i_sb, EXT4_MF_FC_COMMITTING))
+       if (sbi->s_journal->j_flags & JBD2_FULL_COMMIT_ONGOING ||
+               sbi->s_journal->j_flags & JBD2_FAST_COMMIT_ONGOING)
                list_add_tail(&node->fcd_list,
                                &sbi->s_fc_dentry_q[FC_Q_STAGING]);
        else
@@ -502,7 +518,7 @@ void ext4_fc_track_inode(handle_t *handle, struct inode *inode)
 
        if (ext4_should_journal_data(inode)) {
                ext4_fc_mark_ineligible(inode->i_sb,
-                                       EXT4_FC_REASON_INODE_JOURNAL_DATA);
+                                       EXT4_FC_REASON_INODE_JOURNAL_DATA, handle);
                return;
        }
 
@@ -879,7 +895,6 @@ static int ext4_fc_submit_inode_data_all(journal_t *journal)
        int ret = 0;
 
        spin_lock(&sbi->s_fc_lock);
-       ext4_set_mount_flag(sb, EXT4_MF_FC_COMMITTING);
        list_for_each_entry(ei, &sbi->s_fc_q[FC_Q_MAIN], i_fc_list) {
                ext4_set_inode_state(&ei->vfs_inode, EXT4_STATE_FC_COMMITTING);
                while (atomic_read(&ei->i_fc_updates)) {
@@ -1179,7 +1194,7 @@ fallback:
  * Fast commit cleanup routine. This is called after every fast commit and
  * full commit. full is true if we are called after a full commit.
  */
-static void ext4_fc_cleanup(journal_t *journal, int full)
+static void ext4_fc_cleanup(journal_t *journal, int full, tid_t tid)
 {
        struct super_block *sb = journal->j_private;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -1197,7 +1212,8 @@ static void ext4_fc_cleanup(journal_t *journal, int full)
                list_del_init(&iter->i_fc_list);
                ext4_clear_inode_state(&iter->vfs_inode,
                                       EXT4_STATE_FC_COMMITTING);
-               ext4_fc_reset_inode(&iter->vfs_inode);
+               if (iter->i_sync_tid <= tid)
+                       ext4_fc_reset_inode(&iter->vfs_inode);
                /* Make sure EXT4_STATE_FC_COMMITTING bit is clear */
                smp_mb();
 #if (BITS_PER_LONG < 64)
@@ -1226,8 +1242,10 @@ static void ext4_fc_cleanup(journal_t *journal, int full)
        list_splice_init(&sbi->s_fc_q[FC_Q_STAGING],
                                &sbi->s_fc_q[FC_Q_MAIN]);
 
-       ext4_clear_mount_flag(sb, EXT4_MF_FC_COMMITTING);
-       ext4_clear_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
+       if (tid >= sbi->s_fc_ineligible_tid) {
+               sbi->s_fc_ineligible_tid = 0;
+               ext4_clear_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
+       }
 
        if (full)
                sbi->s_fc_bytes = 0;
@@ -1392,14 +1410,15 @@ static int ext4_fc_record_modified_inode(struct super_block *sb, int ino)
                if (state->fc_modified_inodes[i] == ino)
                        return 0;
        if (state->fc_modified_inodes_used == state->fc_modified_inodes_size) {
-               state->fc_modified_inodes_size +=
-                       EXT4_FC_REPLAY_REALLOC_INCREMENT;
                state->fc_modified_inodes = krealloc(
-                                       state->fc_modified_inodes, sizeof(int) *
-                                       state->fc_modified_inodes_size,
-                                       GFP_KERNEL);
+                               state->fc_modified_inodes,
+                               sizeof(int) * (state->fc_modified_inodes_size +
+                               EXT4_FC_REPLAY_REALLOC_INCREMENT),
+                               GFP_KERNEL);
                if (!state->fc_modified_inodes)
                        return -ENOMEM;
+               state->fc_modified_inodes_size +=
+                       EXT4_FC_REPLAY_REALLOC_INCREMENT;
        }
        state->fc_modified_inodes[state->fc_modified_inodes_used++] = ino;
        return 0;
@@ -1431,7 +1450,9 @@ static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl,
        }
        inode = NULL;
 
-       ext4_fc_record_modified_inode(sb, ino);
+       ret = ext4_fc_record_modified_inode(sb, ino);
+       if (ret)
+               goto out;
 
        raw_fc_inode = (struct ext4_inode *)
                (val + offsetof(struct ext4_fc_inode, fc_raw_inode));
@@ -1563,16 +1584,23 @@ out:
 }
 
 /*
- * Record physical disk regions which are in use as per fast commit area. Our
- * simple replay phase allocator excludes these regions from allocation.
+ * Record physical disk regions which are in use as per fast commit area,
+ * and used by inodes during replay phase. Our simple replay phase
+ * allocator excludes these regions from allocation.
  */
-static int ext4_fc_record_regions(struct super_block *sb, int ino,
-               ext4_lblk_t lblk, ext4_fsblk_t pblk, int len)
+int ext4_fc_record_regions(struct super_block *sb, int ino,
+               ext4_lblk_t lblk, ext4_fsblk_t pblk, int len, int replay)
 {
        struct ext4_fc_replay_state *state;
        struct ext4_fc_alloc_region *region;
 
        state = &EXT4_SB(sb)->s_fc_replay_state;
+       /*
+        * during replay phase, the fc_regions_valid may not same as
+        * fc_regions_used, update it when do new additions.
+        */
+       if (replay && state->fc_regions_used != state->fc_regions_valid)
+               state->fc_regions_used = state->fc_regions_valid;
        if (state->fc_regions_used == state->fc_regions_size) {
                state->fc_regions_size +=
                        EXT4_FC_REPLAY_REALLOC_INCREMENT;
@@ -1590,6 +1618,9 @@ static int ext4_fc_record_regions(struct super_block *sb, int ino,
        region->pblk = pblk;
        region->len = len;
 
+       if (replay)
+               state->fc_regions_valid++;
+
        return 0;
 }
 
@@ -1621,6 +1652,8 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
        }
 
        ret = ext4_fc_record_modified_inode(sb, inode->i_ino);
+       if (ret)
+               goto out;
 
        start = le32_to_cpu(ex->ee_block);
        start_pblk = ext4_ext_pblock(ex);
@@ -1638,18 +1671,14 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
                map.m_pblk = 0;
                ret = ext4_map_blocks(NULL, inode, &map, 0);
 
-               if (ret < 0) {
-                       iput(inode);
-                       return 0;
-               }
+               if (ret < 0)
+                       goto out;
 
                if (ret == 0) {
                        /* Range is not mapped */
                        path = ext4_find_extent(inode, cur, NULL, 0);
-                       if (IS_ERR(path)) {
-                               iput(inode);
-                               return 0;
-                       }
+                       if (IS_ERR(path))
+                               goto out;
                        memset(&newex, 0, sizeof(newex));
                        newex.ee_block = cpu_to_le32(cur);
                        ext4_ext_store_pblock(
@@ -1663,10 +1692,8 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
                        up_write((&EXT4_I(inode)->i_data_sem));
                        ext4_ext_drop_refs(path);
                        kfree(path);
-                       if (ret) {
-                               iput(inode);
-                               return 0;
-                       }
+                       if (ret)
+                               goto out;
                        goto next;
                }
 
@@ -1679,10 +1706,8 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
                        ret = ext4_ext_replay_update_ex(inode, cur, map.m_len,
                                        ext4_ext_is_unwritten(ex),
                                        start_pblk + cur - start);
-                       if (ret) {
-                               iput(inode);
-                               return 0;
-                       }
+                       if (ret)
+                               goto out;
                        /*
                         * Mark the old blocks as free since they aren't used
                         * anymore. We maintain an array of all the modified
@@ -1702,10 +1727,8 @@ static int ext4_fc_replay_add_range(struct super_block *sb,
                        ext4_ext_is_unwritten(ex), map.m_pblk);
                ret = ext4_ext_replay_update_ex(inode, cur, map.m_len,
                                        ext4_ext_is_unwritten(ex), map.m_pblk);
-               if (ret) {
-                       iput(inode);
-                       return 0;
-               }
+               if (ret)
+                       goto out;
                /*
                 * We may have split the extent tree while toggling the state.
                 * Try to shrink the extent tree now.
@@ -1717,6 +1740,7 @@ next:
        }
        ext4_ext_replay_shrink_inode(inode, i_size_read(inode) >>
                                        sb->s_blocksize_bits);
+out:
        iput(inode);
        return 0;
 }
@@ -1746,6 +1770,8 @@ ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl,
        }
 
        ret = ext4_fc_record_modified_inode(sb, inode->i_ino);
+       if (ret)
+               goto out;
 
        jbd_debug(1, "DEL_RANGE, inode %ld, lblk %d, len %d\n",
                        inode->i_ino, le32_to_cpu(lrange.fc_lblk),
@@ -1755,10 +1781,8 @@ ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl,
                map.m_len = remaining;
 
                ret = ext4_map_blocks(NULL, inode, &map, 0);
-               if (ret < 0) {
-                       iput(inode);
-                       return 0;
-               }
+               if (ret < 0)
+                       goto out;
                if (ret > 0) {
                        remaining -= ret;
                        cur += ret;
@@ -1770,18 +1794,17 @@ ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl,
        }
 
        down_write(&EXT4_I(inode)->i_data_sem);
-       ret = ext4_ext_remove_space(inode, lrange.fc_lblk,
-                               lrange.fc_lblk + lrange.fc_len - 1);
+       ret = ext4_ext_remove_space(inode, le32_to_cpu(lrange.fc_lblk),
+                               le32_to_cpu(lrange.fc_lblk) +
+                               le32_to_cpu(lrange.fc_len) - 1);
        up_write(&EXT4_I(inode)->i_data_sem);
-       if (ret) {
-               iput(inode);
-               return 0;
-       }
+       if (ret)
+               goto out;
        ext4_ext_replay_shrink_inode(inode,
                i_size_read(inode) >> sb->s_blocksize_bits);
        ext4_mark_inode_dirty(NULL, inode);
+out:
        iput(inode);
-
        return 0;
 }
 
@@ -1937,7 +1960,7 @@ static int ext4_fc_replay_scan(journal_t *journal,
                        ret = ext4_fc_record_regions(sb,
                                le32_to_cpu(ext.fc_ino),
                                le32_to_cpu(ex->ee_block), ext4_ext_pblock(ex),
-                               ext4_ext_get_actual_len(ex));
+                               ext4_ext_get_actual_len(ex), 0);
                        if (ret < 0)
                                break;
                        ret = JBD2_FC_REPLAY_CONTINUE;
index f34f417..147b524 100644 (file)
@@ -290,7 +290,7 @@ static int __ext4fs_dirhash(const struct inode *dir, const char *name, int len,
 int ext4fs_dirhash(const struct inode *dir, const char *name, int len,
                   struct dx_hash_info *hinfo)
 {
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        const struct unicode_map *um = dir->i_sb->s_encoding;
        int r, dlen;
        unsigned char *buff;
index 89efa78..07a8c75 100644 (file)
@@ -696,7 +696,7 @@ static int ext4_ind_trunc_restart_fn(handle_t *handle, struct inode *inode,
         * Drop i_data_sem to avoid deadlock with ext4_map_blocks.  At this
         * moment, get_block can be called only for blocks inside i_size since
         * page cache has been already dropped and writes are blocked by
-        * i_mutex. So we can safely drop the i_data_sem here.
+        * i_rwsem. So we can safely drop the i_data_sem here.
         */
        BUG_ON(EXT4_JOURNAL(inode) == NULL);
        ext4_discard_preallocations(inode, 0);
index 635bcf6..e429418 100644 (file)
@@ -911,7 +911,7 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping,
                                    struct page **pagep,
                                    void **fsdata)
 {
-       int ret, inline_size;
+       int ret;
        handle_t *handle;
        struct page *page;
        struct ext4_iloc iloc;
@@ -928,14 +928,9 @@ retry_journal:
                goto out;
        }
 
-       inline_size = ext4_get_max_inline_size(inode);
-
-       ret = -ENOSPC;
-       if (inline_size >= pos + len) {
-               ret = ext4_prepare_inline_data(handle, inode, pos + len);
-               if (ret && ret != -ENOSPC)
-                       goto out_journal;
-       }
+       ret = ext4_prepare_inline_data(handle, inode, pos + len);
+       if (ret && ret != -ENOSPC)
+               goto out_journal;
 
        /*
         * We cannot recurse into the filesystem as the transaction
@@ -1133,7 +1128,15 @@ static void ext4_restore_inline_data(handle_t *handle, struct inode *inode,
                                     struct ext4_iloc *iloc,
                                     void *buf, int inline_size)
 {
-       ext4_create_inline_data(handle, inode, inline_size);
+       int ret;
+
+       ret = ext4_create_inline_data(handle, inode, inline_size);
+       if (ret) {
+               ext4_msg(inode->i_sb, KERN_EMERG,
+                       "error restoring inline_data for inode -- potential data loss! (inode %lu, error %d)",
+                       inode->i_ino, ret);
+               return;
+       }
        ext4_write_inline_data(inode, iloc, buf, 0, inline_size);
        ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
 }
index 5f79d26..01c9e4f 100644 (file)
@@ -338,7 +338,7 @@ stop_handle:
        return;
 no_delete:
        if (!list_empty(&EXT4_I(inode)->i_fc_list))
-               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_NOMEM);
+               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_NOMEM, NULL);
        ext4_clear_inode(inode);        /* We must guarantee clearing of inode... */
 }
 
@@ -1224,7 +1224,7 @@ retry_journal:
                /*
                 * __block_write_begin may have instantiated a few blocks
                 * outside i_size.  Trim these off again. Don't need
-                * i_size_read because we hold i_mutex.
+                * i_size_read because we hold i_rwsem.
                 *
                 * Add inode to orphan list in case we crash before
                 * truncate finishes
@@ -3979,7 +3979,7 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
 
        }
 
-       /* Wait all existing dio workers, newcomers will block on i_mutex */
+       /* Wait all existing dio workers, newcomers will block on i_rwsem */
        inode_dio_wait(inode);
 
        /*
@@ -4129,7 +4129,7 @@ int ext4_truncate(struct inode *inode)
        /*
         * There is a possibility that we're either freeing the inode
         * or it's a completely new inode. In those cases we might not
-        * have i_mutex locked because it's not necessary.
+        * have i_rwsem locked because it's not necessary.
         */
        if (!(inode->i_state & (I_NEW|I_FREEING)))
                WARN_ON(!inode_is_locked(inode));
@@ -5271,7 +5271,7 @@ static void ext4_wait_for_tail_page_commit(struct inode *inode)
  * transaction are already on disk (truncate waits for pages under
  * writeback).
  *
- * Called with inode->i_mutex down.
+ * Called with inode->i_rwsem down.
  */
 int ext4_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
                 struct iattr *attr)
@@ -5983,7 +5983,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
                return PTR_ERR(handle);
 
        ext4_fc_mark_ineligible(inode->i_sb,
-               EXT4_FC_REASON_JOURNAL_FLAG_CHANGE);
+               EXT4_FC_REASON_JOURNAL_FLAG_CHANGE, handle);
        err = ext4_mark_inode_dirty(handle, inode);
        ext4_handle_sync(handle);
        ext4_journal_stop(handle);
index bbbedf2..a8022c2 100644 (file)
@@ -411,7 +411,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
                err = -EINVAL;
                goto err_out;
        }
-       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_SWAP_BOOT);
+       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_SWAP_BOOT, handle);
 
        /* Protect extent tree against block allocations via delalloc */
        ext4_double_down_write_data_sem(inode, inode_bl);
@@ -1373,7 +1373,7 @@ mext_out:
 
                err = ext4_resize_fs(sb, n_blocks_count);
                if (EXT4_SB(sb)->s_journal) {
-                       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_RESIZE);
+                       ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_RESIZE, NULL);
                        jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
                        err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal, 0);
                        jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
index 9f86dd9..67ac95c 100644 (file)
@@ -5753,7 +5753,8 @@ static ext4_fsblk_t ext4_mb_new_blocks_simple(handle_t *handle,
        struct super_block *sb = ar->inode->i_sb;
        ext4_group_t group;
        ext4_grpblk_t blkoff;
-       int i = sb->s_blocksize;
+       ext4_grpblk_t max = EXT4_CLUSTERS_PER_GROUP(sb);
+       ext4_grpblk_t i = 0;
        ext4_fsblk_t goal, block;
        struct ext4_super_block *es = EXT4_SB(sb)->s_es;
 
@@ -5775,19 +5776,26 @@ static ext4_fsblk_t ext4_mb_new_blocks_simple(handle_t *handle,
                ext4_get_group_no_and_offset(sb,
                        max(ext4_group_first_block_no(sb, group), goal),
                        NULL, &blkoff);
-               i = mb_find_next_zero_bit(bitmap_bh->b_data, sb->s_blocksize,
+               while (1) {
+                       i = mb_find_next_zero_bit(bitmap_bh->b_data, max,
                                                blkoff);
+                       if (i >= max)
+                               break;
+                       if (ext4_fc_replay_check_excluded(sb,
+                               ext4_group_first_block_no(sb, group) + i)) {
+                               blkoff = i + 1;
+                       } else
+                               break;
+               }
                brelse(bitmap_bh);
-               if (i >= sb->s_blocksize)
-                       continue;
-               if (ext4_fc_replay_check_excluded(sb,
-                       ext4_group_first_block_no(sb, group) + i))
-                       continue;
-               break;
+               if (i < max)
+                       break;
        }
 
-       if (group >= ext4_get_groups_count(sb) && i >= sb->s_blocksize)
+       if (group >= ext4_get_groups_count(sb) || i >= max) {
+               *errp = -ENOSPC;
                return 0;
+       }
 
        block = ext4_group_first_block_no(sb, group) + i;
        ext4_mb_mark_bb(sb, block, 1, 1);
index ff8916e..7a5353a 100644 (file)
@@ -485,7 +485,7 @@ int ext4_ext_migrate(struct inode *inode)
         * when we add extents we extent the journal
         */
        /*
-        * Even though we take i_mutex we can still cause block
+        * Even though we take i_rwsem we can still cause block
         * allocation via mmap write to holes. If we have allocated
         * new blocks we fail migrate.  New block allocation will
         * clear EXT4_STATE_EXT_MIGRATE flag.  The flag is updated
index 52c9bd1..8cf0a92 100644 (file)
@@ -1317,7 +1317,7 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block)
        dx_set_count(entries, count + 1);
 }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 /*
  * Test whether a case-insensitive directory entry matches the filename
  * being searched for.  If quick is set, assume the name being looked up
@@ -1428,7 +1428,7 @@ static bool ext4_match(struct inode *parent,
        f.crypto_buf = fname->crypto_buf;
 #endif
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (parent->i_sb->s_encoding && IS_CASEFOLDED(parent) &&
            (!IS_ENCRYPTED(parent) || fscrypt_has_encryption_key(parent))) {
                if (fname->cf_name.name) {
@@ -1800,7 +1800,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
                }
        }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (!inode && IS_CASEFOLDED(dir)) {
                /* Eventually we want to call d_add_ci(dentry, NULL)
                 * for negative dentries in the encoding case as
@@ -2308,7 +2308,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
        if (fscrypt_is_nokey_name(dentry))
                return -ENOKEY;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (sb_has_strict_encoding(sb) && IS_CASEFOLDED(dir) &&
            sb->s_encoding && utf8_validate(sb->s_encoding, &dentry->d_name))
                return -EINVAL;
@@ -3126,7 +3126,7 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
        ext4_fc_track_unlink(handle, dentry);
        retval = ext4_mark_inode_dirty(handle, dir);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        /* VFS negative dentries are incompatible with Encoding and
         * Case-insensitiveness. Eventually we'll want avoid
         * invalidating the dentries here, alongside with returning the
@@ -3231,7 +3231,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
        retval = __ext4_unlink(handle, dir, &dentry->d_name, d_inode(dentry));
        if (!retval)
                ext4_fc_track_unlink(handle, dentry);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        /* VFS negative dentries are incompatible with Encoding and
         * Case-insensitiveness. Eventually we'll want avoid
         * invalidating the dentries here, alongside with returning the
@@ -3889,7 +3889,7 @@ static int ext4_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
                 * dirents in directories.
                 */
                ext4_fc_mark_ineligible(old.inode->i_sb,
-                       EXT4_FC_REASON_RENAME_DIR);
+                       EXT4_FC_REASON_RENAME_DIR, handle);
        } else {
                if (new.inode)
                        ext4_fc_track_unlink(handle, new.dentry);
@@ -4049,7 +4049,7 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (unlikely(retval))
                goto end_rename;
        ext4_fc_mark_ineligible(new.inode->i_sb,
-                               EXT4_FC_REASON_CROSS_RENAME);
+                               EXT4_FC_REASON_CROSS_RENAME, handle);
        if (old.dir_bh) {
                retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino);
                if (retval)
index 53adc8f..7de0612 100644 (file)
@@ -93,7 +93,7 @@ static int ext4_orphan_file_add(handle_t *handle, struct inode *inode)
  * At filesystem recovery time, we walk this list deleting unlinked
  * inodes and truncating linked inodes in ext4_orphan_cleanup().
  *
- * Orphan list manipulation functions must be called under i_mutex unless
+ * Orphan list manipulation functions must be called under i_rwsem unless
  * we are just creating the inode or deleting it.
  */
 int ext4_orphan_add(handle_t *handle, struct inode *inode)
@@ -119,7 +119,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
        /*
         * Orphan handling is only valid for files with data blocks
         * being truncated, or files being unlinked. Note that we either
-        * hold i_mutex, or the inode can not be referenced from outside,
+        * hold i_rwsem, or the inode can not be referenced from outside,
         * so i_nlink should not be bumped due to race
         */
        ASSERT((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
index eee0d9e..c5021ca 100644 (file)
@@ -1301,7 +1301,7 @@ static void ext4_put_super(struct super_block *sb)
        kfree(sbi->s_blockgroup_lock);
        fs_put_dax(sbi->s_daxdev);
        fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        utf8_unload(sb->s_encoding);
 #endif
        kfree(sbi);
@@ -1961,7 +1961,7 @@ static const struct mount_opts {
        {Opt_err, 0, 0}
 };
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 static const struct ext4_sb_encodings {
        __u16 magic;
        char *name;
@@ -3606,7 +3606,7 @@ int ext4_feature_set_ok(struct super_block *sb, int readonly)
                return 0;
        }
 
-#ifndef CONFIG_UNICODE
+#if !IS_ENABLED(CONFIG_UNICODE)
        if (ext4_has_feature_casefold(sb)) {
                ext4_msg(sb, KERN_ERR,
                         "Filesystem with casefold feature cannot be "
@@ -4610,7 +4610,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
        if (err < 0)
                goto failed_mount;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (ext4_has_feature_casefold(sb) && !sb->s_encoding) {
                const struct ext4_sb_encodings *encoding_info;
                struct unicode_map *encoding;
@@ -5082,7 +5082,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
        INIT_LIST_HEAD(&sbi->s_fc_dentry_q[FC_Q_STAGING]);
        sbi->s_fc_bytes = 0;
        ext4_clear_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
-       ext4_clear_mount_flag(sb, EXT4_MF_FC_COMMITTING);
+       sbi->s_fc_ineligible_tid = 0;
        spin_lock_init(&sbi->s_fc_lock);
        memset(&sbi->s_fc_stats, 0, sizeof(sbi->s_fc_stats));
        sbi->s_fc_replay_state.fc_regions = NULL;
@@ -5514,7 +5514,7 @@ failed_mount:
        if (sbi->s_chksum_driver)
                crypto_free_shash(sbi->s_chksum_driver);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        utf8_unload(sb->s_encoding);
 #endif
 
@@ -5540,7 +5540,7 @@ static int ext4_fill_super(struct super_block *sb, struct fs_context *fc)
 
        sbi = ext4_alloc_sbi(sb);
        if (!sbi)
-               ret = -ENOMEM;
+               return -ENOMEM;
 
        fc->s_fs_info = sbi;
 
index f61e65a..d233c24 100644 (file)
@@ -309,7 +309,7 @@ EXT4_ATTR_FEATURE(meta_bg_resize);
 EXT4_ATTR_FEATURE(encryption);
 EXT4_ATTR_FEATURE(test_dummy_encryption_v2);
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 EXT4_ATTR_FEATURE(casefold);
 #endif
 #ifdef CONFIG_FS_VERITY
@@ -317,7 +317,7 @@ EXT4_ATTR_FEATURE(verity);
 #endif
 EXT4_ATTR_FEATURE(metadata_csum_seed);
 EXT4_ATTR_FEATURE(fast_commit);
-#if defined(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION)
+#if IS_ENABLED(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION)
 EXT4_ATTR_FEATURE(encrypted_casefold);
 #endif
 
@@ -329,7 +329,7 @@ static struct attribute *ext4_feat_attrs[] = {
        ATTR_LIST(encryption),
        ATTR_LIST(test_dummy_encryption_v2),
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        ATTR_LIST(casefold),
 #endif
 #ifdef CONFIG_FS_VERITY
@@ -337,7 +337,7 @@ static struct attribute *ext4_feat_attrs[] = {
 #endif
        ATTR_LIST(metadata_csum_seed),
        ATTR_LIST(fast_commit),
-#if defined(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION)
+#if IS_ENABLED(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION)
        ATTR_LIST(encrypted_casefold),
 #endif
        NULL,
index 1e0fc1e..0423253 100644 (file)
@@ -2408,7 +2408,7 @@ retry_inode:
                if (IS_SYNC(inode))
                        ext4_handle_sync(handle);
        }
-       ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR);
+       ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR, handle);
 
 cleanup:
        brelse(is.iloc.bh);
@@ -2486,7 +2486,7 @@ retry:
                if (error == 0)
                        error = error2;
        }
-       ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR);
+       ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR, NULL);
 
        return error;
 }
@@ -2920,7 +2920,7 @@ int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode,
                                         error);
                        goto cleanup;
                }
-               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR);
+               ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR, handle);
        }
        error = 0;
 cleanup:
index 1820e9c..166f086 100644 (file)
@@ -16,7 +16,7 @@
 #include "xattr.h"
 #include <trace/events/f2fs.h>
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 extern struct kmem_cache *f2fs_cf_name_slab;
 #endif
 
@@ -79,7 +79,7 @@ unsigned char f2fs_get_de_type(struct f2fs_dir_entry *de)
 int f2fs_init_casefolded_name(const struct inode *dir,
                              struct f2fs_filename *fname)
 {
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        struct super_block *sb = dir->i_sb;
 
        if (IS_CASEFOLDED(dir)) {
@@ -174,7 +174,7 @@ void f2fs_free_filename(struct f2fs_filename *fname)
        kfree(fname->crypto_buf.name);
        fname->crypto_buf.name = NULL;
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (fname->cf_name.name) {
                kmem_cache_free(f2fs_cf_name_slab, fname->cf_name.name);
                fname->cf_name.name = NULL;
@@ -208,7 +208,7 @@ static struct f2fs_dir_entry *find_in_block(struct inode *dir,
        return f2fs_find_target_dentry(&d, fname, max_slots);
 }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 /*
  * Test whether a case-insensitive directory entry matches the filename
  * being searched for.
@@ -266,7 +266,7 @@ static inline int f2fs_match_name(const struct inode *dir,
 {
        struct fscrypt_name f;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (fname->cf_name.name) {
                struct qstr cf = FSTR_TO_QSTR(&fname->cf_name);
 
index eb22fa9..68b4401 100644 (file)
@@ -488,7 +488,7 @@ struct f2fs_filename {
         */
        struct fscrypt_str crypto_buf;
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        /*
         * For casefolded directories: the casefolded name, but it's left NULL
         * if the original name is not valid Unicode, if the directory is both
index e3beac5..3cb1e7a 100644 (file)
@@ -105,7 +105,7 @@ void f2fs_hash_filename(const struct inode *dir, struct f2fs_filename *fname)
                return;
        }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (IS_CASEFOLDED(dir)) {
                /*
                 * If the casefolded name is provided, hash it instead of the
index a728a0a..5f213f0 100644 (file)
@@ -561,7 +561,7 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
                goto out_iput;
        }
 out_splice:
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (!inode && IS_CASEFOLDED(dir)) {
                /* Eventually we want to call d_add_ci(dentry, NULL)
                 * for negative dentries in the encoding case as
@@ -622,7 +622,7 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
                goto fail;
        }
        f2fs_delete_entry(de, page, dir, inode);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        /* VFS negative dentries are incompatible with Encoding and
         * Case-insensitiveness. Eventually we'll want avoid
         * invalidating the dentries here, alongside with returning the
index 9683c80..79773d3 100644 (file)
@@ -46,7 +46,7 @@
 
 static struct kmem_cache *fsync_entry_slab;
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 extern struct kmem_cache *f2fs_cf_name_slab;
 #endif
 
@@ -149,7 +149,7 @@ static int init_recovered_filename(const struct inode *dir,
                if (err)
                        return err;
                f2fs_hash_filename(dir, fname);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
                /* Case-sensitive match is fine for recovery */
                kmem_cache_free(f2fs_cf_name_slab, fname->cf_name.name);
                fname->cf_name.name = NULL;
index 76e6a3d..baefd39 100644 (file)
@@ -257,7 +257,7 @@ void f2fs_printk(struct f2fs_sb_info *sbi, const char *fmt, ...)
        va_end(args);
 }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 static const struct f2fs_sb_encodings {
        __u16 magic;
        char *name;
@@ -1259,7 +1259,7 @@ default_check:
                return -EINVAL;
        }
 #endif
-#ifndef CONFIG_UNICODE
+#if !IS_ENABLED(CONFIG_UNICODE)
        if (f2fs_sb_has_casefold(sbi)) {
                f2fs_err(sbi,
                        "Filesystem with casefold feature cannot be mounted without CONFIG_UNICODE");
@@ -1619,7 +1619,7 @@ static void f2fs_put_super(struct super_block *sb)
        f2fs_destroy_iostat(sbi);
        for (i = 0; i < NR_PAGE_TYPE; i++)
                kvfree(sbi->write_io[i]);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        utf8_unload(sb->s_encoding);
 #endif
        kfree(sbi);
@@ -3903,7 +3903,7 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
 
 static int f2fs_setup_casefold(struct f2fs_sb_info *sbi)
 {
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (f2fs_sb_has_casefold(sbi) && !sbi->sb->s_encoding) {
                const struct f2fs_sb_encodings *encoding_info;
                struct unicode_map *encoding;
@@ -4458,7 +4458,7 @@ free_bio_info:
        for (i = 0; i < NR_PAGE_TYPE; i++)
                kvfree(sbi->write_io[i]);
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        utf8_unload(sb->s_encoding);
        sb->s_encoding = NULL;
 #endif
index df406c1..8ac5066 100644 (file)
@@ -201,7 +201,7 @@ static ssize_t unusable_show(struct f2fs_attr *a,
 static ssize_t encoding_show(struct f2fs_attr *a,
                struct f2fs_sb_info *sbi, char *buf)
 {
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        struct super_block *sb = sbi->sb;
 
        if (f2fs_sb_has_casefold(sbi))
@@ -778,7 +778,7 @@ F2FS_GENERAL_RO_ATTR(avg_vblocks);
 #ifdef CONFIG_FS_ENCRYPTION
 F2FS_FEATURE_RO_ATTR(encryption);
 F2FS_FEATURE_RO_ATTR(test_dummy_encryption_v2);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 F2FS_FEATURE_RO_ATTR(encrypted_casefold);
 #endif
 #endif /* CONFIG_FS_ENCRYPTION */
@@ -797,7 +797,7 @@ F2FS_FEATURE_RO_ATTR(lost_found);
 F2FS_FEATURE_RO_ATTR(verity);
 #endif
 F2FS_FEATURE_RO_ATTR(sb_checksum);
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 F2FS_FEATURE_RO_ATTR(casefold);
 #endif
 F2FS_FEATURE_RO_ATTR(readonly);
@@ -910,7 +910,7 @@ static struct attribute *f2fs_feat_attrs[] = {
 #ifdef CONFIG_FS_ENCRYPTION
        ATTR_LIST(encryption),
        ATTR_LIST(test_dummy_encryption_v2),
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        ATTR_LIST(encrypted_casefold),
 #endif
 #endif /* CONFIG_FS_ENCRYPTION */
@@ -929,7 +929,7 @@ static struct attribute *f2fs_feat_attrs[] = {
        ATTR_LIST(verity),
 #endif
        ATTR_LIST(sb_checksum),
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        ATTR_LIST(casefold),
 #endif
        ATTR_LIST(readonly),
index 57edef1..7d2e692 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/task_work.h>
 #include <linux/ima.h>
 #include <linux/swap.h>
+#include <linux/kmemleak.h>
 
 #include <linux/atomic.h>
 
@@ -119,6 +120,11 @@ static struct ctl_table fs_stat_sysctls[] = {
 static int __init init_fs_stat_sysctls(void)
 {
        register_sysctl_init("fs", fs_stat_sysctls);
+       if (IS_ENABLED(CONFIG_BINFMT_MISC)) {
+               struct ctl_table_header *hdr;
+               hdr = register_sysctl_mount_point("fs/binfmt_misc");
+               kmemleak_not_leak(hdr);
+       }
        return 0;
 }
 fs_initcall(init_fs_stat_sysctls);
index 3e718cf..8c39a85 100644 (file)
@@ -704,10 +704,11 @@ static int gfs2_release(struct inode *inode, struct file *file)
        kfree(file->private_data);
        file->private_data = NULL;
 
-       if (gfs2_rs_active(&ip->i_res))
-               gfs2_rs_delete(ip, &inode->i_writecount);
-       if (file->f_mode & FMODE_WRITE)
+       if (file->f_mode & FMODE_WRITE) {
+               if (gfs2_rs_active(&ip->i_res))
+                       gfs2_rs_delete(ip, &inode->i_writecount);
                gfs2_qa_put(ip);
+       }
        return 0;
 }
 
index b7ab843..6b23399 100644 (file)
@@ -301,9 +301,6 @@ void gfs2_glock_queue_put(struct gfs2_glock *gl)
 
 void gfs2_glock_put(struct gfs2_glock *gl)
 {
-       /* last put could call sleepable dlm api */
-       might_sleep();
-
        if (lockref_put_or_lock(&gl->gl_lockref))
                return;
 
index e54c412..4715980 100644 (file)
@@ -4567,6 +4567,7 @@ static int io_add_buffers(struct io_provide_buf *pbuf, struct io_buffer **head)
                } else {
                        list_add_tail(&buf->list, &(*head)->list);
                }
+               cond_resched();
        }
 
        return i ? i : -ENOMEM;
@@ -5228,7 +5229,6 @@ static int io_recv(struct io_kiocb *req, unsigned int issue_flags)
                min_ret = iov_iter_count(&msg.msg_iter);
 
        ret = sock_recvmsg(sock, &msg, flags);
-out_free:
        if (ret < min_ret) {
                if (ret == -EAGAIN && force_nonblock)
                        return -EAGAIN;
@@ -5236,9 +5236,9 @@ out_free:
                        ret = -EINTR;
                req_set_fail(req);
        } else if ((flags & MSG_WAITALL) && (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC))) {
+out_free:
                req_set_fail(req);
        }
-
        __io_req_complete(req, issue_flags, ret, io_put_kbuf(req));
        return 0;
 }
@@ -7694,7 +7694,7 @@ static int io_run_task_work_sig(void)
 /* when returns >0, the caller should retry */
 static inline int io_cqring_wait_schedule(struct io_ring_ctx *ctx,
                                          struct io_wait_queue *iowq,
-                                         signed long *timeout)
+                                         ktime_t timeout)
 {
        int ret;
 
@@ -7706,8 +7706,9 @@ static inline int io_cqring_wait_schedule(struct io_ring_ctx *ctx,
        if (test_bit(0, &ctx->check_cq_overflow))
                return 1;
 
-       *timeout = schedule_timeout(*timeout);
-       return !*timeout ? -ETIME : 1;
+       if (!schedule_hrtimeout(&timeout, HRTIMER_MODE_ABS))
+               return -ETIME;
+       return 1;
 }
 
 /*
@@ -7720,7 +7721,7 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
 {
        struct io_wait_queue iowq;
        struct io_rings *rings = ctx->rings;
-       signed long timeout = MAX_SCHEDULE_TIMEOUT;
+       ktime_t timeout = KTIME_MAX;
        int ret;
 
        do {
@@ -7736,7 +7737,7 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
 
                if (get_timespec64(&ts, uts))
                        return -EFAULT;
-               timeout = timespec64_to_jiffies(&ts);
+               timeout = ktime_add_ns(timespec64_to_ktime(ts), ktime_get_ns());
        }
 
        if (sig) {
@@ -7768,7 +7769,7 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
                }
                prepare_to_wait_exclusive(&ctx->cq_wait, &iowq.wq,
                                                TASK_INTERRUPTIBLE);
-               ret = io_cqring_wait_schedule(ctx, &iowq, &timeout);
+               ret = io_cqring_wait_schedule(ctx, &iowq, timeout);
                finish_wait(&ctx->cq_wait, &iowq.wq);
                cond_resched();
        } while (ret > 0);
@@ -7822,10 +7823,15 @@ static __cold void io_rsrc_node_ref_zero(struct percpu_ref *ref)
        struct io_ring_ctx *ctx = node->rsrc_data->ctx;
        unsigned long flags;
        bool first_add = false;
+       unsigned long delay = HZ;
 
        spin_lock_irqsave(&ctx->rsrc_ref_lock, flags);
        node->done = true;
 
+       /* if we are mid-quiesce then do not delay */
+       if (node->rsrc_data->quiesce)
+               delay = 0;
+
        while (!list_empty(&ctx->rsrc_ref_list)) {
                node = list_first_entry(&ctx->rsrc_ref_list,
                                            struct io_rsrc_node, node);
@@ -7838,10 +7844,10 @@ static __cold void io_rsrc_node_ref_zero(struct percpu_ref *ref)
        spin_unlock_irqrestore(&ctx->rsrc_ref_lock, flags);
 
        if (first_add)
-               mod_delayed_work(system_wq, &ctx->rsrc_put_work, HZ);
+               mod_delayed_work(system_wq, &ctx->rsrc_put_work, delay);
 }
 
-static struct io_rsrc_node *io_rsrc_node_alloc(struct io_ring_ctx *ctx)
+static struct io_rsrc_node *io_rsrc_node_alloc(void)
 {
        struct io_rsrc_node *ref_node;
 
@@ -7892,7 +7898,7 @@ static int io_rsrc_node_switch_start(struct io_ring_ctx *ctx)
 {
        if (ctx->rsrc_backup_node)
                return 0;
-       ctx->rsrc_backup_node = io_rsrc_node_alloc(ctx);
+       ctx->rsrc_backup_node = io_rsrc_node_alloc();
        return ctx->rsrc_backup_node ? 0 : -ENOMEM;
 }
 
@@ -7920,7 +7926,15 @@ static __cold int io_rsrc_ref_quiesce(struct io_rsrc_data *data,
                ret = wait_for_completion_interruptible(&data->done);
                if (!ret) {
                        mutex_lock(&ctx->uring_lock);
-                       break;
+                       if (atomic_read(&data->refs) > 0) {
+                               /*
+                                * it has been revived by another thread while
+                                * we were unlocked
+                                */
+                               mutex_unlock(&ctx->uring_lock);
+                       } else {
+                               break;
+                       }
                }
 
                atomic_inc(&data->refs);
@@ -8928,10 +8942,9 @@ static void io_mem_free(void *ptr)
 
 static void *io_mem_alloc(size_t size)
 {
-       gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN | __GFP_COMP |
-                               __GFP_NORETRY | __GFP_ACCOUNT;
+       gfp_t gfp = GFP_KERNEL_ACCOUNT | __GFP_ZERO | __GFP_NOWARN | __GFP_COMP;
 
-       return (void *) __get_free_pages(gfp_flags, get_order(size));
+       return (void *) __get_free_pages(gfp, get_order(size));
 }
 
 static unsigned long rings_size(unsigned sq_entries, unsigned cq_entries,
index c938bba..6c51a75 100644 (file)
@@ -21,6 +21,8 @@
 
 #include "../internal.h"
 
+#define IOEND_BATCH_SIZE       4096
+
 /*
  * Structure allocated for each folio when block size < folio size
  * to track sub-folio uptodate status and I/O completions.
@@ -1039,7 +1041,7 @@ static void iomap_finish_folio_write(struct inode *inode, struct folio *folio,
  * state, release holds on bios, and finally free up memory.  Do not use the
  * ioend after this.
  */
-static void
+static u32
 iomap_finish_ioend(struct iomap_ioend *ioend, int error)
 {
        struct inode *inode = ioend->io_inode;
@@ -1048,6 +1050,7 @@ iomap_finish_ioend(struct iomap_ioend *ioend, int error)
        u64 start = bio->bi_iter.bi_sector;
        loff_t offset = ioend->io_offset;
        bool quiet = bio_flagged(bio, BIO_QUIET);
+       u32 folio_count = 0;
 
        for (bio = &ioend->io_inline_bio; bio; bio = next) {
                struct folio_iter fi;
@@ -1062,9 +1065,11 @@ iomap_finish_ioend(struct iomap_ioend *ioend, int error)
                        next = bio->bi_private;
 
                /* walk all folios in bio, ending page IO on them */
-               bio_for_each_folio_all(fi, bio)
+               bio_for_each_folio_all(fi, bio) {
                        iomap_finish_folio_write(inode, fi.folio, fi.length,
                                        error);
+                       folio_count++;
+               }
                bio_put(bio);
        }
        /* The ioend has been freed by bio_put() */
@@ -1074,20 +1079,36 @@ iomap_finish_ioend(struct iomap_ioend *ioend, int error)
 "%s: writeback error on inode %lu, offset %lld, sector %llu",
                        inode->i_sb->s_id, inode->i_ino, offset, start);
        }
+       return folio_count;
 }
 
+/*
+ * Ioend completion routine for merged bios. This can only be called from task
+ * contexts as merged ioends can be of unbound length. Hence we have to break up
+ * the writeback completions into manageable chunks to avoid long scheduler
+ * holdoffs. We aim to keep scheduler holdoffs down below 10ms so that we get
+ * good batch processing throughput without creating adverse scheduler latency
+ * conditions.
+ */
 void
 iomap_finish_ioends(struct iomap_ioend *ioend, int error)
 {
        struct list_head tmp;
+       u32 completions;
+
+       might_sleep();
 
        list_replace_init(&ioend->io_list, &tmp);
-       iomap_finish_ioend(ioend, error);
+       completions = iomap_finish_ioend(ioend, error);
 
        while (!list_empty(&tmp)) {
+               if (completions > IOEND_BATCH_SIZE * 8) {
+                       cond_resched();
+                       completions = 0;
+               }
                ioend = list_first_entry(&tmp, struct iomap_ioend, io_list);
                list_del_init(&ioend->io_list);
-               iomap_finish_ioend(ioend, error);
+               completions += iomap_finish_ioend(ioend, error);
        }
 }
 EXPORT_SYMBOL_GPL(iomap_finish_ioends);
@@ -1108,6 +1129,18 @@ iomap_ioend_can_merge(struct iomap_ioend *ioend, struct iomap_ioend *next)
                return false;
        if (ioend->io_offset + ioend->io_size != next->io_offset)
                return false;
+       /*
+        * Do not merge physically discontiguous ioends. The filesystem
+        * completion functions will have to iterate the physical
+        * discontiguities even if we merge the ioends at a logical level, so
+        * we don't gain anything by merging physical discontiguities here.
+        *
+        * We cannot use bio->bi_iter.bi_sector here as it is modified during
+        * submission so does not point to the start sector of the bio at
+        * completion.
+        */
+       if (ioend->io_sector + (ioend->io_size >> 9) != next->io_sector)
+               return false;
        return true;
 }
 
@@ -1209,8 +1242,10 @@ iomap_alloc_ioend(struct inode *inode, struct iomap_writepage_ctx *wpc,
        ioend->io_flags = wpc->iomap.flags;
        ioend->io_inode = inode;
        ioend->io_size = 0;
+       ioend->io_folios = 0;
        ioend->io_offset = offset;
        ioend->io_bio = bio;
+       ioend->io_sector = sector;
        return ioend;
 }
 
@@ -1251,6 +1286,13 @@ iomap_can_add_to_ioend(struct iomap_writepage_ctx *wpc, loff_t offset,
                return false;
        if (sector != bio_end_sector(wpc->ioend->io_bio))
                return false;
+       /*
+        * Limit ioend bio chain lengths to minimise IO completion latency. This
+        * also prevents long tight loops ending page writeback on all the
+        * folios in the ioend.
+        */
+       if (wpc->ioend->io_folios >= IOEND_BATCH_SIZE)
+               return false;
        return true;
 }
 
@@ -1335,6 +1377,8 @@ iomap_writepage_map(struct iomap_writepage_ctx *wpc,
                                 &submit_list);
                count++;
        }
+       if (count)
+               wpc->ioend->io_folios++;
 
        WARN_ON_ONCE(!wpc->ioend && !list_empty(&submit_list));
        WARN_ON_ONCE(!folio_test_locked(folio));
index 3cc4ab2..5b9408e 100644 (file)
@@ -484,22 +484,9 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        stats.run.rs_running = jbd2_time_diff(commit_transaction->t_start,
                                              stats.run.rs_locked);
 
-       spin_lock(&commit_transaction->t_handle_lock);
-       while (atomic_read(&commit_transaction->t_updates)) {
-               DEFINE_WAIT(wait);
+       // waits for any t_updates to finish
+       jbd2_journal_wait_updates(journal);
 
-               prepare_to_wait(&journal->j_wait_updates, &wait,
-                                       TASK_UNINTERRUPTIBLE);
-               if (atomic_read(&commit_transaction->t_updates)) {
-                       spin_unlock(&commit_transaction->t_handle_lock);
-                       write_unlock(&journal->j_state_lock);
-                       schedule();
-                       write_lock(&journal->j_state_lock);
-                       spin_lock(&commit_transaction->t_handle_lock);
-               }
-               finish_wait(&journal->j_wait_updates, &wait);
-       }
-       spin_unlock(&commit_transaction->t_handle_lock);
        commit_transaction->t_state = T_SWITCH;
        write_unlock(&journal->j_state_lock);
 
@@ -817,7 +804,7 @@ start_journal_io:
        commit_transaction->t_state = T_COMMIT_DFLUSH;
        write_unlock(&journal->j_state_lock);
 
-       /* 
+       /*
         * If the journal is not located on the file system device,
         * then we must flush the file system device before we issue
         * the commit record
@@ -1170,7 +1157,7 @@ restart_loop:
        if (journal->j_commit_callback)
                journal->j_commit_callback(journal, commit_transaction);
        if (journal->j_fc_cleanup_callback)
-               journal->j_fc_cleanup_callback(journal, 1);
+               journal->j_fc_cleanup_callback(journal, 1, commit_transaction->t_tid);
 
        trace_jbd2_end_commit(journal, commit_transaction);
        jbd_debug(1, "JBD2: commit %d complete, head %d\n",
index f13d548..c2cf74b 100644 (file)
@@ -771,7 +771,7 @@ static int __jbd2_fc_end_commit(journal_t *journal, tid_t tid, bool fallback)
 {
        jbd2_journal_unlock_updates(journal);
        if (journal->j_fc_cleanup_callback)
-               journal->j_fc_cleanup_callback(journal, 0);
+               journal->j_fc_cleanup_callback(journal, 0, tid);
        write_lock(&journal->j_state_lock);
        journal->j_flags &= ~JBD2_FAST_COMMIT_ONGOING;
        if (fallback)
@@ -1287,6 +1287,8 @@ static int jbd2_min_tag_size(void)
 
 /**
  * jbd2_journal_shrink_scan()
+ * @shrink: shrinker to work on
+ * @sc: reclaim request to process
  *
  * Scan the checkpointed buffer on the checkpoint list and release the
  * journal_head.
@@ -1312,6 +1314,8 @@ static unsigned long jbd2_journal_shrink_scan(struct shrinker *shrink,
 
 /**
  * jbd2_journal_shrink_count()
+ * @shrink: shrinker to work on
+ * @sc: reclaim request to process
  *
  * Count the number of checkpoint buffers on the checkpoint list.
  */
@@ -2972,6 +2976,7 @@ struct journal_head *jbd2_journal_grab_journal_head(struct buffer_head *bh)
        jbd_unlock_bh_journal_head(bh);
        return jh;
 }
+EXPORT_SYMBOL(jbd2_journal_grab_journal_head);
 
 static void __journal_remove_journal_head(struct buffer_head *bh)
 {
@@ -3024,6 +3029,7 @@ void jbd2_journal_put_journal_head(struct journal_head *jh)
                jbd_unlock_bh_journal_head(bh);
        }
 }
+EXPORT_SYMBOL(jbd2_journal_put_journal_head);
 
 /*
  * Initialize jbd inode head
index 6a3caed..8e2f827 100644 (file)
@@ -449,7 +449,7 @@ repeat:
        }
 
        /* OK, account for the buffers that this operation expects to
-        * use and add the handle to the running transaction. 
+        * use and add the handle to the running transaction.
         */
        update_t_max_wait(transaction, ts);
        handle->h_transaction = transaction;
@@ -836,6 +836,35 @@ int jbd2_journal_restart(handle_t *handle, int nblocks)
 }
 EXPORT_SYMBOL(jbd2_journal_restart);
 
+/*
+ * Waits for any outstanding t_updates to finish.
+ * This is called with write j_state_lock held.
+ */
+void jbd2_journal_wait_updates(journal_t *journal)
+{
+       transaction_t *commit_transaction = journal->j_running_transaction;
+
+       if (!commit_transaction)
+               return;
+
+       spin_lock(&commit_transaction->t_handle_lock);
+       while (atomic_read(&commit_transaction->t_updates)) {
+               DEFINE_WAIT(wait);
+
+               prepare_to_wait(&journal->j_wait_updates, &wait,
+                                       TASK_UNINTERRUPTIBLE);
+               if (atomic_read(&commit_transaction->t_updates)) {
+                       spin_unlock(&commit_transaction->t_handle_lock);
+                       write_unlock(&journal->j_state_lock);
+                       schedule();
+                       write_lock(&journal->j_state_lock);
+                       spin_lock(&commit_transaction->t_handle_lock);
+               }
+               finish_wait(&journal->j_wait_updates, &wait);
+       }
+       spin_unlock(&commit_transaction->t_handle_lock);
+}
+
 /**
  * jbd2_journal_lock_updates () - establish a transaction barrier.
  * @journal:  Journal to establish a barrier on.
@@ -863,27 +892,9 @@ void jbd2_journal_lock_updates(journal_t *journal)
                write_lock(&journal->j_state_lock);
        }
 
-       /* Wait until there are no running updates */
-       while (1) {
-               transaction_t *transaction = journal->j_running_transaction;
-
-               if (!transaction)
-                       break;
+       /* Wait until there are no running t_updates */
+       jbd2_journal_wait_updates(journal);
 
-               spin_lock(&transaction->t_handle_lock);
-               prepare_to_wait(&journal->j_wait_updates, &wait,
-                               TASK_UNINTERRUPTIBLE);
-               if (!atomic_read(&transaction->t_updates)) {
-                       spin_unlock(&transaction->t_handle_lock);
-                       finish_wait(&journal->j_wait_updates, &wait);
-                       break;
-               }
-               spin_unlock(&transaction->t_handle_lock);
-               write_unlock(&journal->j_state_lock);
-               schedule();
-               finish_wait(&journal->j_wait_updates, &wait);
-               write_lock(&journal->j_state_lock);
-       }
        write_unlock(&journal->j_state_lock);
 
        /*
index dc3d061..911444d 100644 (file)
@@ -29,6 +29,7 @@
 #include "mgmt/user_config.h"
 #include "crypto_ctx.h"
 #include "transport_ipc.h"
+#include "../smbfs_common/arc4.h"
 
 /*
  * Fixed format data defining GSS header and fixed string
@@ -336,6 +337,29 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
                                nt_len - CIFS_ENCPWD_SIZE,
                                domain_name, conn->ntlmssp.cryptkey);
        kfree(domain_name);
+
+       /* The recovered secondary session key */
+       if (conn->ntlmssp.client_flags & NTLMSSP_NEGOTIATE_KEY_XCH) {
+               struct arc4_ctx *ctx_arc4;
+               unsigned int sess_key_off, sess_key_len;
+
+               sess_key_off = le32_to_cpu(authblob->SessionKey.BufferOffset);
+               sess_key_len = le16_to_cpu(authblob->SessionKey.Length);
+
+               if (blob_len < (u64)sess_key_off + sess_key_len)
+                       return -EINVAL;
+
+               ctx_arc4 = kmalloc(sizeof(*ctx_arc4), GFP_KERNEL);
+               if (!ctx_arc4)
+                       return -ENOMEM;
+
+               cifs_arc4_setkey(ctx_arc4, sess->sess_key,
+                                SMB2_NTLMV2_SESSKEY_SIZE);
+               cifs_arc4_crypt(ctx_arc4, sess->sess_key,
+                               (char *)authblob + sess_key_off, sess_key_len);
+               kfree_sensitive(ctx_arc4);
+       }
+
        return ret;
 }
 
@@ -408,6 +432,9 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
            (cflags & NTLMSSP_NEGOTIATE_EXTENDED_SEC))
                flags |= NTLMSSP_NEGOTIATE_EXTENDED_SEC;
 
+       if (cflags & NTLMSSP_NEGOTIATE_KEY_XCH)
+               flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
+
        chgblob->NegotiateFlags = cpu_to_le32(flags);
        len = strlen(ksmbd_netbios_name());
        name = kmalloc(2 + UNICODE_LEN(len), GFP_KERNEL);
index 1866c81..67e8e28 100644 (file)
@@ -2688,7 +2688,7 @@ int smb2_open(struct ksmbd_work *work)
                                        (struct create_posix *)context;
                                if (le16_to_cpu(context->DataOffset) +
                                    le32_to_cpu(context->DataLength) <
-                                   sizeof(struct create_posix)) {
+                                   sizeof(struct create_posix) - 4) {
                                        rc = -EINVAL;
                                        goto err_out1;
                                }
@@ -3422,9 +3422,9 @@ static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level,
                goto free_conv_name;
        }
 
-       struct_sz = readdir_info_level_struct_sz(info_level);
-       next_entry_offset = ALIGN(struct_sz - 1 + conv_len,
-                                 KSMBD_DIR_INFO_ALIGNMENT);
+       struct_sz = readdir_info_level_struct_sz(info_level) - 1 + conv_len;
+       next_entry_offset = ALIGN(struct_sz, KSMBD_DIR_INFO_ALIGNMENT);
+       d_info->last_entry_off_align = next_entry_offset - struct_sz;
 
        if (next_entry_offset > d_info->out_buf_len) {
                d_info->out_buf_len = 0;
@@ -3976,6 +3976,7 @@ int smb2_query_dir(struct ksmbd_work *work)
                ((struct file_directory_info *)
                ((char *)rsp->Buffer + d_info.last_entry_offset))
                ->NextEntryOffset = 0;
+               d_info.data_count -= d_info.last_entry_off_align;
 
                rsp->StructureSize = cpu_to_le16(9);
                rsp->OutputBufferOffset = cpu_to_le16(72);
@@ -6126,13 +6127,26 @@ static int smb2_set_remote_key_for_rdma(struct ksmbd_work *work,
                                        __le16 ChannelInfoOffset,
                                        __le16 ChannelInfoLength)
 {
+       unsigned int i, ch_count;
+
        if (work->conn->dialect == SMB30_PROT_ID &&
            Channel != SMB2_CHANNEL_RDMA_V1)
                return -EINVAL;
 
-       if (ChannelInfoOffset == 0 ||
-           le16_to_cpu(ChannelInfoLength) < sizeof(*desc))
+       ch_count = le16_to_cpu(ChannelInfoLength) / sizeof(*desc);
+       if (ksmbd_debug_types & KSMBD_DEBUG_RDMA) {
+               for (i = 0; i < ch_count; i++) {
+                       pr_info("RDMA r/w request %#x: token %#x, length %#x\n",
+                               i,
+                               le32_to_cpu(desc[i].token),
+                               le32_to_cpu(desc[i].length));
+               }
+       }
+       if (ch_count != 1) {
+               ksmbd_debug(RDMA, "RDMA multiple buffer descriptors %d are not supported yet\n",
+                           ch_count);
                return -EINVAL;
+       }
 
        work->need_invalidate_rkey =
                (Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE);
@@ -6185,9 +6199,15 @@ int smb2_read(struct ksmbd_work *work)
 
        if (req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE ||
            req->Channel == SMB2_CHANNEL_RDMA_V1) {
+               unsigned int ch_offset = le16_to_cpu(req->ReadChannelInfoOffset);
+
+               if (ch_offset < offsetof(struct smb2_read_req, Buffer)) {
+                       err = -EINVAL;
+                       goto out;
+               }
                err = smb2_set_remote_key_for_rdma(work,
                                                   (struct smb2_buffer_desc_v1 *)
-                                                  &req->Buffer[0],
+                                                  ((char *)req + ch_offset),
                                                   req->Channel,
                                                   req->ReadChannelInfoOffset,
                                                   req->ReadChannelInfoLength);
@@ -6428,11 +6448,16 @@ int smb2_write(struct ksmbd_work *work)
 
        if (req->Channel == SMB2_CHANNEL_RDMA_V1 ||
            req->Channel == SMB2_CHANNEL_RDMA_V1_INVALIDATE) {
-               if (req->Length != 0 || req->DataOffset != 0)
-                       return -EINVAL;
+               unsigned int ch_offset = le16_to_cpu(req->WriteChannelInfoOffset);
+
+               if (req->Length != 0 || req->DataOffset != 0 ||
+                   ch_offset < offsetof(struct smb2_write_req, Buffer)) {
+                       err = -EINVAL;
+                       goto out;
+               }
                err = smb2_set_remote_key_for_rdma(work,
                                                   (struct smb2_buffer_desc_v1 *)
-                                                  &req->Buffer[0],
+                                                  ((char *)req + ch_offset),
                                                   req->Channel,
                                                   req->WriteChannelInfoOffset,
                                                   req->WriteChannelInfoLength);
index ef7f42b..9a7e211 100644 (file)
@@ -308,14 +308,17 @@ int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level,
        for (i = 0; i < 2; i++) {
                struct kstat kstat;
                struct ksmbd_kstat ksmbd_kstat;
+               struct dentry *dentry;
 
                if (!dir->dot_dotdot[i]) { /* fill dot entry info */
                        if (i == 0) {
                                d_info->name = ".";
                                d_info->name_len = 1;
+                               dentry = dir->filp->f_path.dentry;
                        } else {
                                d_info->name = "..";
                                d_info->name_len = 2;
+                               dentry = dir->filp->f_path.dentry->d_parent;
                        }
 
                        if (!match_pattern(d_info->name, d_info->name_len,
@@ -327,7 +330,7 @@ int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level,
                        ksmbd_kstat.kstat = &kstat;
                        ksmbd_vfs_fill_dentry_attrs(work,
                                                    user_ns,
-                                                   dir->filp->f_path.dentry->d_parent,
+                                                   dentry,
                                                    &ksmbd_kstat);
                        rc = fn(conn, info_level, d_info, &ksmbd_kstat);
                        if (rc)
index 3c1ec1a..ba5a22b 100644 (file)
@@ -80,7 +80,7 @@ static int smb_direct_max_fragmented_recv_size = 1024 * 1024;
 /*  The maximum single-message size which can be received */
 static int smb_direct_max_receive_size = 8192;
 
-static int smb_direct_max_read_write_size = 1048512;
+static int smb_direct_max_read_write_size = 524224;
 
 static int smb_direct_max_outstanding_rw_ops = 8;
 
index adf94a4..8c37aaf 100644 (file)
@@ -47,6 +47,7 @@ struct ksmbd_dir_info {
        int             last_entry_offset;
        bool            hide_dot_file;
        int             flags;
+       int             last_entry_off_align;
 };
 
 struct ksmbd_readdir_data {
index ba7438a..9741252 100644 (file)
@@ -1379,7 +1379,7 @@ bool is_empty_dir_inode(struct inode *inode)
                (inode->i_op == &empty_dir_inode_operations);
 }
 
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
 /*
  * Determine if the name of a dentry should be casefolded.
  *
@@ -1473,7 +1473,7 @@ static const struct dentry_operations generic_encrypted_dentry_ops = {
 };
 #endif
 
-#if defined(CONFIG_FS_ENCRYPTION) && defined(CONFIG_UNICODE)
+#if defined(CONFIG_FS_ENCRYPTION) && IS_ENABLED(CONFIG_UNICODE)
 static const struct dentry_operations generic_encrypted_ci_dentry_ops = {
        .d_hash = generic_ci_d_hash,
        .d_compare = generic_ci_d_compare,
@@ -1508,10 +1508,10 @@ void generic_set_encrypted_ci_d_ops(struct dentry *dentry)
 #ifdef CONFIG_FS_ENCRYPTION
        bool needs_encrypt_ops = dentry->d_flags & DCACHE_NOKEY_NAME;
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        bool needs_ci_ops = dentry->d_sb->s_encoding;
 #endif
-#if defined(CONFIG_FS_ENCRYPTION) && defined(CONFIG_UNICODE)
+#if defined(CONFIG_FS_ENCRYPTION) && IS_ENABLED(CONFIG_UNICODE)
        if (needs_encrypt_ops && needs_ci_ops) {
                d_set_d_op(dentry, &generic_encrypted_ci_dentry_ops);
                return;
@@ -1523,7 +1523,7 @@ void generic_set_encrypted_ci_d_ops(struct dentry *dentry)
                return;
        }
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        if (needs_ci_ops) {
                d_set_d_op(dentry, &generic_ci_dentry_ops);
                return;
index cb3a751..0a22a2f 100644 (file)
@@ -179,19 +179,21 @@ nlm_delete_file(struct nlm_file *file)
 static int nlm_unlock_files(struct nlm_file *file)
 {
        struct file_lock lock;
-       struct file *f;
 
+       locks_init_lock(&lock);
        lock.fl_type  = F_UNLCK;
        lock.fl_start = 0;
        lock.fl_end   = OFFSET_MAX;
-       for (f = file->f_file[0]; f <= file->f_file[1]; f++) {
-               if (f && vfs_lock_file(f, F_SETLK, &lock, NULL) < 0) {
-                       pr_warn("lockd: unlock failure in %s:%d\n",
-                               __FILE__, __LINE__);
-                       return 1;
-               }
-       }
+       if (file->f_file[O_RDONLY] &&
+           vfs_lock_file(file->f_file[O_RDONLY], F_SETLK, &lock, NULL))
+               goto out_err;
+       if (file->f_file[O_WRONLY] &&
+           vfs_lock_file(file->f_file[O_WRONLY], F_SETLK, &lock, NULL))
+               goto out_err;
        return 0;
+out_err:
+       pr_warn("lockd: unlock failure in %s:%d\n", __FILE__, __LINE__);
+       return 1;
 }
 
 /*
index b867a92..3f1829b 100644 (file)
@@ -4024,13 +4024,12 @@ int vfs_rmdir(struct user_namespace *mnt_userns, struct inode *dir,
        dentry->d_inode->i_flags |= S_DEAD;
        dont_mount(dentry);
        detach_mounts(dentry);
-       fsnotify_rmdir(dir, dentry);
 
 out:
        inode_unlock(dentry->d_inode);
        dput(dentry);
        if (!error)
-               d_delete(dentry);
+               d_delete_notify(dir, dentry);
        return error;
 }
 EXPORT_SYMBOL(vfs_rmdir);
@@ -4152,7 +4151,6 @@ int vfs_unlink(struct user_namespace *mnt_userns, struct inode *dir,
                        if (!error) {
                                dont_mount(dentry);
                                detach_mounts(dentry);
-                               fsnotify_unlink(dir, dentry);
                        }
                }
        }
@@ -4160,9 +4158,11 @@ out:
        inode_unlock(target);
 
        /* We don't d_delete() NFS sillyrenamed files--they still exist. */
-       if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) {
+       if (!error && dentry->d_flags & DCACHE_NFSFS_RENAMED) {
+               fsnotify_unlink(dir, dentry);
+       } else if (!error) {
                fsnotify_link_count(target);
-               d_delete(dentry);
+               d_delete_notify(dir, dentry);
        }
 
        return error;
index 40b994a..de6fae8 100644 (file)
@@ -469,6 +469,24 @@ void mnt_drop_write_file(struct file *file)
 }
 EXPORT_SYMBOL(mnt_drop_write_file);
 
+/**
+ * mnt_hold_writers - prevent write access to the given mount
+ * @mnt: mnt to prevent write access to
+ *
+ * Prevents write access to @mnt if there are no active writers for @mnt.
+ * This function needs to be called and return successfully before changing
+ * properties of @mnt that need to remain stable for callers with write access
+ * to @mnt.
+ *
+ * After this functions has been called successfully callers must pair it with
+ * a call to mnt_unhold_writers() in order to stop preventing write access to
+ * @mnt.
+ *
+ * Context: This function expects lock_mount_hash() to be held serializing
+ *          setting MNT_WRITE_HOLD.
+ * Return: On success 0 is returned.
+ *        On error, -EBUSY is returned.
+ */
 static inline int mnt_hold_writers(struct mount *mnt)
 {
        mnt->mnt.mnt_flags |= MNT_WRITE_HOLD;
@@ -500,6 +518,18 @@ static inline int mnt_hold_writers(struct mount *mnt)
        return 0;
 }
 
+/**
+ * mnt_unhold_writers - stop preventing write access to the given mount
+ * @mnt: mnt to stop preventing write access to
+ *
+ * Stop preventing write access to @mnt allowing callers to gain write access
+ * to @mnt again.
+ *
+ * This function can only be called after a successful call to
+ * mnt_hold_writers().
+ *
+ * Context: This function expects lock_mount_hash() to be held.
+ */
 static inline void mnt_unhold_writers(struct mount *mnt)
 {
        /*
index 6a20331..ccd4f24 100644 (file)
@@ -170,7 +170,7 @@ struct cb_devicenotifyitem {
 };
 
 struct cb_devicenotifyargs {
-       int                              ndevs;
+       uint32_t                         ndevs;
        struct cb_devicenotifyitem       *devs;
 };
 
index 09c5b1c..c343666 100644 (file)
@@ -358,7 +358,7 @@ __be32 nfs4_callback_devicenotify(void *argp, void *resp,
                                  struct cb_process_state *cps)
 {
        struct cb_devicenotifyargs *args = argp;
-       int i;
+       uint32_t i;
        __be32 res = 0;
        struct nfs_client *clp = cps->clp;
        struct nfs_server *server = NULL;
index a67c41e..f90de80 100644 (file)
@@ -258,11 +258,9 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp,
                                void *argp)
 {
        struct cb_devicenotifyargs *args = argp;
+       uint32_t tmp, n, i;
        __be32 *p;
        __be32 status = 0;
-       u32 tmp;
-       int n, i;
-       args->ndevs = 0;
 
        /* Num of device notifications */
        p = xdr_inline_decode(xdr, sizeof(uint32_t));
@@ -271,7 +269,7 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp,
                goto out;
        }
        n = ntohl(*p++);
-       if (n <= 0)
+       if (n == 0)
                goto out;
        if (n > ULONG_MAX / sizeof(*args->devs)) {
                status = htonl(NFS4ERR_BADXDR);
@@ -330,19 +328,21 @@ __be32 decode_devicenotify_args(struct svc_rqst *rqstp,
                        dev->cbd_immediate = 0;
                }
 
-               args->ndevs++;
-
                dprintk("%s: type %d layout 0x%x immediate %d\n",
                        __func__, dev->cbd_notify_type, dev->cbd_layout_type,
                        dev->cbd_immediate);
        }
+       args->ndevs = n;
+       dprintk("%s: ndevs %d\n", __func__, args->ndevs);
+       return 0;
+err:
+       kfree(args->devs);
 out:
+       args->devs = NULL;
+       args->ndevs = 0;
        dprintk("%s: status %d ndevs %d\n",
                __func__, ntohl(status), args->ndevs);
        return status;
-err:
-       kfree(args->devs);
-       goto out;
 }
 
 static __be32 decode_sessionid(struct xdr_stream *xdr,
index 8d8b85b..d1f3422 100644 (file)
@@ -177,6 +177,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
        INIT_LIST_HEAD(&clp->cl_superblocks);
        clp->cl_rpcclient = ERR_PTR(-EINVAL);
 
+       clp->cl_flags = cl_init->init_flags;
        clp->cl_proto = cl_init->proto;
        clp->cl_nconnect = cl_init->nconnect;
        clp->cl_max_connect = cl_init->max_connect ? cl_init->max_connect : 1;
@@ -423,7 +424,6 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init)
                        list_add_tail(&new->cl_share_link,
                                        &nn->nfs_client_list);
                        spin_unlock(&nn->nfs_client_lock);
-                       new->cl_flags = cl_init->init_flags;
                        return rpc_ops->init_client(new, cl_init);
                }
 
@@ -856,6 +856,13 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str
                        server->namelen = pathinfo.max_namelen;
        }
 
+       if (clp->rpc_ops->discover_trunking != NULL &&
+                       (server->caps & NFS_CAP_FS_LOCATIONS)) {
+               error = clp->rpc_ops->discover_trunking(server, mntfh);
+               if (error < 0)
+                       return error;
+       }
+
        return 0;
 }
 
index 3477936..75cb1cb 100644 (file)
@@ -80,6 +80,7 @@ static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir
                ctx->dir_cookie = 0;
                ctx->dup_cookie = 0;
                ctx->page_index = 0;
+               ctx->eof = false;
                spin_lock(&dir->i_lock);
                if (list_empty(&nfsi->open_files) &&
                    (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER))
@@ -168,6 +169,7 @@ struct nfs_readdir_descriptor {
        unsigned int    cache_entry_index;
        signed char duped;
        bool plus;
+       bool eob;
        bool eof;
 };
 
@@ -867,7 +869,8 @@ static int nfs_readdir_xdr_to_array(struct nfs_readdir_descriptor *desc,
 
                status = nfs_readdir_page_filler(desc, entry, pages, pglen,
                                                 arrays, narrays);
-       } while (!status && nfs_readdir_page_needs_filling(page));
+       } while (!status && nfs_readdir_page_needs_filling(page) &&
+               page_mapping(page));
 
        nfs_readdir_free_pages(pages, array_size);
 out:
@@ -988,7 +991,7 @@ static void nfs_do_filldir(struct nfs_readdir_descriptor *desc,
                ent = &array->array[i];
                if (!dir_emit(desc->ctx, ent->name, ent->name_len,
                    nfs_compat_user_ino64(ent->ino), ent->d_type)) {
-                       desc->eof = true;
+                       desc->eob = true;
                        break;
                }
                memcpy(desc->verf, verf, sizeof(desc->verf));
@@ -1004,7 +1007,7 @@ static void nfs_do_filldir(struct nfs_readdir_descriptor *desc,
                        desc->duped = 1;
        }
        if (array->page_is_eof)
-               desc->eof = true;
+               desc->eof = !desc->eob;
 
        kunmap(desc->page);
        dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %llu\n",
@@ -1041,12 +1044,13 @@ static int uncached_readdir(struct nfs_readdir_descriptor *desc)
                goto out;
 
        desc->page_index = 0;
+       desc->cache_entry_index = 0;
        desc->last_cookie = desc->dir_cookie;
        desc->duped = 0;
 
        status = nfs_readdir_xdr_to_array(desc, desc->verf, verf, arrays, sz);
 
-       for (i = 0; !desc->eof && i < sz && arrays[i]; i++) {
+       for (i = 0; !desc->eob && i < sz && arrays[i]; i++) {
                desc->page = arrays[i];
                nfs_do_filldir(desc, verf);
        }
@@ -1105,9 +1109,15 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
        desc->duped = dir_ctx->duped;
        page_index = dir_ctx->page_index;
        desc->attr_gencount = dir_ctx->attr_gencount;
+       desc->eof = dir_ctx->eof;
        memcpy(desc->verf, dir_ctx->verf, sizeof(desc->verf));
        spin_unlock(&file->f_lock);
 
+       if (desc->eof) {
+               res = 0;
+               goto out_free;
+       }
+
        if (test_and_clear_bit(NFS_INO_FORCE_READDIR, &nfsi->flags) &&
            list_is_singular(&nfsi->open_files))
                invalidate_mapping_pages(inode->i_mapping, page_index + 1, -1);
@@ -1141,7 +1151,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
 
                nfs_do_filldir(desc, nfsi->cookieverf);
                nfs_readdir_page_unlock_and_put_cached(desc);
-       } while (!desc->eof);
+       } while (!desc->eob && !desc->eof);
 
        spin_lock(&file->f_lock);
        dir_ctx->dir_cookie = desc->dir_cookie;
@@ -1149,9 +1159,10 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
        dir_ctx->duped = desc->duped;
        dir_ctx->attr_gencount = desc->attr_gencount;
        dir_ctx->page_index = desc->page_index;
+       dir_ctx->eof = desc->eof;
        memcpy(dir_ctx->verf, desc->verf, sizeof(dir_ctx->verf));
        spin_unlock(&file->f_lock);
-
+out_free:
        kfree(desc);
 
 out:
@@ -1193,6 +1204,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence)
                if (offset == 0)
                        memset(dir_ctx->verf, 0, sizeof(dir_ctx->verf));
                dir_ctx->duped = 0;
+               dir_ctx->eof = false;
        }
        spin_unlock(&filp->f_lock);
        return offset;
@@ -1325,6 +1337,14 @@ void nfs_clear_verifier_delegated(struct inode *inode)
 EXPORT_SYMBOL_GPL(nfs_clear_verifier_delegated);
 #endif /* IS_ENABLED(CONFIG_NFS_V4) */
 
+static int nfs_dentry_verify_change(struct inode *dir, struct dentry *dentry)
+{
+       if (nfs_server_capable(dir, NFS_CAP_CASE_INSENSITIVE) &&
+           d_really_is_negative(dentry))
+               return dentry->d_time == inode_peek_iversion_raw(dir);
+       return nfs_verify_change_attribute(dir, dentry->d_time);
+}
+
 /*
  * A check for whether or not the parent directory has changed.
  * In the case it has, we assume that the dentries are untrustworthy
@@ -1338,7 +1358,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry,
                return 1;
        if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONE)
                return 0;
-       if (!nfs_verify_change_attribute(dir, dentry->d_time))
+       if (!nfs_dentry_verify_change(dir, dentry))
                return 0;
        /* Revalidate nfsi->cache_change_attribute before we declare a match */
        if (nfs_mapping_need_revalidate_inode(dir)) {
@@ -1347,7 +1367,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry,
                if (__nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)
                        return 0;
        }
-       if (!nfs_verify_change_attribute(dir, dentry->d_time))
+       if (!nfs_dentry_verify_change(dir, dentry))
                return 0;
        return 1;
 }
@@ -1437,6 +1457,9 @@ int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
                return 0;
        if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG)
                return 1;
+       /* Case insensitive server? Revalidate negative dentries */
+       if (nfs_server_capable(dir, NFS_CAP_CASE_INSENSITIVE))
+               return 1;
        return !nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU);
 }
 
@@ -1537,7 +1560,7 @@ out:
         * If the lookup failed despite the dentry change attribute being
         * a match, then we should revalidate the directory cache.
         */
-       if (!ret && nfs_verify_change_attribute(dir, dentry->d_time))
+       if (!ret && nfs_dentry_verify_change(dir, dentry))
                nfs_mark_dir_for_revalidate(dir);
        return nfs_lookup_revalidate_done(dir, dentry, inode, ret);
 }
@@ -1776,8 +1799,11 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
        dir_verifier = nfs_save_change_attribute(dir);
        trace_nfs_lookup_enter(dir, dentry, flags);
        error = NFS_PROTO(dir)->lookup(dir, dentry, fhandle, fattr);
-       if (error == -ENOENT)
+       if (error == -ENOENT) {
+               if (nfs_server_capable(dir, NFS_CAP_CASE_INSENSITIVE))
+                       dir_verifier = inode_peek_iversion_raw(dir);
                goto no_entry;
+       }
        if (error < 0) {
                res = ERR_PTR(error);
                goto out;
@@ -1806,6 +1832,14 @@ out:
 }
 EXPORT_SYMBOL_GPL(nfs_lookup);
 
+void nfs_d_prune_case_insensitive_aliases(struct inode *inode)
+{
+       /* Case insensitive server? Revalidate dentries */
+       if (inode && nfs_server_capable(inode, NFS_CAP_CASE_INSENSITIVE))
+               d_prune_aliases(inode);
+}
+EXPORT_SYMBOL_GPL(nfs_d_prune_case_insensitive_aliases);
+
 #if IS_ENABLED(CONFIG_NFS_V4)
 static int nfs4_lookup_revalidate(struct dentry *, unsigned int);
 
@@ -1867,6 +1901,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
        struct iattr attr = { .ia_valid = ATTR_OPEN };
        struct inode *inode;
        unsigned int lookup_flags = 0;
+       unsigned long dir_verifier;
        bool switched = false;
        int created = 0;
        int err;
@@ -1940,7 +1975,11 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
                switch (err) {
                case -ENOENT:
                        d_splice_alias(NULL, dentry);
-                       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+                       if (nfs_server_capable(dir, NFS_CAP_CASE_INSENSITIVE))
+                               dir_verifier = inode_peek_iversion_raw(dir);
+                       else
+                               dir_verifier = nfs_save_change_attribute(dir);
+                       nfs_set_verifier(dentry, dir_verifier);
                        break;
                case -EISDIR:
                case -ENOTDIR:
@@ -1968,6 +2007,24 @@ out:
 
 no_open:
        res = nfs_lookup(dir, dentry, lookup_flags);
+       if (!res) {
+               inode = d_inode(dentry);
+               if ((lookup_flags & LOOKUP_DIRECTORY) && inode &&
+                   !(S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)))
+                       res = ERR_PTR(-ENOTDIR);
+               else if (inode && S_ISREG(inode->i_mode))
+                       res = ERR_PTR(-EOPENSTALE);
+       } else if (!IS_ERR(res)) {
+               inode = d_inode(res);
+               if ((lookup_flags & LOOKUP_DIRECTORY) && inode &&
+                   !(S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) {
+                       dput(res);
+                       res = ERR_PTR(-ENOTDIR);
+               } else if (inode && S_ISREG(inode->i_mode)) {
+                       dput(res);
+                       res = ERR_PTR(-EOPENSTALE);
+               }
+       }
        if (switched) {
                d_lookup_done(dentry);
                if (!res)
@@ -2186,8 +2243,10 @@ static void nfs_dentry_remove_handle_error(struct inode *dir,
        switch (error) {
        case -ENOENT:
                d_delete(dentry);
-               fallthrough;
+               nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+               break;
        case 0:
+               nfs_d_prune_case_insensitive_aliases(d_inode(dentry));
                nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        }
 }
@@ -2380,6 +2439,8 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
 
        trace_nfs_link_enter(inode, dir, dentry);
        d_drop(dentry);
+       if (S_ISREG(inode->i_mode))
+               nfs_sync_inode(inode);
        error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
        if (error == 0) {
                nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
@@ -2469,6 +2530,8 @@ int nfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
                }
        }
 
+       if (S_ISREG(old_inode->i_mode))
+               nfs_sync_inode(old_inode);
        task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, NULL);
        if (IS_ERR(task)) {
                error = PTR_ERR(task);
@@ -2529,7 +2592,7 @@ MODULE_PARM_DESC(nfs_access_max_cachesize, "NFS access maximum total cache lengt
 
 static void nfs_access_free_entry(struct nfs_access_entry *entry)
 {
-       put_cred(entry->cred);
+       put_group_info(entry->group_info);
        kfree_rcu(entry, rcu_head);
        smp_mb__before_atomic();
        atomic_long_dec(&nfs_access_nr_entries);
@@ -2655,6 +2718,43 @@ void nfs_access_zap_cache(struct inode *inode)
 }
 EXPORT_SYMBOL_GPL(nfs_access_zap_cache);
 
+static int access_cmp(const struct cred *a, const struct nfs_access_entry *b)
+{
+       struct group_info *ga, *gb;
+       int g;
+
+       if (uid_lt(a->fsuid, b->fsuid))
+               return -1;
+       if (uid_gt(a->fsuid, b->fsuid))
+               return 1;
+
+       if (gid_lt(a->fsgid, b->fsgid))
+               return -1;
+       if (gid_gt(a->fsgid, b->fsgid))
+               return 1;
+
+       ga = a->group_info;
+       gb = b->group_info;
+       if (ga == gb)
+               return 0;
+       if (ga == NULL)
+               return -1;
+       if (gb == NULL)
+               return 1;
+       if (ga->ngroups < gb->ngroups)
+               return -1;
+       if (ga->ngroups > gb->ngroups)
+               return 1;
+
+       for (g = 0; g < ga->ngroups; g++) {
+               if (gid_lt(ga->gid[g], gb->gid[g]))
+                       return -1;
+               if (gid_gt(ga->gid[g], gb->gid[g]))
+                       return 1;
+       }
+       return 0;
+}
+
 static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, const struct cred *cred)
 {
        struct rb_node *n = NFS_I(inode)->access_cache.rb_node;
@@ -2662,7 +2762,7 @@ static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, co
        while (n != NULL) {
                struct nfs_access_entry *entry =
                        rb_entry(n, struct nfs_access_entry, rb_node);
-               int cmp = cred_fscmp(cred, entry->cred);
+               int cmp = access_cmp(cred, entry);
 
                if (cmp < 0)
                        n = n->rb_left;
@@ -2674,7 +2774,7 @@ static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, co
        return NULL;
 }
 
-static int nfs_access_get_cached_locked(struct inode *inode, const struct cred *cred, struct nfs_access_entry *res, bool may_block)
+static int nfs_access_get_cached_locked(struct inode *inode, const struct cred *cred, u32 *mask, bool may_block)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        struct nfs_access_entry *cache;
@@ -2704,8 +2804,7 @@ static int nfs_access_get_cached_locked(struct inode *inode, const struct cred *
                spin_lock(&inode->i_lock);
                retry = false;
        }
-       res->cred = cache->cred;
-       res->mask = cache->mask;
+       *mask = cache->mask;
        list_move_tail(&cache->lru, &nfsi->access_cache_entry_lru);
        err = 0;
 out:
@@ -2717,7 +2816,7 @@ out_zap:
        return -ENOENT;
 }
 
-static int nfs_access_get_cached_rcu(struct inode *inode, const struct cred *cred, struct nfs_access_entry *res)
+static int nfs_access_get_cached_rcu(struct inode *inode, const struct cred *cred, u32 *mask)
 {
        /* Only check the most recently returned cache entry,
         * but do it without locking.
@@ -2733,35 +2832,36 @@ static int nfs_access_get_cached_rcu(struct inode *inode, const struct cred *cre
        lh = rcu_dereference(list_tail_rcu(&nfsi->access_cache_entry_lru));
        cache = list_entry(lh, struct nfs_access_entry, lru);
        if (lh == &nfsi->access_cache_entry_lru ||
-           cred_fscmp(cred, cache->cred) != 0)
+           access_cmp(cred, cache) != 0)
                cache = NULL;
        if (cache == NULL)
                goto out;
        if (nfs_check_cache_invalid(inode, NFS_INO_INVALID_ACCESS))
                goto out;
-       res->cred = cache->cred;
-       res->mask = cache->mask;
+       *mask = cache->mask;
        err = 0;
 out:
        rcu_read_unlock();
        return err;
 }
 
-int nfs_access_get_cached(struct inode *inode, const struct cred *cred, struct
-nfs_access_entry *res, bool may_block)
+int nfs_access_get_cached(struct inode *inode, const struct cred *cred,
+                         u32 *mask, bool may_block)
 {
        int status;
 
-       status = nfs_access_get_cached_rcu(inode, cred, res);
+       status = nfs_access_get_cached_rcu(inode, cred, mask);
        if (status != 0)
-               status = nfs_access_get_cached_locked(inode, cred, res,
+               status = nfs_access_get_cached_locked(inode, cred, mask,
                    may_block);
 
        return status;
 }
 EXPORT_SYMBOL_GPL(nfs_access_get_cached);
 
-static void nfs_access_add_rbtree(struct inode *inode, struct nfs_access_entry *set)
+static void nfs_access_add_rbtree(struct inode *inode,
+                                 struct nfs_access_entry *set,
+                                 const struct cred *cred)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
        struct rb_root *root_node = &nfsi->access_cache;
@@ -2774,7 +2874,7 @@ static void nfs_access_add_rbtree(struct inode *inode, struct nfs_access_entry *
        while (*p != NULL) {
                parent = *p;
                entry = rb_entry(parent, struct nfs_access_entry, rb_node);
-               cmp = cred_fscmp(set->cred, entry->cred);
+               cmp = access_cmp(cred, entry);
 
                if (cmp < 0)
                        p = &parent->rb_left;
@@ -2796,13 +2896,16 @@ found:
        nfs_access_free_entry(entry);
 }
 
-void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
+void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set,
+                         const struct cred *cred)
 {
        struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL);
        if (cache == NULL)
                return;
        RB_CLEAR_NODE(&cache->rb_node);
-       cache->cred = get_cred(set->cred);
+       cache->fsuid = cred->fsuid;
+       cache->fsgid = cred->fsgid;
+       cache->group_info = get_group_info(cred->group_info);
        cache->mask = set->mask;
 
        /* The above field assignments must be visible
@@ -2810,7 +2913,7 @@ void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
         * use rcu_assign_pointer, so just force the memory barrier.
         */
        smp_wmb();
-       nfs_access_add_rbtree(inode, cache);
+       nfs_access_add_rbtree(inode, cache, cred);
 
        /* Update accounting */
        smp_mb__before_atomic();
@@ -2875,7 +2978,7 @@ static int nfs_do_access(struct inode *inode, const struct cred *cred, int mask)
 
        trace_nfs_access_enter(inode);
 
-       status = nfs_access_get_cached(inode, cred, &cache, may_block);
+       status = nfs_access_get_cached(inode, cred, &cache.mask, may_block);
        if (status == 0)
                goto out_cached;
 
@@ -2895,8 +2998,7 @@ static int nfs_do_access(struct inode *inode, const struct cred *cred, int mask)
                cache.mask |= NFS_ACCESS_DELETE | NFS_ACCESS_LOOKUP;
        else
                cache.mask |= NFS_ACCESS_EXECUTE;
-       cache.cred = cred;
-       status = NFS_PROTO(inode)->access(inode, &cache);
+       status = NFS_PROTO(inode)->access(inode, &cache, cred);
        if (status != 0) {
                if (status == -ESTALE) {
                        if (!S_ISDIR(inode->i_mode))
@@ -2906,7 +3008,7 @@ static int nfs_do_access(struct inode *inode, const struct cred *cred, int mask)
                }
                goto out;
        }
-       nfs_access_add_cache(inode, &cache);
+       nfs_access_add_cache(inode, &cache, cred);
 out_cached:
        cache_mask = nfs_access_calc_mask(cache.mask, inode->i_mode);
        if ((mask & ~cache_mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) != 0)
index 79323b5..aed0748 100644 (file)
@@ -51,7 +51,7 @@ struct nfs4_file_layout_dsaddr {
        u32                             stripe_count;
        u8                              *stripe_indices;
        u32                             ds_num;
-       struct nfs4_pnfs_ds             *ds_list[1];
+       struct nfs4_pnfs_ds             *ds_list[];
 };
 
 struct nfs4_filelayout_segment {
index 86c3f7e..acf4b88 100644 (file)
@@ -136,9 +136,7 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
                goto out_err_free_stripe_indices;
        }
 
-       dsaddr = kzalloc(sizeof(*dsaddr) +
-                       (sizeof(struct nfs4_pnfs_ds *) * (num - 1)),
-                       gfp_flags);
+       dsaddr = kzalloc(struct_size(dsaddr, ds_list, num), gfp_flags);
        if (!dsaddr)
                goto out_err_free_stripe_indices;
 
index a918c3a..d96baa4 100644 (file)
@@ -853,12 +853,9 @@ int nfs_getattr(struct user_namespace *mnt_userns, const struct path *path,
        }
 
        /* Flush out writes to the server in order to update c/mtime.  */
-       if ((request_mask & (STATX_CTIME|STATX_MTIME)) &&
-                       S_ISREG(inode->i_mode)) {
-               err = filemap_write_and_wait(inode->i_mapping);
-               if (err)
-                       goto out;
-       }
+       if ((request_mask & (STATX_CTIME | STATX_MTIME)) &&
+           S_ISREG(inode->i_mode))
+               filemap_write_and_wait(inode->i_mapping);
 
        /*
         * We may force a getattr if the user cares about atime.
index 12f6acb..2de7c56 100644 (file)
@@ -373,6 +373,7 @@ extern unsigned long nfs_access_cache_count(struct shrinker *shrink,
 extern unsigned long nfs_access_cache_scan(struct shrinker *shrink,
                                           struct shrink_control *sc);
 struct dentry *nfs_lookup(struct inode *, struct dentry *, unsigned int);
+void nfs_d_prune_case_insensitive_aliases(struct inode *inode);
 int nfs_create(struct user_namespace *, struct inode *, struct dentry *,
               umode_t, bool);
 int nfs_mkdir(struct user_namespace *, struct inode *, struct dentry *,
index 7100514..1597eef 100644 (file)
@@ -220,7 +220,8 @@ static int nfs3_proc_lookupp(struct inode *inode, struct nfs_fh *fhandle,
                                  task_flags);
 }
 
-static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry)
+static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry,
+                           const struct cred *cred)
 {
        struct nfs3_accessargs  arg = {
                .fh             = NFS_FH(inode),
@@ -231,7 +232,7 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry)
                .rpc_proc       = &nfs3_procedures[NFS3PROC_ACCESS],
                .rpc_argp       = &arg,
                .rpc_resp       = &res,
-               .rpc_cred       = entry->cred,
+               .rpc_cred       = cred,
        };
        int status = -ENOMEM;
 
index 8b21ff1..3212944 100644 (file)
@@ -46,7 +46,7 @@ static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
 {
        struct inode *inode = file_inode(filep);
        struct nfs_server *server = NFS_SERVER(inode);
-       u32 bitmask[3];
+       u32 bitmask[NFS_BITMASK_SZ];
        struct nfs42_falloc_args args = {
                .falloc_fh      = NFS_FH(inode),
                .falloc_offset  = offset,
@@ -69,9 +69,8 @@ static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
                return status;
        }
 
-       memcpy(bitmask, server->cache_consistency_bitmask, sizeof(bitmask));
-       if (server->attr_bitmask[1] & FATTR4_WORD1_SPACE_USED)
-               bitmask[1] |= FATTR4_WORD1_SPACE_USED;
+       nfs4_bitmask_set(bitmask, server->cache_consistency_bitmask, inode,
+                        NFS_INO_INVALID_BLOCKS);
 
        res.falloc_fattr = nfs_alloc_fattr();
        if (!res.falloc_fattr)
@@ -1044,13 +1043,14 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
        struct inode *src_inode = file_inode(src_f);
        struct inode *dst_inode = file_inode(dst_f);
        struct nfs_server *server = NFS_SERVER(dst_inode);
+       __u32 dst_bitmask[NFS_BITMASK_SZ];
        struct nfs42_clone_args args = {
                .src_fh = NFS_FH(src_inode),
                .dst_fh = NFS_FH(dst_inode),
                .src_offset = src_offset,
                .dst_offset = dst_offset,
                .count = count,
-               .dst_bitmask = server->cache_consistency_bitmask,
+               .dst_bitmask = dst_bitmask,
        };
        struct nfs42_clone_res res = {
                .server = server,
@@ -1079,6 +1079,9 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
        if (!res.dst_fattr)
                return -ENOMEM;
 
+       nfs4_bitmask_set(dst_bitmask, server->cache_consistency_bitmask,
+                        dst_inode, NFS_INO_INVALID_BLOCKS);
+
        status = nfs4_call_sync(server->client, server, msg,
                                &args.seq_args, &res.seq_res, 0);
        trace_nfs4_clone(src_inode, dst_inode, &args, status);
index ed5eaca..84f39b6 100644 (file)
@@ -260,8 +260,8 @@ struct nfs4_state_maintenance_ops {
 };
 
 struct nfs4_mig_recovery_ops {
-       int (*get_locations)(struct inode *, struct nfs4_fs_locations *,
-               struct page *, const struct cred *);
+       int (*get_locations)(struct nfs_server *, struct nfs_fh *,
+               struct nfs4_fs_locations *, struct page *, const struct cred *);
        int (*fsid_present)(struct inode *, const struct cred *);
 };
 
@@ -280,7 +280,8 @@ struct rpc_clnt *nfs4_negotiate_security(struct rpc_clnt *, struct inode *,
 int nfs4_submount(struct fs_context *, struct nfs_server *);
 int nfs4_replace_transport(struct nfs_server *server,
                                const struct nfs4_fs_locations *locations);
-
+size_t nfs_parse_server_name(char *string, size_t len, struct sockaddr *sa,
+                            size_t salen, struct net *net, int port);
 /* nfs4proc.c */
 extern int nfs4_handle_exception(struct nfs_server *, int, struct nfs4_exception *);
 extern int nfs4_async_handle_error(struct rpc_task *task,
@@ -302,8 +303,9 @@ extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait);
 extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
 extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struct qstr *,
                                  struct nfs4_fs_locations *, struct page *);
-extern int nfs4_proc_get_locations(struct inode *, struct nfs4_fs_locations *,
-               struct page *page, const struct cred *);
+extern int nfs4_proc_get_locations(struct nfs_server *, struct nfs_fh *,
+                                  struct nfs4_fs_locations *,
+                                  struct page *page, const struct cred *);
 extern int nfs4_proc_fsid_present(struct inode *, const struct cred *);
 extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *,
                                                    struct dentry *,
@@ -315,6 +317,8 @@ extern int nfs4_set_rw_stateid(nfs4_stateid *stateid,
                const struct nfs_open_context *ctx,
                const struct nfs_lock_context *l_ctx,
                fmode_t fmode);
+extern void nfs4_bitmask_set(__u32 bitmask[], const __u32 src[],
+                            struct inode *inode, unsigned long cache_validity);
 extern int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
                             struct nfs_fattr *fattr, struct inode *inode);
 extern int update_open_stateid(struct nfs4_state *state,
index d8b5a25..47a6cf8 100644 (file)
@@ -1343,8 +1343,11 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname,
        }
        nfs_put_client(clp);
 
-       if (server->nfs_client->cl_hostname == NULL)
+       if (server->nfs_client->cl_hostname == NULL) {
                server->nfs_client->cl_hostname = kstrdup(hostname, GFP_KERNEL);
+               if (server->nfs_client->cl_hostname == NULL)
+                       return -ENOMEM;
+       }
        nfs_server_insert_lists(server);
 
        return nfs_probe_server(server, NFS_FH(d_inode(server->super->s_root)));
index 8733423..3680c8d 100644 (file)
@@ -164,16 +164,21 @@ static int nfs4_validate_fspath(struct dentry *dentry,
        return 0;
 }
 
-static size_t nfs_parse_server_name(char *string, size_t len,
-               struct sockaddr *sa, size_t salen, struct net *net)
+size_t nfs_parse_server_name(char *string, size_t len, struct sockaddr *sa,
+                            size_t salen, struct net *net, int port)
 {
        ssize_t ret;
 
        ret = rpc_pton(net, string, len, sa, salen);
        if (ret == 0) {
-               ret = nfs_dns_resolve_name(net, string, len, sa, salen);
-               if (ret < 0)
-                       ret = 0;
+               ret = rpc_uaddr2sockaddr(net, string, len, sa, salen);
+               if (ret == 0) {
+                       ret = nfs_dns_resolve_name(net, string, len, sa, salen);
+                       if (ret < 0)
+                               ret = 0;
+               }
+       } else if (port) {
+               rpc_set_port(sa, port);
        }
        return ret;
 }
@@ -328,7 +333,7 @@ static int try_location(struct fs_context *fc,
                        nfs_parse_server_name(buf->data, buf->len,
                                              &ctx->nfs_server.address,
                                              sizeof(ctx->nfs_server._address),
-                                             fc->net_ns);
+                                             fc->net_ns, 0);
                if (ctx->nfs_server.addrlen == 0)
                        continue;
 
@@ -496,7 +501,7 @@ static int nfs4_try_replacing_one_location(struct nfs_server *server,
                        continue;
 
                salen = nfs_parse_server_name(buf->data, buf->len,
-                                               sap, addr_bufsize, net);
+                                               sap, addr_bufsize, net, 0);
                if (salen == 0)
                        continue;
                rpc_set_port(sap, NFS_PORT);
index ee3bc79..0e0db6c 100644 (file)
@@ -108,10 +108,6 @@ static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *,
 static int nfs41_free_stateid(struct nfs_server *, const nfs4_stateid *,
                const struct cred *, bool);
 #endif
-static void nfs4_bitmask_set(__u32 bitmask[NFS4_BITMASK_SZ],
-                            const __u32 *src, struct inode *inode,
-                            struct nfs_server *server,
-                            struct nfs4_label *label);
 
 #ifdef CONFIG_NFS_V4_SECURITY_LABEL
 static inline struct nfs4_label *
@@ -1233,8 +1229,7 @@ nfs4_update_changeattr_locked(struct inode *inode,
                                NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL |
                                NFS_INO_INVALID_SIZE | NFS_INO_INVALID_OTHER |
                                NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_NLINK |
-                               NFS_INO_INVALID_MODE | NFS_INO_INVALID_XATTR |
-                               NFS_INO_REVAL_PAGECACHE;
+                               NFS_INO_INVALID_MODE | NFS_INO_INVALID_XATTR;
                nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
        }
        nfsi->attrtimeo_timestamp = jiffies;
@@ -2653,9 +2648,8 @@ static int nfs4_opendata_access(const struct cred *cred,
        } else if ((fmode & FMODE_READ) && !opendata->file_created)
                mask = NFS4_ACCESS_READ;
 
-       cache.cred = cred;
        nfs_access_set_mask(&cache, opendata->o_res.access_result);
-       nfs_access_add_cache(state->inode, &cache);
+       nfs_access_add_cache(state->inode, &cache, cred);
 
        flags = NFS4_ACCESS_READ | NFS4_ACCESS_EXECUTE | NFS4_ACCESS_LOOKUP;
        if ((mask & ~cache.mask & flags) == 0)
@@ -3670,7 +3664,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
                if (!nfs4_have_delegation(inode, FMODE_READ)) {
                        nfs4_bitmask_set(calldata->arg.bitmask_store,
                                         server->cache_consistency_bitmask,
-                                        inode, server, NULL);
+                                        inode, 0);
                        calldata->arg.bitmask = calldata->arg.bitmask_store;
                } else
                        calldata->arg.bitmask = NULL;
@@ -3841,7 +3835,9 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
                     FATTR4_WORD0_FH_EXPIRE_TYPE |
                     FATTR4_WORD0_LINK_SUPPORT |
                     FATTR4_WORD0_SYMLINK_SUPPORT |
-                    FATTR4_WORD0_ACLSUPPORT;
+                    FATTR4_WORD0_ACLSUPPORT |
+                    FATTR4_WORD0_CASE_INSENSITIVE |
+                    FATTR4_WORD0_CASE_PRESERVING;
        if (minorversion)
                bitmask[2] = FATTR4_WORD2_SUPPATTR_EXCLCREAT;
 
@@ -3870,10 +3866,16 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
                        server->caps |= NFS_CAP_HARDLINKS;
                if (res.has_symlinks != 0)
                        server->caps |= NFS_CAP_SYMLINKS;
+               if (res.case_insensitive)
+                       server->caps |= NFS_CAP_CASE_INSENSITIVE;
+               if (res.case_preserving)
+                       server->caps |= NFS_CAP_CASE_PRESERVING;
 #ifdef CONFIG_NFS_V4_SECURITY_LABEL
                if (res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL)
                        server->caps |= NFS_CAP_SECURITY_LABEL;
 #endif
+               if (res.attr_bitmask[0] & FATTR4_WORD0_FS_LOCATIONS)
+                       server->caps |= NFS_CAP_FS_LOCATIONS;
                if (!(res.attr_bitmask[0] & FATTR4_WORD0_FILEID))
                        server->fattr_valid &= ~NFS_ATTR_FATTR_FILEID;
                if (!(res.attr_bitmask[1] & FATTR4_WORD1_MODE))
@@ -3932,6 +3934,114 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
        return err;
 }
 
+static void test_fs_location_for_trunking(struct nfs4_fs_location *location,
+                                         struct nfs_client *clp,
+                                         struct nfs_server *server)
+{
+       int i;
+
+       for (i = 0; i < location->nservers; i++) {
+               struct nfs4_string *srv_loc = &location->servers[i];
+               struct sockaddr addr;
+               size_t addrlen;
+               struct xprt_create xprt_args = {
+                       .ident = 0,
+                       .net = clp->cl_net,
+               };
+               struct nfs4_add_xprt_data xprtdata = {
+                       .clp = clp,
+               };
+               struct rpc_add_xprt_test rpcdata = {
+                       .add_xprt_test = clp->cl_mvops->session_trunk,
+                       .data = &xprtdata,
+               };
+               char *servername = NULL;
+
+               if (!srv_loc->len)
+                       continue;
+
+               addrlen = nfs_parse_server_name(srv_loc->data, srv_loc->len,
+                                               &addr, sizeof(addr),
+                                               clp->cl_net, server->port);
+               if (!addrlen)
+                       return;
+               xprt_args.dstaddr = &addr;
+               xprt_args.addrlen = addrlen;
+               servername = kmalloc(srv_loc->len + 1, GFP_KERNEL);
+               if (!servername)
+                       return;
+               memcpy(servername, srv_loc->data, srv_loc->len);
+               servername[srv_loc->len] = '\0';
+               xprt_args.servername = servername;
+
+               xprtdata.cred = nfs4_get_clid_cred(clp);
+               rpc_clnt_add_xprt(clp->cl_rpcclient, &xprt_args,
+                                 rpc_clnt_setup_test_and_add_xprt,
+                                 &rpcdata);
+               if (xprtdata.cred)
+                       put_cred(xprtdata.cred);
+               kfree(servername);
+       }
+}
+
+static int _nfs4_discover_trunking(struct nfs_server *server,
+                                  struct nfs_fh *fhandle)
+{
+       struct nfs4_fs_locations *locations = NULL;
+       struct page *page;
+       const struct cred *cred;
+       struct nfs_client *clp = server->nfs_client;
+       const struct nfs4_state_maintenance_ops *ops =
+               clp->cl_mvops->state_renewal_ops;
+       int status = -ENOMEM, i;
+
+       cred = ops->get_state_renewal_cred(clp);
+       if (cred == NULL) {
+               cred = nfs4_get_clid_cred(clp);
+               if (cred == NULL)
+                       return -ENOKEY;
+       }
+
+       page = alloc_page(GFP_KERNEL);
+       locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
+       if (page == NULL || locations == NULL)
+               goto out;
+
+       status = nfs4_proc_get_locations(server, fhandle, locations, page,
+                                        cred);
+       if (status)
+               goto out;
+
+       for (i = 0; i < locations->nlocations; i++)
+               test_fs_location_for_trunking(&locations->locations[i], clp,
+                                             server);
+out:
+       if (page)
+               __free_page(page);
+       kfree(locations);
+       return status;
+}
+
+static int nfs4_discover_trunking(struct nfs_server *server,
+                                 struct nfs_fh *fhandle)
+{
+       struct nfs4_exception exception = {
+               .interruptible = true,
+       };
+       struct nfs_client *clp = server->nfs_client;
+       int err = 0;
+
+       if (!nfs4_has_session(clp))
+               goto out;
+       do {
+               err = nfs4_handle_exception(server,
+                               _nfs4_discover_trunking(server, fhandle),
+                               &exception);
+       } while (exception.retry);
+out:
+       return err;
+}
+
 static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
                struct nfs_fsinfo *info)
 {
@@ -4441,7 +4551,8 @@ static int nfs4_proc_lookupp(struct inode *inode, struct nfs_fh *fhandle,
        return err;
 }
 
-static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
+static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry,
+                            const struct cred *cred)
 {
        struct nfs_server *server = NFS_SERVER(inode);
        struct nfs4_accessargs args = {
@@ -4455,7 +4566,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
                .rpc_argp = &args,
                .rpc_resp = &res,
-               .rpc_cred = entry->cred,
+               .rpc_cred = cred,
        };
        int status = 0;
 
@@ -4475,14 +4586,15 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
        return status;
 }
 
-static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
+static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry,
+                           const struct cred *cred)
 {
        struct nfs4_exception exception = {
                .interruptible = true,
        };
        int err;
        do {
-               err = _nfs4_proc_access(inode, entry);
+               err = _nfs4_proc_access(inode, entry, cred);
                trace_nfs4_access(inode, err);
                err = nfs4_handle_exception(NFS_SERVER(inode), err,
                                &exception);
@@ -4663,8 +4775,10 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg,
 
        nfs_fattr_init(res->dir_attr);
 
-       if (inode)
+       if (inode) {
                nfs4_inode_return_delegation(inode);
+               nfs_d_prune_case_insensitive_aliases(inode);
+       }
 }
 
 static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
@@ -4730,6 +4844,7 @@ static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
                return 0;
 
        if (task->tk_status == 0) {
+               nfs_d_prune_case_insensitive_aliases(d_inode(data->old_dentry));
                if (new_dir != old_dir) {
                        /* Note: If we moved a directory, nlink will change */
                        nfs4_update_changeattr(old_dir, &res->old_cinfo,
@@ -5422,14 +5537,14 @@ bool nfs4_write_need_cache_consistency_data(struct nfs_pgio_header *hdr)
        return nfs4_have_delegation(hdr->inode, FMODE_READ) == 0;
 }
 
-static void nfs4_bitmask_set(__u32 bitmask[NFS4_BITMASK_SZ], const __u32 *src,
-                            struct inode *inode, struct nfs_server *server,
-                            struct nfs4_label *label)
+void nfs4_bitmask_set(__u32 bitmask[], const __u32 src[],
+                     struct inode *inode, unsigned long cache_validity)
 {
-       unsigned long cache_validity = READ_ONCE(NFS_I(inode)->cache_validity);
+       struct nfs_server *server = NFS_SERVER(inode);
        unsigned int i;
 
        memcpy(bitmask, src, sizeof(*bitmask) * NFS4_BITMASK_SZ);
+       cache_validity |= READ_ONCE(NFS_I(inode)->cache_validity);
 
        if (cache_validity & NFS_INO_INVALID_CHANGE)
                bitmask[0] |= FATTR4_WORD0_CHANGE;
@@ -5441,8 +5556,6 @@ static void nfs4_bitmask_set(__u32 bitmask[NFS4_BITMASK_SZ], const __u32 *src,
                bitmask[1] |= FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP;
        if (cache_validity & NFS_INO_INVALID_NLINK)
                bitmask[1] |= FATTR4_WORD1_NUMLINKS;
-       if (label && label->len && cache_validity & NFS_INO_INVALID_LABEL)
-               bitmask[2] |= FATTR4_WORD2_SECURITY_LABEL;
        if (cache_validity & NFS_INO_INVALID_CTIME)
                bitmask[1] |= FATTR4_WORD1_TIME_METADATA;
        if (cache_validity & NFS_INO_INVALID_MTIME)
@@ -5469,7 +5582,7 @@ static void nfs4_proc_write_setup(struct nfs_pgio_header *hdr,
        } else {
                nfs4_bitmask_set(hdr->args.bitmask_store,
                                 server->cache_consistency_bitmask,
-                                hdr->inode, server, NULL);
+                                hdr->inode, NFS_INO_INVALID_BLOCKS);
                hdr->args.bitmask = hdr->args.bitmask_store;
        }
 
@@ -6507,8 +6620,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred,
        data->args.fhandle = &data->fh;
        data->args.stateid = &data->stateid;
        nfs4_bitmask_set(data->args.bitmask_store,
-                        server->cache_consistency_bitmask, inode, server,
-                        NULL);
+                        server->cache_consistency_bitmask, inode, 0);
        data->args.bitmask = data->args.bitmask_store;
        nfs_copy_fh(&data->fh, NFS_FH(inode));
        nfs4_stateid_copy(&data->stateid, stateid);
@@ -7611,7 +7723,7 @@ static int nfs4_xattr_set_nfs4_user(const struct xattr_handler *handler,
                                    const char *key, const void *buf,
                                    size_t buflen, int flags)
 {
-       struct nfs_access_entry cache;
+       u32 mask;
        int ret;
 
        if (!nfs_server_capable(inode, NFS_CAP_XATTR))
@@ -7626,8 +7738,8 @@ static int nfs4_xattr_set_nfs4_user(const struct xattr_handler *handler,
         * do a cached access check for the XA* flags to possibly avoid
         * doing an RPC and getting EACCES back.
         */
-       if (!nfs_access_get_cached(inode, current_cred(), &cache, true)) {
-               if (!(cache.mask & NFS_ACCESS_XAWRITE))
+       if (!nfs_access_get_cached(inode, current_cred(), &mask, true)) {
+               if (!(mask & NFS_ACCESS_XAWRITE))
                        return -EACCES;
        }
 
@@ -7648,14 +7760,14 @@ static int nfs4_xattr_get_nfs4_user(const struct xattr_handler *handler,
                                    struct dentry *unused, struct inode *inode,
                                    const char *key, void *buf, size_t buflen)
 {
-       struct nfs_access_entry cache;
+       u32 mask;
        ssize_t ret;
 
        if (!nfs_server_capable(inode, NFS_CAP_XATTR))
                return -EOPNOTSUPP;
 
-       if (!nfs_access_get_cached(inode, current_cred(), &cache, true)) {
-               if (!(cache.mask & NFS_ACCESS_XAREAD))
+       if (!nfs_access_get_cached(inode, current_cred(), &mask, true)) {
+               if (!(mask & NFS_ACCESS_XAREAD))
                        return -EACCES;
        }
 
@@ -7680,13 +7792,13 @@ nfs4_listxattr_nfs4_user(struct inode *inode, char *list, size_t list_len)
        ssize_t ret, size;
        char *buf;
        size_t buflen;
-       struct nfs_access_entry cache;
+       u32 mask;
 
        if (!nfs_server_capable(inode, NFS_CAP_XATTR))
                return 0;
 
-       if (!nfs_access_get_cached(inode, current_cred(), &cache, true)) {
-               if (!(cache.mask & NFS_ACCESS_XALIST))
+       if (!nfs_access_get_cached(inode, current_cred(), &mask, true)) {
+               if (!(mask & NFS_ACCESS_XALIST))
                        return 0;
        }
 
@@ -7818,18 +7930,18 @@ int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
  * appended to this compound to identify the client ID which is
  * performing recovery.
  */
-static int _nfs40_proc_get_locations(struct inode *inode,
+static int _nfs40_proc_get_locations(struct nfs_server *server,
+                                    struct nfs_fh *fhandle,
                                     struct nfs4_fs_locations *locations,
                                     struct page *page, const struct cred *cred)
 {
-       struct nfs_server *server = NFS_SERVER(inode);
        struct rpc_clnt *clnt = server->client;
        u32 bitmask[2] = {
                [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
        };
        struct nfs4_fs_locations_arg args = {
                .clientid       = server->nfs_client->cl_clientid,
-               .fh             = NFS_FH(inode),
+               .fh             = fhandle,
                .page           = page,
                .bitmask        = bitmask,
                .migration      = 1,            /* skip LOOKUP */
@@ -7875,17 +7987,17 @@ static int _nfs40_proc_get_locations(struct inode *inode,
  * When the client supports GETATTR(fs_locations_info), it can
  * be plumbed in here.
  */
-static int _nfs41_proc_get_locations(struct inode *inode,
+static int _nfs41_proc_get_locations(struct nfs_server *server,
+                                    struct nfs_fh *fhandle,
                                     struct nfs4_fs_locations *locations,
                                     struct page *page, const struct cred *cred)
 {
-       struct nfs_server *server = NFS_SERVER(inode);
        struct rpc_clnt *clnt = server->client;
        u32 bitmask[2] = {
                [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
        };
        struct nfs4_fs_locations_arg args = {
-               .fh             = NFS_FH(inode),
+               .fh             = fhandle,
                .page           = page,
                .bitmask        = bitmask,
                .migration      = 1,            /* skip LOOKUP */
@@ -7919,7 +8031,8 @@ static int _nfs41_proc_get_locations(struct inode *inode,
 
 /**
  * nfs4_proc_get_locations - discover locations for a migrated FSID
- * @inode: inode on FSID that is migrating
+ * @server: pointer to nfs_server to process
+ * @fhandle: pointer to the kernel NFS client file handle
  * @locations: result of query
  * @page: buffer
  * @cred: credential to use for this operation
@@ -7934,11 +8047,11 @@ static int _nfs41_proc_get_locations(struct inode *inode,
  * -NFS4ERR_LEASE_MOVED is returned if the server still has leases
  * from this client that require migration recovery.
  */
-int nfs4_proc_get_locations(struct inode *inode,
+int nfs4_proc_get_locations(struct nfs_server *server,
+                           struct nfs_fh *fhandle,
                            struct nfs4_fs_locations *locations,
                            struct page *page, const struct cred *cred)
 {
-       struct nfs_server *server = NFS_SERVER(inode);
        struct nfs_client *clp = server->nfs_client;
        const struct nfs4_mig_recovery_ops *ops =
                                        clp->cl_mvops->mig_recovery_ops;
@@ -7951,10 +8064,11 @@ int nfs4_proc_get_locations(struct inode *inode,
                (unsigned long long)server->fsid.major,
                (unsigned long long)server->fsid.minor,
                clp->cl_hostname);
-       nfs_display_fhandle(NFS_FH(inode), __func__);
+       nfs_display_fhandle(fhandle, __func__);
 
        do {
-               status = ops->get_locations(inode, locations, page, cred);
+               status = ops->get_locations(server, fhandle, locations, page,
+                                           cred);
                if (status != -NFS4ERR_DELAY)
                        break;
                nfs4_handle_exception(server, status, &exception);
@@ -10423,6 +10537,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
        .free_client    = nfs4_free_client,
        .create_server  = nfs4_create_server,
        .clone_server   = nfs_clone_server,
+       .discover_trunking = nfs4_discover_trunking,
 };
 
 static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
index d88b779..f5a62c0 100644 (file)
@@ -2098,7 +2098,8 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred
        }
 
        inode = d_inode(server->super->s_root);
-       result = nfs4_proc_get_locations(inode, locations, page, cred);
+       result = nfs4_proc_get_locations(server, NFS_FH(inode), locations,
+                                        page, cred);
        if (result) {
                dprintk("<-- %s: failed to retrieve fs_locations: %d\n",
                        __func__, result);
@@ -2106,6 +2107,9 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred
        }
 
        result = -NFS4ERR_NXIO;
+       if (!locations->nlocations)
+               goto out;
+
        if (!(locations->fattr.valid & NFS_ATTR_FATTR_V4_LOCATIONS)) {
                dprintk("<-- %s: No fs_locations data, migration skipped\n",
                        __func__);
index 69862bf..8e70b92 100644 (file)
@@ -3533,6 +3533,42 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint
        return 0;
 }
 
+static int decode_attr_case_insensitive(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+       __be32 *p;
+
+       *res = 0;
+       if (unlikely(bitmap[0] & (FATTR4_WORD0_CASE_INSENSITIVE - 1U)))
+               return -EIO;
+       if (likely(bitmap[0] & FATTR4_WORD0_CASE_INSENSITIVE)) {
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p))
+                       return -EIO;
+               *res = be32_to_cpup(p);
+               bitmap[0] &= ~FATTR4_WORD0_CASE_INSENSITIVE;
+       }
+       dprintk("%s: case_insensitive=%s\n", __func__, *res == 0 ? "false" : "true");
+       return 0;
+}
+
+static int decode_attr_case_preserving(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+       __be32 *p;
+
+       *res = 0;
+       if (unlikely(bitmap[0] & (FATTR4_WORD0_CASE_PRESERVING - 1U)))
+               return -EIO;
+       if (likely(bitmap[0] & FATTR4_WORD0_CASE_PRESERVING)) {
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p))
+                       return -EIO;
+               *res = be32_to_cpup(p);
+               bitmap[0] &= ~FATTR4_WORD0_CASE_PRESERVING;
+       }
+       dprintk("%s: case_preserving=%s\n", __func__, *res == 0 ? "false" : "true");
+       return 0;
+}
+
 static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
 {
        __be32 *p;
@@ -3696,8 +3732,6 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
        if (unlikely(!p))
                goto out_eio;
        n = be32_to_cpup(p);
-       if (n <= 0)
-               goto out_eio;
        for (res->nlocations = 0; res->nlocations < n; res->nlocations++) {
                u32 m;
                struct nfs4_fs_location *loc;
@@ -4200,10 +4234,11 @@ static int decode_attr_security_label(struct xdr_stream *xdr, uint32_t *bitmap,
                } else
                        printk(KERN_WARNING "%s: label too long (%u)!\n",
                                        __func__, len);
+               if (label && label->label)
+                       dprintk("%s: label=%.*s, len=%d, PI=%d, LFS=%d\n",
+                               __func__, label->len, (char *)label->label,
+                               label->len, label->pi, label->lfs);
        }
-       if (label && label->label)
-               dprintk("%s: label=%s, len=%d, PI=%d, LFS=%d\n", __func__,
-                       (char *)label->label, label->len, label->pi, label->lfs);
        return status;
 }
 
@@ -4412,6 +4447,10 @@ static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_re
                goto xdr_error;
        if ((status = decode_attr_aclsupport(xdr, bitmap, &res->acl_bitmask)) != 0)
                goto xdr_error;
+       if ((status = decode_attr_case_insensitive(xdr, bitmap, &res->case_insensitive)) != 0)
+               goto xdr_error;
+       if ((status = decode_attr_case_preserving(xdr, bitmap, &res->case_preserving)) != 0)
+               goto xdr_error;
        if ((status = decode_attr_exclcreat_supported(xdr, bitmap,
                                res->exclcreat_bitmask)) != 0)
                goto xdr_error;
index 8cb7075..a6f7403 100644 (file)
@@ -142,10 +142,11 @@ static struct attribute *nfs_netns_client_attrs[] = {
        &nfs_netns_client_id.attr,
        NULL,
 };
+ATTRIBUTE_GROUPS(nfs_netns_client);
 
 static struct kobj_type nfs_netns_client_type = {
        .release = nfs_netns_client_release,
-       .default_attrs = nfs_netns_client_attrs,
+       .default_groups = nfs_netns_client_groups,
        .sysfs_ops = &kobj_sysfs_ops,
        .namespace = nfs_netns_client_namespace,
 };
index 8ef53f6..936eebd 100644 (file)
@@ -150,13 +150,17 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
        unsigned int len;
        int v;
 
-       argp->count = min_t(u32, argp->count, max_blocksize);
-
        dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
                                SVCFH_fmt(&argp->fh),
                                (unsigned long) argp->count,
                                (unsigned long long) argp->offset);
 
+       argp->count = min_t(u32, argp->count, max_blocksize);
+       if (argp->offset > (u64)OFFSET_MAX)
+               argp->offset = (u64)OFFSET_MAX;
+       if (argp->offset + argp->count > (u64)OFFSET_MAX)
+               argp->count = (u64)OFFSET_MAX - argp->offset;
+
        v = 0;
        len = argp->count;
        resp->pages = rqstp->rq_next_page;
@@ -199,6 +203,11 @@ nfsd3_proc_write(struct svc_rqst *rqstp)
                                (unsigned long long) argp->offset,
                                argp->stable? " stable" : "");
 
+       resp->status = nfserr_fbig;
+       if (argp->offset > (u64)OFFSET_MAX ||
+           argp->offset + argp->len > (u64)OFFSET_MAX)
+               return rpc_success;
+
        fh_copy(&resp->fh, &argp->fh);
        resp->committed = argp->stable;
        nvecs = svc_fill_write_vector(rqstp, &argp->payload);
@@ -651,15 +660,9 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
                                argp->count,
                                (unsigned long long) argp->offset);
 
-       if (argp->offset > NFS_OFFSET_MAX) {
-               resp->status = nfserr_inval;
-               goto out;
-       }
-
        fh_copy(&resp->fh, &argp->fh);
        resp->status = nfsd_commit(rqstp, &resp->fh, argp->offset,
                                   argp->count, resp->verf);
-out:
        return rpc_success;
 }
 
index 7c45ba4..0293b8d 100644 (file)
@@ -254,7 +254,7 @@ svcxdr_decode_sattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr,
                if (xdr_stream_decode_u64(xdr, &newsize) < 0)
                        return false;
                iap->ia_valid |= ATTR_SIZE;
-               iap->ia_size = min_t(u64, newsize, NFS_OFFSET_MAX);
+               iap->ia_size = newsize;
        }
        if (xdr_stream_decode_u32(xdr, &set_it) < 0)
                return false;
@@ -1060,7 +1060,7 @@ svcxdr_encode_entry3_common(struct nfsd3_readdirres *resp, const char *name,
                return false;
        /* cookie */
        resp->cookie_offset = dirlist->len;
-       if (xdr_stream_encode_u64(xdr, NFS_OFFSET_MAX) < 0)
+       if (xdr_stream_encode_u64(xdr, OFFSET_MAX) < 0)
                return false;
 
        return true;
index ed1ee25..b207c76 100644 (file)
@@ -782,12 +782,16 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        __be32 status;
 
        read->rd_nf = NULL;
-       if (read->rd_offset >= OFFSET_MAX)
-               return nfserr_inval;
 
        trace_nfsd_read_start(rqstp, &cstate->current_fh,
                              read->rd_offset, read->rd_length);
 
+       read->rd_length = min_t(u32, read->rd_length, svc_max_payload(rqstp));
+       if (read->rd_offset > (u64)OFFSET_MAX)
+               read->rd_offset = (u64)OFFSET_MAX;
+       if (read->rd_offset + read->rd_length > (u64)OFFSET_MAX)
+               read->rd_length = (u64)OFFSET_MAX - read->rd_offset;
+
        /*
         * If we do a zero copy read, then a client will see read data
         * that reflects the state of the file *after* performing the
@@ -1018,8 +1022,9 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        unsigned long cnt;
        int nvecs;
 
-       if (write->wr_offset >= OFFSET_MAX)
-               return nfserr_inval;
+       if (write->wr_offset > (u64)OFFSET_MAX ||
+           write->wr_offset + write->wr_buflen > (u64)OFFSET_MAX)
+               return nfserr_fbig;
 
        cnt = write->wr_buflen;
        trace_nfsd_write_start(rqstp, &cstate->current_fh,
index 72900b8..3206373 100644 (file)
@@ -4130,8 +4130,10 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                        status = nfserr_clid_inuse;
                        if (client_has_state(old)
                                        && !same_creds(&unconf->cl_cred,
-                                                       &old->cl_cred))
+                                                       &old->cl_cred)) {
+                               old = NULL;
                                goto out;
+                       }
                        status = mark_client_expired_locked(old);
                        if (status) {
                                old = NULL;
index 899de43..714a3a3 100644 (file)
@@ -3495,7 +3495,7 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
        p = xdr_reserve_space(xdr, 3*4 + namlen);
        if (!p)
                goto fail;
-       p = xdr_encode_hyper(p, NFS_OFFSET_MAX);    /* offset of next entry */
+       p = xdr_encode_hyper(p, OFFSET_MAX);        /* offset of next entry */
        p = xdr_encode_array(p, name, namlen);      /* name length & name */
 
        nfserr = nfsd4_encode_dirent_fattr(xdr, cd, name, namlen);
@@ -3986,10 +3986,8 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
        }
        xdr_commit_encode(xdr);
 
-       maxcount = svc_max_payload(resp->rqstp);
-       maxcount = min_t(unsigned long, maxcount,
+       maxcount = min_t(unsigned long, read->rd_length,
                         (xdr->buf->buflen - xdr->buf->len));
-       maxcount = min_t(unsigned long, maxcount, read->rd_length);
 
        if (file->f_op->splice_read &&
            test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags))
@@ -4826,10 +4824,8 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
                return nfserr_resource;
        xdr_commit_encode(xdr);
 
-       maxcount = svc_max_payload(resp->rqstp);
-       maxcount = min_t(unsigned long, maxcount,
+       maxcount = min_t(unsigned long, read->rd_length,
                         (xdr->buf->buflen - xdr->buf->len));
-       maxcount = min_t(unsigned long, maxcount, read->rd_length);
        count    = maxcount;
 
        eof = read->rd_offset >= i_size_read(file_inode(file));
index b9f27fb..68b020f 100644 (file)
@@ -1247,7 +1247,8 @@ static void nfsdfs_remove_file(struct inode *dir, struct dentry *dentry)
        clear_ncl(d_inode(dentry));
        dget(dentry);
        ret = simple_unlink(dir, dentry);
-       d_delete(dentry);
+       d_drop(dentry);
+       fsnotify_unlink(dir, dentry);
        dput(dentry);
        WARN_ON_ONCE(ret);
 }
@@ -1338,8 +1339,8 @@ void nfsd_client_rmdir(struct dentry *dentry)
        dget(dentry);
        ret = simple_rmdir(dir, dentry);
        WARN_ON_ONCE(ret);
+       d_drop(dentry);
        fsnotify_rmdir(dir, dentry);
-       d_delete(dentry);
        dput(dentry);
        inode_unlock(dir);
 }
index c4cf563..5889db6 100644 (file)
@@ -306,14 +306,14 @@ TRACE_EVENT(nfsd_export_update,
 DECLARE_EVENT_CLASS(nfsd_io_class,
        TP_PROTO(struct svc_rqst *rqstp,
                 struct svc_fh  *fhp,
-                loff_t         offset,
-                unsigned long  len),
+                u64            offset,
+                u32            len),
        TP_ARGS(rqstp, fhp, offset, len),
        TP_STRUCT__entry(
                __field(u32, xid)
                __field(u32, fh_hash)
-               __field(loff_t, offset)
-               __field(unsigned long, len)
+               __field(u64, offset)
+               __field(u32, len)
        ),
        TP_fast_assign(
                __entry->xid = be32_to_cpu(rqstp->rq_xid);
@@ -321,7 +321,7 @@ DECLARE_EVENT_CLASS(nfsd_io_class,
                __entry->offset = offset;
                __entry->len = len;
        ),
-       TP_printk("xid=0x%08x fh_hash=0x%08x offset=%lld len=%lu",
+       TP_printk("xid=0x%08x fh_hash=0x%08x offset=%llu len=%u",
                  __entry->xid, __entry->fh_hash,
                  __entry->offset, __entry->len)
 )
@@ -330,8 +330,8 @@ DECLARE_EVENT_CLASS(nfsd_io_class,
 DEFINE_EVENT(nfsd_io_class, nfsd_##name,       \
        TP_PROTO(struct svc_rqst *rqstp,        \
                 struct svc_fh  *fhp,           \
-                loff_t         offset,         \
-                unsigned long  len),           \
+                u64            offset,         \
+                u32            len),           \
        TP_ARGS(rqstp, fhp, offset, len))
 
 DEFINE_NFSD_IO_EVENT(read_start);
index 99c2b9d..91600e7 100644 (file)
@@ -435,6 +435,10 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
                        .ia_size        = iap->ia_size,
                };
 
+               host_err = -EFBIG;
+               if (iap->ia_size < 0)
+                       goto out_unlock;
+
                host_err = notify_change(&init_user_ns, dentry, &size_attr, NULL);
                if (host_err)
                        goto out_unlock;
@@ -1110,42 +1114,61 @@ out:
 }
 
 #ifdef CONFIG_NFSD_V3
-/*
- * Commit all pending writes to stable storage.
+/**
+ * nfsd_commit - Commit pending writes to stable storage
+ * @rqstp: RPC request being processed
+ * @fhp: NFS filehandle
+ * @offset: raw offset from beginning of file
+ * @count: raw count of bytes to sync
+ * @verf: filled in with the server's current write verifier
  *
- * Note: we only guarantee that data that lies within the range specified
- * by the 'offset' and 'count' parameters will be synced.
+ * Note: we guarantee that data that lies within the range specified
+ * by the 'offset' and 'count' parameters will be synced. The server
+ * is permitted to sync data that lies outside this range at the
+ * same time.
  *
  * Unfortunately we cannot lock the file to make sure we return full WCC
  * data to the client, as locking happens lower down in the filesystem.
+ *
+ * Return values:
+ *   An nfsstat value in network byte order.
  */
 __be32
-nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
-               loff_t offset, unsigned long count, __be32 *verf)
+nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset,
+           u32 count, __be32 *verf)
 {
+       u64                     maxbytes;
+       loff_t                  start, end;
        struct nfsd_net         *nn;
        struct nfsd_file        *nf;
-       loff_t                  end = LLONG_MAX;
-       __be32                  err = nfserr_inval;
-
-       if (offset < 0)
-               goto out;
-       if (count != 0) {
-               end = offset + (loff_t)count - 1;
-               if (end < offset)
-                       goto out;
-       }
+       __be32                  err;
 
        err = nfsd_file_acquire(rqstp, fhp,
                        NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &nf);
        if (err)
                goto out;
+
+       /*
+        * Convert the client-provided (offset, count) range to a
+        * (start, end) range. If the client-provided range falls
+        * outside the maximum file size of the underlying FS,
+        * clamp the sync range appropriately.
+        */
+       start = 0;
+       end = LLONG_MAX;
+       maxbytes = (u64)fhp->fh_dentry->d_sb->s_maxbytes;
+       if (offset < maxbytes) {
+               start = offset;
+               if (count && (offset + count - 1 < maxbytes))
+                       end = offset + count - 1;
+       }
+
        nn = net_generic(nf->nf_net, nfsd_net_id);
        if (EX_ISSYNC(fhp->fh_export)) {
                errseq_t since = READ_ONCE(nf->nf_file->f_wb_err);
                int err2;
 
-               err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
+               err2 = vfs_fsync_range(nf->nf_file, start, end, 0);
                switch (err2) {
                case 0:
                        nfsd_copy_write_verifier(verf, nn);
index 9f56dcb..2c43d10 100644 (file)
@@ -74,8 +74,8 @@ __be32                do_nfsd_create(struct svc_rqst *, struct svc_fh *,
                                char *name, int len, struct iattr *attrs,
                                struct svc_fh *res, int createmode,
                                u32 *verifier, bool *truncp, bool *created);
-__be32         nfsd_commit(struct svc_rqst *, struct svc_fh *,
-                               loff_t, unsigned long, __be32 *verf);
+__be32         nfsd_commit(struct svc_rqst *rqst, struct svc_fh *fhp,
+                               u64 offset, u32 count, __be32 *verf);
 #endif /* CONFIG_NFSD_V3 */
 #ifdef CONFIG_NFSD_V4
 __be32         nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
index 73b1615..2ff6bd8 100644 (file)
@@ -158,7 +158,6 @@ static size_t fanotify_event_len(unsigned int info_mode,
                                 struct fanotify_event *event)
 {
        size_t event_len = FAN_EVENT_METADATA_LEN;
-       struct fanotify_info *info;
        int fh_len;
        int dot_len = 0;
 
@@ -168,8 +167,6 @@ static size_t fanotify_event_len(unsigned int info_mode,
        if (fanotify_is_error_event(event->mask))
                event_len += FANOTIFY_ERROR_INFO_LEN;
 
-       info = fanotify_event_info(event);
-
        if (fanotify_event_has_any_dir_fh(event)) {
                event_len += fanotify_dir_name_info_len(event);
        } else if ((info_mode & FAN_REPORT_NAME) &&
@@ -704,9 +701,6 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
        if (fanotify_is_perm_event(event->mask))
                FANOTIFY_PERM(event)->fd = fd;
 
-       if (f)
-               fd_install(fd, f);
-
        if (info_mode) {
                ret = copy_info_records_to_user(event, info, info_mode, pidfd,
                                                buf, count);
@@ -714,6 +708,9 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
                        goto out_close_fd;
        }
 
+       if (f)
+               fd_install(fd, f);
+
        return metadata.event_len;
 
 out_close_fd:
index 731558a..dd77b7a 100644 (file)
@@ -661,17 +661,6 @@ static struct ctl_table ocfs2_nm_table[] = {
        { }
 };
 
-static struct ctl_table ocfs2_mod_table[] = {
-       {
-               .procname       = "nm",
-               .data           = NULL,
-               .maxlen         = 0,
-               .mode           = 0555,
-               .child          = ocfs2_nm_table
-       },
-       { }
-};
-
 static struct ctl_table_header *ocfs2_table_header;
 
 /*
@@ -682,7 +671,7 @@ static int __init ocfs2_stack_glue_init(void)
 {
        strcpy(cluster_stack_name, OCFS2_STACK_PLUGIN_O2CB);
 
-       ocfs2_table_header = register_sysctl("fs/ocfs2", ocfs2_mod_table);
+       ocfs2_table_header = register_sysctl("fs/ocfs2/nm", ocfs2_nm_table);
        if (!ocfs2_table_header) {
                printk(KERN_ERR
                       "ocfs2 stack glue: unable to register sysctl\n");
index 481017e..166c891 100644 (file)
@@ -1251,26 +1251,23 @@ static int ocfs2_test_bg_bit_allocatable(struct buffer_head *bg_bh,
 {
        struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) bg_bh->b_data;
        struct journal_head *jh;
-       int ret = 1;
+       int ret;
 
        if (ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap))
                return 0;
 
-       if (!buffer_jbd(bg_bh))
+       jh = jbd2_journal_grab_journal_head(bg_bh);
+       if (!jh)
                return 1;
 
-       jbd_lock_bh_journal_head(bg_bh);
-       if (buffer_jbd(bg_bh)) {
-               jh = bh2jh(bg_bh);
-               spin_lock(&jh->b_state_lock);
-               bg = (struct ocfs2_group_desc *) jh->b_committed_data;
-               if (bg)
-                       ret = !ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap);
-               else
-                       ret = 1;
-               spin_unlock(&jh->b_state_lock);
-       }
-       jbd_unlock_bh_journal_head(bg_bh);
+       spin_lock(&jh->b_state_lock);
+       bg = (struct ocfs2_group_desc *) jh->b_committed_data;
+       if (bg)
+               ret = !ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap);
+       else
+               ret = 1;
+       spin_unlock(&jh->b_state_lock);
+       jbd2_journal_put_journal_head(jh);
 
        return ret;
 }
index b193d08..e040970 100644 (file)
@@ -145,7 +145,7 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old,
                if (err == -ENOTTY || err == -EINVAL)
                        return 0;
                pr_warn("failed to retrieve lower fileattr (%pd2, err=%i)\n",
-                       old, err);
+                       old->dentry, err);
                return err;
        }
 
@@ -157,7 +157,9 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old,
         */
        if (oldfa.flags & OVL_PROT_FS_FLAGS_MASK) {
                err = ovl_set_protattr(inode, new->dentry, &oldfa);
-               if (err)
+               if (err == -EPERM)
+                       pr_warn_once("copying fileattr: no xattr on upper\n");
+               else if (err)
                        return err;
        }
 
@@ -167,8 +169,16 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old,
 
        err = ovl_real_fileattr_get(new, &newfa);
        if (err) {
+               /*
+                * Returning an error if upper doesn't support fileattr will
+                * result in a regression, so revert to the old behavior.
+                */
+               if (err == -ENOTTY || err == -EINVAL) {
+                       pr_warn_once("copying fileattr: no support on upper\n");
+                       return 0;
+               }
                pr_warn("failed to retrieve upper fileattr (%pd2, err=%i)\n",
-                       new, err);
+                       new->dentry, err);
                return err;
        }
 
index 18f8c3a..6e97ed7 100644 (file)
@@ -440,7 +440,8 @@ static void smaps_page_accumulate(struct mem_size_stats *mss,
 }
 
 static void smaps_account(struct mem_size_stats *mss, struct page *page,
-               bool compound, bool young, bool dirty, bool locked)
+               bool compound, bool young, bool dirty, bool locked,
+               bool migration)
 {
        int i, nr = compound ? compound_nr(page) : 1;
        unsigned long size = nr * PAGE_SIZE;
@@ -467,8 +468,15 @@ static void smaps_account(struct mem_size_stats *mss, struct page *page,
         * page_count(page) == 1 guarantees the page is mapped exactly once.
         * If any subpage of the compound page mapped with PTE it would elevate
         * page_count().
+        *
+        * The page_mapcount() is called to get a snapshot of the mapcount.
+        * Without holding the page lock this snapshot can be slightly wrong as
+        * we cannot always read the mapcount atomically.  It is not safe to
+        * call page_mapcount() even with PTL held if the page is not mapped,
+        * especially for migration entries.  Treat regular migration entries
+        * as mapcount == 1.
         */
-       if (page_count(page) == 1) {
+       if ((page_count(page) == 1) || migration) {
                smaps_page_accumulate(mss, page, size, size << PSS_SHIFT, dirty,
                        locked, true);
                return;
@@ -517,6 +525,7 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr,
        struct vm_area_struct *vma = walk->vma;
        bool locked = !!(vma->vm_flags & VM_LOCKED);
        struct page *page = NULL;
+       bool migration = false;
 
        if (pte_present(*pte)) {
                page = vm_normal_page(vma, addr, *pte);
@@ -536,8 +545,11 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr,
                        } else {
                                mss->swap_pss += (u64)PAGE_SIZE << PSS_SHIFT;
                        }
-               } else if (is_pfn_swap_entry(swpent))
+               } else if (is_pfn_swap_entry(swpent)) {
+                       if (is_migration_entry(swpent))
+                               migration = true;
                        page = pfn_swap_entry_to_page(swpent);
+               }
        } else {
                smaps_pte_hole_lookup(addr, walk);
                return;
@@ -546,7 +558,8 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr,
        if (!page)
                return;
 
-       smaps_account(mss, page, false, pte_young(*pte), pte_dirty(*pte), locked);
+       smaps_account(mss, page, false, pte_young(*pte), pte_dirty(*pte),
+                     locked, migration);
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
@@ -557,6 +570,7 @@ static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
        struct vm_area_struct *vma = walk->vma;
        bool locked = !!(vma->vm_flags & VM_LOCKED);
        struct page *page = NULL;
+       bool migration = false;
 
        if (pmd_present(*pmd)) {
                /* FOLL_DUMP will return -EFAULT on huge zero page */
@@ -564,8 +578,10 @@ static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
        } else if (unlikely(thp_migration_supported() && is_swap_pmd(*pmd))) {
                swp_entry_t entry = pmd_to_swp_entry(*pmd);
 
-               if (is_migration_entry(entry))
+               if (is_migration_entry(entry)) {
+                       migration = true;
                        page = pfn_swap_entry_to_page(entry);
+               }
        }
        if (IS_ERR_OR_NULL(page))
                return;
@@ -577,7 +593,9 @@ static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
                /* pass */;
        else
                mss->file_thp += HPAGE_PMD_SIZE;
-       smaps_account(mss, page, true, pmd_young(*pmd), pmd_dirty(*pmd), locked);
+
+       smaps_account(mss, page, true, pmd_young(*pmd), pmd_dirty(*pmd),
+                     locked, migration);
 }
 #else
 static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
@@ -1378,6 +1396,7 @@ static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm,
 {
        u64 frame = 0, flags = 0;
        struct page *page = NULL;
+       bool migration = false;
 
        if (pte_present(pte)) {
                if (pm->show_pfn)
@@ -1399,13 +1418,14 @@ static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm,
                        frame = swp_type(entry) |
                                (swp_offset(entry) << MAX_SWAPFILES_SHIFT);
                flags |= PM_SWAP;
+               migration = is_migration_entry(entry);
                if (is_pfn_swap_entry(entry))
                        page = pfn_swap_entry_to_page(entry);
        }
 
        if (page && !PageAnon(page))
                flags |= PM_FILE;
-       if (page && page_mapcount(page) == 1)
+       if (page && !migration && page_mapcount(page) == 1)
                flags |= PM_MMAP_EXCLUSIVE;
        if (vma->vm_flags & VM_SOFTDIRTY)
                flags |= PM_SOFT_DIRTY;
@@ -1421,8 +1441,9 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end,
        spinlock_t *ptl;
        pte_t *pte, *orig_pte;
        int err = 0;
-
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
+       bool migration = false;
+
        ptl = pmd_trans_huge_lock(pmdp, vma);
        if (ptl) {
                u64 flags = 0, frame = 0;
@@ -1461,11 +1482,12 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end,
                        if (pmd_swp_uffd_wp(pmd))
                                flags |= PM_UFFD_WP;
                        VM_BUG_ON(!is_pmd_migration_entry(pmd));
+                       migration = is_migration_entry(entry);
                        page = pfn_swap_entry_to_page(entry);
                }
 #endif
 
-               if (page && page_mapcount(page) == 1)
+               if (page && !migration && page_mapcount(page) == 1)
                        flags |= PM_MMAP_EXCLUSIVE;
 
                for (; addr != end; addr += PAGE_SIZE) {
index 22d904b..a74aef9 100644 (file)
@@ -690,9 +690,14 @@ int dquot_quota_sync(struct super_block *sb, int type)
        /* This is not very clever (and fast) but currently I don't know about
         * any other simple way of getting quota data to disk and we must get
         * them there for userspace to be visible... */
-       if (sb->s_op->sync_fs)
-               sb->s_op->sync_fs(sb, 1);
-       sync_blockdev(sb->s_bdev);
+       if (sb->s_op->sync_fs) {
+               ret = sb->s_op->sync_fs(sb, 1);
+               if (ret)
+                       return ret;
+       }
+       ret = sync_blockdev(sb->s_bdev);
+       if (ret)
+               return ret;
 
        /*
         * Now when everything is written we can discard the pagecache so
index 7af820b..f1d4a19 100644 (file)
@@ -1616,11 +1616,9 @@ static void lockdep_sb_freeze_acquire(struct super_block *sb)
                percpu_rwsem_acquire(sb->s_writers.rw_sem + level, 0, _THIS_IP_);
 }
 
-static void sb_freeze_unlock(struct super_block *sb)
+static void sb_freeze_unlock(struct super_block *sb, int level)
 {
-       int level;
-
-       for (level = SB_FREEZE_LEVELS - 1; level >= 0; level--)
+       for (level--; level >= 0; level--)
                percpu_up_write(sb->s_writers.rw_sem + level);
 }
 
@@ -1691,7 +1689,14 @@ int freeze_super(struct super_block *sb)
        sb_wait_write(sb, SB_FREEZE_PAGEFAULT);
 
        /* All writers are done so after syncing there won't be dirty data */
-       sync_filesystem(sb);
+       ret = sync_filesystem(sb);
+       if (ret) {
+               sb->s_writers.frozen = SB_UNFROZEN;
+               sb_freeze_unlock(sb, SB_FREEZE_PAGEFAULT);
+               wake_up(&sb->s_writers.wait_unfrozen);
+               deactivate_locked_super(sb);
+               return ret;
+       }
 
        /* Now wait for internal filesystem counter */
        sb->s_writers.frozen = SB_FREEZE_FS;
@@ -1703,7 +1708,7 @@ int freeze_super(struct super_block *sb)
                        printk(KERN_ERR
                                "VFS:Filesystem freeze failed\n");
                        sb->s_writers.frozen = SB_UNFROZEN;
-                       sb_freeze_unlock(sb);
+                       sb_freeze_unlock(sb, SB_FREEZE_FS);
                        wake_up(&sb->s_writers.wait_unfrozen);
                        deactivate_locked_super(sb);
                        return ret;
@@ -1748,7 +1753,7 @@ static int thaw_super_locked(struct super_block *sb)
        }
 
        sb->s_writers.frozen = SB_UNFROZEN;
-       sb_freeze_unlock(sb);
+       sb_freeze_unlock(sb, SB_FREEZE_FS);
 out:
        wake_up(&sb->s_writers.wait_unfrozen);
        deactivate_locked_super(sb);
index 3ce8e21..c769001 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -29,7 +29,7 @@
  */
 int sync_filesystem(struct super_block *sb)
 {
-       int ret;
+       int ret = 0;
 
        /*
         * We need to be protected against the filesystem going from
@@ -52,15 +52,21 @@ int sync_filesystem(struct super_block *sb)
         * at a time.
         */
        writeback_inodes_sb(sb, WB_REASON_SYNC);
-       if (sb->s_op->sync_fs)
-               sb->s_op->sync_fs(sb, 0);
+       if (sb->s_op->sync_fs) {
+               ret = sb->s_op->sync_fs(sb, 0);
+               if (ret)
+                       return ret;
+       }
        ret = sync_blockdev_nowait(sb->s_bdev);
-       if (ret < 0)
+       if (ret)
                return ret;
 
        sync_inodes_sb(sb);
-       if (sb->s_op->sync_fs)
-               sb->s_op->sync_fs(sb, 1);
+       if (sb->s_op->sync_fs) {
+               ret = sb->s_op->sync_fs(sb, 1);
+               if (ret)
+                       return ret;
+       }
        return sync_blockdev(sb->s_bdev);
 }
 EXPORT_SYMBOL(sync_filesystem);
index bafc02b..de72527 100644 (file)
@@ -264,7 +264,6 @@ static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts)
                        if (!gid_valid(gid))
                                return -EINVAL;
                        opts->gid = gid;
-                       set_gid(tracefs_mount->mnt_root, gid);
                        break;
                case Opt_mode:
                        if (match_octal(&args[0], &option))
@@ -291,7 +290,9 @@ static int tracefs_apply_options(struct super_block *sb)
        inode->i_mode |= opts->mode;
 
        inode->i_uid = opts->uid;
-       inode->i_gid = opts->gid;
+
+       /* Set all the group ids to the mount option */
+       set_gid(sb->s_root, opts->gid);
 
        return 0;
 }
index 1d6b7a5..ea8f6cd 100644 (file)
@@ -258,10 +258,6 @@ int udf_expand_file_adinicb(struct inode *inode)
        char *kaddr;
        struct udf_inode_info *iinfo = UDF_I(inode);
        int err;
-       struct writeback_control udf_wbc = {
-               .sync_mode = WB_SYNC_NONE,
-               .nr_to_write = 1,
-       };
 
        WARN_ON_ONCE(!inode_is_locked(inode));
        if (!iinfo->i_lenAlloc) {
@@ -305,8 +301,10 @@ int udf_expand_file_adinicb(struct inode *inode)
                iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
        /* from now on we have normal address_space methods */
        inode->i_data.a_ops = &udf_aops;
+       set_page_dirty(page);
+       unlock_page(page);
        up_write(&iinfo->i_data_sem);
-       err = inode->i_data.a_ops->writepage(page, &udf_wbc);
+       err = filemap_fdatawrite(inode->i_mapping);
        if (err) {
                /* Restore everything back so that we don't lose data... */
                lock_page(page);
@@ -317,6 +315,7 @@ int udf_expand_file_adinicb(struct inode *inode)
                unlock_page(page);
                iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB;
                inode->i_data.a_ops = &udf_adinicb_aops;
+               iinfo->i_lenAlloc = inode->i_size;
                up_write(&iinfo->i_data_sem);
        }
        put_page(page);
index 610d7bc..da786a6 100644 (file)
@@ -3,21 +3,13 @@
 # UTF-8 normalization
 #
 config UNICODE
-       bool "UTF-8 normalization and casefolding support"
+       tristate "UTF-8 normalization and casefolding support"
        help
          Say Y here to enable UTF-8 NFD normalization and NFD+CF casefolding
-         support.
-
-config UNICODE_UTF8_DATA
-       tristate "UTF-8 normalization and casefolding tables"
-       depends on UNICODE
-       default UNICODE
-       help
-         This contains a large table of case foldings, which can be loaded as
-         a separate module if you say M here.  To be on the safe side stick
-         to the default of Y.  Saying N here makes no sense, if you do not want
-         utf8 casefolding support, disable CONFIG_UNICODE instead.
+         support.  If you say M here the large table of case foldings will
+         be a separate loadable module that gets requested only when a file
+         system actually use it.
 
 config UNICODE_NORMALIZATION_SELFTEST
        tristate "Test UTF-8 normalization support"
-       depends on UNICODE_UTF8_DATA
+       depends on UNICODE
index 2f9d918..0cc8742 100644 (file)
@@ -1,8 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-$(CONFIG_UNICODE) += unicode.o
+ifneq ($(CONFIG_UNICODE),)
+obj-y                  += unicode.o
+endif
+obj-$(CONFIG_UNICODE)  += utf8data.o
 obj-$(CONFIG_UNICODE_NORMALIZATION_SELFTEST) += utf8-selftest.o
-obj-$(CONFIG_UNICODE_UTF8_DATA) += utf8data.o
 
 unicode-y := utf8-norm.o utf8-core.o
 
index 2705f91..9d6a67c 100644 (file)
@@ -136,7 +136,20 @@ done:
        memalloc_nofs_restore(nofs_flag);
 }
 
-/* Finish all pending io completions. */
+/*
+ * Finish all pending IO completions that require transactional modifications.
+ *
+ * We try to merge physical and logically contiguous ioends before completion to
+ * minimise the number of transactions we need to perform during IO completion.
+ * Both unwritten extent conversion and COW remapping need to iterate and modify
+ * one physical extent at a time, so we gain nothing by merging physically
+ * discontiguous extents here.
+ *
+ * The ioend chain length that we can be processing here is largely unbound in
+ * length and we may have to perform significant amounts of work on each ioend
+ * to complete it. Hence we have to be careful about holding the CPU for too
+ * long in this loop.
+ */
 void
 xfs_end_io(
        struct work_struct      *work)
@@ -157,6 +170,7 @@ xfs_end_io(
                list_del_init(&ioend->io_list);
                iomap_ioend_try_merge(ioend, &tmp);
                xfs_end_ioend(ioend);
+               cond_resched();
        }
 }
 
index d4a387d..eb2e387 100644 (file)
@@ -850,9 +850,6 @@ xfs_alloc_file_space(
                        rblocks = 0;
                }
 
-               /*
-                * Allocate and setup the transaction.
-                */
                error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_write,
                                dblocks, rblocks, false, &tp);
                if (error)
@@ -869,9 +866,9 @@ xfs_alloc_file_space(
                if (error)
                        goto error;
 
-               /*
-                * Complete the transaction
-                */
+               ip->i_diflags |= XFS_DIFLAG_PREALLOC;
+               xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
                error = xfs_trans_commit(tp);
                xfs_iunlock(ip, XFS_ILOCK_EXCL);
                if (error)
index 22ad207..5bddb1e 100644 (file)
@@ -66,40 +66,6 @@ xfs_is_falloc_aligned(
        return !((pos | len) & mask);
 }
 
-int
-xfs_update_prealloc_flags(
-       struct xfs_inode        *ip,
-       enum xfs_prealloc_flags flags)
-{
-       struct xfs_trans        *tp;
-       int                     error;
-
-       error = xfs_trans_alloc(ip->i_mount, &M_RES(ip->i_mount)->tr_writeid,
-                       0, 0, 0, &tp);
-       if (error)
-               return error;
-
-       xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-
-       if (!(flags & XFS_PREALLOC_INVISIBLE)) {
-               VFS_I(ip)->i_mode &= ~S_ISUID;
-               if (VFS_I(ip)->i_mode & S_IXGRP)
-                       VFS_I(ip)->i_mode &= ~S_ISGID;
-               xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-       }
-
-       if (flags & XFS_PREALLOC_SET)
-               ip->i_diflags |= XFS_DIFLAG_PREALLOC;
-       if (flags & XFS_PREALLOC_CLEAR)
-               ip->i_diflags &= ~XFS_DIFLAG_PREALLOC;
-
-       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-       if (flags & XFS_PREALLOC_SYNC)
-               xfs_trans_set_sync(tp);
-       return xfs_trans_commit(tp);
-}
-
 /*
  * Fsync operations on directories are much simpler than on regular files,
  * as there is no file data to flush, and thus also no need for explicit
@@ -895,6 +861,21 @@ xfs_break_layouts(
        return error;
 }
 
+/* Does this file, inode, or mount want synchronous writes? */
+static inline bool xfs_file_sync_writes(struct file *filp)
+{
+       struct xfs_inode        *ip = XFS_I(file_inode(filp));
+
+       if (xfs_has_wsync(ip->i_mount))
+               return true;
+       if (filp->f_flags & (__O_SYNC | O_DSYNC))
+               return true;
+       if (IS_SYNC(file_inode(filp)))
+               return true;
+
+       return false;
+}
+
 #define        XFS_FALLOC_FL_SUPPORTED                                         \
                (FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |           \
                 FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE |      \
@@ -910,7 +891,6 @@ xfs_file_fallocate(
        struct inode            *inode = file_inode(file);
        struct xfs_inode        *ip = XFS_I(inode);
        long                    error;
-       enum xfs_prealloc_flags flags = 0;
        uint                    iolock = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL;
        loff_t                  new_size = 0;
        bool                    do_file_insert = false;
@@ -955,6 +935,10 @@ xfs_file_fallocate(
                        goto out_unlock;
        }
 
+       error = file_modified(file);
+       if (error)
+               goto out_unlock;
+
        if (mode & FALLOC_FL_PUNCH_HOLE) {
                error = xfs_free_file_space(ip, offset, len);
                if (error)
@@ -1004,8 +988,6 @@ xfs_file_fallocate(
                }
                do_file_insert = true;
        } else {
-               flags |= XFS_PREALLOC_SET;
-
                if (!(mode & FALLOC_FL_KEEP_SIZE) &&
                    offset + len > i_size_read(inode)) {
                        new_size = offset + len;
@@ -1057,13 +1039,6 @@ xfs_file_fallocate(
                }
        }
 
-       if (file->f_flags & O_DSYNC)
-               flags |= XFS_PREALLOC_SYNC;
-
-       error = xfs_update_prealloc_flags(ip, flags);
-       if (error)
-               goto out_unlock;
-
        /* Change file size if needed */
        if (new_size) {
                struct iattr iattr;
@@ -1082,8 +1057,14 @@ xfs_file_fallocate(
         * leave shifted extents past EOF and hence losing access to
         * the data that is contained within them.
         */
-       if (do_file_insert)
+       if (do_file_insert) {
                error = xfs_insert_file_space(ip, offset, len);
+               if (error)
+                       goto out_unlock;
+       }
+
+       if (xfs_file_sync_writes(file))
+               error = xfs_log_force_inode(ip);
 
 out_unlock:
        xfs_iunlock(ip, iolock);
@@ -1115,21 +1096,6 @@ xfs_file_fadvise(
        return ret;
 }
 
-/* Does this file, inode, or mount want synchronous writes? */
-static inline bool xfs_file_sync_writes(struct file *filp)
-{
-       struct xfs_inode        *ip = XFS_I(file_inode(filp));
-
-       if (xfs_has_wsync(ip->i_mount))
-               return true;
-       if (filp->f_flags & (__O_SYNC | O_DSYNC))
-               return true;
-       if (IS_SYNC(file_inode(filp)))
-               return true;
-
-       return false;
-}
-
 STATIC loff_t
 xfs_file_remap_range(
        struct file             *file_in,
index c447bf0..b7e8f14 100644 (file)
@@ -462,15 +462,6 @@ xfs_itruncate_extents(
 }
 
 /* from xfs_file.c */
-enum xfs_prealloc_flags {
-       XFS_PREALLOC_SET        = (1 << 1),
-       XFS_PREALLOC_CLEAR      = (1 << 2),
-       XFS_PREALLOC_SYNC       = (1 << 3),
-       XFS_PREALLOC_INVISIBLE  = (1 << 4),
-};
-
-int    xfs_update_prealloc_flags(struct xfs_inode *ip,
-                                 enum xfs_prealloc_flags flags);
 int    xfs_break_layouts(struct inode *inode, uint *iolock,
                enum layout_break_reason reason);
 
index 03a6198..2515fe8 100644 (file)
@@ -1464,7 +1464,7 @@ xfs_ioc_getbmap(
 
        if (bmx.bmv_count < 2)
                return -EINVAL;
-       if (bmx.bmv_count > ULONG_MAX / recsize)
+       if (bmx.bmv_count >= INT_MAX / recsize)
                return -ENOMEM;
 
        buf = kvcalloc(bmx.bmv_count, sizeof(*buf), GFP_KERNEL);
index d6334ab..4abe173 100644 (file)
@@ -70,6 +70,40 @@ xfs_fs_get_uuid(
        return 0;
 }
 
+/*
+ * We cannot use file based VFS helpers such as file_modified() to update
+ * inode state as we modify the data/metadata in the inode here. Hence we have
+ * to open code the timestamp updates and SUID/SGID stripping. We also need
+ * to set the inode prealloc flag to ensure that the extents we allocate are not
+ * removed if the inode is reclaimed from memory before xfs_fs_block_commit()
+ * is from the client to indicate that data has been written and the file size
+ * can be extended.
+ */
+static int
+xfs_fs_map_update_inode(
+       struct xfs_inode        *ip)
+{
+       struct xfs_trans        *tp;
+       int                     error;
+
+       error = xfs_trans_alloc(ip->i_mount, &M_RES(ip->i_mount)->tr_writeid,
+                       0, 0, 0, &tp);
+       if (error)
+               return error;
+
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+
+       VFS_I(ip)->i_mode &= ~S_ISUID;
+       if (VFS_I(ip)->i_mode & S_IXGRP)
+               VFS_I(ip)->i_mode &= ~S_ISGID;
+       xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+       ip->i_diflags |= XFS_DIFLAG_PREALLOC;
+
+       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+       return xfs_trans_commit(tp);
+}
+
 /*
  * Get a layout for the pNFS client.
  */
@@ -164,10 +198,12 @@ xfs_fs_map_blocks(
                 * that the blocks allocated and handed out to the client are
                 * guaranteed to be present even after a server crash.
                 */
-               error = xfs_update_prealloc_flags(ip,
-                               XFS_PREALLOC_SET | XFS_PREALLOC_SYNC);
+               error = xfs_fs_map_update_inode(ip);
+               if (!error)
+                       error = xfs_log_force_inode(ip);
                if (error)
                        goto out_unlock;
+
        } else {
                xfs_iunlock(ip, lock_flags);
        }
@@ -255,7 +291,7 @@ xfs_fs_commit_blocks(
                length = end - start;
                if (!length)
                        continue;
-       
+
                /*
                 * Make sure reads through the pagecache see the new data.
                 */
index e8f37bd..d84714e 100644 (file)
@@ -735,6 +735,7 @@ xfs_fs_sync_fs(
        int                     wait)
 {
        struct xfs_mount        *mp = XFS_M(sb);
+       int                     error;
 
        trace_xfs_fs_sync_fs(mp, __return_address);
 
@@ -744,7 +745,10 @@ xfs_fs_sync_fs(
        if (!wait)
                return 0;
 
-       xfs_log_force(mp, XFS_LOG_SYNC);
+       error = xfs_log_force(mp, XFS_LOG_SYNC);
+       if (error)
+               return error;
+
        if (laptop_mode) {
                /*
                 * The disk must be active because we're syncing.
@@ -1749,6 +1753,11 @@ xfs_remount_ro(
        };
        int                     error;
 
+       /* Flush all the dirty data to disk. */
+       error = sync_filesystem(mp->m_super);
+       if (error)
+               return error;
+
        /*
         * Cancel background eofb scanning so it cannot race with the final
         * log force+buftarg wait and deadlock the remount.
@@ -1827,8 +1836,6 @@ xfs_fs_reconfigure(
        if (error)
                return error;
 
-       sync_filesystem(mp->m_super);
-
        /* inode32 -> inode64 */
        if (xfs_has_small_inums(mp) && !xfs_has_small_inums(new_mp)) {
                mp->m_features &= ~XFS_FEAT_SMALL_INUMS;
index d39cfa0..52363ee 100644 (file)
@@ -24,14 +24,11 @@ static inline void blake2s_set_lastblock(struct blake2s_state *state)
        state->f[0] = -1;
 }
 
-typedef void (*blake2s_compress_t)(struct blake2s_state *state,
-                                  const u8 *block, size_t nblocks, u32 inc);
-
 /* Helper functions for BLAKE2s shared by the library and shash APIs */
 
-static inline void __blake2s_update(struct blake2s_state *state,
-                                   const u8 *in, size_t inlen,
-                                   blake2s_compress_t compress)
+static __always_inline void
+__blake2s_update(struct blake2s_state *state, const u8 *in, size_t inlen,
+                bool force_generic)
 {
        const size_t fill = BLAKE2S_BLOCK_SIZE - state->buflen;
 
@@ -39,7 +36,12 @@ static inline void __blake2s_update(struct blake2s_state *state,
                return;
        if (inlen > fill) {
                memcpy(state->buf + state->buflen, in, fill);
-               (*compress)(state, state->buf, 1, BLAKE2S_BLOCK_SIZE);
+               if (force_generic)
+                       blake2s_compress_generic(state, state->buf, 1,
+                                                BLAKE2S_BLOCK_SIZE);
+               else
+                       blake2s_compress(state, state->buf, 1,
+                                        BLAKE2S_BLOCK_SIZE);
                state->buflen = 0;
                in += fill;
                inlen -= fill;
@@ -47,7 +49,12 @@ static inline void __blake2s_update(struct blake2s_state *state,
        if (inlen > BLAKE2S_BLOCK_SIZE) {
                const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_SIZE);
                /* Hash one less (full) block than strictly possible */
-               (*compress)(state, in, nblocks - 1, BLAKE2S_BLOCK_SIZE);
+               if (force_generic)
+                       blake2s_compress_generic(state, in, nblocks - 1,
+                                                BLAKE2S_BLOCK_SIZE);
+               else
+                       blake2s_compress(state, in, nblocks - 1,
+                                        BLAKE2S_BLOCK_SIZE);
                in += BLAKE2S_BLOCK_SIZE * (nblocks - 1);
                inlen -= BLAKE2S_BLOCK_SIZE * (nblocks - 1);
        }
@@ -55,13 +62,16 @@ static inline void __blake2s_update(struct blake2s_state *state,
        state->buflen += inlen;
 }
 
-static inline void __blake2s_final(struct blake2s_state *state, u8 *out,
-                                  blake2s_compress_t compress)
+static __always_inline void
+__blake2s_final(struct blake2s_state *state, u8 *out, bool force_generic)
 {
        blake2s_set_lastblock(state);
        memset(state->buf + state->buflen, 0,
               BLAKE2S_BLOCK_SIZE - state->buflen); /* Padding */
-       (*compress)(state, state->buf, 1, state->buflen);
+       if (force_generic)
+               blake2s_compress_generic(state, state->buf, 1, state->buflen);
+       else
+               blake2s_compress(state, state->buf, 1, state->buflen);
        cpu_to_le32_array(state->h, ARRAY_SIZE(state->h));
        memcpy(out, state->h, state->outlen);
 }
@@ -99,20 +109,20 @@ static inline int crypto_blake2s_init(struct shash_desc *desc)
 
 static inline int crypto_blake2s_update(struct shash_desc *desc,
                                        const u8 *in, unsigned int inlen,
-                                       blake2s_compress_t compress)
+                                       bool force_generic)
 {
        struct blake2s_state *state = shash_desc_ctx(desc);
 
-       __blake2s_update(state, in, inlen, compress);
+       __blake2s_update(state, in, inlen, force_generic);
        return 0;
 }
 
 static inline int crypto_blake2s_final(struct shash_desc *desc, u8 *out,
-                                      blake2s_compress_t compress)
+                                      bool force_generic)
 {
        struct blake2s_state *state = shash_desc_ctx(desc);
 
-       __blake2s_final(state, out, compress);
+       __blake2s_final(state, out, force_generic);
        return 0;
 }
 
index 7d57063..29ff6b8 100644 (file)
 #define DRA7_L3_MAIN_2_CLKCTRL DRA7_CLKCTRL_INDEX(0x20)
 #define DRA7_L3_INSTR_CLKCTRL  DRA7_CLKCTRL_INDEX(0x28)
 
-/* iva clocks */
-#define DRA7_IVA_CLKCTRL       DRA7_CLKCTRL_INDEX(0x20)
-#define DRA7_SL2IF_CLKCTRL     DRA7_CLKCTRL_INDEX(0x28)
-
 /* dss clocks */
 #define DRA7_DSS_CORE_CLKCTRL  DRA7_CLKCTRL_INDEX(0x20)
 #define DRA7_BB2D_CLKCTRL      DRA7_CLKCTRL_INDEX(0x30)
 
-/* gpu clocks */
-#define DRA7_GPU_CLKCTRL       DRA7_CLKCTRL_INDEX(0x20)
-
 /* l3init clocks */
 #define DRA7_MMC1_CLKCTRL      DRA7_CLKCTRL_INDEX(0x28)
 #define DRA7_MMC2_CLKCTRL      DRA7_CLKCTRL_INDEX(0x30)
 #define DRA7_L3INSTR_L3_MAIN_2_CLKCTRL DRA7_CLKCTRL_INDEX(0x20)
 #define DRA7_L3INSTR_L3_INSTR_CLKCTRL  DRA7_CLKCTRL_INDEX(0x28)
 
+/* iva clocks */
+#define DRA7_IVA_CLKCTRL               DRA7_CLKCTRL_INDEX(0x20)
+#define DRA7_SL2IF_CLKCTRL             DRA7_CLKCTRL_INDEX(0x28)
+
 /* dss clocks */
 #define DRA7_DSS_DSS_CORE_CLKCTRL      DRA7_CLKCTRL_INDEX(0x20)
 #define DRA7_DSS_BB2D_CLKCTRL  DRA7_CLKCTRL_INDEX(0x30)
 
+/* gpu clocks */
+#define DRA7_GPU_CLKCTRL               DRA7_CLKCTRL_INDEX(0x20)
+
 /* l3init clocks */
 #define DRA7_L3INIT_MMC1_CLKCTRL       DRA7_CLKCTRL_INDEX(0x28)
 #define DRA7_L3INIT_MMC2_CLKCTRL       DRA7_CLKCTRL_INDEX(0x30)
diff --git a/include/dt-bindings/reset/delta,tn48m-reset.h b/include/dt-bindings/reset/delta,tn48m-reset.h
new file mode 100644 (file)
index 0000000..d4e9ed1
--- /dev/null
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Delta TN48M CPLD GPIO driver
+ *
+ * Copyright (C) 2021 Sartura Ltd.
+ *
+ * Author: Robert Marko <robert.marko@sartura.hr>
+ */
+
+#ifndef _DT_BINDINGS_RESET_TN48M_H
+#define _DT_BINDINGS_RESET_TN48M_H
+
+#define CPU_88F7040_RESET      0
+#define CPU_88F6820_RESET      1
+#define MAC_98DX3265_RESET     2
+#define PHY_88E1680_RESET      3
+#define PHY_88E1512_RESET      4
+#define POE_RESET              5
+
+#endif /* _DT_BINDINGS_RESET_TN48M_H */
index 199e47e..21292b5 100644 (file)
@@ -324,12 +324,12 @@ enum {
        ATA_LOG_NCQ_NON_DATA    = 0x12,
        ATA_LOG_NCQ_SEND_RECV   = 0x13,
        ATA_LOG_IDENTIFY_DEVICE = 0x30,
+       ATA_LOG_CONCURRENT_POSITIONING_RANGES = 0x47,
 
        /* Identify device log pages: */
        ATA_LOG_SECURITY          = 0x06,
        ATA_LOG_SATA_SETTINGS     = 0x08,
        ATA_LOG_ZONED_INFORMATION = 0x09,
-       ATA_LOG_CONCURRENT_POSITIONING_RANGES = 0x47,
 
        /* Identify device SATA settings log:*/
        ATA_LOG_DEVSLP_OFFSET     = 0x30,
index 9c95df2..16b4703 100644 (file)
@@ -748,7 +748,8 @@ extern bool blk_queue_can_use_dma_map_merging(struct request_queue *q,
 
 bool __must_check blk_get_queue(struct request_queue *);
 extern void blk_put_queue(struct request_queue *);
-extern void blk_set_queue_dying(struct request_queue *);
+
+void blk_mark_disk_dead(struct gendisk *disk);
 
 #ifdef CONFIG_BLOCK
 /*
@@ -1258,6 +1259,7 @@ unsigned long disk_start_io_acct(struct gendisk *disk, unsigned int sectors,
 void disk_end_io_acct(struct gendisk *disk, unsigned int op,
                unsigned long start_time);
 
+void bio_start_io_acct_time(struct bio *bio, unsigned long start_time);
 unsigned long bio_start_io_acct(struct bio *bio);
 void bio_end_io_acct_remapped(struct bio *bio, unsigned long start_time,
                struct block_device *orig_bdev);
index fa517ae..d0ad379 100644 (file)
@@ -209,11 +209,9 @@ static inline bool map_value_has_timer(const struct bpf_map *map)
 static inline void check_and_init_map_value(struct bpf_map *map, void *dst)
 {
        if (unlikely(map_value_has_spin_lock(map)))
-               *(struct bpf_spin_lock *)(dst + map->spin_lock_off) =
-                       (struct bpf_spin_lock){};
+               memset(dst + map->spin_lock_off, 0, sizeof(struct bpf_spin_lock));
        if (unlikely(map_value_has_timer(map)))
-               *(struct bpf_timer *)(dst + map->timer_off) =
-                       (struct bpf_timer){};
+               memset(dst + map->timer_off, 0, sizeof(struct bpf_timer));
 }
 
 /* copy everything but bpf_spin_lock and bpf_timer. There could be one of each. */
@@ -224,7 +222,8 @@ static inline void copy_map_value(struct bpf_map *map, void *dst, void *src)
        if (unlikely(map_value_has_spin_lock(map))) {
                s_off = map->spin_lock_off;
                s_sz = sizeof(struct bpf_spin_lock);
-       } else if (unlikely(map_value_has_timer(map))) {
+       }
+       if (unlikely(map_value_has_timer(map))) {
                t_off = map->timer_off;
                t_sz = sizeof(struct bpf_timer);
        }
index 6a89ea4..edf62ea 100644 (file)
@@ -35,6 +35,7 @@
 #define CEPH_OPT_TCP_NODELAY      (1<<4) /* TCP_NODELAY on TCP sockets */
 #define CEPH_OPT_NOMSGSIGN        (1<<5) /* don't sign msgs (msgr1) */
 #define CEPH_OPT_ABORT_ON_FULL    (1<<6) /* abort w/ ENOSPC when full */
+#define CEPH_OPT_RXBOUNCE         (1<<7) /* double-buffer read data */
 
 #define CEPH_OPT_DEFAULT   (CEPH_OPT_TCP_NODELAY)
 
index ff99ce0..e7f2fb2 100644 (file)
@@ -383,6 +383,10 @@ struct ceph_connection_v2_info {
        struct ceph_gcm_nonce in_gcm_nonce;
        struct ceph_gcm_nonce out_gcm_nonce;
 
+       struct page **in_enc_pages;
+       int in_enc_page_cnt;
+       int in_enc_resid;
+       int in_enc_i;
        struct page **out_enc_pages;
        int out_enc_page_cnt;
        int out_enc_resid;
@@ -457,6 +461,7 @@ struct ceph_connection {
        struct ceph_msg *out_msg;        /* sending message (== tail of
                                            out_sent) */
 
+       struct page *bounce_page;
        u32 in_front_crc, in_middle_crc, in_data_crc;  /* calculated crc */
 
        struct timespec64 last_keepalive_ack; /* keepalive2 ack stamp */
index 429dceb..0f7fd20 100644 (file)
@@ -117,14 +117,6 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
  */
 #define __stringify_label(n) #n
 
-#define __annotate_reachable(c) ({                                     \
-       asm volatile(__stringify_label(c) ":\n\t"                       \
-                    ".pushsection .discard.reachable\n\t"              \
-                    ".long " __stringify_label(c) "b - .\n\t"          \
-                    ".popsection\n\t" : : "i" (c));                    \
-})
-#define annotate_reachable() __annotate_reachable(__COUNTER__)
-
 #define __annotate_unreachable(c) ({                                   \
        asm volatile(__stringify_label(c) ":\n\t"                       \
                     ".pushsection .discard.unreachable\n\t"            \
@@ -133,24 +125,21 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
 })
 #define annotate_unreachable() __annotate_unreachable(__COUNTER__)
 
-#define ASM_UNREACHABLE                                                        \
-       "999:\n\t"                                                      \
-       ".pushsection .discard.unreachable\n\t"                         \
-       ".long 999b - .\n\t"                                            \
+#define ASM_REACHABLE                                                  \
+       "998:\n\t"                                                      \
+       ".pushsection .discard.reachable\n\t"                           \
+       ".long 998b - .\n\t"                                            \
        ".popsection\n\t"
 
 /* Annotate a C jump table to allow objtool to follow the code flow */
 #define __annotate_jump_table __section(".rodata..c_jump_table")
 
 #else
-#define annotate_reachable()
 #define annotate_unreachable()
+# define ASM_REACHABLE
 #define __annotate_jump_table
 #endif
 
-#ifndef ASM_UNREACHABLE
-# define ASM_UNREACHABLE
-#endif
 #ifndef unreachable
 # define unreachable() do {            \
        annotate_unreachable();         \
index 1ab29e6..3522a27 100644 (file)
@@ -382,6 +382,9 @@ struct cpufreq_driver {
        int             (*suspend)(struct cpufreq_policy *policy);
        int             (*resume)(struct cpufreq_policy *policy);
 
+       /* Will be called after the driver is fully initialized */
+       void            (*ready)(struct cpufreq_policy *policy);
+
        struct freq_attr **attr;
 
        /* platform specific boost support code */
index dca2b13..6150d11 100644 (file)
  */
 #define DMA_ATTR_PRIVILEGED            (1UL << 9)
 
+/*
+ * This is a hint to the DMA-mapping subsystem that the device is expected
+ * to overwrite the entire mapped size, thus the caller does not require any
+ * of the previous buffer contents to be preserved. This allows
+ * bounce-buffering implementations to optimise DMA_FROM_DEVICE transfers.
+ */
+#define DMA_ATTR_OVERWRITE             (1UL << 10)
+
 /*
  * A dma_addr_t can hold any valid DMA or bus address for the platform.  It can
  * be given to a device to use as a DMA source or target.  It is specific to a
index a26f37a..11efc45 100644 (file)
@@ -111,7 +111,7 @@ struct ethtool_link_ext_state_info {
                enum ethtool_link_ext_substate_bad_signal_integrity bad_signal_integrity;
                enum ethtool_link_ext_substate_cable_issue cable_issue;
                enum ethtool_link_ext_substate_module module;
-               u8 __link_ext_substate;
+               u32 __link_ext_substate;
        };
 };
 
index 3da9584..02f362c 100644 (file)
@@ -262,7 +262,7 @@ struct fb_ops {
 
        /* Draws a rectangle */
        void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
-       /* Copy data from area to another. Obsolete. */
+       /* Copy data from area to another */
        void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
        /* Draws a image to the display */
        void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
index c3e5ab0..aad497a 100644 (file)
@@ -321,8 +321,6 @@ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE)
 #define INTEL_SIP_SMC_ECC_DBE \
        INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_ECC_DBE)
 
-#endif
-
 /**
  * Request INTEL_SIP_SMC_RSU_NOTIFY
  *
@@ -404,3 +402,22 @@ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE)
 #define INTEL_SIP_SMC_FUNCID_RSU_MAX_RETRY 18
 #define INTEL_SIP_SMC_RSU_MAX_RETRY \
        INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_RSU_MAX_RETRY)
+
+/**
+ * Request INTEL_SIP_SMC_FIRMWARE_VERSION
+ *
+ * Sync call used to query the version of running firmware
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_FIRMWARE_VERSION
+ * a1-a7 not used
+ *
+ * Return status:
+ * a0 INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_STATUS_ERROR
+ * a1 running firmware version
+ */
+#define INTEL_SIP_SMC_FUNCID_FIRMWARE_VERSION 31
+#define INTEL_SIP_SMC_FIRMWARE_VERSION \
+        INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FIRMWARE_VERSION)
+
+#endif
index 19781b0..18c1841 100644 (file)
@@ -104,6 +104,9 @@ struct stratix10_svc_chan;
  *
  * @COMMAND_RSU_DCMF_VERSION: query firmware for the DCMF version, return status
  * is SVC_STATUS_OK or SVC_STATUS_ERROR
+ *
+ * @COMMAND_FIRMWARE_VERSION: query running firmware version, return status
+ * is SVC_STATUS_OK or SVC_STATUS_ERROR
  */
 enum stratix10_svc_command_code {
        COMMAND_NOOP = 0,
@@ -117,6 +120,7 @@ enum stratix10_svc_command_code {
        COMMAND_RSU_RETRY,
        COMMAND_RSU_MAX_RETRY,
        COMMAND_RSU_DCMF_VERSION,
+       COMMAND_FIRMWARE_VERSION,
 };
 
 /**
index 907cb01..cf557fb 100644 (file)
@@ -143,6 +143,9 @@ enum pm_ioctl_id {
        IOCTL_OSPI_MUX_SELECT = 21,
        /* Register SGI to ATF */
        IOCTL_REGISTER_SGI = 25,
+       /* Runtime feature configuration */
+       IOCTL_SET_FEATURE_CONFIG = 26,
+       IOCTL_GET_FEATURE_CONFIG = 27,
 };
 
 enum pm_query_id {
@@ -376,6 +379,14 @@ enum ospi_mux_select_type {
        PM_OSPI_MUX_SEL_LINEAR = 1,
 };
 
+enum pm_feature_config_id {
+       PM_FEATURE_INVALID = 0,
+       PM_FEATURE_OVERTEMP_STATUS = 1,
+       PM_FEATURE_OVERTEMP_VALUE = 2,
+       PM_FEATURE_EXTWDT_STATUS = 3,
+       PM_FEATURE_EXTWDT_VALUE = 4,
+};
+
 /**
  * struct zynqmp_pm_query_data - PM query data
  * @qid:       query ID
@@ -447,6 +458,8 @@ int zynqmp_pm_load_pdi(const u32 src, const u64 address);
 int zynqmp_pm_register_notifier(const u32 node, const u32 event,
                                const u32 wake, const u32 enable);
 int zynqmp_pm_feature(const u32 api_id);
+int zynqmp_pm_set_feature_config(enum pm_feature_config_id id, u32 value);
+int zynqmp_pm_get_feature_config(enum pm_feature_config_id id, u32 *payload);
 #else
 static inline int zynqmp_pm_get_api_version(u32 *version)
 {
@@ -689,6 +702,18 @@ static inline int zynqmp_pm_feature(const u32 api_id)
 {
        return -ENODEV;
 }
+
+static inline int zynqmp_pm_set_feature_config(enum pm_feature_config_id id,
+                                              u32 value)
+{
+       return -ENODEV;
+}
+
+static inline int zynqmp_pm_get_feature_config(enum pm_feature_config_id id,
+                                              u32 *payload)
+{
+       return -ENODEV;
+}
 #endif
 
 #endif /* __FIRMWARE_ZYNQMP_H__ */
index f3daaea..e2d892b 100644 (file)
@@ -1483,7 +1483,7 @@ struct super_block {
 #ifdef CONFIG_FS_VERITY
        const struct fsverity_operations *s_vop;
 #endif
-#ifdef CONFIG_UNICODE
+#if IS_ENABLED(CONFIG_UNICODE)
        struct unicode_map *s_encoding;
        __u16 s_encoding_flags;
 #endif
index 3a2d7dc..bb8467c 100644 (file)
@@ -224,6 +224,43 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode,
                      dir, &new_dentry->d_name, 0);
 }
 
+/*
+ * fsnotify_delete - @dentry was unlinked and unhashed
+ *
+ * Caller must make sure that dentry->d_name is stable.
+ *
+ * Note: unlike fsnotify_unlink(), we have to pass also the unlinked inode
+ * as this may be called after d_delete() and old_dentry may be negative.
+ */
+static inline void fsnotify_delete(struct inode *dir, struct inode *inode,
+                                  struct dentry *dentry)
+{
+       __u32 mask = FS_DELETE;
+
+       if (S_ISDIR(inode->i_mode))
+               mask |= FS_ISDIR;
+
+       fsnotify_name(mask, inode, FSNOTIFY_EVENT_INODE, dir, &dentry->d_name,
+                     0);
+}
+
+/**
+ * d_delete_notify - delete a dentry and call fsnotify_delete()
+ * @dentry: The dentry to delete
+ *
+ * This helper is used to guaranty that the unlinked inode cannot be found
+ * by lookup of this name after fsnotify_delete() event has been delivered.
+ */
+static inline void d_delete_notify(struct inode *dir, struct dentry *dentry)
+{
+       struct inode *inode = d_inode(dentry);
+
+       ihold(inode);
+       d_delete(dentry);
+       fsnotify_delete(dir, inode, dentry);
+       iput(inode);
+}
+
 /*
  * fsnotify_unlink - 'name' was unlinked
  *
@@ -231,10 +268,10 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode,
  */
 static inline void fsnotify_unlink(struct inode *dir, struct dentry *dentry)
 {
-       /* Expected to be called before d_delete() */
-       WARN_ON_ONCE(d_is_negative(dentry));
+       if (WARN_ON_ONCE(d_is_negative(dentry)))
+               return;
 
-       fsnotify_dirent(dir, dentry, FS_DELETE);
+       fsnotify_delete(dir, d_inode(dentry), dentry);
 }
 
 /*
@@ -258,10 +295,10 @@ static inline void fsnotify_mkdir(struct inode *dir, struct dentry *dentry)
  */
 static inline void fsnotify_rmdir(struct inode *dir, struct dentry *dentry)
 {
-       /* Expected to be called before d_delete() */
-       WARN_ON_ONCE(d_is_negative(dentry));
+       if (WARN_ON_ONCE(d_is_negative(dentry)))
+               return;
 
-       fsnotify_dirent(dir, dentry, FS_DELETE | FS_ISDIR);
+       fsnotify_delete(dir, d_inode(dentry), dentry);
 }
 
 /*
index f565a89..fe2e017 100644 (file)
@@ -1262,6 +1262,7 @@ struct hv_device {
        struct vmbus_channel *channel;
        struct kset          *channels_kset;
        struct device_dma_parameters dma_parms;
+       u64 dma_mask;
 
        /* place holder to keep track of the dir for hv device in debugfs */
        struct dentry *debug_dir;
index 8420fe5..2be4dd7 100644 (file)
@@ -46,8 +46,10 @@ struct vlan_hdr {
  *     @h_vlan_encapsulated_proto: packet type ID or len
  */
 struct vlan_ethhdr {
-       unsigned char   h_dest[ETH_ALEN];
-       unsigned char   h_source[ETH_ALEN];
+       struct_group(addrs,
+               unsigned char   h_dest[ETH_ALEN];
+               unsigned char   h_source[ETH_ALEN];
+       );
        __be16          h_vlan_proto;
        __be16          h_vlan_TCI;
        __be16          h_vlan_encapsulated_proto;
index b55bd49..97a3a2e 100644 (file)
@@ -263,9 +263,11 @@ struct iomap_ioend {
        struct list_head        io_list;        /* next ioend in chain */
        u16                     io_type;
        u16                     io_flags;       /* IOMAP_F_* */
+       u32                     io_folios;      /* folios added to ioend */
        struct inode            *io_inode;      /* file being written to */
        size_t                  io_size;        /* size of the extent */
        loff_t                  io_offset;      /* offset in the file */
+       sector_t                io_sector;      /* start sector of ioend */
        struct bio              *io_bio;        /* bio being built */
        struct bio              io_inline_bio;  /* MUST BE LAST! */
 };
index fd933c4..9c3ada7 100644 (file)
@@ -594,7 +594,7 @@ struct transaction_s
         */
        unsigned long           t_log_start;
 
-       /* 
+       /*
         * Number of buffers on the t_buffers list [j_list_lock, no locks
         * needed for jbd2 thread]
         */
@@ -1295,7 +1295,7 @@ struct journal_s
         * Clean-up after fast commit or full commit. JBD2 calls this function
         * after every commit operation.
         */
-       void (*j_fc_cleanup_callback)(struct journal_s *journal, int);
+       void (*j_fc_cleanup_callback)(struct journal_s *journal, int full, tid_t tid);
 
        /**
         * @j_fc_replay_callback:
@@ -1419,9 +1419,7 @@ extern void jbd2_journal_unfile_buffer(journal_t *, struct journal_head *);
 extern bool __jbd2_journal_refile_buffer(struct journal_head *);
 extern void jbd2_journal_refile_buffer(journal_t *, struct journal_head *);
 extern void __jbd2_journal_file_buffer(struct journal_head *, transaction_t *, int);
-extern void __journal_free_buffer(struct journal_head *bh);
 extern void jbd2_journal_file_buffer(struct journal_head *, transaction_t *, int);
-extern void __journal_clean_data_list(transaction_t *transaction);
 static inline void jbd2_file_log_bh(struct list_head *head, struct buffer_head *bh)
 {
        list_add_tail(&bh->b_assoc_buffers, head);
@@ -1486,9 +1484,6 @@ extern int jbd2_journal_write_metadata_buffer(transaction_t *transaction,
                                              struct buffer_head **bh_out,
                                              sector_t blocknr);
 
-/* Transaction locking */
-extern void            __wait_on_journal (journal_t *);
-
 /* Transaction cache support */
 extern void jbd2_journal_destroy_transaction_cache(void);
 extern int __init jbd2_journal_init_transaction_cache(void);
@@ -1543,6 +1538,8 @@ extern int         jbd2_journal_flush(journal_t *journal, unsigned int flags);
 extern void     jbd2_journal_lock_updates (journal_t *);
 extern void     jbd2_journal_unlock_updates (journal_t *);
 
+void jbd2_journal_wait_updates(journal_t *);
+
 extern journal_t * jbd2_journal_init_dev(struct block_device *bdev,
                                struct block_device *fs_dev,
                                unsigned long long start, int len, int bsize);
@@ -1774,8 +1771,6 @@ static inline unsigned long jbd2_log_space_left(journal_t *journal)
 #define BJ_Reserved    4       /* Buffer is reserved for access by journal */
 #define BJ_Types       5
 
-extern int jbd_blocks_per_page(struct inode *inode);
-
 /* JBD uses a CRC32 checksum */
 #define JBD_MAX_CHECKSUM_SIZE 4
 
index 4b5e367..f49e642 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/atomic.h>
 #include <linux/static_key.h>
 
+extern unsigned long kfence_sample_interval;
+
 /*
  * We allocate an even number of pages, as it simplifies calculations to map
  * address to metadata indices; effectively, the very first page serves as an
index 06912d6..f110399 100644 (file)
@@ -29,7 +29,9 @@
 #include <linux/refcount.h>
 #include <linux/nospec.h>
 #include <linux/notifier.h>
+#include <linux/ftrace.h>
 #include <linux/hashtable.h>
+#include <linux/instrumentation.h>
 #include <linux/interval_tree.h>
 #include <linux/rbtree.h>
 #include <linux/xarray.h>
@@ -368,8 +370,11 @@ struct kvm_vcpu {
        u64 last_used_slot_gen;
 };
 
-/* must be called with irqs disabled */
-static __always_inline void guest_enter_irqoff(void)
+/*
+ * Start accounting time towards a guest.
+ * Must be called before entering guest context.
+ */
+static __always_inline void guest_timing_enter_irqoff(void)
 {
        /*
         * This is running in ioctl context so its safe to assume that it's the
@@ -378,7 +383,18 @@ static __always_inline void guest_enter_irqoff(void)
        instrumentation_begin();
        vtime_account_guest_enter();
        instrumentation_end();
+}
 
+/*
+ * Enter guest context and enter an RCU extended quiescent state.
+ *
+ * Between guest_context_enter_irqoff() and guest_context_exit_irqoff() it is
+ * unsafe to use any code which may directly or indirectly use RCU, tracing
+ * (including IRQ flag tracing), or lockdep. All code in this period must be
+ * non-instrumentable.
+ */
+static __always_inline void guest_context_enter_irqoff(void)
+{
        /*
         * KVM does not hold any references to rcu protected data when it
         * switches CPU into a guest mode. In fact switching to a guest mode
@@ -394,16 +410,79 @@ static __always_inline void guest_enter_irqoff(void)
        }
 }
 
-static __always_inline void guest_exit_irqoff(void)
+/*
+ * Deprecated. Architectures should move to guest_timing_enter_irqoff() and
+ * guest_state_enter_irqoff().
+ */
+static __always_inline void guest_enter_irqoff(void)
+{
+       guest_timing_enter_irqoff();
+       guest_context_enter_irqoff();
+}
+
+/**
+ * guest_state_enter_irqoff - Fixup state when entering a guest
+ *
+ * Entry to a guest will enable interrupts, but the kernel state is interrupts
+ * disabled when this is invoked. Also tell RCU about it.
+ *
+ * 1) Trace interrupts on state
+ * 2) Invoke context tracking if enabled to adjust RCU state
+ * 3) Tell lockdep that interrupts are enabled
+ *
+ * Invoked from architecture specific code before entering a guest.
+ * Must be called with interrupts disabled and the caller must be
+ * non-instrumentable.
+ * The caller has to invoke guest_timing_enter_irqoff() before this.
+ *
+ * Note: this is analogous to exit_to_user_mode().
+ */
+static __always_inline void guest_state_enter_irqoff(void)
+{
+       instrumentation_begin();
+       trace_hardirqs_on_prepare();
+       lockdep_hardirqs_on_prepare(CALLER_ADDR0);
+       instrumentation_end();
+
+       guest_context_enter_irqoff();
+       lockdep_hardirqs_on(CALLER_ADDR0);
+}
+
+/*
+ * Exit guest context and exit an RCU extended quiescent state.
+ *
+ * Between guest_context_enter_irqoff() and guest_context_exit_irqoff() it is
+ * unsafe to use any code which may directly or indirectly use RCU, tracing
+ * (including IRQ flag tracing), or lockdep. All code in this period must be
+ * non-instrumentable.
+ */
+static __always_inline void guest_context_exit_irqoff(void)
 {
        context_tracking_guest_exit();
+}
 
+/*
+ * Stop accounting time towards a guest.
+ * Must be called after exiting guest context.
+ */
+static __always_inline void guest_timing_exit_irqoff(void)
+{
        instrumentation_begin();
        /* Flush the guest cputime we spent on the guest */
        vtime_account_guest_exit();
        instrumentation_end();
 }
 
+/*
+ * Deprecated. Architectures should move to guest_state_exit_irqoff() and
+ * guest_timing_exit_irqoff().
+ */
+static __always_inline void guest_exit_irqoff(void)
+{
+       guest_context_exit_irqoff();
+       guest_timing_exit_irqoff();
+}
+
 static inline void guest_exit(void)
 {
        unsigned long flags;
@@ -413,6 +492,33 @@ static inline void guest_exit(void)
        local_irq_restore(flags);
 }
 
+/**
+ * guest_state_exit_irqoff - Establish state when returning from guest mode
+ *
+ * Entry from a guest disables interrupts, but guest mode is traced as
+ * interrupts enabled. Also with NO_HZ_FULL RCU might be idle.
+ *
+ * 1) Tell lockdep that interrupts are disabled
+ * 2) Invoke context tracking if enabled to reactivate RCU
+ * 3) Trace interrupts off state
+ *
+ * Invoked from architecture specific code after exiting a guest.
+ * Must be invoked with interrupts disabled and the caller must be
+ * non-instrumentable.
+ * The caller has to invoke guest_timing_exit_irqoff() after this.
+ *
+ * Note: this is analogous to enter_from_user_mode().
+ */
+static __always_inline void guest_state_exit_irqoff(void)
+{
+       lockdep_hardirqs_off(CALLER_ADDR0);
+       guest_context_exit_irqoff();
+
+       instrumentation_begin();
+       trace_hardirqs_off_finish();
+       instrumentation_end();
+}
+
 static inline int kvm_vcpu_exiting_guest_mode(struct kvm_vcpu *vcpu)
 {
        /*
index 605756f..7f99b4d 100644 (file)
@@ -380,6 +380,7 @@ enum {
        ATA_HORKAGE_MAX_TRIM_128M = (1 << 26),  /* Limit max trim size to 128M */
        ATA_HORKAGE_NO_NCQ_ON_ATI = (1 << 27),  /* Disable NCQ on ATI chipset */
        ATA_HORKAGE_NO_ID_DEV_LOG = (1 << 28),  /* Identify device log missing */
+       ATA_HORKAGE_NO_LOG_DIR  = (1 << 29),    /* Do not read log directory */
 
         /* DMA mask for user DMA control: User visible values; DO NOT
            renumber */
index a5a724c..819ec92 100644 (file)
@@ -80,7 +80,7 @@ LSM_HOOK(int, 0, sb_clone_mnt_opts, const struct super_block *oldsb,
         unsigned long *set_kern_flags)
 LSM_HOOK(int, 0, move_mount, const struct path *from_path,
         const struct path *to_path)
-LSM_HOOK(int, 0, dentry_init_security, struct dentry *dentry,
+LSM_HOOK(int, -EOPNOTSUPP, dentry_init_security, struct dentry *dentry,
         int mode, const struct qstr *name, const char **xattr_name,
         void **ctx, u32 *ctxlen)
 LSM_HOOK(int, 0, dentry_create_files_as, struct dentry *dentry, int mode,
index b72d751..0abbd68 100644 (file)
@@ -219,7 +219,7 @@ struct obj_cgroup {
        struct mem_cgroup *memcg;
        atomic_t nr_charged_bytes;
        union {
-               struct list_head list;
+               struct list_head list; /* protected by objcg_lock */
                struct rcu_head rcu;
        };
 };
@@ -315,7 +315,8 @@ struct mem_cgroup {
 #ifdef CONFIG_MEMCG_KMEM
        int kmemcg_id;
        struct obj_cgroup __rcu *objcg;
-       struct list_head objcg_list; /* list of inherited objcgs */
+       /* list of inherited objcgs, protected by objcg_lock */
+       struct list_head objcg_list;
 #endif
 
        MEMCG_PADDING(_pad2_);
index e1a84b1..213cc56 100644 (file)
@@ -1506,11 +1506,18 @@ static inline u8 page_kasan_tag(const struct page *page)
 
 static inline void page_kasan_tag_set(struct page *page, u8 tag)
 {
-       if (kasan_enabled()) {
-               tag ^= 0xff;
-               page->flags &= ~(KASAN_TAG_MASK << KASAN_TAG_PGSHIFT);
-               page->flags |= (tag & KASAN_TAG_MASK) << KASAN_TAG_PGSHIFT;
-       }
+       unsigned long old_flags, flags;
+
+       if (!kasan_enabled())
+               return;
+
+       tag ^= 0xff;
+       old_flags = READ_ONCE(page->flags);
+       do {
+               flags = old_flags;
+               flags &= ~(KASAN_TAG_MASK << KASAN_TAG_PGSHIFT);
+               flags |= (tag & KASAN_TAG_MASK) << KASAN_TAG_PGSHIFT;
+       } while (unlikely(!try_cmpxchg(&page->flags, &old_flags, flags)));
 }
 
 static inline void page_kasan_tag_reset(struct page *page)
index 9db36dc..5140e5f 100644 (file)
@@ -261,6 +261,7 @@ static_assert(sizeof(struct page) == sizeof(struct folio));
        static_assert(offsetof(struct page, pg) == offsetof(struct folio, fl))
 FOLIO_MATCH(flags, flags);
 FOLIO_MATCH(lru, lru);
+FOLIO_MATCH(mapping, mapping);
 FOLIO_MATCH(compound_head, lru);
 FOLIO_MATCH(index, index);
 FOLIO_MATCH(private, private);
index 7a09b04..2e25c83 100644 (file)
 
 struct device;
 struct mux_control;
+struct mux_state;
 
 unsigned int mux_control_states(struct mux_control *mux);
 int __must_check mux_control_select_delay(struct mux_control *mux,
                                          unsigned int state,
                                          unsigned int delay_us);
+int __must_check mux_state_select_delay(struct mux_state *mstate,
+                                       unsigned int delay_us);
 int __must_check mux_control_try_select_delay(struct mux_control *mux,
                                              unsigned int state,
                                              unsigned int delay_us);
+int __must_check mux_state_try_select_delay(struct mux_state *mstate,
+                                           unsigned int delay_us);
 
 static inline int __must_check mux_control_select(struct mux_control *mux,
                                                  unsigned int state)
@@ -29,18 +34,31 @@ static inline int __must_check mux_control_select(struct mux_control *mux,
        return mux_control_select_delay(mux, state, 0);
 }
 
+static inline int __must_check mux_state_select(struct mux_state *mstate)
+{
+       return mux_state_select_delay(mstate, 0);
+}
+
 static inline int __must_check mux_control_try_select(struct mux_control *mux,
                                                      unsigned int state)
 {
        return mux_control_try_select_delay(mux, state, 0);
 }
 
+static inline int __must_check mux_state_try_select(struct mux_state *mstate)
+{
+       return mux_state_try_select_delay(mstate, 0);
+}
+
 int mux_control_deselect(struct mux_control *mux);
+int mux_state_deselect(struct mux_state *mstate);
 
 struct mux_control *mux_control_get(struct device *dev, const char *mux_name);
 void mux_control_put(struct mux_control *mux);
 
 struct mux_control *devm_mux_control_get(struct device *dev,
                                         const char *mux_name);
+struct mux_state *devm_mux_state_get(struct device *dev,
+                                    const char *mux_name);
 
 #endif /* _LINUX_MUX_CONSUMER_H */
index 3213c72..8b5a314 100644 (file)
@@ -2158,7 +2158,7 @@ struct net_device {
        struct netdev_queue     *_tx ____cacheline_aligned_in_smp;
        unsigned int            num_tx_queues;
        unsigned int            real_num_tx_queues;
-       struct Qdisc            *qdisc;
+       struct Qdisc __rcu      *qdisc;
        unsigned int            tx_queue_len;
        spinlock_t              tx_global_lock;
 
@@ -2548,6 +2548,7 @@ struct packet_type {
                                              struct net_device *);
        bool                    (*id_match)(struct packet_type *ptype,
                                            struct sock *sk);
+       struct net              *af_packet_net;
        void                    *af_packet_priv;
        struct list_head        list;
 };
index b46c39d..614f222 100644 (file)
@@ -244,6 +244,13 @@ struct netfs_cache_ops {
        int (*prepare_write)(struct netfs_cache_resources *cres,
                             loff_t *_start, size_t *_len, loff_t i_size,
                             bool no_space_allocated_yet);
+
+       /* Query the occupancy of the cache in a region, returning where the
+        * next chunk of data starts and how long it is.
+        */
+       int (*query_occupancy)(struct netfs_cache_resources *cres,
+                              loff_t start, size_t len, size_t granularity,
+                              loff_t *_data_start, size_t *_data_len);
 };
 
 struct readahead_control;
index 0dc7ad3..b06375e 100644 (file)
@@ -36,14 +36,6 @@ static inline void nfs_copy_fh(struct nfs_fh *target, const struct nfs_fh *sourc
        memcpy(target->data, source->data, source->size);
 }
 
-
-/*
- * This is really a general kernel constant, but since nothing like
- * this is defined in the kernel headers, I have to do it here.
- */
-#define NFS_OFFSET_MAX         ((__s64)((~(__u64)0) >> 1))
-
-
 enum nfs3_stable_how {
        NFS_UNSTABLE = 0,
        NFS_DATA_SYNC = 1,
index 00835ba..68f81d8 100644 (file)
@@ -61,7 +61,9 @@
 struct nfs_access_entry {
        struct rb_node          rb_node;
        struct list_head        lru;
-       const struct cred *     cred;
+       kuid_t                  fsuid;
+       kgid_t                  fsgid;
+       struct group_info       *group_info;
        __u32                   mask;
        struct rcu_head         rcu_head;
 };
@@ -105,6 +107,7 @@ struct nfs_open_dir_context {
        __u64 dup_cookie;
        pgoff_t page_index;
        signed char duped;
+       bool eof;
 };
 
 /*
@@ -395,7 +398,7 @@ extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fa
 extern int nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fattr *fattr);
 extern int nfs_getattr(struct user_namespace *, const struct path *,
                       struct kstat *, u32, unsigned int);
-extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
+extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *, const struct cred *);
 extern void nfs_access_set_mask(struct nfs_access_entry *, u32);
 extern int nfs_permission(struct user_namespace *, struct inode *, int);
 extern int nfs_open(struct inode *, struct file *);
@@ -532,8 +535,8 @@ extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh,
                        struct nfs_fattr *fattr);
 extern int nfs_may_open(struct inode *inode, const struct cred *cred, int openflags);
 extern void nfs_access_zap_cache(struct inode *inode);
-extern int nfs_access_get_cached(struct inode *inode, const struct cred *cred, struct nfs_access_entry *res,
-                                bool may_block);
+extern int nfs_access_get_cached(struct inode *inode, const struct cred *cred,
+                                u32 *mask, bool may_block);
 
 /*
  * linux/fs/nfs/symlink.c
index 77b2dba..ca0959e 100644 (file)
@@ -266,6 +266,8 @@ struct nfs_server {
 #define NFS_CAP_ACLS           (1U << 3)
 #define NFS_CAP_ATOMIC_OPEN    (1U << 4)
 #define NFS_CAP_LGOPEN         (1U << 5)
+#define NFS_CAP_CASE_INSENSITIVE       (1U << 6)
+#define NFS_CAP_CASE_PRESERVING        (1U << 7)
 #define NFS_CAP_POSIX_LOCK     (1U << 14)
 #define NFS_CAP_UIDGID_NOMAP   (1U << 15)
 #define NFS_CAP_STATEID_NFSV41 (1U << 16)
@@ -282,5 +284,5 @@ struct nfs_server {
 #define NFS_CAP_COPY_NOTIFY    (1U << 27)
 #define NFS_CAP_XATTR          (1U << 28)
 #define NFS_CAP_READ_PLUS      (1U << 29)
-
+#define NFS_CAP_FS_LOCATIONS   (1U << 30)
 #endif
index 967a009..728cb0c 100644 (file)
@@ -1194,6 +1194,8 @@ struct nfs4_server_caps_res {
        u32                             has_links;
        u32                             has_symlinks;
        u32                             fh_expire_type;
+       u32                             case_insensitive;
+       u32                             case_preserving;
 };
 
 #define NFS4_PATHNAME_MAXCOMPONENTS 512
@@ -1737,7 +1739,7 @@ struct nfs_rpc_ops {
                            struct nfs_fh *, struct nfs_fattr *);
        int     (*lookupp) (struct inode *, struct nfs_fh *,
                            struct nfs_fattr *);
-       int     (*access)  (struct inode *, struct nfs_access_entry *);
+       int     (*access)  (struct inode *, struct nfs_access_entry *, const struct cred *);
        int     (*readlink)(struct inode *, struct page *, unsigned int,
                            unsigned int);
        int     (*create)  (struct inode *, struct dentry *,
@@ -1795,6 +1797,7 @@ struct nfs_rpc_ops {
        struct nfs_server *(*create_server)(struct fs_context *);
        struct nfs_server *(*clone_server)(struct nfs_server *, struct nfs_fh *,
                                           struct nfs_fattr *, rpc_authflavor_t);
+       int     (*discover_trunking)(struct nfs_server *, struct nfs_fh *);
 };
 
 /*
index 959e0bd..7547015 100644 (file)
@@ -12,6 +12,7 @@
 #define NVME_TCP_DISC_PORT     8009
 #define NVME_TCP_ADMIN_CCSZ    SZ_8K
 #define NVME_TCP_DIGEST_LENGTH 4
+#define NVME_TCP_MIN_MAXH2CDATA 4096
 
 enum nvme_tcp_pfv {
        NVME_TCP_PFV_1_0 = 0x0,
index 98efb7b..50caa11 100644 (file)
@@ -70,7 +70,8 @@ struct nvmem_keepout {
  * @word_size: Minimum read/write access granularity.
  * @stride:    Minimum read/write access stride.
  * @priv:      User context passed to read/write callbacks.
- * @wp-gpio:   Write protect pin
+ * @wp-gpio:   Write protect pin
+ * @ignore_wp:  Write Protect pin is managed by the provider.
  *
  * Note: A default "nvmem<id>" name will be assigned to the device if
  * no name is specified in its configuration. In such case "<id>" is
@@ -92,6 +93,7 @@ struct nvmem_config {
        enum nvmem_type         type;
        bool                    read_only;
        bool                    root_only;
+       bool                    ignore_wp;
        struct device_node      *of_node;
        bool                    no_of_node;
        nvmem_reg_read_t        reg_read;
@@ -133,8 +135,6 @@ void nvmem_unregister(struct nvmem_device *nvmem);
 struct nvmem_device *devm_nvmem_register(struct device *dev,
                                         const struct nvmem_config *cfg);
 
-int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem);
-
 void nvmem_add_cell_table(struct nvmem_cell_table *table);
 void nvmem_del_cell_table(struct nvmem_cell_table *table);
 
@@ -153,12 +153,6 @@ devm_nvmem_register(struct device *dev, const struct nvmem_config *c)
        return nvmem_register(c);
 }
 
-static inline int
-devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem)
-{
-       return -EOPNOTSUPP;
-}
-
 static inline void nvmem_add_cell_table(struct nvmem_cell_table *table) {}
 static inline void nvmem_del_cell_table(struct nvmem_cell_table *table) {}
 
index 38cace1..01e16c7 100644 (file)
@@ -26,6 +26,9 @@ void __page_table_check_pmd_set(struct mm_struct *mm, unsigned long addr,
                                pmd_t *pmdp, pmd_t pmd);
 void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr,
                                pud_t *pudp, pud_t pud);
+void __page_table_check_pte_clear_range(struct mm_struct *mm,
+                                       unsigned long addr,
+                                       pmd_t pmd);
 
 static inline void page_table_check_alloc(struct page *page, unsigned int order)
 {
@@ -100,6 +103,16 @@ static inline void page_table_check_pud_set(struct mm_struct *mm,
        __page_table_check_pud_set(mm, addr, pudp, pud);
 }
 
+static inline void page_table_check_pte_clear_range(struct mm_struct *mm,
+                                                   unsigned long addr,
+                                                   pmd_t pmd)
+{
+       if (static_branch_likely(&page_table_check_disabled))
+               return;
+
+       __page_table_check_pte_clear_range(mm, addr, pmd);
+}
+
 #else
 
 static inline void page_table_check_alloc(struct page *page, unsigned int order)
@@ -143,5 +156,11 @@ static inline void page_table_check_pud_set(struct mm_struct *mm,
 {
 }
 
+static inline void page_table_check_pte_clear_range(struct mm_struct *mm,
+                                                   unsigned long addr,
+                                                   pmd_t pmd)
+{
+}
+
 #endif /* CONFIG_PAGE_TABLE_CHECK */
 #endif /* __LINUX_PAGE_TABLE_CHECK_H */
diff --git a/include/linux/peci-cpu.h b/include/linux/peci-cpu.h
new file mode 100644 (file)
index 0000000..ff8ae9c
--- /dev/null
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2021 Intel Corporation */
+
+#ifndef __LINUX_PECI_CPU_H
+#define __LINUX_PECI_CPU_H
+
+#include <linux/types.h>
+
+#include "../../arch/x86/include/asm/intel-family.h"
+
+#define PECI_PCS_PKG_ID                        0  /* Package Identifier Read */
+#define  PECI_PKG_ID_CPU_ID            0x0000  /* CPUID Info */
+#define  PECI_PKG_ID_PLATFORM_ID       0x0001  /* Platform ID */
+#define  PECI_PKG_ID_DEVICE_ID         0x0002  /* Uncore Device ID */
+#define  PECI_PKG_ID_MAX_THREAD_ID     0x0003  /* Max Thread ID */
+#define  PECI_PKG_ID_MICROCODE_REV     0x0004  /* CPU Microcode Update Revision */
+#define  PECI_PKG_ID_MCA_ERROR_LOG     0x0005  /* Machine Check Status */
+#define PECI_PCS_MODULE_TEMP           9  /* Per Core DTS Temperature Read */
+#define PECI_PCS_THERMAL_MARGIN                10 /* DTS thermal margin */
+#define PECI_PCS_DDR_DIMM_TEMP         14 /* DDR DIMM Temperature */
+#define PECI_PCS_TEMP_TARGET           16 /* Temperature Target Read */
+#define PECI_PCS_TDP_UNITS             30 /* Units for power/energy registers */
+
+struct peci_device;
+
+int peci_temp_read(struct peci_device *device, s16 *temp_raw);
+
+int peci_pcs_read(struct peci_device *device, u8 index,
+                 u16 param, u32 *data);
+
+int peci_pci_local_read(struct peci_device *device, u8 bus, u8 dev,
+                       u8 func, u16 reg, u32 *data);
+
+int peci_ep_pci_local_read(struct peci_device *device, u8 seg,
+                          u8 bus, u8 dev, u8 func, u16 reg, u32 *data);
+
+int peci_mmio_read(struct peci_device *device, u8 bar, u8 seg,
+                  u8 bus, u8 dev, u8 func, u64 address, u32 *data);
+
+#endif /* __LINUX_PECI_CPU_H */
diff --git a/include/linux/peci.h b/include/linux/peci.h
new file mode 100644 (file)
index 0000000..06e6ef9
--- /dev/null
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2018-2021 Intel Corporation */
+
+#ifndef __LINUX_PECI_H
+#define __LINUX_PECI_H
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+/*
+ * Currently we don't support any PECI command over 32 bytes.
+ */
+#define PECI_REQUEST_MAX_BUF_SIZE 32
+
+struct peci_controller;
+struct peci_request;
+
+/**
+ * struct peci_controller_ops - PECI controller specific methods
+ * @xfer: PECI transfer function
+ *
+ * PECI controllers may have different hardware interfaces - the drivers
+ * implementing PECI controllers can use this structure to abstract away those
+ * differences by exposing a common interface for PECI core.
+ */
+struct peci_controller_ops {
+       int (*xfer)(struct peci_controller *controller, u8 addr, struct peci_request *req);
+};
+
+/**
+ * struct peci_controller - PECI controller
+ * @dev: device object to register PECI controller to the device model
+ * @ops: pointer to device specific controller operations
+ * @bus_lock: lock used to protect multiple callers
+ * @id: PECI controller ID
+ *
+ * PECI controllers usually connect to their drivers using non-PECI bus,
+ * such as the platform bus.
+ * Each PECI controller can communicate with one or more PECI devices.
+ */
+struct peci_controller {
+       struct device dev;
+       struct peci_controller_ops *ops;
+       struct mutex bus_lock; /* held for the duration of xfer */
+       u8 id;
+};
+
+struct peci_controller *devm_peci_controller_add(struct device *parent,
+                                                struct peci_controller_ops *ops);
+
+static inline struct peci_controller *to_peci_controller(void *d)
+{
+       return container_of(d, struct peci_controller, dev);
+}
+
+/**
+ * struct peci_device - PECI device
+ * @dev: device object to register PECI device to the device model
+ * @controller: manages the bus segment hosting this PECI device
+ * @info: PECI device characteristics
+ * @info.family: device family
+ * @info.model: device model
+ * @info.peci_revision: PECI revision supported by the PECI device
+ * @info.socket_id: the socket ID represented by the PECI device
+ * @addr: address used on the PECI bus connected to the parent controller
+ * @deleted: indicates that PECI device was already deleted
+ *
+ * A peci_device identifies a single device (i.e. CPU) connected to a PECI bus.
+ * The behaviour exposed to the rest of the system is defined by the PECI driver
+ * managing the device.
+ */
+struct peci_device {
+       struct device dev;
+       struct {
+               u16 family;
+               u8 model;
+               u8 peci_revision;
+               u8 socket_id;
+       } info;
+       u8 addr;
+       bool deleted;
+};
+
+static inline struct peci_device *to_peci_device(struct device *d)
+{
+       return container_of(d, struct peci_device, dev);
+}
+
+/**
+ * struct peci_request - PECI request
+ * @device: PECI device to which the request is sent
+ * @tx: TX buffer specific data
+ * @tx.buf: TX buffer
+ * @tx.len: transfer data length in bytes
+ * @rx: RX buffer specific data
+ * @rx.buf: RX buffer
+ * @rx.len: received data length in bytes
+ *
+ * A peci_request represents a request issued by PECI originator (TX) and
+ * a response received from PECI responder (RX).
+ */
+struct peci_request {
+       struct peci_device *device;
+       struct {
+               u8 buf[PECI_REQUEST_MAX_BUF_SIZE];
+               u8 len;
+       } rx, tx;
+};
+
+#endif /* __LINUX_PECI_H */
index 117f230..7336491 100644 (file)
@@ -693,18 +693,6 @@ struct perf_event {
        u64                             total_time_running;
        u64                             tstamp;
 
-       /*
-        * timestamp shadows the actual context timing but it can
-        * be safely used in NMI interrupt context. It reflects the
-        * context time as it was when the event was last scheduled in,
-        * or when ctx_sched_in failed to schedule the event because we
-        * run out of PMC.
-        *
-        * ctx_time already accounts for ctx->timestamp. Therefore to
-        * compute ctx_time for a sample, simply add perf_clock().
-        */
-       u64                             shadow_ctx_time;
-
        struct perf_event_attr          attr;
        u16                             header_size;
        u16                             id_header_size;
@@ -852,6 +840,7 @@ struct perf_event_context {
         */
        u64                             time;
        u64                             timestamp;
+       u64                             timeoffset;
 
        /*
         * These fields let us detect when two contexts have both
@@ -934,6 +923,8 @@ struct bpf_perf_event_data_kern {
 struct perf_cgroup_info {
        u64                             time;
        u64                             timestamp;
+       u64                             timeoffset;
+       int                             active;
 };
 
 struct perf_cgroup {
index bc8713a..f4f4077 100644 (file)
@@ -62,6 +62,7 @@ static inline unsigned long pte_index(unsigned long address)
 {
        return (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
 }
+#define pte_index pte_index
 
 #ifndef pmd_index
 static inline unsigned long pmd_index(unsigned long address)
index 7c7e627..07481bb 100644 (file)
@@ -86,4 +86,9 @@ extern struct pid_namespace *task_active_pid_ns(struct task_struct *tsk);
 void pidhash_init(void);
 void pid_idr_init(void);
 
+static inline bool task_is_in_init_pid_ns(struct task_struct *tsk)
+{
+       return task_active_pid_ns(tsk) == &init_pid_ns;
+}
+
 #endif /* _LINUX_PID_NS_H */
index a70ca83..7f7d1d8 100644 (file)
@@ -25,18 +25,17 @@ void psi_memstall_enter(unsigned long *flags);
 void psi_memstall_leave(unsigned long *flags);
 
 int psi_show(struct seq_file *s, struct psi_group *group, enum psi_res res);
-
-#ifdef CONFIG_CGROUPS
-int psi_cgroup_alloc(struct cgroup *cgrp);
-void psi_cgroup_free(struct cgroup *cgrp);
-void cgroup_move_task(struct task_struct *p, struct css_set *to);
-
 struct psi_trigger *psi_trigger_create(struct psi_group *group,
                        char *buf, size_t nbytes, enum psi_res res);
-void psi_trigger_replace(void **trigger_ptr, struct psi_trigger *t);
+void psi_trigger_destroy(struct psi_trigger *t);
 
 __poll_t psi_trigger_poll(void **trigger_ptr, struct file *file,
                        poll_table *wait);
+
+#ifdef CONFIG_CGROUPS
+int psi_cgroup_alloc(struct cgroup *cgrp);
+void psi_cgroup_free(struct cgroup *cgrp);
+void cgroup_move_task(struct task_struct *p, struct css_set *to);
 #endif
 
 #else /* CONFIG_PSI */
index 516c0fe..1a3cef2 100644 (file)
@@ -141,9 +141,6 @@ struct psi_trigger {
         * events to one per window
         */
        u64 last_event_time;
-
-       /* Refcounting to prevent premature destruction */
-       struct kref refcount;
 };
 
 struct psi_group {
index 18ebd39..fd692b4 100644 (file)
@@ -91,7 +91,7 @@ extern bool qid_valid(struct kqid qid);
  *
  *     When there is no mapping defined for the user-namespace, type,
  *     qid tuple an invalid kqid is returned.  Callers are expected to
- *     test for and handle handle invalid kqids being returned.
+ *     test for and handle invalid kqids being returned.
  *     Invalid kqids may be tested for using qid_valid().
  */
 static inline struct kqid make_kqid(struct user_namespace *from,
index 4ab7bfc..3d780b4 100644 (file)
@@ -1095,7 +1095,7 @@ struct pcr_ops {
        unsigned int    (*cd_deglitch)(struct rtsx_pcr *pcr);
        int             (*conv_clk_and_div_n)(int clk, int dir);
        void            (*fetch_vendor_settings)(struct rtsx_pcr *pcr);
-       void            (*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state);
+       void            (*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state, bool runtime);
        void            (*stop_cmd)(struct rtsx_pcr *pcr);
 
        void (*set_aspm)(struct rtsx_pcr *pcr, bool enable);
@@ -1201,8 +1201,6 @@ struct rtsx_pcr {
        unsigned int                    card_exist;
 
        struct delayed_work             carddet_work;
-       struct delayed_work             idle_work;
-       struct delayed_work             rtd3_work;
 
        spinlock_t                      lock;
        struct mutex                    pcr_mutex;
@@ -1212,7 +1210,6 @@ struct rtsx_pcr {
        unsigned int                    cur_clock;
        bool                            remove_pci;
        bool                            msi_en;
-       bool                            is_runtime_suspended;
 
 #define EXTRA_CAPS_SD_SDR50            (1 << 0)
 #define EXTRA_CAPS_SD_SDR104           (1 << 1)
index 508b91d..75ba8aa 100644 (file)
@@ -619,10 +619,6 @@ struct sched_dl_entity {
         * task has to wait for a replenishment to be performed at the
         * next firing of dl_timer.
         *
-        * @dl_boosted tells if we are boosted due to DI. If so we are
-        * outside bandwidth enforcement mechanism (but only until we
-        * exit the critical section);
-        *
         * @dl_yielded tells if task gave up the CPU before consuming
         * all its available runtime during the last job.
         *
@@ -1684,7 +1680,6 @@ extern struct pid *cad_pid;
 #define PF_MEMALLOC            0x00000800      /* Allocating memory */
 #define PF_NPROC_EXCEEDED      0x00001000      /* set_user() noticed that RLIMIT_NPROC was exceeded */
 #define PF_USED_MATH           0x00002000      /* If unset the fpu must be initialized before use */
-#define PF_USED_ASYNC          0x00004000      /* Used async_schedule*(), used by module init */
 #define PF_NOFREEZE            0x00008000      /* This thread should not be frozen */
 #define PF_FROZEN              0x00010000      /* Frozen for system suspend */
 #define PF_KSWAPD              0x00020000      /* I am kswapd */
index b9198a1..e84e54d 100644 (file)
@@ -54,8 +54,8 @@ extern asmlinkage void schedule_tail(struct task_struct *prev);
 extern void init_idle(struct task_struct *idle, int cpu);
 
 extern int sched_fork(unsigned long clone_flags, struct task_struct *p);
-extern void sched_post_fork(struct task_struct *p,
-                           struct kernel_clone_args *kargs);
+extern void sched_cgroup_fork(struct task_struct *p, struct kernel_clone_args *kargs);
+extern void sched_post_fork(struct task_struct *p);
 extern void sched_dead(struct task_struct *p);
 
 void __noreturn do_task_dead(void);
index bf11e1f..8a636e6 100644 (file)
@@ -318,7 +318,7 @@ enum skb_drop_reason {
        SKB_DROP_REASON_NO_SOCKET,
        SKB_DROP_REASON_PKT_TOO_SMALL,
        SKB_DROP_REASON_TCP_CSUM,
-       SKB_DROP_REASON_TCP_FILTER,
+       SKB_DROP_REASON_SOCKET_FILTER,
        SKB_DROP_REASON_UDP_CSUM,
        SKB_DROP_REASON_MAX,
 };
index 37bde99..5b6193f 100644 (file)
@@ -660,8 +660,7 @@ static inline __alloc_size(1, 2) void *kcalloc(size_t n, size_t size, gfp_t flag
  * allocator where we care about the real place the memory allocation
  * request comes from.
  */
-extern void *__kmalloc_track_caller(size_t size, gfp_t flags, unsigned long caller)
-                                  __alloc_size(1);
+extern void *__kmalloc_track_caller(size_t size, gfp_t flags, unsigned long caller);
 #define kmalloc_track_caller(size, flags) \
        __kmalloc_track_caller(size, flags, _RET_IP_)
 
index 5785d90..300273f 100644 (file)
@@ -430,15 +430,7 @@ struct platform_hibernation_ops {
 
 #ifdef CONFIG_HIBERNATION
 /* kernel/power/snapshot.c */
-extern void __register_nosave_region(unsigned long b, unsigned long e, int km);
-static inline void __init register_nosave_region(unsigned long b, unsigned long e)
-{
-       __register_nosave_region(b, e, 0);
-}
-static inline void __init register_nosave_region_late(unsigned long b, unsigned long e)
-{
-       __register_nosave_region(b, e, 1);
-}
+extern void register_nosave_region(unsigned long b, unsigned long e);
 extern int swsusp_page_is_forbidden(struct page *);
 extern void swsusp_set_page_free(struct page *);
 extern void swsusp_unset_page_free(struct page *);
@@ -458,7 +450,6 @@ int pfn_is_nosave(unsigned long pfn);
 int hibernate_quiet_exec(int (*func)(void *data), void *data);
 #else /* CONFIG_HIBERNATION */
 static inline void register_nosave_region(unsigned long b, unsigned long e) {}
-static inline void register_nosave_region_late(unsigned long b, unsigned long e) {}
 static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
 static inline void swsusp_set_page_free(struct page *p) {}
 static inline void swsusp_unset_page_free(struct page *p) {}
@@ -506,14 +497,14 @@ extern void ksys_sync_helper(void);
 
 /* drivers/base/power/wakeup.c */
 extern bool events_check_enabled;
-extern unsigned int pm_wakeup_irq;
 extern suspend_state_t pm_suspend_target_state;
 
 extern bool pm_wakeup_pending(void);
 extern void pm_system_wakeup(void);
 extern void pm_system_cancel_wakeup(void);
-extern void pm_wakeup_clear(bool reset);
+extern void pm_wakeup_clear(unsigned int irq_number);
 extern void pm_system_irq_wakeup(unsigned int irq_number);
+extern unsigned int pm_wakeup_irq(void);
 extern bool pm_get_wakeup_count(unsigned int *count, bool block);
 extern bool pm_save_wakeup_count(unsigned int count);
 extern void pm_wakep_autosleep_enabled(bool set);
index 180adf7..6353d6d 100644 (file)
@@ -265,7 +265,7 @@ static inline struct ctl_table_header *register_sysctl_table(struct ctl_table *
        return NULL;
 }
 
-static inline struct sysctl_header *register_sysctl_mount_point(const char *path)
+static inline struct ctl_table_header *register_sysctl_mount_point(const char *path)
 {
        return NULL;
 }
index 70c069a..dcea51f 100644 (file)
@@ -699,6 +699,8 @@ event_triggers_post_call(struct trace_event_file *file,
 
 bool trace_event_ignore_this_pid(struct trace_event_file *trace_file);
 
+bool __trace_trigger_soft_disabled(struct trace_event_file *file);
+
 /**
  * trace_trigger_soft_disabled - do triggers and test if soft disabled
  * @file: The file pointer of the event to test
@@ -708,20 +710,20 @@ bool trace_event_ignore_this_pid(struct trace_event_file *trace_file);
  * triggers that require testing the fields, it will return true,
  * otherwise false.
  */
-static inline bool
+static __always_inline bool
 trace_trigger_soft_disabled(struct trace_event_file *file)
 {
        unsigned long eflags = file->flags;
 
-       if (!(eflags & EVENT_FILE_FL_TRIGGER_COND)) {
-               if (eflags & EVENT_FILE_FL_TRIGGER_MODE)
-                       event_triggers_call(file, NULL, NULL, NULL);
-               if (eflags & EVENT_FILE_FL_SOFT_DISABLED)
-                       return true;
-               if (eflags & EVENT_FILE_FL_PID_FILTER)
-                       return trace_event_ignore_this_pid(file);
-       }
-       return false;
+       if (likely(!(eflags & (EVENT_FILE_FL_TRIGGER_MODE |
+                              EVENT_FILE_FL_SOFT_DISABLED |
+                              EVENT_FILE_FL_PID_FILTER))))
+               return false;
+
+       if (likely(eflags & EVENT_FILE_FL_TRIGGER_COND))
+               return false;
+
+       return __trace_trigger_soft_disabled(file);
 }
 
 #ifdef CONFIG_BPF_EVENTS
index 031f148..b5deafd 100644 (file)
@@ -91,6 +91,12 @@ fwnode_usb_role_switch_get(struct fwnode_handle *node)
 
 static inline void usb_role_switch_put(struct usb_role_switch *sw) { }
 
+static inline struct usb_role_switch *
+usb_role_switch_find_by_fwnode(const struct fwnode_handle *fwnode)
+{
+       return NULL;
+}
+
 static inline struct usb_role_switch *
 usb_role_switch_register(struct device *parent,
                         const struct usb_role_switch_desc *desc)
index e36cb11..6fb663b 100644 (file)
 #include <linux/bits.h>
 
 /* Register offsets. */
-#define VMCI_STATUS_ADDR      0x00
-#define VMCI_CONTROL_ADDR     0x04
-#define VMCI_ICR_ADDR        0x08
-#define VMCI_IMR_ADDR         0x0c
-#define VMCI_DATA_OUT_ADDR    0x10
-#define VMCI_DATA_IN_ADDR     0x14
-#define VMCI_CAPS_ADDR        0x18
-#define VMCI_RESULT_LOW_ADDR  0x1c
-#define VMCI_RESULT_HIGH_ADDR 0x20
+#define VMCI_STATUS_ADDR        0x00
+#define VMCI_CONTROL_ADDR       0x04
+#define VMCI_ICR_ADDR           0x08
+#define VMCI_IMR_ADDR           0x0c
+#define VMCI_DATA_OUT_ADDR      0x10
+#define VMCI_DATA_IN_ADDR       0x14
+#define VMCI_CAPS_ADDR          0x18
+#define VMCI_RESULT_LOW_ADDR    0x1c
+#define VMCI_RESULT_HIGH_ADDR   0x20
+#define VMCI_DATA_OUT_LOW_ADDR  0x24
+#define VMCI_DATA_OUT_HIGH_ADDR 0x28
+#define VMCI_DATA_IN_LOW_ADDR   0x2c
+#define VMCI_DATA_IN_HIGH_ADDR  0x30
+#define VMCI_GUEST_PAGE_SHIFT   0x34
 
 /* Max number of devices. */
 #define VMCI_MAX_DEVICES 1
 #define VMCI_CAPS_DATAGRAM      BIT(2)
 #define VMCI_CAPS_NOTIFICATIONS BIT(3)
 #define VMCI_CAPS_PPN64         BIT(4)
+#define VMCI_CAPS_DMA_DATAGRAM  BIT(5)
 
 /* Interrupt Cause register bits. */
 #define VMCI_ICR_DATAGRAM      BIT(0)
 #define VMCI_ICR_NOTIFICATION  BIT(1)
+#define VMCI_ICR_DMA_DATAGRAM  BIT(2)
 
 /* Interrupt Mask register bits. */
 #define VMCI_IMR_DATAGRAM      BIT(0)
 #define VMCI_IMR_NOTIFICATION  BIT(1)
+#define VMCI_IMR_DMA_DATAGRAM  BIT(2)
 
-/* Maximum MSI/MSI-X interrupt vectors in the device. */
-#define VMCI_MAX_INTRS 2
+/*
+ * Maximum MSI/MSI-X interrupt vectors in the device.
+ * If VMCI_CAPS_DMA_DATAGRAM is supported by the device,
+ * VMCI_MAX_INTRS_DMA_DATAGRAM vectors are available,
+ * otherwise only VMCI_MAX_INTRS_NOTIFICATION.
+ */
+#define VMCI_MAX_INTRS_NOTIFICATION 2
+#define VMCI_MAX_INTRS_DMA_DATAGRAM 3
+#define VMCI_MAX_INTRS              VMCI_MAX_INTRS_DMA_DATAGRAM
 
 /*
  * Supported interrupt vectors.  There is one for each ICR value above,
@@ -58,6 +73,7 @@
 enum {
        VMCI_INTR_DATAGRAM = 0,
        VMCI_INTR_NOTIFICATION = 1,
+       VMCI_INTR_DMA_DATAGRAM = 2,
 };
 
 /*
@@ -82,6 +98,52 @@ enum {
  */
 #define VMCI_MAX_PINNED_QP_MEMORY ((size_t)(32 * 1024))
 
+/*
+ * The version of the VMCI device that supports MMIO access to registers
+ * requests 256KB for BAR1 whereas the version of VMCI that supports
+ * MSI/MSI-X only requests 8KB. The layout of the larger 256KB region is:
+ * - the first 128KB are used for MSI/MSI-X.
+ * - the following 64KB are used for MMIO register access.
+ * - the remaining 64KB are unused.
+ */
+#define VMCI_WITH_MMIO_ACCESS_BAR_SIZE ((size_t)(256 * 1024))
+#define VMCI_MMIO_ACCESS_OFFSET        ((size_t)(128 * 1024))
+#define VMCI_MMIO_ACCESS_SIZE          ((size_t)(64 * 1024))
+
+/*
+ * For VMCI devices supporting the VMCI_CAPS_DMA_DATAGRAM capability, the
+ * sending and receiving of datagrams can be performed using DMA to/from
+ * a driver allocated buffer.
+ * Sending and receiving will be handled as follows:
+ * - when sending datagrams, the driver initializes the buffer where the
+ *   data part will refer to the outgoing VMCI datagram, sets the busy flag
+ *   to 1 and writes the address of the buffer to VMCI_DATA_OUT_HIGH_ADDR
+ *   and VMCI_DATA_OUT_LOW_ADDR. Writing to VMCI_DATA_OUT_LOW_ADDR triggers
+ *   the device processing of the buffer. When the device has processed the
+ *   buffer, it will write the result value to the buffer and then clear the
+ *   busy flag.
+ * - when receiving datagrams, the driver initializes the buffer where the
+ *   data part will describe the receive buffer, clears the busy flag and
+ *   writes the address of the buffer to VMCI_DATA_IN_HIGH_ADDR and
+ *   VMCI_DATA_IN_LOW_ADDR. Writing to VMCI_DATA_IN_LOW_ADDR triggers the
+ *   device processing of the buffer. The device will copy as many available
+ *   datagrams into the buffer as possible, and then sets the busy flag.
+ *   When the busy flag is set, the driver will process the datagrams in the
+ *   buffer.
+ */
+struct vmci_data_in_out_header {
+       uint32_t busy;
+       uint32_t opcode;
+       uint32_t size;
+       uint32_t rsvd;
+       uint64_t result;
+};
+
+struct vmci_sg_elem {
+       uint64_t addr;
+       uint64_t size;
+};
+
 /*
  * We have a fixed set of resource IDs available in the VMX.
  * This allows us to have a very simple implementation since we statically
index 78ea3e3..59940e2 100644 (file)
@@ -6,6 +6,8 @@
 #define RTR_SOLICITATION_INTERVAL      (4*HZ)
 #define RTR_SOLICITATION_MAX_INTERVAL  (3600*HZ)       /* 1 hour */
 
+#define MIN_VALID_LIFETIME             (2*3600)        /* 2 hours */
+
 #define TEMP_VALID_LIFETIME            (7*86400)
 #define TEMP_PREFERRED_LIFETIME                (86400)
 #define REGEN_MAX_RETRY                        (3)
@@ -107,8 +109,6 @@ struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net,
 int ipv6_dev_get_saddr(struct net *net, const struct net_device *dev,
                       const struct in6_addr *daddr, unsigned int srcprefs,
                       struct in6_addr *saddr);
-int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr,
-                     u32 banned_flags);
 int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
                    u32 banned_flags);
 bool inet_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2,
index 526e495..8221af1 100644 (file)
@@ -239,6 +239,7 @@ typedef struct ax25_dev {
 #if defined(CONFIG_AX25_DAMA_SLAVE) || defined(CONFIG_AX25_DAMA_MASTER)
        ax25_dama_info          dama;
 #endif
+       refcount_t              refcount;
 } ax25_dev;
 
 typedef struct ax25_cb {
@@ -293,6 +294,17 @@ static __inline__ void ax25_cb_put(ax25_cb *ax25)
        }
 }
 
+static inline void ax25_dev_hold(ax25_dev *ax25_dev)
+{
+       refcount_inc(&ax25_dev->refcount);
+}
+
+static inline void ax25_dev_put(ax25_dev *ax25_dev)
+{
+       if (refcount_dec_and_test(&ax25_dev->refcount)) {
+               kfree(ax25_dev);
+       }
+}
 static inline __be16 ax25_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
        skb->dev      = dev;
index 38785d4..184105d 100644 (file)
@@ -262,7 +262,7 @@ struct ad_system {
 struct ad_bond_info {
        struct ad_system system;        /* 802.3ad system structure */
        struct bond_3ad_stats stats;
-       u32 agg_select_timer;           /* Timer to select aggregator after all adapter's hand shakes */
+       atomic_t agg_select_timer;              /* Timer to select aggregator after all adapter's hand shakes */
        u16 aggregator_identifier;
 };
 
index f6ae3a4..83cfd2d 100644 (file)
@@ -346,7 +346,7 @@ static inline bool bond_uses_primary(struct bonding *bond)
 
 static inline struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond)
 {
-       struct slave *slave = rcu_dereference(bond->curr_active_slave);
+       struct slave *slave = rcu_dereference_rtnl(bond->curr_active_slave);
 
        return bond_uses_primary(bond) && slave ? slave->dev : NULL;
 }
index 5218041..79c67f1 100644 (file)
@@ -22,7 +22,7 @@
 #include <asm/checksum.h>
 
 #ifndef _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
-static inline
+static __always_inline
 __wsum csum_and_copy_from_user (const void __user *src, void *dst,
                                      int len)
 {
@@ -33,7 +33,7 @@ __wsum csum_and_copy_from_user (const void __user *src, void *dst,
 #endif
 
 #ifndef HAVE_CSUM_COPY_USER
-static __inline__ __wsum csum_and_copy_to_user
+static __always_inline __wsum csum_and_copy_to_user
 (const void *src, void __user *dst, int len)
 {
        __wsum sum = csum_partial(src, len, ~0U);
@@ -45,7 +45,7 @@ static __inline__ __wsum csum_and_copy_to_user
 #endif
 
 #ifndef _HAVE_ARCH_CSUM_AND_COPY
-static inline __wsum
+static __always_inline __wsum
 csum_partial_copy_nocheck(const void *src, void *dst, int len)
 {
        memcpy(dst, src, len);
@@ -54,7 +54,7 @@ csum_partial_copy_nocheck(const void *src, void *dst, int len)
 #endif
 
 #ifndef HAVE_ARCH_CSUM_ADD
-static inline __wsum csum_add(__wsum csum, __wsum addend)
+static __always_inline __wsum csum_add(__wsum csum, __wsum addend)
 {
        u32 res = (__force u32)csum;
        res += (__force u32)addend;
@@ -62,12 +62,12 @@ static inline __wsum csum_add(__wsum csum, __wsum addend)
 }
 #endif
 
-static inline __wsum csum_sub(__wsum csum, __wsum addend)
+static __always_inline __wsum csum_sub(__wsum csum, __wsum addend)
 {
        return csum_add(csum, ~addend);
 }
 
-static inline __sum16 csum16_add(__sum16 csum, __be16 addend)
+static __always_inline __sum16 csum16_add(__sum16 csum, __be16 addend)
 {
        u16 res = (__force u16)csum;
 
@@ -75,12 +75,12 @@ static inline __sum16 csum16_add(__sum16 csum, __be16 addend)
        return (__force __sum16)(res + (res < (__force u16)addend));
 }
 
-static inline __sum16 csum16_sub(__sum16 csum, __be16 addend)
+static __always_inline __sum16 csum16_sub(__sum16 csum, __be16 addend)
 {
        return csum16_add(csum, ~addend);
 }
 
-static inline __wsum csum_shift(__wsum sum, int offset)
+static __always_inline __wsum csum_shift(__wsum sum, int offset)
 {
        /* rotate sum to align it with a 16b boundary */
        if (offset & 1)
@@ -88,42 +88,43 @@ static inline __wsum csum_shift(__wsum sum, int offset)
        return sum;
 }
 
-static inline __wsum
+static __always_inline __wsum
 csum_block_add(__wsum csum, __wsum csum2, int offset)
 {
        return csum_add(csum, csum_shift(csum2, offset));
 }
 
-static inline __wsum
+static __always_inline __wsum
 csum_block_add_ext(__wsum csum, __wsum csum2, int offset, int len)
 {
        return csum_block_add(csum, csum2, offset);
 }
 
-static inline __wsum
+static __always_inline __wsum
 csum_block_sub(__wsum csum, __wsum csum2, int offset)
 {
        return csum_block_add(csum, ~csum2, offset);
 }
 
-static inline __wsum csum_unfold(__sum16 n)
+static __always_inline __wsum csum_unfold(__sum16 n)
 {
        return (__force __wsum)n;
 }
 
-static inline __wsum csum_partial_ext(const void *buff, int len, __wsum sum)
+static __always_inline
+__wsum csum_partial_ext(const void *buff, int len, __wsum sum)
 {
        return csum_partial(buff, len, sum);
 }
 
 #define CSUM_MANGLED_0 ((__force __sum16)0xffff)
 
-static inline void csum_replace_by_diff(__sum16 *sum, __wsum diff)
+static __always_inline void csum_replace_by_diff(__sum16 *sum, __wsum diff)
 {
        *sum = csum_fold(csum_add(diff, ~csum_unfold(*sum)));
 }
 
-static inline void csum_replace4(__sum16 *sum, __be32 from, __be32 to)
+static __always_inline void csum_replace4(__sum16 *sum, __be32 from, __be32 to)
 {
        __wsum tmp = csum_sub(~csum_unfold(*sum), (__force __wsum)from);
 
@@ -136,11 +137,16 @@ static inline void csum_replace4(__sum16 *sum, __be32 from, __be32 to)
  *  m : old value of a 16bit field
  *  m' : new value of a 16bit field
  */
-static inline void csum_replace2(__sum16 *sum, __be16 old, __be16 new)
+static __always_inline void csum_replace2(__sum16 *sum, __be16 old, __be16 new)
 {
        *sum = ~csum16_add(csum16_sub(~(*sum), old), new);
 }
 
+static inline void csum_replace(__wsum *csum, __wsum old, __wsum new)
+{
+       *csum = csum_add(csum_sub(*csum, old), new);
+}
+
 struct sk_buff;
 void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
                              __be32 from, __be32 to, bool pseudohdr);
@@ -150,16 +156,16 @@ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
 void inet_proto_csum_replace_by_diff(__sum16 *sum, struct sk_buff *skb,
                                     __wsum diff, bool pseudohdr);
 
-static inline void inet_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,
-                                           __be16 from, __be16 to,
-                                           bool pseudohdr)
+static __always_inline
+void inet_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,
+                             __be16 from, __be16 to, bool pseudohdr)
 {
        inet_proto_csum_replace4(sum, skb, (__force __be32)from,
                                 (__force __be32)to, pseudohdr);
 }
 
-static inline __wsum remcsum_adjust(void *ptr, __wsum csum,
-                                   int start, int offset)
+static __always_inline __wsum remcsum_adjust(void *ptr, __wsum csum,
+                                            int start, int offset)
 {
        __sum16 *psum = (__sum16 *)(ptr + offset);
        __wsum delta;
@@ -175,12 +181,12 @@ static inline __wsum remcsum_adjust(void *ptr, __wsum csum,
        return delta;
 }
 
-static inline void remcsum_unadjust(__sum16 *psum, __wsum delta)
+static __always_inline void remcsum_unadjust(__sum16 *psum, __wsum delta)
 {
        *psum = csum_fold(csum_sub(delta, (__force __wsum)*psum));
 }
 
-static inline __wsum wsum_negate(__wsum val)
+static __always_inline __wsum wsum_negate(__wsum val)
 {
        return (__force __wsum)-((__force u32)val);
 }
index 57b3e4e..85a5ba3 100644 (file)
@@ -1187,6 +1187,7 @@ void dsa_unregister_switch(struct dsa_switch *ds);
 int dsa_register_switch(struct dsa_switch *ds);
 void dsa_switch_shutdown(struct dsa_switch *ds);
 struct dsa_switch *dsa_switch_find(int tree_index, int sw_index);
+void dsa_flush_workqueue(void);
 #ifdef CONFIG_PM_SLEEP
 int dsa_switch_suspend(struct dsa_switch *ds);
 int dsa_switch_resume(struct dsa_switch *ds);
index 14efa0d..adab27b 100644 (file)
@@ -123,8 +123,20 @@ static inline struct metadata_dst *tun_dst_unclone(struct sk_buff *skb)
 
        memcpy(&new_md->u.tun_info, &md_dst->u.tun_info,
               sizeof(struct ip_tunnel_info) + md_size);
+#ifdef CONFIG_DST_CACHE
+       /* Unclone the dst cache if there is one */
+       if (new_md->u.tun_info.dst_cache.cache) {
+               int ret;
+
+               ret = dst_cache_init(&new_md->u.tun_info.dst_cache, GFP_ATOMIC);
+               if (ret) {
+                       metadata_dst_free(new_md);
+                       return ERR_PTR(ret);
+               }
+       }
+#endif
+
        skb_dst_drop(skb);
-       dst_hold(&new_md->dst);
        skb_dst_set(skb, &new_md->dst);
        return new_md;
 }
index 81e23a1..b51bae4 100644 (file)
@@ -525,19 +525,18 @@ static inline void ip_select_ident_segs(struct net *net, struct sk_buff *skb,
 {
        struct iphdr *iph = ip_hdr(skb);
 
+       /* We had many attacks based on IPID, use the private
+        * generator as much as we can.
+        */
+       if (sk && inet_sk(sk)->inet_daddr) {
+               iph->id = htons(inet_sk(sk)->inet_id);
+               inet_sk(sk)->inet_id += segs;
+               return;
+       }
        if ((iph->frag_off & htons(IP_DF)) && !skb->ignore_df) {
-               /* This is only to work around buggy Windows95/2000
-                * VJ compression implementations.  If the ID field
-                * does not change, they drop every other packet in
-                * a TCP stream using header compression.
-                */
-               if (sk && inet_sk(sk)->inet_daddr) {
-                       iph->id = htons(inet_sk(sk)->inet_id);
-                       inet_sk(sk)->inet_id += segs;
-               } else {
-                       iph->id = 0;
-               }
+               iph->id = 0;
        } else {
+               /* Unfortunately we need the big hammer to get a suitable IPID */
                __ip_select_ident(net, iph, segs);
        }
 }
index a9a4ccc..2048bc8 100644 (file)
@@ -190,14 +190,16 @@ struct fib6_info {
        u32                             fib6_metric;
        u8                              fib6_protocol;
        u8                              fib6_type;
+
+       u8                              offload;
+       u8                              trap;
+       u8                              offload_failed;
+
        u8                              should_flush:1,
                                        dst_nocount:1,
                                        dst_nopolicy:1,
                                        fib6_destroying:1,
-                                       offload:1,
-                                       trap:1,
-                                       offload_failed:1,
-                                       unused:1;
+                                       unused:4;
 
        struct rcu_head                 rcu;
        struct nexthop                  *nh;
@@ -282,7 +284,7 @@ static inline bool fib6_get_cookie_safe(const struct fib6_info *f6i,
        fn = rcu_dereference(f6i->fib6_node);
 
        if (fn) {
-               *cookie = fn->fn_sernum;
+               *cookie = READ_ONCE(fn->fn_sernum);
                /* pairs with smp_wmb() in __fib6_update_sernum_upto_root() */
                smp_rmb();
                status = true;
index 3afcb12..92eec13 100644 (file)
@@ -393,17 +393,20 @@ static inline void txopt_put(struct ipv6_txoptions *opt)
                kfree_rcu(opt, rcu);
 }
 
+#if IS_ENABLED(CONFIG_IPV6)
 struct ip6_flowlabel *__fl6_sock_lookup(struct sock *sk, __be32 label);
 
 extern struct static_key_false_deferred ipv6_flowlabel_exclusive;
 static inline struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk,
                                                    __be32 label)
 {
-       if (static_branch_unlikely(&ipv6_flowlabel_exclusive.key))
+       if (static_branch_unlikely(&ipv6_flowlabel_exclusive.key) &&
+           READ_ONCE(sock_net(sk)->ipv6.flowlabel_has_excl))
                return __fl6_sock_lookup(sk, label) ? : ERR_PTR(-ENOENT);
 
        return NULL;
 }
+#endif
 
 struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space,
                                         struct ip6_flowlabel *fl,
index 937389e..87419f7 100644 (file)
@@ -350,7 +350,8 @@ static inline struct neighbour *neigh_create(struct neigh_table *tbl,
        return __neigh_create(tbl, pkey, dev, true);
 }
 void neigh_destroy(struct neighbour *neigh);
-int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb);
+int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb,
+                      const bool immediate_ok);
 int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, u32 flags,
                 u32 nlmsg_pid);
 void __neigh_set_probe_once(struct neighbour *neigh);
@@ -460,17 +461,24 @@ static inline struct neighbour * neigh_clone(struct neighbour *neigh)
 
 #define neigh_hold(n)  refcount_inc(&(n)->refcnt)
 
-static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
+static __always_inline int neigh_event_send_probe(struct neighbour *neigh,
+                                                 struct sk_buff *skb,
+                                                 const bool immediate_ok)
 {
        unsigned long now = jiffies;
-       
+
        if (READ_ONCE(neigh->used) != now)
                WRITE_ONCE(neigh->used, now);
-       if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE)))
-               return __neigh_event_send(neigh, skb);
+       if (!(neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE)))
+               return __neigh_event_send(neigh, skb, immediate_ok);
        return 0;
 }
 
+static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
+{
+       return neigh_event_send_probe(neigh, skb, true);
+}
+
 #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
 static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb)
 {
index eaf55da..c4c0861 100644 (file)
@@ -905,9 +905,9 @@ struct nft_expr_ops {
        int                             (*offload)(struct nft_offload_ctx *ctx,
                                                   struct nft_flow_rule *flow,
                                                   const struct nft_expr *expr);
+       bool                            (*offload_action)(const struct nft_expr *expr);
        void                            (*offload_stats)(struct nft_expr *expr,
                                                         const struct flow_stats *stats);
-       u32                             offload_flags;
        const struct nft_expr_type      *type;
        void                            *data;
 };
index f9d95ff..7971478 100644 (file)
@@ -67,8 +67,6 @@ struct nft_flow_rule {
        struct flow_rule        *rule;
 };
 
-#define NFT_OFFLOAD_F_ACTION   (1 << 0)
-
 void nft_flow_rule_set_addr_type(struct nft_flow_rule *flow,
                                 enum flow_dissector_key_id addr_type);
 
index a4b5503..6bd7e5a 100644 (file)
@@ -77,9 +77,10 @@ struct netns_ipv6 {
        spinlock_t              fib6_gc_lock;
        unsigned int             ip6_rt_gc_expire;
        unsigned long            ip6_rt_last_gc;
+       unsigned char           flowlabel_has_excl;
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
-       unsigned int            fib6_rules_require_fldissect;
        bool                    fib6_has_custom_rules;
+       unsigned int            fib6_rules_require_fldissect;
 #ifdef CONFIG_IPV6_SUBTREES
        unsigned int            fib6_routes_require_src;
 #endif
index 4c858dc..25404fc 100644 (file)
@@ -370,7 +370,7 @@ static inline struct neighbour *ip_neigh_gw4(struct net_device *dev,
 {
        struct neighbour *neigh;
 
-       neigh = __ipv4_neigh_lookup_noref(dev, daddr);
+       neigh = __ipv4_neigh_lookup_noref(dev, (__force u32)daddr);
        if (unlikely(!neigh))
                neigh = __neigh_create(&arp_tbl, &daddr, dev, false);
 
index ff9b508..50aecd2 100644 (file)
@@ -507,7 +507,7 @@ struct sock {
 #endif
        u16                     sk_tsflags;
        u8                      sk_shutdown;
-       u32                     sk_tskey;
+       atomic_t                sk_tskey;
        atomic_t                sk_zckey;
 
        u8                      sk_clockid;
@@ -2667,7 +2667,7 @@ static inline void _sock_tx_timestamp(struct sock *sk, __u16 tsflags,
                __sock_tx_timestamp(tsflags, tx_flags);
                if (tsflags & SOF_TIMESTAMPING_OPT_ID && tskey &&
                    tsflags & SOF_TIMESTAMPING_TX_RECORD_MASK)
-                       *tskey = sk->sk_tskey++;
+                       *tskey = atomic_inc_return(&sk->sk_tskey) - 1;
        }
        if (unlikely(sock_flag(sk, SOCK_WIFI_STATUS)))
                *tx_flags |= SKBTX_WIFI_STATUS;
index 44e442b..b9fc978 100644 (file)
@@ -1369,6 +1369,7 @@ static inline bool tcp_checksum_complete(struct sk_buff *skb)
 
 bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb);
 
+#ifdef CONFIG_INET
 void __sk_defer_free_flush(struct sock *sk);
 
 static inline void sk_defer_free_flush(struct sock *sk)
@@ -1377,6 +1378,9 @@ static inline void sk_defer_free_flush(struct sock *sk)
                return;
        __sk_defer_free_flush(sk);
 }
+#else
+static inline void sk_defer_free_flush(struct sock *sk) {}
+#endif
 
 int tcp_filter(struct sock *sk, struct sk_buff *skb);
 void tcp_set_state(struct sock *sk, int state);
index 9b187d8..36da42c 100644 (file)
@@ -617,6 +617,7 @@ void snd_pcm_stream_unlock(struct snd_pcm_substream *substream);
 void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream);
 void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream);
 unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream);
+unsigned long _snd_pcm_stream_lock_irqsave_nested(struct snd_pcm_substream *substream);
 
 /**
  * snd_pcm_stream_lock_irqsave - Lock the PCM stream
@@ -635,6 +636,20 @@ unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream);
 void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
                                      unsigned long flags);
 
+/**
+ * snd_pcm_stream_lock_irqsave_nested - Single-nested PCM stream locking
+ * @substream: PCM substream
+ * @flags: irq flags
+ *
+ * This locks the PCM stream like snd_pcm_stream_lock_irqsave() but with
+ * the single-depth lockdep subclass.
+ */
+#define snd_pcm_stream_lock_irqsave_nested(substream, flags)           \
+       do {                                                            \
+               typecheck(unsigned long, flags);                        \
+               flags = _snd_pcm_stream_lock_irqsave_nested(substream); \
+       } while (0)
+
 /**
  * snd_pcm_group_for_each_entry - iterate over the linked substreams
  * @s: the iterator
index 9832cb8..c9a72e8 100644 (file)
@@ -122,6 +122,92 @@ TRACE_EVENT(fsi_master_break,
        )
 );
 
+TRACE_EVENT(fsi_slave_init,
+       TP_PROTO(const struct fsi_slave *slave),
+       TP_ARGS(slave),
+       TP_STRUCT__entry(
+               __field(int,    master_idx)
+               __field(int,    master_n_links)
+               __field(int,    idx)
+               __field(int,    link)
+               __field(int,    chip_id)
+               __field(__u32,  cfam_id)
+               __field(__u32,  size)
+       ),
+       TP_fast_assign(
+               __entry->master_idx = slave->master->idx;
+               __entry->master_n_links = slave->master->n_links;
+               __entry->idx = slave->cdev_idx;
+               __entry->link = slave->link;
+               __entry->chip_id = slave->chip_id;
+               __entry->cfam_id = slave->cfam_id;
+               __entry->size = slave->size;
+       ),
+       TP_printk("fsi%d: idx:%d link:%d/%d cid:%d cfam:%08x %08x",
+               __entry->master_idx,
+               __entry->idx,
+               __entry->link,
+               __entry->master_n_links,
+               __entry->chip_id,
+               __entry->cfam_id,
+               __entry->size
+       )
+);
+
+TRACE_EVENT(fsi_slave_invalid_cfam,
+       TP_PROTO(const struct fsi_master *master, int link, uint32_t cfam_id),
+       TP_ARGS(master, link, cfam_id),
+       TP_STRUCT__entry(
+               __field(int,    master_idx)
+               __field(int,    master_n_links)
+               __field(int,    link)
+               __field(__u32,  cfam_id)
+       ),
+       TP_fast_assign(
+               __entry->master_idx = master->idx;
+               __entry->master_n_links = master->n_links;
+               __entry->link = link;
+               __entry->cfam_id = cfam_id;
+       ),
+       TP_printk("fsi%d: cfam:%08x link:%d/%d",
+               __entry->master_idx,
+               __entry->cfam_id,
+               __entry->link,
+               __entry->master_n_links
+       )
+);
+
+TRACE_EVENT(fsi_dev_init,
+       TP_PROTO(const struct fsi_device *dev),
+       TP_ARGS(dev),
+       TP_STRUCT__entry(
+               __field(int,    master_idx)
+               __field(int,    link)
+               __field(int,    type)
+               __field(int,    unit)
+               __field(int,    version)
+               __field(__u32,  addr)
+               __field(__u32,  size)
+       ),
+       TP_fast_assign(
+               __entry->master_idx = dev->slave->master->idx;
+               __entry->link = dev->slave->link;
+               __entry->type = dev->engine_type;
+               __entry->unit = dev->unit;
+               __entry->version = dev->version;
+               __entry->addr = dev->addr;
+               __entry->size = dev->size;
+       ),
+       TP_printk("fsi%d: slv%d: t:%02x u:%02x v:%02x %08x@%08x",
+               __entry->master_idx,
+               __entry->link,
+               __entry->type,
+               __entry->unit,
+               __entry->version,
+               __entry->size,
+               __entry->addr
+       )
+);
 
 #endif /* _TRACE_FSI_H */
 
index a355cea..0fff873 100644 (file)
@@ -72,6 +72,18 @@ TRACE_EVENT(fsi_master_aspeed_opb_error,
                )
        );
 
+TRACE_EVENT(fsi_master_aspeed_cfam_reset,
+       TP_PROTO(bool start),
+       TP_ARGS(start),
+       TP_STRUCT__entry(
+               __field(bool,   start)
+       ),
+       TP_fast_assign(
+               __entry->start = start;
+       ),
+       TP_printk("%s", __entry->start ? "start" : "end")
+);
+
 #endif
 
 #include <trace/define_trace.h>
index 3e042ca..a8a64b9 100644 (file)
@@ -14,7 +14,7 @@
        EM(SKB_DROP_REASON_NO_SOCKET, NO_SOCKET)                \
        EM(SKB_DROP_REASON_PKT_TOO_SMALL, PKT_TOO_SMALL)        \
        EM(SKB_DROP_REASON_TCP_CSUM, TCP_CSUM)                  \
-       EM(SKB_DROP_REASON_TCP_FILTER, TCP_FILTER)              \
+       EM(SKB_DROP_REASON_SOCKET_FILTER, SOCKET_FILTER)        \
        EM(SKB_DROP_REASON_UDP_CSUM, UDP_CSUM)                  \
        EMe(SKB_DROP_REASON_MAX, MAX)
 
index 1e566ac..29982d6 100644 (file)
@@ -794,6 +794,9 @@ RPC_SHOW_SOCKET
 
 RPC_SHOW_SOCK
 
+
+#include <trace/events/net_probe_common.h>
+
 /*
  * Now redefine the EM() and EMe() macros to map the enums to the strings
  * that will be printed in the output.
@@ -816,27 +819,32 @@ DECLARE_EVENT_CLASS(xs_socket_event,
                        __field(unsigned int, socket_state)
                        __field(unsigned int, sock_state)
                        __field(unsigned long long, ino)
-                       __string(dstaddr,
-                               xprt->address_strings[RPC_DISPLAY_ADDR])
-                       __string(dstport,
-                               xprt->address_strings[RPC_DISPLAY_PORT])
+                       __array(__u8, saddr, sizeof(struct sockaddr_in6))
+                       __array(__u8, daddr, sizeof(struct sockaddr_in6))
                ),
 
                TP_fast_assign(
                        struct inode *inode = SOCK_INODE(socket);
+                       const struct sock *sk = socket->sk;
+                       const struct inet_sock *inet = inet_sk(sk);
+
+                       memset(__entry->saddr, 0, sizeof(struct sockaddr_in6));
+                       memset(__entry->daddr, 0, sizeof(struct sockaddr_in6));
+
+                       TP_STORE_ADDR_PORTS(__entry, inet, sk);
+
                        __entry->socket_state = socket->state;
                        __entry->sock_state = socket->sk->sk_state;
                        __entry->ino = (unsigned long long)inode->i_ino;
-                       __assign_str(dstaddr,
-                               xprt->address_strings[RPC_DISPLAY_ADDR]);
-                       __assign_str(dstport,
-                               xprt->address_strings[RPC_DISPLAY_PORT]);
+
                ),
 
                TP_printk(
-                       "socket:[%llu] dstaddr=%s/%s "
+                       "socket:[%llu] srcaddr=%pISpc dstaddr=%pISpc "
                        "state=%u (%s) sk_state=%u (%s)",
-                       __entry->ino, __get_str(dstaddr), __get_str(dstport),
+                       __entry->ino,
+                       __entry->saddr,
+                       __entry->daddr,
                        __entry->socket_state,
                        rpc_show_socket_state(__entry->socket_state),
                        __entry->sock_state,
@@ -866,29 +874,33 @@ DECLARE_EVENT_CLASS(xs_socket_event_done,
                        __field(unsigned int, socket_state)
                        __field(unsigned int, sock_state)
                        __field(unsigned long long, ino)
-                       __string(dstaddr,
-                               xprt->address_strings[RPC_DISPLAY_ADDR])
-                       __string(dstport,
-                               xprt->address_strings[RPC_DISPLAY_PORT])
+                       __array(__u8, saddr, sizeof(struct sockaddr_in6))
+                       __array(__u8, daddr, sizeof(struct sockaddr_in6))
                ),
 
                TP_fast_assign(
                        struct inode *inode = SOCK_INODE(socket);
+                       const struct sock *sk = socket->sk;
+                       const struct inet_sock *inet = inet_sk(sk);
+
+                       memset(__entry->saddr, 0, sizeof(struct sockaddr_in6));
+                       memset(__entry->daddr, 0, sizeof(struct sockaddr_in6));
+
+                       TP_STORE_ADDR_PORTS(__entry, inet, sk);
+
                        __entry->socket_state = socket->state;
                        __entry->sock_state = socket->sk->sk_state;
                        __entry->ino = (unsigned long long)inode->i_ino;
                        __entry->error = error;
-                       __assign_str(dstaddr,
-                               xprt->address_strings[RPC_DISPLAY_ADDR]);
-                       __assign_str(dstport,
-                               xprt->address_strings[RPC_DISPLAY_PORT]);
                ),
 
                TP_printk(
-                       "error=%d socket:[%llu] dstaddr=%s/%s "
+                       "error=%d socket:[%llu] srcaddr=%pISpc dstaddr=%pISpc "
                        "state=%u (%s) sk_state=%u (%s)",
                        __entry->error,
-                       __entry->ino, __get_str(dstaddr), __get_str(dstport),
+                       __entry->ino,
+                       __entry->saddr,
+                       __entry->daddr,
                        __entry->socket_state,
                        rpc_show_socket_state(__entry->socket_state),
                        __entry->sock_state,
@@ -953,7 +965,8 @@ TRACE_EVENT(rpc_socket_nospace,
                { BIT(XPRT_REMOVE),             "REMOVE" },             \
                { BIT(XPRT_CONGESTED),          "CONGESTED" },          \
                { BIT(XPRT_CWND_WAIT),          "CWND_WAIT" },          \
-               { BIT(XPRT_WRITE_SPACE),        "WRITE_SPACE" })
+               { BIT(XPRT_WRITE_SPACE),        "WRITE_SPACE" },        \
+               { BIT(XPRT_SND_IS_COOKIE),      "SND_IS_COOKIE" })
 
 DECLARE_EVENT_CLASS(rpc_xprt_lifetime_class,
        TP_PROTO(
@@ -1150,8 +1163,11 @@ DECLARE_EVENT_CLASS(xprt_writelock_event,
                        __entry->task_id = -1;
                        __entry->client_id = -1;
                }
-               __entry->snd_task_id = xprt->snd_task ?
-                                       xprt->snd_task->tk_pid : -1;
+               if (xprt->snd_task &&
+                   !test_bit(XPRT_SND_IS_COOKIE, &xprt->state))
+                       __entry->snd_task_id = xprt->snd_task->tk_pid;
+               else
+                       __entry->snd_task_id = -1;
        ),
 
        TP_printk(SUNRPC_TRACE_TASK_SPECIFIER
@@ -1196,8 +1212,12 @@ DECLARE_EVENT_CLASS(xprt_cong_event,
                        __entry->task_id = -1;
                        __entry->client_id = -1;
                }
-               __entry->snd_task_id = xprt->snd_task ?
-                                       xprt->snd_task->tk_pid : -1;
+               if (xprt->snd_task &&
+                   !test_bit(XPRT_SND_IS_COOKIE, &xprt->state))
+                       __entry->snd_task_id = xprt->snd_task->tk_pid;
+               else
+                       __entry->snd_task_id = -1;
+
                __entry->cong = xprt->cong;
                __entry->cwnd = xprt->cwnd;
                __entry->wait = test_bit(XPRT_CWND_WAIT, &xprt->state);
index ea4405d..5d48c46 100644 (file)
@@ -23,8 +23,9 @@
 
 #undef __get_rel_dynamic_array
 #define __get_rel_dynamic_array(field) \
-               ((void *)(&__entry->__rel_loc_##field) +        \
-                sizeof(__entry->__rel_loc_##field) +           \
+               ((void *)__entry +                                      \
+                offsetof(typeof(*__entry), __rel_loc_##field) +        \
+                sizeof(__entry->__rel_loc_##field) +                   \
                 (__entry->__rel_loc_##field & 0xffff))
 
 #undef __get_rel_dynamic_array_len
index 8c6f7c4..3d29919 100644 (file)
@@ -128,7 +128,7 @@ TRACE_MAKE_SYSTEM_STR();
        struct trace_event_raw_##name {                                 \
                struct trace_entry      ent;                            \
                tstruct                                                 \
-               char                    __data[0];                      \
+               char                    __data[];                       \
        };                                                              \
                                                                        \
        static struct trace_event_class event_class_##name;
@@ -318,9 +318,10 @@ TRACE_MAKE_SYSTEM_STR();
 #define __get_str(field) ((char *)__get_dynamic_array(field))
 
 #undef __get_rel_dynamic_array
-#define __get_rel_dynamic_array(field) \
-               ((void *)(&__entry->__rel_loc_##field) +        \
-                sizeof(__entry->__rel_loc_##field) +           \
+#define __get_rel_dynamic_array(field)                                 \
+               ((void *)__entry +                                      \
+                offsetof(typeof(*__entry), __rel_loc_##field) +        \
+                sizeof(__entry->__rel_loc_##field) +                   \
                 (__entry->__rel_loc_##field & 0xffff))
 
 #undef __get_rel_dynamic_array_len
diff --git a/include/uapi/linux/cyclades.h b/include/uapi/linux/cyclades.h
new file mode 100644 (file)
index 0000000..6225c5a
--- /dev/null
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#ifndef _UAPI_LINUX_CYCLADES_H
+#define _UAPI_LINUX_CYCLADES_H
+
+#warning "Support for features provided by this header has been removed"
+#warning "Please consider updating your code"
+
+struct cyclades_monitor {
+       unsigned long int_count;
+       unsigned long char_count;
+       unsigned long char_max;
+       unsigned long char_last;
+};
+
+#define CYGETMON               0x435901
+#define CYGETTHRESH            0x435902
+#define CYSETTHRESH            0x435903
+#define CYGETDEFTHRESH         0x435904
+#define CYSETDEFTHRESH         0x435905
+#define CYGETTIMEOUT           0x435906
+#define CYSETTIMEOUT           0x435907
+#define CYGETDEFTIMEOUT                0x435908
+#define CYSETDEFTIMEOUT                0x435909
+#define CYSETRFLOW             0x43590a
+#define CYGETRFLOW             0x43590b
+#define CYSETRTSDTR_INV                0x43590c
+#define CYGETRTSDTR_INV                0x43590d
+#define CYZSETPOLLCYCLE                0x43590e
+#define CYZGETPOLLCYCLE                0x43590f
+#define CYGETCD1400VER         0x435910
+#define CYSETWAIT              0x435912
+#define CYGETWAIT              0x435913
+
+#endif /* _UAPI_LINUX_CYCLADES_H */
index da577ec..b2f1977 100644 (file)
@@ -55,4 +55,18 @@ struct scom_access {
 #define FSI_SCOM_WRITE _IOWR('s', 0x02, struct scom_access)
 #define FSI_SCOM_RESET _IOW('s', 0x03, __u32)
 
+/*
+ * /dev/sbefifo* ioctl interface
+ */
+
+/**
+ * FSI_SBEFIFO_READ_TIMEOUT sets the read timeout for response from SBE.
+ *
+ * The read timeout is specified in seconds.  The minimum value of read
+ * timeout is 10 seconds (default) and the maximum value of read timeout is
+ * 120 seconds.  A read timeout of 0 will reset the value to the default of
+ * (10 seconds).
+ */
+#define FSI_SBEFIFO_READ_TIMEOUT_SECONDS       _IOW('s', 0x00, __u32)
+
 #endif /* _UAPI_LINUX_FSI_H */
index 9563d29..507ee1f 100644 (file)
@@ -1133,6 +1133,8 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM 206
 #define KVM_CAP_VM_GPA_BITS 207
 #define KVM_CAP_XSAVE2 208
+#define KVM_CAP_SYS_ATTRIBUTES 209
+#define KVM_CAP_PPC_AIL_MODE_3 210
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -1623,9 +1625,6 @@ struct kvm_enc_region {
 #define KVM_S390_NORMAL_RESET  _IO(KVMIO,   0xc3)
 #define KVM_S390_CLEAR_RESET   _IO(KVMIO,   0xc4)
 
-/* Available with KVM_CAP_XSAVE2 */
-#define KVM_GET_XSAVE2           _IOR(KVMIO,  0xcf, struct kvm_xsave)
-
 struct kvm_s390_pv_sec_parm {
        __u64 origin;
        __u64 length;
@@ -2047,4 +2046,7 @@ struct kvm_stats_desc {
 
 #define KVM_GET_STATS_FD  _IO(KVMIO,  0xce)
 
+/* Available with KVM_CAP_XSAVE2 */
+#define KVM_GET_XSAVE2           _IOR(KVMIO,  0xcf, struct kvm_xsave)
+
 #endif /* __LINUX_KVM_H */
index 4b33950..2607102 100644 (file)
@@ -106,7 +106,7 @@ enum ip_conntrack_status {
        IPS_NAT_CLASH = IPS_UNTRACKED,
 #endif
 
-       /* Conntrack got a helper explicitly attached via CT target. */
+       /* Conntrack got a helper explicitly attached (ruleset, ctnetlink). */
        IPS_HELPER_BIT = 13,
        IPS_HELPER = (1 << IPS_HELPER_BIT),
 
index 1b65042..82858b6 100644 (file)
@@ -465,6 +465,8 @@ struct perf_event_attr {
        /*
         * User provided data if sigtrap=1, passed back to user via
         * siginfo_t::si_perf_data, e.g. to permit user to identify the event.
+        * Note, siginfo_t::si_perf_data is long-sized, and sig_data will be
+        * truncated accordingly on 32 bit architectures.
         */
        __u64   sig_data;
 };
index c7008d8..8cb3a6f 100644 (file)
@@ -84,12 +84,11 @@ struct smc_diag_conninfo {
 /* SMC_DIAG_LINKINFO */
 
 struct smc_diag_linkinfo {
-       __u8            link_id;                    /* link identifier */
-       __u8            ibname[IB_DEVICE_NAME_MAX]; /* name of the RDMA device */
-       __u8            ibport;                     /* RDMA device port number */
-       __u8            gid[40];                    /* local GID */
-       __u8            peer_gid[40];               /* peer GID */
-       __aligned_u64   net_cookie;                 /* RDMA device net namespace */
+       __u8 link_id;                   /* link identifier */
+       __u8 ibname[IB_DEVICE_NAME_MAX]; /* name of the RDMA device */
+       __u8 ibport;                    /* RDMA device port number */
+       __u8 gid[40];                   /* local GID */
+       __u8 peer_gid[40];              /* peer GID */
 };
 
 struct smc_diag_lgrinfo {
index 371dfc4..1d6b4f0 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
  *
- * Copyright 2016-2020 HabanaLabs, Ltd.
+ * Copyright 2016-2022 HabanaLabs, Ltd.
  * All Rights Reserved.
  *
  */
@@ -30,6 +30,9 @@
  */
 #define GAUDI_FIRST_AVAILABLE_W_S_MONITOR              72
 
+/* Max number of elements in timestamps registration buffers */
+#define        TS_MAX_ELEMENTS_NUM                             (1 << 20) /* 1MB */
+
 /*
  * Goya queue Numbering
  *
@@ -404,6 +407,8 @@ enum hl_server_type {
  * @cpucp_version: The CPUCP f/w version.
  * @card_name: The card name as passed by the f/w.
  * @dram_page_size: The DRAM physical page size.
+ * @number_of_user_interrupts: The number of interrupts that are available to the userspace
+ *                             application to use. Relevant for Gaudi2 and later.
  */
 struct hl_info_hw_ip_info {
        __u64 sram_base_address;
@@ -428,6 +433,9 @@ struct hl_info_hw_ip_info {
        __u8 card_name[HL_INFO_CARD_NAME_MAX_LEN];
        __u64 reserved2;
        __u64 dram_page_size;
+       __u32 reserved3;
+       __u16 number_of_user_interrupts;
+       __u16 pad2;
 };
 
 struct hl_info_dram_usage {
@@ -690,10 +698,12 @@ struct hl_cb_in {
        __u64 cb_handle;
        /* HL_CB_OP_* */
        __u32 op;
+
        /* Size of CB. Maximum size is HL_MAX_CB_SIZE. The minimum size that
         * will be allocated, regardless of this parameter's value, is PAGE_SIZE
         */
        __u32 cb_size;
+
        /* Context ID - Currently not in use */
        __u32 ctx_id;
        /* HL_CB_FLAGS_* */
@@ -959,6 +969,7 @@ union hl_cs_args {
 #define HL_WAIT_CS_FLAGS_INTERRUPT_MASK                0xFFF00000
 #define HL_WAIT_CS_FLAGS_MULTI_CS              0x4
 #define HL_WAIT_CS_FLAGS_INTERRUPT_KERNEL_CQ   0x10
+#define HL_WAIT_CS_FLAGS_REGISTER_INTERRUPT    0x20
 
 #define HL_WAIT_MULTI_CS_LIST_MAX_LEN  32
 
@@ -1031,6 +1042,20 @@ struct hl_wait_cs_in {
         * relevant only when HL_WAIT_CS_FLAGS_INTERRUPT_KERNEL_CQ is set
         */
        __u64 cq_counters_offset;
+
+       /*
+        * Timestamp_handle timestamps buffer handle.
+        * relevant only when HL_WAIT_CS_FLAGS_REGISTER_INTERRUPT is set
+        */
+       __u64 timestamp_handle;
+
+       /*
+        * Timestamp_offset is offset inside the timestamp buffer pointed by timestamp_handle above.
+        * upon interrupt, if the cq reached the target value then driver will write
+        * timestamp to this offset.
+        * relevant only when HL_WAIT_CS_FLAGS_REGISTER_INTERRUPT is set
+        */
+       __u64 timestamp_offset;
 };
 
 #define HL_WAIT_CS_STATUS_COMPLETED    0
@@ -1077,100 +1102,119 @@ union hl_wait_cs_args {
  */
 #define HL_MEM_OP_EXPORT_DMABUF_FD     5
 
+/* Opcode to create timestamps pool for user interrupts registration support
+ * The memory will be allocated by the kernel driver, A timestamp buffer which the user
+ * will get handle to it for mmap, and another internal buffer used by the
+ * driver for registration management
+ * The memory will be freed when the user closes the file descriptor(ctx close)
+ */
+#define HL_MEM_OP_TS_ALLOC             6
+
 /* Memory flags */
 #define HL_MEM_CONTIGUOUS      0x1
 #define HL_MEM_SHARED          0x2
 #define HL_MEM_USERPTR         0x4
 #define HL_MEM_FORCE_HINT      0x8
 
+/**
+ * structure hl_mem_in - structure that handle input args for memory IOCTL
+ * @union arg: union of structures to be used based on the input operation
+ * @op: specify the requested memory operation (one of the HL_MEM_OP_* definitions).
+ * @flags: flags for the memory operation (one of the HL_MEM_* definitions).
+ *         For the HL_MEM_OP_EXPORT_DMABUF_FD opcode, this field holds the DMA-BUF file/FD flags.
+ * @ctx_id: context ID - currently not in use.
+ * @num_of_elements: number of timestamp elements used only with HL_MEM_OP_TS_ALLOC opcode.
+ */
 struct hl_mem_in {
        union {
-               /* HL_MEM_OP_ALLOC- allocate device memory */
+               /**
+                * structure for device memory allocation (used with the HL_MEM_OP_ALLOC op)
+                * @mem_size: memory size to allocate
+                * @page_size: page size to use on allocation. when the value is 0 the default page
+                *             size will be taken.
+                */
                struct {
-                       /* Size to alloc */
                        __u64 mem_size;
+                       __u64 page_size;
                } alloc;
 
-               /* HL_MEM_OP_FREE - free device memory */
+               /**
+                * structure for free-ing device memory (used with the HL_MEM_OP_FREE op)
+                * @handle: handle returned from HL_MEM_OP_ALLOC
+                */
                struct {
-                       /* Handle returned from HL_MEM_OP_ALLOC */
                        __u64 handle;
                } free;
 
-               /* HL_MEM_OP_MAP - map device memory */
+               /**
+                * structure for mapping device memory (used with the HL_MEM_OP_MAP op)
+                * @hint_addr: requested virtual address of mapped memory.
+                *             the driver will try to map the requested region to this hint
+                *             address, as long as the address is valid and not already mapped.
+                *             the user should check the returned address of the IOCTL to make
+                *             sure he got the hint address.
+                *             passing 0 here means that the driver will choose the address itself.
+                * @handle: handle returned from HL_MEM_OP_ALLOC.
+                */
                struct {
-                       /*
-                        * Requested virtual address of mapped memory.
-                        * The driver will try to map the requested region to
-                        * this hint address, as long as the address is valid
-                        * and not already mapped. The user should check the
-                        * returned address of the IOCTL to make sure he got
-                        * the hint address. Passing 0 here means that the
-                        * driver will choose the address itself.
-                        */
                        __u64 hint_addr;
-                       /* Handle returned from HL_MEM_OP_ALLOC */
                        __u64 handle;
                } map_device;
 
-               /* HL_MEM_OP_MAP - map host memory */
+               /**
+                * structure for mapping host memory (used with the HL_MEM_OP_MAP op)
+                * @host_virt_addr: address of allocated host memory.
+                * @hint_addr: requested virtual address of mapped memory.
+                *             the driver will try to map the requested region to this hint
+                *             address, as long as the address is valid and not already mapped.
+                *             the user should check the returned address of the IOCTL to make
+                *             sure he got the hint address.
+                *             passing 0 here means that the driver will choose the address itself.
+                * @size: size of allocated host memory.
+                */
                struct {
-                       /* Address of allocated host memory */
                        __u64 host_virt_addr;
-                       /*
-                        * Requested virtual address of mapped memory.
-                        * The driver will try to map the requested region to
-                        * this hint address, as long as the address is valid
-                        * and not already mapped. The user should check the
-                        * returned address of the IOCTL to make sure he got
-                        * the hint address. Passing 0 here means that the
-                        * driver will choose the address itself.
-                        */
                        __u64 hint_addr;
-                       /* Size of allocated host memory */
                        __u64 mem_size;
                } map_host;
 
-               /* HL_MEM_OP_MAP_BLOCK - map a hw block */
+               /**
+                * structure for mapping hw block (used with the HL_MEM_OP_MAP_BLOCK op)
+                * @block_addr:HW block address to map, a handle and size will be returned
+                *             to the user and will be used to mmap the relevant block.
+                *             only addresses from configuration space are allowed.
+                */
                struct {
-                       /*
-                        * HW block address to map, a handle and size will be
-                        * returned to the user and will be used to mmap the
-                        * relevant block. Only addresses from configuration
-                        * space are allowed.
-                        */
                        __u64 block_addr;
                } map_block;
 
-               /* HL_MEM_OP_UNMAP - unmap host memory */
+               /**
+                * structure for unmapping host memory (used with the HL_MEM_OP_UNMAP op)
+                * @device_virt_addr: virtual address returned from HL_MEM_OP_MAP
+                */
                struct {
-                       /* Virtual address returned from HL_MEM_OP_MAP */
                        __u64 device_virt_addr;
                } unmap;
 
-               /* HL_MEM_OP_EXPORT_DMABUF_FD */
+               /**
+                * structure for exporting DMABUF object (used with
+                * the HL_MEM_OP_EXPORT_DMABUF_FD op)
+                * @handle: handle returned from HL_MEM_OP_ALLOC.
+                *          in Gaudi, where we don't have MMU for the device memory, the
+                *          driver expects a physical address (instead of a handle) in the
+                *          device memory space.
+                * @mem_size: size of memory allocation. Relevant only for GAUDI
+                */
                struct {
-                       /* Handle returned from HL_MEM_OP_ALLOC. In Gaudi,
-                        * where we don't have MMU for the device memory, the
-                        * driver expects a physical address (instead of
-                        * a handle) in the device memory space.
-                        */
                        __u64 handle;
-                       /* Size of memory allocation. Relevant only for GAUDI */
                        __u64 mem_size;
                } export_dmabuf_fd;
        };
 
-       /* HL_MEM_OP_* */
        __u32 op;
-       /* HL_MEM_* flags.
-        * For the HL_MEM_OP_EXPORT_DMABUF_FD opcode, this field holds the
-        * DMA-BUF file/FD flags.
-        */
        __u32 flags;
-       /* Context ID - Currently not in use */
        __u32 ctx_id;
-       __u32 pad;
+       __u32 num_of_elements;
 };
 
 struct hl_mem_out {
index ef0cafe..2d3e5df 100644 (file)
  *                                                                          *
  ****************************************************************************/
 
+#define AES_IEC958_STATUS_SIZE         24
+
 struct snd_aes_iec958 {
-       unsigned char status[24];       /* AES/IEC958 channel status bits */
+       unsigned char status[AES_IEC958_STATUS_SIZE]; /* AES/IEC958 channel status bits */
        unsigned char subcode[147];     /* AES/IEC958 subcode bits */
        unsigned char pad;              /* nothing */
        unsigned char dig_subframe[4];  /* AES/IEC958 subframe bits */
index 9ac5515..7a71453 100644 (file)
@@ -47,7 +47,13 @@ struct ioctl_gntdev_grant_ref {
 /*
  * Inserts the grant references into the mapping table of an instance
  * of gntdev. N.B. This does not perform the mapping, which is deferred
- * until mmap() is called with @index as the offset.
+ * until mmap() is called with @index as the offset. @index should be
+ * considered opaque to userspace, with one exception: if no grant
+ * references have ever been inserted into the mapping table of this
+ * instance, @index will be set to 0. This is necessary to use gntdev
+ * with userspace APIs that expect a file descriptor that can be
+ * mmap()'d at offset 0, such as Wayland. If @count is set to 0, this
+ * ioctl will fail.
  */
 #define IOCTL_GNTDEV_MAP_GRANT_REF \
 _IOC(_IOC_NONE, 'G', 0, sizeof(struct ioctl_gntdev_map_grant_ref))
index bbee8c6..4dc45a5 100644 (file)
@@ -1,6 +1,4 @@
 /******************************************************************************
- * evtchn.h
- *
  * Interface to /dev/xen/xenbus_backend.
  *
  * Copyright (c) 2011 Bastian Blank <waldi@debian.org>
index 6693daf..0dbdb98 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1964,6 +1964,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
         */
        un = lookup_undo(ulp, semid);
        if (un) {
+               spin_unlock(&ulp->lock);
                kvfree(new);
                goto success;
        }
@@ -1976,9 +1977,8 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
        ipc_assert_locked_object(&sma->sem_perm);
        list_add(&new->list_id, &sma->list_id);
        un = new;
-
-success:
        spin_unlock(&ulp->lock);
+success:
        sem_unlock(sma, -1);
 out:
        return un;
index b8d7a66..b2c4ba5 100644 (file)
@@ -205,9 +205,6 @@ async_cookie_t async_schedule_node_domain(async_func_t func, void *data,
        atomic_inc(&entry_count);
        spin_unlock_irqrestore(&async_lock, flags);
 
-       /* mark that this task has queued an async job, used by module init */
-       current->flags |= PF_USED_ASYNC;
-
        /* schedule for execution */
        queue_work_node(node, system_unbound_wq, &entry->work);
 
index e4bbe2c..7690c29 100644 (file)
@@ -541,20 +541,22 @@ static void kauditd_printk_skb(struct sk_buff *skb)
 /**
  * kauditd_rehold_skb - Handle a audit record send failure in the hold queue
  * @skb: audit record
+ * @error: error code (unused)
  *
  * Description:
  * This should only be used by the kauditd_thread when it fails to flush the
  * hold queue.
  */
-static void kauditd_rehold_skb(struct sk_buff *skb)
+static void kauditd_rehold_skb(struct sk_buff *skb, __always_unused int error)
 {
-       /* put the record back in the queue at the same place */
-       skb_queue_head(&audit_hold_queue, skb);
+       /* put the record back in the queue */
+       skb_queue_tail(&audit_hold_queue, skb);
 }
 
 /**
  * kauditd_hold_skb - Queue an audit record, waiting for auditd
  * @skb: audit record
+ * @error: error code
  *
  * Description:
  * Queue the audit record, waiting for an instance of auditd.  When this
@@ -564,19 +566,31 @@ static void kauditd_rehold_skb(struct sk_buff *skb)
  * and queue it, if we have room.  If we want to hold on to the record, but we
  * don't have room, record a record lost message.
  */
-static void kauditd_hold_skb(struct sk_buff *skb)
+static void kauditd_hold_skb(struct sk_buff *skb, int error)
 {
        /* at this point it is uncertain if we will ever send this to auditd so
         * try to send the message via printk before we go any further */
        kauditd_printk_skb(skb);
 
        /* can we just silently drop the message? */
-       if (!audit_default) {
-               kfree_skb(skb);
-               return;
+       if (!audit_default)
+               goto drop;
+
+       /* the hold queue is only for when the daemon goes away completely,
+        * not -EAGAIN failures; if we are in a -EAGAIN state requeue the
+        * record on the retry queue unless it's full, in which case drop it
+        */
+       if (error == -EAGAIN) {
+               if (!audit_backlog_limit ||
+                   skb_queue_len(&audit_retry_queue) < audit_backlog_limit) {
+                       skb_queue_tail(&audit_retry_queue, skb);
+                       return;
+               }
+               audit_log_lost("kauditd retry queue overflow");
+               goto drop;
        }
 
-       /* if we have room, queue the message */
+       /* if we have room in the hold queue, queue the message */
        if (!audit_backlog_limit ||
            skb_queue_len(&audit_hold_queue) < audit_backlog_limit) {
                skb_queue_tail(&audit_hold_queue, skb);
@@ -585,24 +599,32 @@ static void kauditd_hold_skb(struct sk_buff *skb)
 
        /* we have no other options - drop the message */
        audit_log_lost("kauditd hold queue overflow");
+drop:
        kfree_skb(skb);
 }
 
 /**
  * kauditd_retry_skb - Queue an audit record, attempt to send again to auditd
  * @skb: audit record
+ * @error: error code (unused)
  *
  * Description:
  * Not as serious as kauditd_hold_skb() as we still have a connected auditd,
  * but for some reason we are having problems sending it audit records so
  * queue the given record and attempt to resend.
  */
-static void kauditd_retry_skb(struct sk_buff *skb)
+static void kauditd_retry_skb(struct sk_buff *skb, __always_unused int error)
 {
-       /* NOTE: because records should only live in the retry queue for a
-        * short period of time, before either being sent or moved to the hold
-        * queue, we don't currently enforce a limit on this queue */
-       skb_queue_tail(&audit_retry_queue, skb);
+       if (!audit_backlog_limit ||
+           skb_queue_len(&audit_retry_queue) < audit_backlog_limit) {
+               skb_queue_tail(&audit_retry_queue, skb);
+               return;
+       }
+
+       /* we have to drop the record, send it via printk as a last effort */
+       kauditd_printk_skb(skb);
+       audit_log_lost("kauditd retry queue overflow");
+       kfree_skb(skb);
 }
 
 /**
@@ -640,7 +662,7 @@ static void auditd_reset(const struct auditd_connection *ac)
        /* flush the retry queue to the hold queue, but don't touch the main
         * queue since we need to process that normally for multicast */
        while ((skb = skb_dequeue(&audit_retry_queue)))
-               kauditd_hold_skb(skb);
+               kauditd_hold_skb(skb, -ECONNREFUSED);
 }
 
 /**
@@ -714,16 +736,18 @@ static int kauditd_send_queue(struct sock *sk, u32 portid,
                              struct sk_buff_head *queue,
                              unsigned int retry_limit,
                              void (*skb_hook)(struct sk_buff *skb),
-                             void (*err_hook)(struct sk_buff *skb))
+                             void (*err_hook)(struct sk_buff *skb, int error))
 {
        int rc = 0;
-       struct sk_buff *skb;
+       struct sk_buff *skb = NULL;
+       struct sk_buff *skb_tail;
        unsigned int failed = 0;
 
        /* NOTE: kauditd_thread takes care of all our locking, we just use
         *       the netlink info passed to us (e.g. sk and portid) */
 
-       while ((skb = skb_dequeue(queue))) {
+       skb_tail = skb_peek_tail(queue);
+       while ((skb != skb_tail) && (skb = skb_dequeue(queue))) {
                /* call the skb_hook for each skb we touch */
                if (skb_hook)
                        (*skb_hook)(skb);
@@ -731,7 +755,7 @@ static int kauditd_send_queue(struct sock *sk, u32 portid,
                /* can we send to anyone via unicast? */
                if (!sk) {
                        if (err_hook)
-                               (*err_hook)(skb);
+                               (*err_hook)(skb, -ECONNREFUSED);
                        continue;
                }
 
@@ -745,7 +769,7 @@ retry:
                            rc == -ECONNREFUSED || rc == -EPERM) {
                                sk = NULL;
                                if (err_hook)
-                                       (*err_hook)(skb);
+                                       (*err_hook)(skb, rc);
                                if (rc == -EAGAIN)
                                        rc = 0;
                                /* continue to drain the queue */
index fce5d43..a83928c 100644 (file)
@@ -185,7 +185,7 @@ static int audit_match_perm(struct audit_context *ctx, int mask)
        case AUDITSC_EXECVE:
                return mask & AUDIT_PERM_EXEC;
        case AUDITSC_OPENAT2:
-               return mask & ACC_MODE((u32)((struct open_how *)ctx->argv[2])->flags);
+               return mask & ACC_MODE((u32)ctx->openat2.flags);
        default:
                return 0;
        }
index 0606237..9e4ecc9 100644 (file)
@@ -207,7 +207,7 @@ BTF_ID(func, bpf_lsm_socket_socketpair)
 
 BTF_ID(func, bpf_lsm_syslog)
 BTF_ID(func, bpf_lsm_task_alloc)
-BTF_ID(func, bpf_lsm_task_getsecid_subj)
+BTF_ID(func, bpf_lsm_current_getsecid_subj)
 BTF_ID(func, bpf_lsm_task_getsecid_obj)
 BTF_ID(func, bpf_lsm_task_prctl)
 BTF_ID(func, bpf_lsm_task_setscheduler)
index e16dafe..3e23b3f 100644 (file)
@@ -5688,7 +5688,8 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
                        }
                        if (check_ptr_off_reg(env, reg, regno))
                                return -EINVAL;
-               } else if (is_kfunc && (reg->type == PTR_TO_BTF_ID || reg2btf_ids[reg->type])) {
+               } else if (is_kfunc && (reg->type == PTR_TO_BTF_ID ||
+                          (reg2btf_ids[base_type(reg->type)] && !type_flag(reg->type)))) {
                        const struct btf_type *reg_ref_t;
                        const struct btf *reg_btf;
                        const char *reg_ref_tname;
@@ -5706,7 +5707,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
                                reg_ref_id = reg->btf_id;
                        } else {
                                reg_btf = btf_vmlinux;
-                               reg_ref_id = *reg2btf_ids[reg->type];
+                               reg_ref_id = *reg2btf_ids[base_type(reg->type)];
                        }
 
                        reg_ref_t = btf_type_skip_modifiers(reg_btf, reg_ref_id,
index 01cfdf4..55c0842 100644 (file)
@@ -2,6 +2,7 @@
 /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
  */
 #include <linux/bpf.h>
+#include <linux/btf.h>
 #include <linux/bpf-cgroup.h>
 #include <linux/rcupdate.h>
 #include <linux/random.h>
@@ -1075,6 +1076,7 @@ static enum hrtimer_restart bpf_timer_cb(struct hrtimer *hrtimer)
        void *key;
        u32 idx;
 
+       BTF_TYPE_EMIT(struct bpf_timer);
        callback_fn = rcu_dereference_check(t->callback_fn, rcu_read_lock_bh_held());
        if (!callback_fn)
                goto out;
index 638d7fd..710ba9d 100644 (file)
@@ -104,7 +104,7 @@ static struct bpf_ringbuf *bpf_ringbuf_area_alloc(size_t data_sz, int numa_node)
        }
 
        rb = vmap(pages, nr_meta_pages + 2 * nr_data_pages,
-                 VM_ALLOC | VM_USERMAP, PAGE_KERNEL);
+                 VM_MAP | VM_USERMAP, PAGE_KERNEL);
        if (rb) {
                kmemleak_not_leak(pages);
                rb->pages = pages;
index 49e5672..22c8ae9 100644 (file)
@@ -472,13 +472,14 @@ BPF_CALL_4(bpf_get_task_stack, struct task_struct *, task, void *, buf,
           u32, size, u64, flags)
 {
        struct pt_regs *regs;
-       long res;
+       long res = -EINVAL;
 
        if (!try_get_task_stack(task))
                return -EFAULT;
 
        regs = task_pt_regs(task);
-       res = __bpf_get_stack(regs, task, NULL, buf, size, flags);
+       if (regs)
+               res = __bpf_get_stack(regs, task, NULL, buf, size, flags);
        put_task_stack(task);
 
        return res;
index fa4505f..ca70fe6 100644 (file)
@@ -1355,6 +1355,7 @@ int generic_map_delete_batch(struct bpf_map *map,
                maybe_wait_bpf_programs(map);
                if (err)
                        break;
+               cond_resched();
        }
        if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp)))
                err = -EFAULT;
@@ -1412,6 +1413,7 @@ int generic_map_update_batch(struct bpf_map *map,
 
                if (err)
                        break;
+               cond_resched();
        }
 
        if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp)))
@@ -1509,6 +1511,7 @@ int generic_map_lookup_batch(struct bpf_map *map,
                swap(prev_key, key);
                retry = MAP_LOOKUP_RETRIES;
                cp++;
+               cond_resched();
        }
 
        if (err == -EFAULT)
index 4b6974a..5e7edf9 100644 (file)
@@ -550,11 +550,12 @@ static __always_inline u64 notrace bpf_prog_start_time(void)
 static void notrace inc_misses_counter(struct bpf_prog *prog)
 {
        struct bpf_prog_stats *stats;
+       unsigned int flags;
 
        stats = this_cpu_ptr(prog->stats);
-       u64_stats_update_begin(&stats->syncp);
+       flags = u64_stats_update_begin_irqsave(&stats->syncp);
        u64_stats_inc(&stats->misses);
-       u64_stats_update_end(&stats->syncp);
+       u64_stats_update_end_irqrestore(&stats->syncp, flags);
 }
 
 /* The logic is similar to bpf_prog_run(), but with an explicit
index 41e0837..afc6c0e 100644 (file)
@@ -546,9 +546,19 @@ static ssize_t cgroup_release_agent_write(struct kernfs_open_file *of,
                                          char *buf, size_t nbytes, loff_t off)
 {
        struct cgroup *cgrp;
+       struct cgroup_file_ctx *ctx;
 
        BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);
 
+       /*
+        * Release agent gets called with all capabilities,
+        * require capabilities to set release agent.
+        */
+       ctx = of->priv;
+       if ((ctx->ns->user_ns != &init_user_ns) ||
+           !file_ns_capable(of->file, &init_user_ns, CAP_SYS_ADMIN))
+               return -EPERM;
+
        cgrp = cgroup_kn_lock_live(of->kn, false);
        if (!cgrp)
                return -ENODEV;
@@ -954,6 +964,12 @@ int cgroup1_parse_param(struct fs_context *fc, struct fs_parameter *param)
                /* Specifying two release agents is forbidden */
                if (ctx->release_agent)
                        return invalfc(fc, "release_agent respecified");
+               /*
+                * Release agent gets called with all capabilities,
+                * require capabilities to set release agent.
+                */
+               if ((fc->user_ns != &init_user_ns) || !capable(CAP_SYS_ADMIN))
+                       return invalfc(fc, "Setting release_agent not allowed");
                ctx->release_agent = param->string;
                param->string = NULL;
                break;
index b31e146..a557eea 100644 (file)
@@ -3643,6 +3643,12 @@ static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf,
        cgroup_get(cgrp);
        cgroup_kn_unlock(of->kn);
 
+       /* Allow only one trigger per file descriptor */
+       if (ctx->psi.trigger) {
+               cgroup_put(cgrp);
+               return -EBUSY;
+       }
+
        psi = cgroup_ino(cgrp) == 1 ? &psi_system : &cgrp->psi;
        new = psi_trigger_create(psi, buf, nbytes, res);
        if (IS_ERR(new)) {
@@ -3650,8 +3656,7 @@ static ssize_t cgroup_pressure_write(struct kernfs_open_file *of, char *buf,
                return PTR_ERR(new);
        }
 
-       psi_trigger_replace(&ctx->psi.trigger, new);
-
+       smp_store_release(&ctx->psi.trigger, new);
        cgroup_put(cgrp);
 
        return nbytes;
@@ -3690,7 +3695,7 @@ static void cgroup_pressure_release(struct kernfs_open_file *of)
 {
        struct cgroup_file_ctx *ctx = of->priv;
 
-       psi_trigger_replace(&ctx->psi.trigger, NULL);
+       psi_trigger_destroy(ctx->psi.trigger);
 }
 
 bool cgroup_psi_enabled(void)
@@ -6161,6 +6166,20 @@ static int cgroup_css_set_fork(struct kernel_clone_args *kargs)
        if (ret)
                goto err;
 
+       /*
+        * Spawning a task directly into a cgroup works by passing a file
+        * descriptor to the target cgroup directory. This can even be an O_PATH
+        * file descriptor. But it can never be a cgroup.procs file descriptor.
+        * This was done on purpose so spawning into a cgroup could be
+        * conceptualized as an atomic
+        *
+        *   fd = openat(dfd_cgroup, "cgroup.procs", ...);
+        *   write(fd, <child-pid>, ...);
+        *
+        * sequence, i.e. it's a shorthand for the caller opening and writing
+        * cgroup.procs of the cgroup indicated by @dfd_cgroup. This allows us
+        * to always use the caller's credentials.
+        */
        ret = cgroup_attach_permissions(cset->dfl_cgrp, dst_cgrp, sb,
                                        !(kargs->flags & CLONE_THREAD),
                                        current->nsproxy->cgroup_ns);
index dc653ab..5de1844 100644 (file)
@@ -590,6 +590,35 @@ static inline void free_cpuset(struct cpuset *cs)
        kfree(cs);
 }
 
+/*
+ * validate_change_legacy() - Validate conditions specific to legacy (v1)
+ *                            behavior.
+ */
+static int validate_change_legacy(struct cpuset *cur, struct cpuset *trial)
+{
+       struct cgroup_subsys_state *css;
+       struct cpuset *c, *par;
+       int ret;
+
+       WARN_ON_ONCE(!rcu_read_lock_held());
+
+       /* Each of our child cpusets must be a subset of us */
+       ret = -EBUSY;
+       cpuset_for_each_child(c, css, cur)
+               if (!is_cpuset_subset(c, trial))
+                       goto out;
+
+       /* On legacy hierarchy, we must be a subset of our parent cpuset. */
+       ret = -EACCES;
+       par = parent_cs(cur);
+       if (par && !is_cpuset_subset(trial, par))
+               goto out;
+
+       ret = 0;
+out:
+       return ret;
+}
+
 /*
  * validate_change() - Used to validate that any proposed cpuset change
  *                    follows the structural rules for cpusets.
@@ -614,20 +643,21 @@ static int validate_change(struct cpuset *cur, struct cpuset *trial)
 {
        struct cgroup_subsys_state *css;
        struct cpuset *c, *par;
-       int ret;
-
-       /* The checks don't apply to root cpuset */
-       if (cur == &top_cpuset)
-               return 0;
+       int ret = 0;
 
        rcu_read_lock();
-       par = parent_cs(cur);
 
-       /* On legacy hierarchy, we must be a subset of our parent cpuset. */
-       ret = -EACCES;
-       if (!is_in_v2_mode() && !is_cpuset_subset(trial, par))
+       if (!is_in_v2_mode())
+               ret = validate_change_legacy(cur, trial);
+       if (ret)
+               goto out;
+
+       /* Remaining checks don't apply to root cpuset */
+       if (cur == &top_cpuset)
                goto out;
 
+       par = parent_cs(cur);
+
        /*
         * If either I or some sibling (!= me) is exclusive, we can't
         * overlap
@@ -1175,9 +1205,7 @@ enum subparts_cmd {
  *
  * Because of the implicit cpu exclusive nature of a partition root,
  * cpumask changes that violates the cpu exclusivity rule will not be
- * permitted when checked by validate_change(). The validate_change()
- * function will also prevent any changes to the cpu list if it is not
- * a superset of children's cpu lists.
+ * permitted when checked by validate_change().
  */
 static int update_parent_subparts_cpumask(struct cpuset *cpuset, int cmd,
                                          struct cpumask *newmask,
@@ -1522,10 +1550,15 @@ static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs,
        struct cpuset *sibling;
        struct cgroup_subsys_state *pos_css;
 
+       percpu_rwsem_assert_held(&cpuset_rwsem);
+
        /*
         * Check all its siblings and call update_cpumasks_hier()
         * if their use_parent_ecpus flag is set in order for them
         * to use the right effective_cpus value.
+        *
+        * The update_cpumasks_hier() function may sleep. So we have to
+        * release the RCU read lock before calling it.
         */
        rcu_read_lock();
        cpuset_for_each_child(sibling, pos_css, parent) {
@@ -1533,8 +1566,13 @@ static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs,
                        continue;
                if (!sibling->use_parent_ecpus)
                        continue;
+               if (!css_tryget_online(&sibling->css))
+                       continue;
 
+               rcu_read_unlock();
                update_cpumasks_hier(sibling, tmp);
+               rcu_read_lock();
+               css_put(&sibling->css);
        }
        rcu_read_unlock();
 }
@@ -1607,8 +1645,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
         * Make sure that subparts_cpus is a subset of cpus_allowed.
         */
        if (cs->nr_subparts_cpus) {
-               cpumask_andnot(cs->subparts_cpus, cs->subparts_cpus,
-                              cs->cpus_allowed);
+               cpumask_and(cs->subparts_cpus, cs->subparts_cpus, cs->cpus_allowed);
                cs->nr_subparts_cpus = cpumask_weight(cs->subparts_cpus);
        }
        spin_unlock_irq(&callback_lock);
@@ -2252,6 +2289,7 @@ static void cpuset_attach(struct cgroup_taskset *tset)
        cgroup_taskset_first(tset, &css);
        cs = css_cs(css);
 
+       cpus_read_lock();
        percpu_down_write(&cpuset_rwsem);
 
        guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
@@ -2305,6 +2343,7 @@ static void cpuset_attach(struct cgroup_taskset *tset)
                wake_up(&cpuset_attach_wq);
 
        percpu_up_write(&cpuset_rwsem);
+       cpus_read_unlock();
 }
 
 /* The various types of files and directories in a cpuset file system */
@@ -3485,8 +3524,8 @@ static struct cpuset *nearest_hardwall_ancestor(struct cpuset *cs)
        return cs;
 }
 
-/**
- * cpuset_node_allowed - Can we allocate on a memory node?
+/*
+ * __cpuset_node_allowed - Can we allocate on a memory node?
  * @node: is this an allowed node?
  * @gfp_mask: memory allocation flags
  *
@@ -3657,8 +3696,8 @@ void cpuset_print_current_mems_allowed(void)
 
 int cpuset_memory_pressure_enabled __read_mostly;
 
-/**
- * cpuset_memory_pressure_bump - keep stats of per-cpuset reclaims.
+/*
+ * __cpuset_memory_pressure_bump - keep stats of per-cpuset reclaims.
  *
  * Keep a running average of the rate of synchronous (direct)
  * page reclaim efforts initiated by tasks in each cpuset.
@@ -3673,7 +3712,7 @@ int cpuset_memory_pressure_enabled __read_mostly;
  * "memory_pressure".  Value displayed is an integer
  * representing the recent rate of entry into the synchronous
  * (direct) page reclaim by any task attached to the cpuset.
- **/
+ */
 
 void __cpuset_memory_pressure_bump(void)
 {
index eb0029c..e400fbb 100644 (file)
@@ -1,5 +1,5 @@
 #  KEEP ALPHABETICALLY SORTED
-# CONFIG_AIO is not set
+# CONFIG_BPF_UNPRIV_DEFAULT_OFF is not set
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_LEGACY_PTYS is not set
index 473d17c..933155c 100644 (file)
@@ -665,21 +665,16 @@ EXPORT_SYMBOL(cred_fscmp);
 
 int set_cred_ucounts(struct cred *new)
 {
-       struct task_struct *task = current;
-       const struct cred *old = task->real_cred;
        struct ucounts *new_ucounts, *old_ucounts = new->ucounts;
 
-       if (new->user == old->user && new->user_ns == old->user_ns)
-               return 0;
-
        /*
         * This optimization is needed because alloc_ucounts() uses locks
         * for table lookups.
         */
-       if (old_ucounts->ns == new->user_ns && uid_eq(old_ucounts->uid, new->euid))
+       if (old_ucounts->ns == new->user_ns && uid_eq(old_ucounts->uid, new->uid))
                return 0;
 
-       if (!(new_ucounts = alloc_ucounts(new->user_ns, new->euid)))
+       if (!(new_ucounts = alloc_ucounts(new->user_ns, new->uid)))
                return -EAGAIN;
 
        new->ucounts = new_ucounts;
index f1e7ea1..bfc56cb 100644 (file)
@@ -628,7 +628,8 @@ phys_addr_t swiotlb_tbl_map_single(struct device *dev, phys_addr_t orig_addr,
                mem->slots[index + i].orig_addr = slot_addr(orig_addr, i);
        tlb_addr = slot_addr(mem->start, index) + offset;
        if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
-           (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
+           (!(attrs & DMA_ATTR_OVERWRITE) || dir == DMA_TO_DEVICE ||
+           dir == DMA_BIDIRECTIONAL))
                swiotlb_bounce(dev, tlb_addr, mapping_size, DMA_TO_DEVICE);
        return tlb_addr;
 }
index fc18664..6859229 100644 (file)
@@ -674,6 +674,23 @@ perf_event_set_state(struct perf_event *event, enum perf_event_state state)
        WRITE_ONCE(event->state, state);
 }
 
+/*
+ * UP store-release, load-acquire
+ */
+
+#define __store_release(ptr, val)                                      \
+do {                                                                   \
+       barrier();                                                      \
+       WRITE_ONCE(*(ptr), (val));                                      \
+} while (0)
+
+#define __load_acquire(ptr)                                            \
+({                                                                     \
+       __unqual_scalar_typeof(*(ptr)) ___p = READ_ONCE(*(ptr));        \
+       barrier();                                                      \
+       ___p;                                                           \
+})
+
 #ifdef CONFIG_CGROUP_PERF
 
 static inline bool
@@ -719,34 +736,51 @@ static inline u64 perf_cgroup_event_time(struct perf_event *event)
        return t->time;
 }
 
-static inline void __update_cgrp_time(struct perf_cgroup *cgrp)
+static inline u64 perf_cgroup_event_time_now(struct perf_event *event, u64 now)
 {
-       struct perf_cgroup_info *info;
-       u64 now;
-
-       now = perf_clock();
+       struct perf_cgroup_info *t;
 
-       info = this_cpu_ptr(cgrp->info);
+       t = per_cpu_ptr(event->cgrp->info, event->cpu);
+       if (!__load_acquire(&t->active))
+               return t->time;
+       now += READ_ONCE(t->timeoffset);
+       return now;
+}
 
-       info->time += now - info->timestamp;
+static inline void __update_cgrp_time(struct perf_cgroup_info *info, u64 now, bool adv)
+{
+       if (adv)
+               info->time += now - info->timestamp;
        info->timestamp = now;
+       /*
+        * see update_context_time()
+        */
+       WRITE_ONCE(info->timeoffset, info->time - info->timestamp);
 }
 
-static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx)
+static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx, bool final)
 {
        struct perf_cgroup *cgrp = cpuctx->cgrp;
        struct cgroup_subsys_state *css;
+       struct perf_cgroup_info *info;
 
        if (cgrp) {
+               u64 now = perf_clock();
+
                for (css = &cgrp->css; css; css = css->parent) {
                        cgrp = container_of(css, struct perf_cgroup, css);
-                       __update_cgrp_time(cgrp);
+                       info = this_cpu_ptr(cgrp->info);
+
+                       __update_cgrp_time(info, now, true);
+                       if (final)
+                               __store_release(&info->active, 0);
                }
        }
 }
 
 static inline void update_cgrp_time_from_event(struct perf_event *event)
 {
+       struct perf_cgroup_info *info;
        struct perf_cgroup *cgrp;
 
        /*
@@ -760,8 +794,10 @@ static inline void update_cgrp_time_from_event(struct perf_event *event)
        /*
         * Do not update time when cgroup is not active
         */
-       if (cgroup_is_descendant(cgrp->css.cgroup, event->cgrp->css.cgroup))
-               __update_cgrp_time(event->cgrp);
+       if (cgroup_is_descendant(cgrp->css.cgroup, event->cgrp->css.cgroup)) {
+               info = this_cpu_ptr(event->cgrp->info);
+               __update_cgrp_time(info, perf_clock(), true);
+       }
 }
 
 static inline void
@@ -785,7 +821,8 @@ perf_cgroup_set_timestamp(struct task_struct *task,
        for (css = &cgrp->css; css; css = css->parent) {
                cgrp = container_of(css, struct perf_cgroup, css);
                info = this_cpu_ptr(cgrp->info);
-               info->timestamp = ctx->timestamp;
+               __update_cgrp_time(info, ctx->timestamp, false);
+               __store_release(&info->active, 1);
        }
 }
 
@@ -802,7 +839,7 @@ static DEFINE_PER_CPU(struct list_head, cgrp_cpuctx_list);
  */
 static void perf_cgroup_switch(struct task_struct *task, int mode)
 {
-       struct perf_cpu_context *cpuctx;
+       struct perf_cpu_context *cpuctx, *tmp;
        struct list_head *list;
        unsigned long flags;
 
@@ -813,7 +850,7 @@ static void perf_cgroup_switch(struct task_struct *task, int mode)
        local_irq_save(flags);
 
        list = this_cpu_ptr(&cgrp_cpuctx_list);
-       list_for_each_entry(cpuctx, list, cgrp_cpuctx_entry) {
+       list_for_each_entry_safe(cpuctx, tmp, list, cgrp_cpuctx_entry) {
                WARN_ON_ONCE(cpuctx->ctx.nr_cgroups == 0);
 
                perf_ctx_lock(cpuctx, cpuctx->task_ctx);
@@ -981,14 +1018,6 @@ out:
        return ret;
 }
 
-static inline void
-perf_cgroup_set_shadow_time(struct perf_event *event, u64 now)
-{
-       struct perf_cgroup_info *t;
-       t = per_cpu_ptr(event->cgrp->info, event->cpu);
-       event->shadow_ctx_time = now - t->timestamp;
-}
-
 static inline void
 perf_cgroup_event_enable(struct perf_event *event, struct perf_event_context *ctx)
 {
@@ -1066,7 +1095,8 @@ static inline void update_cgrp_time_from_event(struct perf_event *event)
 {
 }
 
-static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx)
+static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx,
+                                               bool final)
 {
 }
 
@@ -1098,12 +1128,12 @@ perf_cgroup_switch(struct task_struct *task, struct task_struct *next)
 {
 }
 
-static inline void
-perf_cgroup_set_shadow_time(struct perf_event *event, u64 now)
+static inline u64 perf_cgroup_event_time(struct perf_event *event)
 {
+       return 0;
 }
 
-static inline u64 perf_cgroup_event_time(struct perf_event *event)
+static inline u64 perf_cgroup_event_time_now(struct perf_event *event, u64 now)
 {
        return 0;
 }
@@ -1525,22 +1555,59 @@ static void perf_unpin_context(struct perf_event_context *ctx)
 /*
  * Update the record of the current time in a context.
  */
-static void update_context_time(struct perf_event_context *ctx)
+static void __update_context_time(struct perf_event_context *ctx, bool adv)
 {
        u64 now = perf_clock();
 
-       ctx->time += now - ctx->timestamp;
+       if (adv)
+               ctx->time += now - ctx->timestamp;
        ctx->timestamp = now;
+
+       /*
+        * The above: time' = time + (now - timestamp), can be re-arranged
+        * into: time` = now + (time - timestamp), which gives a single value
+        * offset to compute future time without locks on.
+        *
+        * See perf_event_time_now(), which can be used from NMI context where
+        * it's (obviously) not possible to acquire ctx->lock in order to read
+        * both the above values in a consistent manner.
+        */
+       WRITE_ONCE(ctx->timeoffset, ctx->time - ctx->timestamp);
+}
+
+static void update_context_time(struct perf_event_context *ctx)
+{
+       __update_context_time(ctx, true);
 }
 
 static u64 perf_event_time(struct perf_event *event)
 {
        struct perf_event_context *ctx = event->ctx;
 
+       if (unlikely(!ctx))
+               return 0;
+
        if (is_cgroup_event(event))
                return perf_cgroup_event_time(event);
 
-       return ctx ? ctx->time : 0;
+       return ctx->time;
+}
+
+static u64 perf_event_time_now(struct perf_event *event, u64 now)
+{
+       struct perf_event_context *ctx = event->ctx;
+
+       if (unlikely(!ctx))
+               return 0;
+
+       if (is_cgroup_event(event))
+               return perf_cgroup_event_time_now(event, now);
+
+       if (!(__load_acquire(&ctx->is_active) & EVENT_TIME))
+               return ctx->time;
+
+       now += READ_ONCE(ctx->timeoffset);
+       return now;
 }
 
 static enum event_type_t get_event_type(struct perf_event *event)
@@ -2350,7 +2417,7 @@ __perf_remove_from_context(struct perf_event *event,
 
        if (ctx->is_active & EVENT_TIME) {
                update_context_time(ctx);
-               update_cgrp_time_from_cpuctx(cpuctx);
+               update_cgrp_time_from_cpuctx(cpuctx, false);
        }
 
        event_sched_out(event, cpuctx, ctx);
@@ -2361,6 +2428,9 @@ __perf_remove_from_context(struct perf_event *event,
        list_del_event(event, ctx);
 
        if (!ctx->nr_events && ctx->is_active) {
+               if (ctx == &cpuctx->ctx)
+                       update_cgrp_time_from_cpuctx(cpuctx, true);
+
                ctx->is_active = 0;
                ctx->rotate_necessary = 0;
                if (ctx->task) {
@@ -2392,7 +2462,11 @@ static void perf_remove_from_context(struct perf_event *event, unsigned long fla
         * event_function_call() user.
         */
        raw_spin_lock_irq(&ctx->lock);
-       if (!ctx->is_active) {
+       /*
+        * Cgroup events are per-cpu events, and must IPI because of
+        * cgrp_cpuctx_list.
+        */
+       if (!ctx->is_active && !is_cgroup_event(event)) {
                __perf_remove_from_context(event, __get_cpu_context(ctx),
                                           ctx, (void *)flags);
                raw_spin_unlock_irq(&ctx->lock);
@@ -2482,40 +2556,6 @@ void perf_event_disable_inatomic(struct perf_event *event)
        irq_work_queue(&event->pending);
 }
 
-static void perf_set_shadow_time(struct perf_event *event,
-                                struct perf_event_context *ctx)
-{
-       /*
-        * use the correct time source for the time snapshot
-        *
-        * We could get by without this by leveraging the
-        * fact that to get to this function, the caller
-        * has most likely already called update_context_time()
-        * and update_cgrp_time_xx() and thus both timestamp
-        * are identical (or very close). Given that tstamp is,
-        * already adjusted for cgroup, we could say that:
-        *    tstamp - ctx->timestamp
-        * is equivalent to
-        *    tstamp - cgrp->timestamp.
-        *
-        * Then, in perf_output_read(), the calculation would
-        * work with no changes because:
-        * - event is guaranteed scheduled in
-        * - no scheduled out in between
-        * - thus the timestamp would be the same
-        *
-        * But this is a bit hairy.
-        *
-        * So instead, we have an explicit cgroup call to remain
-        * within the time source all along. We believe it
-        * is cleaner and simpler to understand.
-        */
-       if (is_cgroup_event(event))
-               perf_cgroup_set_shadow_time(event, event->tstamp);
-       else
-               event->shadow_ctx_time = event->tstamp - ctx->timestamp;
-}
-
 #define MAX_INTERRUPTS (~0ULL)
 
 static void perf_log_throttle(struct perf_event *event, int enable);
@@ -2556,8 +2596,6 @@ event_sched_in(struct perf_event *event,
 
        perf_pmu_disable(event->pmu);
 
-       perf_set_shadow_time(event, ctx);
-
        perf_log_itrace_start(event);
 
        if (event->pmu->add(event, PERF_EF_START)) {
@@ -2861,11 +2899,14 @@ perf_install_in_context(struct perf_event_context *ctx,
         * perf_event_attr::disabled events will not run and can be initialized
         * without IPI. Except when this is the first event for the context, in
         * that case we need the magic of the IPI to set ctx->is_active.
+        * Similarly, cgroup events for the context also needs the IPI to
+        * manipulate the cgrp_cpuctx_list.
         *
         * The IOC_ENABLE that is sure to follow the creation of a disabled
         * event will issue the IPI and reprogram the hardware.
         */
-       if (__perf_effective_state(event) == PERF_EVENT_STATE_OFF && ctx->nr_events) {
+       if (__perf_effective_state(event) == PERF_EVENT_STATE_OFF &&
+           ctx->nr_events && !is_cgroup_event(event)) {
                raw_spin_lock_irq(&ctx->lock);
                if (ctx->task == TASK_TOMBSTONE) {
                        raw_spin_unlock_irq(&ctx->lock);
@@ -3197,6 +3238,15 @@ static int perf_event_modify_breakpoint(struct perf_event *bp,
        return err;
 }
 
+/*
+ * Copy event-type-independent attributes that may be modified.
+ */
+static void perf_event_modify_copy_attr(struct perf_event_attr *to,
+                                       const struct perf_event_attr *from)
+{
+       to->sig_data = from->sig_data;
+}
+
 static int perf_event_modify_attr(struct perf_event *event,
                                  struct perf_event_attr *attr)
 {
@@ -3219,10 +3269,17 @@ static int perf_event_modify_attr(struct perf_event *event,
        WARN_ON_ONCE(event->ctx->parent_ctx);
 
        mutex_lock(&event->child_mutex);
+       /*
+        * Event-type-independent attributes must be copied before event-type
+        * modification, which will validate that final attributes match the
+        * source attributes after all relevant attributes have been copied.
+        */
+       perf_event_modify_copy_attr(&event->attr, attr);
        err = func(event, attr);
        if (err)
                goto out;
        list_for_each_entry(child, &event->child_list, child_list) {
+               perf_event_modify_copy_attr(&child->attr, attr);
                err = func(child, attr);
                if (err)
                        goto out;
@@ -3251,16 +3308,6 @@ static void ctx_sched_out(struct perf_event_context *ctx,
                return;
        }
 
-       ctx->is_active &= ~event_type;
-       if (!(ctx->is_active & EVENT_ALL))
-               ctx->is_active = 0;
-
-       if (ctx->task) {
-               WARN_ON_ONCE(cpuctx->task_ctx != ctx);
-               if (!ctx->is_active)
-                       cpuctx->task_ctx = NULL;
-       }
-
        /*
         * Always update time if it was set; not only when it changes.
         * Otherwise we can 'forget' to update time for any but the last
@@ -3274,7 +3321,22 @@ static void ctx_sched_out(struct perf_event_context *ctx,
        if (is_active & EVENT_TIME) {
                /* update (and stop) ctx time */
                update_context_time(ctx);
-               update_cgrp_time_from_cpuctx(cpuctx);
+               update_cgrp_time_from_cpuctx(cpuctx, ctx == &cpuctx->ctx);
+               /*
+                * CPU-release for the below ->is_active store,
+                * see __load_acquire() in perf_event_time_now()
+                */
+               barrier();
+       }
+
+       ctx->is_active &= ~event_type;
+       if (!(ctx->is_active & EVENT_ALL))
+               ctx->is_active = 0;
+
+       if (ctx->task) {
+               WARN_ON_ONCE(cpuctx->task_ctx != ctx);
+               if (!ctx->is_active)
+                       cpuctx->task_ctx = NULL;
        }
 
        is_active ^= ctx->is_active; /* changed bits */
@@ -3711,13 +3773,19 @@ static noinline int visit_groups_merge(struct perf_cpu_context *cpuctx,
        return 0;
 }
 
+/*
+ * Because the userpage is strictly per-event (there is no concept of context,
+ * so there cannot be a context indirection), every userpage must be updated
+ * when context time starts :-(
+ *
+ * IOW, we must not miss EVENT_TIME edges.
+ */
 static inline bool event_update_userpage(struct perf_event *event)
 {
        if (likely(!atomic_read(&event->mmap_count)))
                return false;
 
        perf_event_update_time(event);
-       perf_set_shadow_time(event, event->ctx);
        perf_event_update_userpage(event);
 
        return true;
@@ -3801,13 +3869,23 @@ ctx_sched_in(struct perf_event_context *ctx,
             struct task_struct *task)
 {
        int is_active = ctx->is_active;
-       u64 now;
 
        lockdep_assert_held(&ctx->lock);
 
        if (likely(!ctx->nr_events))
                return;
 
+       if (is_active ^ EVENT_TIME) {
+               /* start ctx time */
+               __update_context_time(ctx, false);
+               perf_cgroup_set_timestamp(task, ctx);
+               /*
+                * CPU-release for the below ->is_active store,
+                * see __load_acquire() in perf_event_time_now()
+                */
+               barrier();
+       }
+
        ctx->is_active |= (event_type | EVENT_TIME);
        if (ctx->task) {
                if (!is_active)
@@ -3818,13 +3896,6 @@ ctx_sched_in(struct perf_event_context *ctx,
 
        is_active ^= ctx->is_active; /* changed bits */
 
-       if (is_active & EVENT_TIME) {
-               /* start ctx time */
-               now = perf_clock();
-               ctx->timestamp = now;
-               perf_cgroup_set_timestamp(task, ctx);
-       }
-
        /*
         * First go through the list and put on any pinned groups
         * in order to give them the best chance of going on.
@@ -4418,6 +4489,18 @@ static inline u64 perf_event_count(struct perf_event *event)
        return local64_read(&event->count) + atomic64_read(&event->child_count);
 }
 
+static void calc_timer_values(struct perf_event *event,
+                               u64 *now,
+                               u64 *enabled,
+                               u64 *running)
+{
+       u64 ctx_time;
+
+       *now = perf_clock();
+       ctx_time = perf_event_time_now(event, *now);
+       __perf_update_times(event, ctx_time, enabled, running);
+}
+
 /*
  * NMI-safe method to read a local event, that is an event that
  * is:
@@ -4477,10 +4560,9 @@ int perf_event_read_local(struct perf_event *event, u64 *value,
 
        *value = local64_read(&event->count);
        if (enabled || running) {
-               u64 now = event->shadow_ctx_time + perf_clock();
-               u64 __enabled, __running;
+               u64 __enabled, __running, __now;;
 
-               __perf_update_times(event, now, &__enabled, &__running);
+               calc_timer_values(event, &__now, &__enabled, &__running);
                if (enabled)
                        *enabled = __enabled;
                if (running)
@@ -5802,18 +5884,6 @@ static int perf_event_index(struct perf_event *event)
        return event->pmu->event_idx(event);
 }
 
-static void calc_timer_values(struct perf_event *event,
-                               u64 *now,
-                               u64 *enabled,
-                               u64 *running)
-{
-       u64 ctx_time;
-
-       *now = perf_clock();
-       ctx_time = event->shadow_ctx_time + *now;
-       __perf_update_times(event, ctx_time, enabled, running);
-}
-
 static void perf_event_init_userpage(struct perf_event *event)
 {
        struct perf_event_mmap_page *userpg;
@@ -5938,6 +6008,8 @@ static void ring_buffer_attach(struct perf_event *event,
        struct perf_buffer *old_rb = NULL;
        unsigned long flags;
 
+       WARN_ON_ONCE(event->parent);
+
        if (event->rb) {
                /*
                 * Should be impossible, we set this when removing
@@ -5995,6 +6067,9 @@ static void ring_buffer_wakeup(struct perf_event *event)
 {
        struct perf_buffer *rb;
 
+       if (event->parent)
+               event = event->parent;
+
        rcu_read_lock();
        rb = rcu_dereference(event->rb);
        if (rb) {
@@ -6008,6 +6083,9 @@ struct perf_buffer *ring_buffer_get(struct perf_event *event)
 {
        struct perf_buffer *rb;
 
+       if (event->parent)
+               event = event->parent;
+
        rcu_read_lock();
        rb = rcu_dereference(event->rb);
        if (rb) {
@@ -6353,7 +6431,6 @@ accounting:
                ring_buffer_attach(event, rb);
 
                perf_event_update_time(event);
-               perf_set_shadow_time(event, event->ctx);
                perf_event_init_userpage(event);
                perf_event_update_userpage(event);
        } else {
@@ -6717,7 +6794,7 @@ static unsigned long perf_prepare_sample_aux(struct perf_event *event,
        if (WARN_ON_ONCE(READ_ONCE(sampler->oncpu) != smp_processor_id()))
                goto out;
 
-       rb = ring_buffer_get(sampler->parent ? sampler->parent : sampler);
+       rb = ring_buffer_get(sampler);
        if (!rb)
                goto out;
 
@@ -6783,7 +6860,7 @@ static void perf_aux_sample_output(struct perf_event *event,
        if (WARN_ON_ONCE(!sampler || !data->aux_size))
                return;
 
-       rb = ring_buffer_get(sampler->parent ? sampler->parent : sampler);
+       rb = ring_buffer_get(sampler);
        if (!rb)
                return;
 
index d75a528..a024bf6 100644 (file)
@@ -2021,18 +2021,18 @@ static __latent_entropy struct task_struct *copy_process(
 #ifdef CONFIG_PROVE_LOCKING
        DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
 #endif
+       retval = copy_creds(p, clone_flags);
+       if (retval < 0)
+               goto bad_fork_free;
+
        retval = -EAGAIN;
        if (is_ucounts_overlimit(task_ucounts(p), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC))) {
                if (p->real_cred->user != INIT_USER &&
                    !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))
-                       goto bad_fork_free;
+                       goto bad_fork_cleanup_count;
        }
        current->flags &= ~PF_NPROC_EXCEEDED;
 
-       retval = copy_creds(p, clone_flags);
-       if (retval < 0)
-               goto bad_fork_free;
-
        /*
         * If multiple threads are within copy_process(), then this check
         * triggers too late. This doesn't hurt, the check is only there
@@ -2266,6 +2266,17 @@ static __latent_entropy struct task_struct *copy_process(
        if (retval)
                goto bad_fork_put_pidfd;
 
+       /*
+        * Now that the cgroups are pinned, re-clone the parent cgroup and put
+        * the new task on the correct runqueue. All this *before* the task
+        * becomes visible.
+        *
+        * This isn't part of ->can_fork() because while the re-cloning is
+        * cgroup specific, it unconditionally needs to place the task on a
+        * runqueue.
+        */
+       sched_cgroup_fork(p, args);
+
        /*
         * From this point on we must avoid any synchronous user-space
         * communication until we take the tasklist-lock. In particular, we do
@@ -2323,10 +2334,6 @@ static __latent_entropy struct task_struct *copy_process(
                goto bad_fork_cancel_cgroup;
        }
 
-       /* past the last point of failure */
-       if (pidfile)
-               fd_install(pidfd, pidfile);
-
        init_task_pid_links(p);
        if (likely(p->pid)) {
                ptrace_init_task(p, (clone_flags & CLONE_PTRACE) || trace);
@@ -2375,8 +2382,11 @@ static __latent_entropy struct task_struct *copy_process(
        syscall_tracepoint_update(p);
        write_unlock_irq(&tasklist_lock);
 
+       if (pidfile)
+               fd_install(pidfd, pidfile);
+
        proc_fork_connector(p);
-       sched_post_fork(p, args);
+       sched_post_fork(p);
        cgroup_post_fork(p, args);
        perf_event_fork(p);
 
index 4a882f8..f8a0212 100644 (file)
@@ -3462,7 +3462,7 @@ struct lock_class *lock_chain_get_class(struct lock_chain *chain, int i)
        u16 chain_hlock = chain_hlocks[chain->base + i];
        unsigned int class_idx = chain_hlock_class_idx(chain_hlock);
 
-       return lock_classes + class_idx - 1;
+       return lock_classes + class_idx;
 }
 
 /*
@@ -3530,7 +3530,7 @@ static void print_chain_keys_chain(struct lock_chain *chain)
                hlock_id = chain_hlocks[chain->base + i];
                chain_key = print_chain_key_iteration(hlock_id, chain_key);
 
-               print_lock_name(lock_classes + chain_hlock_class_idx(hlock_id) - 1);
+               print_lock_name(lock_classes + chain_hlock_class_idx(hlock_id));
                printk("\n");
        }
 }
index 24dab04..46a5c2e 100644 (file)
@@ -3725,12 +3725,6 @@ static noinline int do_init_module(struct module *mod)
        }
        freeinit->module_init = mod->init_layout.base;
 
-       /*
-        * We want to find out whether @mod uses async during init.  Clear
-        * PF_USED_ASYNC.  async_schedule*() will set it.
-        */
-       current->flags &= ~PF_USED_ASYNC;
-
        do_mod_ctors(mod);
        /* Start the module */
        if (mod->init != NULL)
@@ -3756,22 +3750,13 @@ static noinline int do_init_module(struct module *mod)
 
        /*
         * We need to finish all async code before the module init sequence
-        * is done.  This has potential to deadlock.  For example, a newly
-        * detected block device can trigger request_module() of the
-        * default iosched from async probing task.  Once userland helper
-        * reaches here, async_synchronize_full() will wait on the async
-        * task waiting on request_module() and deadlock.
-        *
-        * This deadlock is avoided by perfomring async_synchronize_full()
-        * iff module init queued any async jobs.  This isn't a full
-        * solution as it will deadlock the same if module loading from
-        * async jobs nests more than once; however, due to the various
-        * constraints, this hack seems to be the best option for now.
-        * Please refer to the following thread for details.
+        * is done. This has potential to deadlock if synchronous module
+        * loading is requested from async (which is not allowed!).
         *
-        * http://thread.gmane.org/gmane.linux.kernel/1420814
+        * See commit 0fdff3ec6d87 ("async, kmod: warn on synchronous
+        * request_module() from async workers") for more details.
         */
-       if (!mod->async_probe_requested && (current->flags & PF_USED_ASYNC))
+       if (!mod->async_probe_requested)
                async_synchronize_full();
 
        ftrace_free_mem(mod, mod->init_layout.base, mod->init_layout.base +
index b01c69c..ffef98a 100644 (file)
@@ -250,6 +250,7 @@ void module_decompress_cleanup(struct load_info *info)
        info->max_pages = info->used_pages = 0;
 }
 
+#ifdef CONFIG_SYSFS
 static ssize_t compression_show(struct kobject *kobj,
                                struct kobj_attribute *attr, char *buf)
 {
@@ -269,3 +270,4 @@ static int __init module_decompress_sysfs_init(void)
        return 0;
 }
 late_initcall(module_decompress_sysfs_init);
+#endif
index 44169f3..7e64607 100644 (file)
@@ -504,7 +504,10 @@ static ssize_t pm_wakeup_irq_show(struct kobject *kobj,
                                        struct kobj_attribute *attr,
                                        char *buf)
 {
-       return pm_wakeup_irq ? sprintf(buf, "%u\n", pm_wakeup_irq) : -ENODATA;
+       if (!pm_wakeup_irq())
+               return -ENODATA;
+
+       return sprintf(buf, "%u\n", pm_wakeup_irq());
 }
 
 power_attr_ro(pm_wakeup_irq);
index b7e7798..11b570f 100644 (file)
@@ -134,7 +134,7 @@ int freeze_processes(void)
        if (!pm_freezing)
                atomic_inc(&system_freezing_cnt);
 
-       pm_wakeup_clear(true);
+       pm_wakeup_clear(0);
        pr_info("Freezing user space processes ... ");
        pm_freezing = true;
        error = try_to_freeze_tasks(true);
index f7a9860..330d499 100644 (file)
@@ -978,8 +978,7 @@ static void memory_bm_recycle(struct memory_bitmap *bm)
  * Register a range of page frames the contents of which should not be saved
  * during hibernation (to be used in the early initialization code).
  */
-void __init __register_nosave_region(unsigned long start_pfn,
-                                    unsigned long end_pfn, int use_kmalloc)
+void __init register_nosave_region(unsigned long start_pfn, unsigned long end_pfn)
 {
        struct nosave_region *region;
 
@@ -995,18 +994,12 @@ void __init __register_nosave_region(unsigned long start_pfn,
                        goto Report;
                }
        }
-       if (use_kmalloc) {
-               /* During init, this shouldn't fail */
-               region = kmalloc(sizeof(struct nosave_region), GFP_KERNEL);
-               BUG_ON(!region);
-       } else {
-               /* This allocation cannot fail */
-               region = memblock_alloc(sizeof(struct nosave_region),
-                                       SMP_CACHE_BYTES);
-               if (!region)
-                       panic("%s: Failed to allocate %zu bytes\n", __func__,
-                             sizeof(struct nosave_region));
-       }
+       /* This allocation cannot fail */
+       region = memblock_alloc(sizeof(struct nosave_region),
+                               SMP_CACHE_BYTES);
+       if (!region)
+               panic("%s: Failed to allocate %zu bytes\n", __func__,
+                     sizeof(struct nosave_region));
        region->start_pfn = start_pfn;
        region->end_pfn = end_pfn;
        list_add_tail(&region->list, &nosave_regions);
index 80cc1f0..6fcdee7 100644 (file)
@@ -136,8 +136,6 @@ static void s2idle_loop(void)
                        break;
                }
 
-               pm_wakeup_clear(false);
-
                s2idle_enter();
        }
 
index 105df4d..52571dc 100644 (file)
@@ -39,23 +39,20 @@ ssize_t pm_show_wakelocks(char *buf, bool show_active)
 {
        struct rb_node *node;
        struct wakelock *wl;
-       char *str = buf;
-       char *end = buf + PAGE_SIZE;
+       int len = 0;
 
        mutex_lock(&wakelocks_lock);
 
        for (node = rb_first(&wakelocks_tree); node; node = rb_next(node)) {
                wl = rb_entry(node, struct wakelock, node);
                if (wl->ws->active == show_active)
-                       str += scnprintf(str, end - str, "%s ", wl->name);
+                       len += sysfs_emit_at(buf, len, "%s ", wl->name);
        }
-       if (str > buf)
-               str--;
 
-       str += scnprintf(str, end - str, "\n");
+       len += sysfs_emit_at(buf, len, "\n");
 
        mutex_unlock(&wakelocks_lock);
-       return (str - buf);
+       return len;
 }
 
 #if CONFIG_PM_WAKELOCKS_LIMIT > 0
index 653ae04..c228343 100644 (file)
@@ -12,7 +12,7 @@
 static const int ten_thousand = 10000;
 
 static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write,
-                               void __user *buffer, size_t *lenp, loff_t *ppos)
+                               void *buffer, size_t *lenp, loff_t *ppos)
 {
        if (write && !capable(CAP_SYS_ADMIN))
                return -EPERM;
index 84f1d91..d64f0b1 100644 (file)
@@ -123,7 +123,7 @@ static struct rcu_tasks rt_name =                                                   \
        .call_func = call,                                                              \
        .rtpcpu = &rt_name ## __percpu,                                                 \
        .name = n,                                                                      \
-       .percpu_enqueue_shift = ilog2(CONFIG_NR_CPUS),                                  \
+       .percpu_enqueue_shift = ilog2(CONFIG_NR_CPUS) + 1,                              \
        .percpu_enqueue_lim = 1,                                                        \
        .percpu_dequeue_lim = 1,                                                        \
        .barrier_q_mutex = __MUTEX_INITIALIZER(rt_name.barrier_q_mutex),                \
@@ -216,6 +216,7 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
        int cpu;
        unsigned long flags;
        int lim;
+       int shift;
 
        raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
        if (rcu_task_enqueue_lim < 0) {
@@ -229,7 +230,10 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
 
        if (lim > nr_cpu_ids)
                lim = nr_cpu_ids;
-       WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids / lim));
+       shift = ilog2(nr_cpu_ids / lim);
+       if (((nr_cpu_ids - 1) >> shift) >= lim)
+               shift++;
+       WRITE_ONCE(rtp->percpu_enqueue_shift, shift);
        WRITE_ONCE(rtp->percpu_dequeue_lim, lim);
        smp_store_release(&rtp->percpu_enqueue_lim, lim);
        for_each_possible_cpu(cpu) {
@@ -298,7 +302,7 @@ static void call_rcu_tasks_generic(struct rcu_head *rhp, rcu_callback_t func,
        if (unlikely(needadjust)) {
                raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
                if (rtp->percpu_enqueue_lim != nr_cpu_ids) {
-                       WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids));
+                       WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids) + 1);
                        WRITE_ONCE(rtp->percpu_dequeue_lim, nr_cpu_ids);
                        smp_store_release(&rtp->percpu_enqueue_lim, nr_cpu_ids);
                        pr_info("Switching %s to per-CPU callback queuing.\n", rtp->name);
@@ -413,7 +417,7 @@ static int rcu_tasks_need_gpcb(struct rcu_tasks *rtp)
        if (rcu_task_cb_adjust && ncbs <= rcu_task_collapse_lim) {
                raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
                if (rtp->percpu_enqueue_lim > 1) {
-                       WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids));
+                       WRITE_ONCE(rtp->percpu_enqueue_shift, ilog2(nr_cpu_ids) + 1);
                        smp_store_release(&rtp->percpu_enqueue_lim, 1);
                        rtp->percpu_dequeue_gpseq = get_state_synchronize_rcu();
                        pr_info("Starting switch %s to CPU-0 callback queuing.\n", rtp->name);
index 2e4ae00..9745613 100644 (file)
@@ -4424,6 +4424,7 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p)
 
        init_entity_runnable_average(&p->se);
 
+
 #ifdef CONFIG_SCHED_INFO
        if (likely(sched_info_on()))
                memset(&p->sched_info, 0, sizeof(p->sched_info));
@@ -4439,18 +4440,23 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p)
        return 0;
 }
 
-void sched_post_fork(struct task_struct *p, struct kernel_clone_args *kargs)
+void sched_cgroup_fork(struct task_struct *p, struct kernel_clone_args *kargs)
 {
        unsigned long flags;
-#ifdef CONFIG_CGROUP_SCHED
-       struct task_group *tg;
-#endif
 
+       /*
+        * Because we're not yet on the pid-hash, p->pi_lock isn't strictly
+        * required yet, but lockdep gets upset if rules are violated.
+        */
        raw_spin_lock_irqsave(&p->pi_lock, flags);
 #ifdef CONFIG_CGROUP_SCHED
-       tg = container_of(kargs->cset->subsys[cpu_cgrp_id],
-                         struct task_group, css);
-       p->sched_task_group = autogroup_task_group(p, tg);
+       if (1) {
+               struct task_group *tg;
+               tg = container_of(kargs->cset->subsys[cpu_cgrp_id],
+                                 struct task_group, css);
+               tg = autogroup_task_group(p, tg);
+               p->sched_task_group = tg;
+       }
 #endif
        rseq_migrate(p);
        /*
@@ -4461,7 +4467,10 @@ void sched_post_fork(struct task_struct *p, struct kernel_clone_args *kargs)
        if (p->sched_class->task_fork)
                p->sched_class->task_fork(p);
        raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+}
 
+void sched_post_fork(struct task_struct *p)
+{
        uclamp_post_fork(p);
 }
 
@@ -5822,8 +5831,7 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
        }
 
        if (schedstat_enabled() && rq->core->core_forceidle_count) {
-               if (cookie)
-                       rq->core->core_forceidle_start = rq_clock(rq->core);
+               rq->core->core_forceidle_start = rq_clock(rq->core);
                rq->core->core_forceidle_occupation = occ;
        }
 
@@ -8219,9 +8227,7 @@ int __cond_resched_lock(spinlock_t *lock)
 
        if (spin_needbreak(lock) || resched) {
                spin_unlock(lock);
-               if (resched)
-                       preempt_schedule_common();
-               else
+               if (!_cond_resched())
                        cpu_relax();
                ret = 1;
                spin_lock(lock);
@@ -8239,9 +8245,7 @@ int __cond_resched_rwlock_read(rwlock_t *lock)
 
        if (rwlock_needbreak(lock) || resched) {
                read_unlock(lock);
-               if (resched)
-                       preempt_schedule_common();
-               else
+               if (!_cond_resched())
                        cpu_relax();
                ret = 1;
                read_lock(lock);
@@ -8259,9 +8263,7 @@ int __cond_resched_rwlock_write(rwlock_t *lock)
 
        if (rwlock_needbreak(lock) || resched) {
                write_unlock(lock);
-               if (resched)
-                       preempt_schedule_common();
-               else
+               if (!_cond_resched())
                        cpu_relax();
                ret = 1;
                write_lock(lock);
index 1fb4567..c8746a9 100644 (file)
@@ -277,7 +277,7 @@ void __sched_core_account_forceidle(struct rq *rq)
                rq_i = cpu_rq(i);
                p = rq_i->core_pick ?: rq_i->curr;
 
-               if (!p->core_cookie)
+               if (p == rq_i->idle)
                        continue;
 
                __schedstat_add(p->stats.core_forceidle_sum, delta);
index 095b0aa..5146163 100644 (file)
@@ -3028,9 +3028,11 @@ enqueue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 static inline void
 dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       u32 divider = get_pelt_divider(&se->avg);
        sub_positive(&cfs_rq->avg.load_avg, se->avg.load_avg);
-       cfs_rq->avg.load_sum = cfs_rq->avg.load_avg * divider;
+       sub_positive(&cfs_rq->avg.load_sum, se_weight(se) * se->avg.load_sum);
+       /* See update_cfs_rq_load_avg() */
+       cfs_rq->avg.load_sum = max_t(u32, cfs_rq->avg.load_sum,
+                                         cfs_rq->avg.load_avg * PELT_MIN_DIVIDER);
 }
 #else
 static inline void
@@ -3381,7 +3383,6 @@ void set_task_rq_fair(struct sched_entity *se,
        se->avg.last_update_time = n_last_update_time;
 }
 
-
 /*
  * When on migration a sched_entity joins/leaves the PELT hierarchy, we need to
  * propagate its contribution. The key to this propagation is the invariant
@@ -3449,15 +3450,14 @@ void set_task_rq_fair(struct sched_entity *se,
  * XXX: only do this for the part of runnable > running ?
  *
  */
-
 static inline void
 update_tg_cfs_util(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq *gcfs_rq)
 {
-       long delta = gcfs_rq->avg.util_avg - se->avg.util_avg;
-       u32 divider;
+       long delta_sum, delta_avg = gcfs_rq->avg.util_avg - se->avg.util_avg;
+       u32 new_sum, divider;
 
        /* Nothing to update */
-       if (!delta)
+       if (!delta_avg)
                return;
 
        /*
@@ -3466,23 +3466,30 @@ update_tg_cfs_util(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq
         */
        divider = get_pelt_divider(&cfs_rq->avg);
 
+
        /* Set new sched_entity's utilization */
        se->avg.util_avg = gcfs_rq->avg.util_avg;
-       se->avg.util_sum = se->avg.util_avg * divider;
+       new_sum = se->avg.util_avg * divider;
+       delta_sum = (long)new_sum - (long)se->avg.util_sum;
+       se->avg.util_sum = new_sum;
 
        /* Update parent cfs_rq utilization */
-       add_positive(&cfs_rq->avg.util_avg, delta);
-       cfs_rq->avg.util_sum = cfs_rq->avg.util_avg * divider;
+       add_positive(&cfs_rq->avg.util_avg, delta_avg);
+       add_positive(&cfs_rq->avg.util_sum, delta_sum);
+
+       /* See update_cfs_rq_load_avg() */
+       cfs_rq->avg.util_sum = max_t(u32, cfs_rq->avg.util_sum,
+                                         cfs_rq->avg.util_avg * PELT_MIN_DIVIDER);
 }
 
 static inline void
 update_tg_cfs_runnable(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq *gcfs_rq)
 {
-       long delta = gcfs_rq->avg.runnable_avg - se->avg.runnable_avg;
-       u32 divider;
+       long delta_sum, delta_avg = gcfs_rq->avg.runnable_avg - se->avg.runnable_avg;
+       u32 new_sum, divider;
 
        /* Nothing to update */
-       if (!delta)
+       if (!delta_avg)
                return;
 
        /*
@@ -3493,19 +3500,25 @@ update_tg_cfs_runnable(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cf
 
        /* Set new sched_entity's runnable */
        se->avg.runnable_avg = gcfs_rq->avg.runnable_avg;
-       se->avg.runnable_sum = se->avg.runnable_avg * divider;
+       new_sum = se->avg.runnable_avg * divider;
+       delta_sum = (long)new_sum - (long)se->avg.runnable_sum;
+       se->avg.runnable_sum = new_sum;
 
        /* Update parent cfs_rq runnable */
-       add_positive(&cfs_rq->avg.runnable_avg, delta);
-       cfs_rq->avg.runnable_sum = cfs_rq->avg.runnable_avg * divider;
+       add_positive(&cfs_rq->avg.runnable_avg, delta_avg);
+       add_positive(&cfs_rq->avg.runnable_sum, delta_sum);
+       /* See update_cfs_rq_load_avg() */
+       cfs_rq->avg.runnable_sum = max_t(u32, cfs_rq->avg.runnable_sum,
+                                             cfs_rq->avg.runnable_avg * PELT_MIN_DIVIDER);
 }
 
 static inline void
 update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq *gcfs_rq)
 {
-       long delta, running_sum, runnable_sum = gcfs_rq->prop_runnable_sum;
+       long delta_avg, running_sum, runnable_sum = gcfs_rq->prop_runnable_sum;
        unsigned long load_avg;
        u64 load_sum = 0;
+       s64 delta_sum;
        u32 divider;
 
        if (!runnable_sum)
@@ -3532,7 +3545,7 @@ update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq
                 * assuming all tasks are equally runnable.
                 */
                if (scale_load_down(gcfs_rq->load.weight)) {
-                       load_sum = div_s64(gcfs_rq->avg.load_sum,
+                       load_sum = div_u64(gcfs_rq->avg.load_sum,
                                scale_load_down(gcfs_rq->load.weight));
                }
 
@@ -3549,19 +3562,22 @@ update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq
        running_sum = se->avg.util_sum >> SCHED_CAPACITY_SHIFT;
        runnable_sum = max(runnable_sum, running_sum);
 
-       load_sum = (s64)se_weight(se) * runnable_sum;
-       load_avg = div_s64(load_sum, divider);
-
-       se->avg.load_sum = runnable_sum;
+       load_sum = se_weight(se) * runnable_sum;
+       load_avg = div_u64(load_sum, divider);
 
-       delta = load_avg - se->avg.load_avg;
-       if (!delta)
+       delta_avg = load_avg - se->avg.load_avg;
+       if (!delta_avg)
                return;
 
-       se->avg.load_avg = load_avg;
+       delta_sum = load_sum - (s64)se_weight(se) * se->avg.load_sum;
 
-       add_positive(&cfs_rq->avg.load_avg, delta);
-       cfs_rq->avg.load_sum = cfs_rq->avg.load_avg * divider;
+       se->avg.load_sum = runnable_sum;
+       se->avg.load_avg = load_avg;
+       add_positive(&cfs_rq->avg.load_avg, delta_avg);
+       add_positive(&cfs_rq->avg.load_sum, delta_sum);
+       /* See update_cfs_rq_load_avg() */
+       cfs_rq->avg.load_sum = max_t(u32, cfs_rq->avg.load_sum,
+                                         cfs_rq->avg.load_avg * PELT_MIN_DIVIDER);
 }
 
 static inline void add_tg_cfs_propagate(struct cfs_rq *cfs_rq, long runnable_sum)
@@ -3652,7 +3668,7 @@ static inline void add_tg_cfs_propagate(struct cfs_rq *cfs_rq, long runnable_sum
  *
  * cfs_rq->avg is used for task_h_load() and update_cfs_share() for example.
  *
- * Returns true if the load decayed or we removed load.
+ * Return: true if the load decayed or we removed load.
  *
  * Since both these conditions indicate a changed cfs_rq->avg.load we should
  * call update_tg_load_avg() when this function returns true.
@@ -3677,15 +3693,32 @@ update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq)
 
                r = removed_load;
                sub_positive(&sa->load_avg, r);
-               sa->load_sum = sa->load_avg * divider;
+               sub_positive(&sa->load_sum, r * divider);
+               /* See sa->util_sum below */
+               sa->load_sum = max_t(u32, sa->load_sum, sa->load_avg * PELT_MIN_DIVIDER);
 
                r = removed_util;
                sub_positive(&sa->util_avg, r);
-               sa->util_sum = sa->util_avg * divider;
+               sub_positive(&sa->util_sum, r * divider);
+               /*
+                * Because of rounding, se->util_sum might ends up being +1 more than
+                * cfs->util_sum. Although this is not a problem by itself, detaching
+                * a lot of tasks with the rounding problem between 2 updates of
+                * util_avg (~1ms) can make cfs->util_sum becoming null whereas
+                * cfs_util_avg is not.
+                * Check that util_sum is still above its lower bound for the new
+                * util_avg. Given that period_contrib might have moved since the last
+                * sync, we are only sure that util_sum must be above or equal to
+                *    util_avg * minimum possible divider
+                */
+               sa->util_sum = max_t(u32, sa->util_sum, sa->util_avg * PELT_MIN_DIVIDER);
 
                r = removed_runnable;
                sub_positive(&sa->runnable_avg, r);
-               sa->runnable_sum = sa->runnable_avg * divider;
+               sub_positive(&sa->runnable_sum, r * divider);
+               /* See sa->util_sum above */
+               sa->runnable_sum = max_t(u32, sa->runnable_sum,
+                                             sa->runnable_avg * PELT_MIN_DIVIDER);
 
                /*
                 * removed_runnable is the unweighted version of removed_load so we
@@ -3772,17 +3805,18 @@ static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s
  */
 static void detach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       /*
-        * cfs_rq->avg.period_contrib can be used for both cfs_rq and se.
-        * See ___update_load_avg() for details.
-        */
-       u32 divider = get_pelt_divider(&cfs_rq->avg);
-
        dequeue_load_avg(cfs_rq, se);
        sub_positive(&cfs_rq->avg.util_avg, se->avg.util_avg);
-       cfs_rq->avg.util_sum = cfs_rq->avg.util_avg * divider;
+       sub_positive(&cfs_rq->avg.util_sum, se->avg.util_sum);
+       /* See update_cfs_rq_load_avg() */
+       cfs_rq->avg.util_sum = max_t(u32, cfs_rq->avg.util_sum,
+                                         cfs_rq->avg.util_avg * PELT_MIN_DIVIDER);
+
        sub_positive(&cfs_rq->avg.runnable_avg, se->avg.runnable_avg);
-       cfs_rq->avg.runnable_sum = cfs_rq->avg.runnable_avg * divider;
+       sub_positive(&cfs_rq->avg.runnable_sum, se->avg.runnable_sum);
+       /* See update_cfs_rq_load_avg() */
+       cfs_rq->avg.runnable_sum = max_t(u32, cfs_rq->avg.runnable_sum,
+                                             cfs_rq->avg.runnable_avg * PELT_MIN_DIVIDER);
 
        add_tg_cfs_propagate(cfs_rq, -se->avg.load_sum);
 
@@ -8539,6 +8573,8 @@ group_type group_classify(unsigned int imbalance_pct,
  *
  * If @sg does not have SMT siblings, only pull tasks if all of the SMT siblings
  * of @dst_cpu are idle and @sg has lower priority.
+ *
+ * Return: true if @dst_cpu can pull tasks, false otherwise.
  */
 static bool asym_smt_can_pull_tasks(int dst_cpu, struct sd_lb_stats *sds,
                                    struct sg_lb_stats *sgs,
@@ -8614,6 +8650,7 @@ sched_asym(struct lb_env *env, struct sd_lb_stats *sds,  struct sg_lb_stats *sgs
 /**
  * update_sg_lb_stats - Update sched_group's statistics for load balancing.
  * @env: The load balancing environment.
+ * @sds: Load-balancing data with statistics of the local group.
  * @group: sched_group whose statistics are to be updated.
  * @sgs: variable to hold the statistics for this group.
  * @sg_status: Holds flag indicating the status of the sched_group
@@ -9421,12 +9458,11 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
 /**
  * find_busiest_group - Returns the busiest group within the sched_domain
  * if there is an imbalance.
+ * @env: The load balancing environment.
  *
  * Also calculates the amount of runnable load which should be moved
  * to restore balance.
  *
- * @env: The load balancing environment.
- *
  * Return:     - The busiest group if imbalance exists.
  */
 static struct sched_group *find_busiest_group(struct lb_env *env)
index b5add64..3d28254 100644 (file)
 #endif
 
 #ifdef CONFIG_RSEQ
-#define MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ_BITMASK          \
+#define MEMBARRIER_PRIVATE_EXPEDITED_RSEQ_BITMASK              \
        (MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ                  \
-       | MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ_BITMASK)
+       | MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ)
 #else
-#define MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ_BITMASK  0
+#define MEMBARRIER_PRIVATE_EXPEDITED_RSEQ_BITMASK      0
 #endif
 
 #define MEMBARRIER_CMD_BITMASK                                         \
        | MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED                      \
        | MEMBARRIER_CMD_PRIVATE_EXPEDITED                              \
        | MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED                     \
-       | MEMBARRIER_PRIVATE_EXPEDITED_SYNC_CORE_BITMASK)
+       | MEMBARRIER_PRIVATE_EXPEDITED_SYNC_CORE_BITMASK                \
+       | MEMBARRIER_PRIVATE_EXPEDITED_RSEQ_BITMASK)
 
 static void ipi_mb(void *info)
 {
index e06071b..c336f5f 100644 (file)
@@ -37,9 +37,11 @@ update_irq_load_avg(struct rq *rq, u64 running)
 }
 #endif
 
+#define PELT_MIN_DIVIDER       (LOAD_AVG_MAX - 1024)
+
 static inline u32 get_pelt_divider(struct sched_avg *avg)
 {
-       return LOAD_AVG_MAX - 1024 + avg->period_contrib;
+       return PELT_MIN_DIVIDER + avg->period_contrib;
 }
 
 static inline void cfs_se_util_change(struct sched_avg *avg)
index a679613..e143581 100644 (file)
@@ -1082,44 +1082,6 @@ int psi_show(struct seq_file *m, struct psi_group *group, enum psi_res res)
        return 0;
 }
 
-static int psi_io_show(struct seq_file *m, void *v)
-{
-       return psi_show(m, &psi_system, PSI_IO);
-}
-
-static int psi_memory_show(struct seq_file *m, void *v)
-{
-       return psi_show(m, &psi_system, PSI_MEM);
-}
-
-static int psi_cpu_show(struct seq_file *m, void *v)
-{
-       return psi_show(m, &psi_system, PSI_CPU);
-}
-
-static int psi_open(struct file *file, int (*psi_show)(struct seq_file *, void *))
-{
-       if (file->f_mode & FMODE_WRITE && !capable(CAP_SYS_RESOURCE))
-               return -EPERM;
-
-       return single_open(file, psi_show, NULL);
-}
-
-static int psi_io_open(struct inode *inode, struct file *file)
-{
-       return psi_open(file, psi_io_show);
-}
-
-static int psi_memory_open(struct inode *inode, struct file *file)
-{
-       return psi_open(file, psi_memory_show);
-}
-
-static int psi_cpu_open(struct inode *inode, struct file *file)
-{
-       return psi_open(file, psi_cpu_show);
-}
-
 struct psi_trigger *psi_trigger_create(struct psi_group *group,
                        char *buf, size_t nbytes, enum psi_res res)
 {
@@ -1162,7 +1124,6 @@ struct psi_trigger *psi_trigger_create(struct psi_group *group,
        t->event = 0;
        t->last_event_time = 0;
        init_waitqueue_head(&t->event_wait);
-       kref_init(&t->refcount);
 
        mutex_lock(&group->trigger_lock);
 
@@ -1191,15 +1152,19 @@ struct psi_trigger *psi_trigger_create(struct psi_group *group,
        return t;
 }
 
-static void psi_trigger_destroy(struct kref *ref)
+void psi_trigger_destroy(struct psi_trigger *t)
 {
-       struct psi_trigger *t = container_of(ref, struct psi_trigger, refcount);
-       struct psi_group *group = t->group;
+       struct psi_group *group;
        struct task_struct *task_to_destroy = NULL;
 
-       if (static_branch_likely(&psi_disabled))
+       /*
+        * We do not check psi_disabled since it might have been disabled after
+        * the trigger got created.
+        */
+       if (!t)
                return;
 
+       group = t->group;
        /*
         * Wakeup waiters to stop polling. Can happen if cgroup is deleted
         * from under a polling process.
@@ -1235,9 +1200,9 @@ static void psi_trigger_destroy(struct kref *ref)
        mutex_unlock(&group->trigger_lock);
 
        /*
-        * Wait for both *trigger_ptr from psi_trigger_replace and
-        * poll_task RCUs to complete their read-side critical sections
-        * before destroying the trigger and optionally the poll_task
+        * Wait for psi_schedule_poll_work RCU to complete its read-side
+        * critical section before destroying the trigger and optionally the
+        * poll_task.
         */
        synchronize_rcu();
        /*
@@ -1254,18 +1219,6 @@ static void psi_trigger_destroy(struct kref *ref)
        kfree(t);
 }
 
-void psi_trigger_replace(void **trigger_ptr, struct psi_trigger *new)
-{
-       struct psi_trigger *old = *trigger_ptr;
-
-       if (static_branch_likely(&psi_disabled))
-               return;
-
-       rcu_assign_pointer(*trigger_ptr, new);
-       if (old)
-               kref_put(&old->refcount, psi_trigger_destroy);
-}
-
 __poll_t psi_trigger_poll(void **trigger_ptr,
                                struct file *file, poll_table *wait)
 {
@@ -1275,27 +1228,57 @@ __poll_t psi_trigger_poll(void **trigger_ptr,
        if (static_branch_likely(&psi_disabled))
                return DEFAULT_POLLMASK | EPOLLERR | EPOLLPRI;
 
-       rcu_read_lock();
-
-       t = rcu_dereference(*(void __rcu __force **)trigger_ptr);
-       if (!t) {
-               rcu_read_unlock();
+       t = smp_load_acquire(trigger_ptr);
+       if (!t)
                return DEFAULT_POLLMASK | EPOLLERR | EPOLLPRI;
-       }
-       kref_get(&t->refcount);
-
-       rcu_read_unlock();
 
        poll_wait(file, &t->event_wait, wait);
 
        if (cmpxchg(&t->event, 1, 0) == 1)
                ret |= EPOLLPRI;
 
-       kref_put(&t->refcount, psi_trigger_destroy);
-
        return ret;
 }
 
+#ifdef CONFIG_PROC_FS
+static int psi_io_show(struct seq_file *m, void *v)
+{
+       return psi_show(m, &psi_system, PSI_IO);
+}
+
+static int psi_memory_show(struct seq_file *m, void *v)
+{
+       return psi_show(m, &psi_system, PSI_MEM);
+}
+
+static int psi_cpu_show(struct seq_file *m, void *v)
+{
+       return psi_show(m, &psi_system, PSI_CPU);
+}
+
+static int psi_open(struct file *file, int (*psi_show)(struct seq_file *, void *))
+{
+       if (file->f_mode & FMODE_WRITE && !capable(CAP_SYS_RESOURCE))
+               return -EPERM;
+
+       return single_open(file, psi_show, NULL);
+}
+
+static int psi_io_open(struct inode *inode, struct file *file)
+{
+       return psi_open(file, psi_io_show);
+}
+
+static int psi_memory_open(struct inode *inode, struct file *file)
+{
+       return psi_open(file, psi_memory_show);
+}
+
+static int psi_cpu_open(struct inode *inode, struct file *file)
+{
+       return psi_open(file, psi_cpu_show);
+}
+
 static ssize_t psi_write(struct file *file, const char __user *user_buf,
                         size_t nbytes, enum psi_res res)
 {
@@ -1316,14 +1299,24 @@ static ssize_t psi_write(struct file *file, const char __user *user_buf,
 
        buf[buf_size - 1] = '\0';
 
-       new = psi_trigger_create(&psi_system, buf, nbytes, res);
-       if (IS_ERR(new))
-               return PTR_ERR(new);
-
        seq = file->private_data;
+
        /* Take seq->lock to protect seq->private from concurrent writes */
        mutex_lock(&seq->lock);
-       psi_trigger_replace(&seq->private, new);
+
+       /* Allow only one trigger per file descriptor */
+       if (seq->private) {
+               mutex_unlock(&seq->lock);
+               return -EBUSY;
+       }
+
+       new = psi_trigger_create(&psi_system, buf, nbytes, res);
+       if (IS_ERR(new)) {
+               mutex_unlock(&seq->lock);
+               return PTR_ERR(new);
+       }
+
+       smp_store_release(&seq->private, new);
        mutex_unlock(&seq->lock);
 
        return nbytes;
@@ -1358,7 +1351,7 @@ static int psi_fop_release(struct inode *inode, struct file *file)
 {
        struct seq_file *seq = file->private_data;
 
-       psi_trigger_replace(&seq->private, NULL);
+       psi_trigger_destroy(seq->private);
        return single_release(inode, file);
 }
 
@@ -1400,3 +1393,5 @@ static int __init psi_proc_init(void)
        return 0;
 }
 module_init(psi_proc_init);
+
+#endif /* CONFIG_PROC_FS */
index 4d8f44a..db10e73 100644 (file)
@@ -29,6 +29,9 @@
 #include <linux/syscalls.h>
 #include <linux/sysctl.h>
 
+/* Not exposed in headers: strictly internal use only. */
+#define SECCOMP_MODE_DEAD      (SECCOMP_MODE_FILTER + 1)
+
 #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
 #include <asm/syscall.h>
 #endif
@@ -1010,6 +1013,7 @@ static void __secure_computing_strict(int this_syscall)
 #ifdef SECCOMP_DEBUG
        dump_stack();
 #endif
+       current->seccomp.mode = SECCOMP_MODE_DEAD;
        seccomp_log(this_syscall, SIGKILL, SECCOMP_RET_KILL_THREAD, true);
        do_exit(SIGKILL);
 }
@@ -1261,6 +1265,7 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
        case SECCOMP_RET_KILL_THREAD:
        case SECCOMP_RET_KILL_PROCESS:
        default:
+               current->seccomp.mode = SECCOMP_MODE_DEAD;
                seccomp_log(this_syscall, SIGSYS, action, true);
                /* Dump core only if this is the last remaining thread. */
                if (action != SECCOMP_RET_KILL_THREAD ||
@@ -1309,6 +1314,11 @@ int __secure_computing(const struct seccomp_data *sd)
                return 0;
        case SECCOMP_MODE_FILTER:
                return __seccomp_filter(this_syscall, sd, false);
+       /* Surviving SECCOMP_RET_KILL_* must be proactively impossible. */
+       case SECCOMP_MODE_DEAD:
+               WARN_ON_ONCE(1);
+               do_exit(SIGKILL);
+               return -1;
        default:
                BUG();
        }
index 3860273..9b04631 100644 (file)
@@ -1342,9 +1342,10 @@ force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t,
        }
        /*
         * Don't clear SIGNAL_UNKILLABLE for traced tasks, users won't expect
-        * debugging to leave init killable.
+        * debugging to leave init killable. But HANDLER_EXIT is always fatal.
         */
-       if (action->sa.sa_handler == SIG_DFL && !t->ptrace)
+       if (action->sa.sa_handler == SIG_DFL &&
+           (!t->ptrace || (handler == HANDLER_EXIT)))
                t->signal->flags &= ~SIGNAL_UNKILLABLE;
        ret = send_signal(sig, info, t, PIDTYPE_PID);
        spin_unlock_irqrestore(&t->sighand->siglock, flags);
index 66b8af3..ddb5a7f 100644 (file)
@@ -70,7 +70,7 @@ late_initcall(stackleak_sysctls_init);
 #define skip_erasing() false
 #endif /* CONFIG_STACKLEAK_RUNTIME_DISABLE */
 
-asmlinkage void notrace stackleak_erase(void)
+asmlinkage void noinstr stackleak_erase(void)
 {
        /* It would be nice not to have 'kstack_ptr' and 'boundary' on stack */
        unsigned long kstack_ptr = current->lowest_stack;
@@ -124,9 +124,8 @@ asmlinkage void notrace stackleak_erase(void)
        /* Reset the 'lowest_stack' value for the next syscall */
        current->lowest_stack = current_top_of_stack() - THREAD_SIZE/64;
 }
-NOKPROBE_SYMBOL(stackleak_erase);
 
-void __used __no_caller_saved_registers notrace stackleak_track_stack(void)
+void __used __no_caller_saved_registers noinstr stackleak_track_stack(void)
 {
        unsigned long sp = current_stack_pointer;
 
index ecc4cf0..97dc9e5 100644 (file)
@@ -472,6 +472,16 @@ static int set_user(struct cred *new)
        if (!new_user)
                return -EAGAIN;
 
+       free_uid(new->user);
+       new->user = new_user;
+       return 0;
+}
+
+static void flag_nproc_exceeded(struct cred *new)
+{
+       if (new->ucounts == current_ucounts())
+               return;
+
        /*
         * We don't fail in case of NPROC limit excess here because too many
         * poorly written programs don't check set*uid() return code, assuming
@@ -480,15 +490,10 @@ static int set_user(struct cred *new)
         * failure to the execve() stage.
         */
        if (is_ucounts_overlimit(new->ucounts, UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC)) &&
-                       new_user != INIT_USER &&
-                       !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))
+                       new->user != INIT_USER)
                current->flags |= PF_NPROC_EXCEEDED;
        else
                current->flags &= ~PF_NPROC_EXCEEDED;
-
-       free_uid(new->user);
-       new->user = new_user;
-       return 0;
 }
 
 /*
@@ -563,6 +568,7 @@ long __sys_setreuid(uid_t ruid, uid_t euid)
        if (retval < 0)
                goto error;
 
+       flag_nproc_exceeded(new);
        return commit_creds(new);
 
 error:
@@ -625,6 +631,7 @@ long __sys_setuid(uid_t uid)
        if (retval < 0)
                goto error;
 
+       flag_nproc_exceeded(new);
        return commit_creds(new);
 
 error:
@@ -704,6 +711,7 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
        if (retval < 0)
                goto error;
 
+       flag_nproc_exceeded(new);
        return commit_creds(new);
 
 error:
index 752ed89..a5eb5e7 100644 (file)
@@ -70,10 +70,16 @@ config HAVE_C_RECORDMCOUNT
        help
          C version of recordmcount available?
 
+config HAVE_BUILDTIME_MCOUNT_SORT
+       bool
+       help
+         An architecture selects this if it sorts the mcount_loc section
+        at build time.
+
 config BUILDTIME_MCOUNT_SORT
        bool
        default y
-       depends on BUILDTIME_TABLE_SORT && !S390
+       depends on HAVE_BUILDTIME_MCOUNT_SORT && DYNAMIC_FTRACE
        help
          Sort the mcount_loc section at build time.
 
index f9feb19..a4b462b 100644 (file)
@@ -7191,7 +7191,6 @@ static int __init ftrace_nodyn_init(void)
 core_initcall(ftrace_nodyn_init);
 
 static inline int ftrace_init_dyn_tracefs(struct dentry *d_tracer) { return 0; }
-static inline void ftrace_startup_enable(int command) { }
 static inline void ftrace_startup_all(int command) { }
 
 # define ftrace_startup_sysctl()       do { } while (0)
index a569a0c..3050892 100644 (file)
@@ -252,6 +252,10 @@ __setup("trace_clock=", set_trace_boot_clock);
 
 static int __init set_tracepoint_printk(char *str)
 {
+       /* Ignore the "tp_printk_stop_on_boot" param */
+       if (*str == '_')
+               return 0;
+
        if ((strcmp(str, "=0") != 0 && strcmp(str, "=off") != 0))
                tracepoint_printk = 1;
        return 1;
@@ -1470,10 +1474,12 @@ static int __init set_buf_size(char *str)
        if (!str)
                return 0;
        buf_size = memparse(str, &str);
-       /* nr_entries can not be zero */
-       if (buf_size == 0)
-               return 0;
-       trace_buf_size = buf_size;
+       /*
+        * nr_entries can not be zero and the startup
+        * tests require some buffer space. Therefore
+        * ensure we have at least 4096 bytes of buffer.
+        */
+       trace_buf_size = max(4096UL, buf_size);
        return 1;
 }
 __setup("trace_buf_size=", set_buf_size);
@@ -7740,7 +7746,8 @@ static struct tracing_log_err *get_tracing_log_err(struct trace_array *tr)
                err = kzalloc(sizeof(*err), GFP_KERNEL);
                if (!err)
                        err = ERR_PTR(-ENOMEM);
-               tr->n_err_log_entries++;
+               else
+                       tr->n_err_log_entries++;
 
                return err;
        }
index d038ddb..c5b09c3 100644 (file)
@@ -136,7 +136,6 @@ struct kprobe_trace_entry_head {
 
 struct eprobe_trace_entry_head {
        struct trace_entry      ent;
-       unsigned int            type;
 };
 
 struct kretprobe_trace_entry_head {
index 191db32..541aa13 100644 (file)
@@ -242,7 +242,6 @@ static int trace_eprobe_tp_arg_update(struct trace_eprobe *ep, int i)
 
 static int eprobe_event_define_fields(struct trace_event_call *event_call)
 {
-       int ret;
        struct eprobe_trace_entry_head field;
        struct trace_probe *tp;
 
@@ -250,8 +249,6 @@ static int eprobe_event_define_fields(struct trace_event_call *event_call)
        if (WARN_ON_ONCE(!tp))
                return -ENOENT;
 
-       DEFINE_FIELD(unsigned int, type, FIELD_STRING_TYPE, 0);
-
        return traceprobe_define_arg_fields(event_call, sizeof(field), tp);
 }
 
@@ -270,7 +267,9 @@ print_eprobe_event(struct trace_iterator *iter, int flags,
        struct trace_event_call *pevent;
        struct trace_event *probed_event;
        struct trace_seq *s = &iter->seq;
+       struct trace_eprobe *ep;
        struct trace_probe *tp;
+       unsigned int type;
 
        field = (struct eprobe_trace_entry_head *)iter->ent;
        tp = trace_probe_primary_from_call(
@@ -278,15 +277,18 @@ print_eprobe_event(struct trace_iterator *iter, int flags,
        if (WARN_ON_ONCE(!tp))
                goto out;
 
+       ep = container_of(tp, struct trace_eprobe, tp);
+       type = ep->event->event.type;
+
        trace_seq_printf(s, "%s: (", trace_probe_name(tp));
 
-       probed_event = ftrace_find_event(field->type);
+       probed_event = ftrace_find_event(type);
        if (probed_event) {
                pevent = container_of(probed_event, struct trace_event_call, event);
                trace_seq_printf(s, "%s.%s", pevent->class->system,
                                 trace_event_name(pevent));
        } else {
-               trace_seq_printf(s, "%u", field->type);
+               trace_seq_printf(s, "%u", type);
        }
 
        trace_seq_putc(s, ')');
@@ -498,10 +500,6 @@ __eprobe_trace_func(struct eprobe_data *edata, void *rec)
                return;
 
        entry = fbuffer.entry = ring_buffer_event_data(fbuffer.event);
-       if (edata->ep->event)
-               entry->type = edata->ep->event->event.type;
-       else
-               entry->type = 0;
        store_trace_args(&entry[1], &edata->ep->tp, rec, sizeof(*entry), dsize);
 
        trace_event_buffer_commit(&fbuffer);
index 5e6a988..ada87bf 100644 (file)
@@ -2503,6 +2503,8 @@ static struct hist_field *parse_unary(struct hist_trigger_data *hist_data,
                (HIST_FIELD_FL_TIMESTAMP | HIST_FIELD_FL_TIMESTAMP_USECS);
        expr->fn = hist_field_unary_minus;
        expr->operands[0] = operand1;
+       expr->size = operand1->size;
+       expr->is_signed = operand1->is_signed;
        expr->operator = FIELD_OP_UNARY_MINUS;
        expr->name = expr_str(expr, 0);
        expr->type = kstrdup_const(operand1->type, GFP_KERNEL);
@@ -2719,6 +2721,7 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
 
                /* The operand sizes should be the same, so just pick one */
                expr->size = operand1->size;
+               expr->is_signed = operand1->is_signed;
 
                expr->operator = field_op;
                expr->type = kstrdup_const(operand1->type, GFP_KERNEL);
@@ -3935,6 +3938,7 @@ static int trace_action_create(struct hist_trigger_data *hist_data,
 
                        var_ref_idx = find_var_ref_idx(hist_data, var_ref);
                        if (WARN_ON(var_ref_idx < 0)) {
+                               kfree(p);
                                ret = var_ref_idx;
                                goto err;
                        }
@@ -6163,7 +6167,9 @@ static int event_hist_trigger_parse(struct event_command *cmd_ops,
 
        lockdep_assert_held(&event_mutex);
 
-       if (glob && strlen(glob)) {
+       WARN_ON(!glob);
+
+       if (strlen(glob)) {
                hist_err_clear();
                last_cmd_set(file, param);
        }
@@ -6196,7 +6202,7 @@ static int event_hist_trigger_parse(struct event_command *cmd_ops,
                        continue;
                }
                break;
-       } while (p);
+       } while (1);
 
        if (!p)
                param = NULL;
index d00fee7..7eb9d04 100644 (file)
@@ -84,6 +84,20 @@ event_triggers_call(struct trace_event_file *file,
 }
 EXPORT_SYMBOL_GPL(event_triggers_call);
 
+bool __trace_trigger_soft_disabled(struct trace_event_file *file)
+{
+       unsigned long eflags = file->flags;
+
+       if (eflags & EVENT_FILE_FL_TRIGGER_MODE)
+               event_triggers_call(file, NULL, NULL, NULL);
+       if (eflags & EVENT_FILE_FL_SOFT_DISABLED)
+               return true;
+       if (eflags & EVENT_FILE_FL_PID_FILTER)
+               return trace_event_ignore_this_pid(file);
+       return false;
+}
+EXPORT_SYMBOL_GPL(__trace_trigger_soft_disabled);
+
 /**
  * event_triggers_post_call - Call 'post_triggers' for a trace event
  * @file: The trace_event_file associated with the event
@@ -1295,6 +1309,16 @@ traceon_trigger(struct event_trigger_data *data,
                struct trace_buffer *buffer, void *rec,
                struct ring_buffer_event *event)
 {
+       struct trace_event_file *file = data->private_data;
+
+       if (file) {
+               if (tracer_tracing_is_on(file->tr))
+                       return;
+
+               tracer_tracing_on(file->tr);
+               return;
+       }
+
        if (tracing_is_on())
                return;
 
@@ -1306,8 +1330,15 @@ traceon_count_trigger(struct event_trigger_data *data,
                      struct trace_buffer *buffer, void *rec,
                      struct ring_buffer_event *event)
 {
-       if (tracing_is_on())
-               return;
+       struct trace_event_file *file = data->private_data;
+
+       if (file) {
+               if (tracer_tracing_is_on(file->tr))
+                       return;
+       } else {
+               if (tracing_is_on())
+                       return;
+       }
 
        if (!data->count)
                return;
@@ -1315,7 +1346,10 @@ traceon_count_trigger(struct event_trigger_data *data,
        if (data->count != -1)
                (data->count)--;
 
-       tracing_on();
+       if (file)
+               tracer_tracing_on(file->tr);
+       else
+               tracing_on();
 }
 
 static void
@@ -1323,6 +1357,16 @@ traceoff_trigger(struct event_trigger_data *data,
                 struct trace_buffer *buffer, void *rec,
                 struct ring_buffer_event *event)
 {
+       struct trace_event_file *file = data->private_data;
+
+       if (file) {
+               if (!tracer_tracing_is_on(file->tr))
+                       return;
+
+               tracer_tracing_off(file->tr);
+               return;
+       }
+
        if (!tracing_is_on())
                return;
 
@@ -1334,8 +1378,15 @@ traceoff_count_trigger(struct event_trigger_data *data,
                       struct trace_buffer *buffer, void *rec,
                       struct ring_buffer_event *event)
 {
-       if (!tracing_is_on())
-               return;
+       struct trace_event_file *file = data->private_data;
+
+       if (file) {
+               if (!tracer_tracing_is_on(file->tr))
+                       return;
+       } else {
+               if (!tracing_is_on())
+                       return;
+       }
 
        if (!data->count)
                return;
@@ -1343,7 +1394,10 @@ traceoff_count_trigger(struct event_trigger_data *data,
        if (data->count != -1)
                (data->count)--;
 
-       tracing_off();
+       if (file)
+               tracer_tracing_off(file->tr);
+       else
+               tracing_off();
 }
 
 static int
@@ -1540,7 +1594,12 @@ stacktrace_trigger(struct event_trigger_data *data,
                   struct trace_buffer *buffer,  void *rec,
                   struct ring_buffer_event *event)
 {
-       trace_dump_stack(STACK_SKIP);
+       struct trace_event_file *file = data->private_data;
+
+       if (file)
+               __trace_stack(file->tr, tracing_gen_ctx(), STACK_SKIP);
+       else
+               trace_dump_stack(STACK_SKIP);
 }
 
 static void
index 870a08d..cfddb30 100644 (file)
@@ -1436,6 +1436,37 @@ out:
 static struct cpumask osnoise_cpumask;
 static struct cpumask save_cpumask;
 
+/*
+ * osnoise_sleep - sleep until the next period
+ */
+static void osnoise_sleep(void)
+{
+       u64 interval;
+       ktime_t wake_time;
+
+       mutex_lock(&interface_lock);
+       interval = osnoise_data.sample_period - osnoise_data.sample_runtime;
+       mutex_unlock(&interface_lock);
+
+       /*
+        * differently from hwlat_detector, the osnoise tracer can run
+        * without a pause because preemption is on.
+        */
+       if (!interval) {
+               /* Let synchronize_rcu_tasks() make progress */
+               cond_resched_tasks_rcu_qs();
+               return;
+       }
+
+       wake_time = ktime_add_us(ktime_get(), interval);
+       __set_current_state(TASK_INTERRUPTIBLE);
+
+       while (schedule_hrtimeout_range(&wake_time, 0, HRTIMER_MODE_ABS)) {
+               if (kthread_should_stop())
+                       break;
+       }
+}
+
 /*
  * osnoise_main - The osnoise detection kernel thread
  *
@@ -1444,30 +1475,10 @@ static struct cpumask save_cpumask;
  */
 static int osnoise_main(void *data)
 {
-       u64 interval;
 
        while (!kthread_should_stop()) {
-
                run_osnoise();
-
-               mutex_lock(&interface_lock);
-               interval = osnoise_data.sample_period - osnoise_data.sample_runtime;
-               mutex_unlock(&interface_lock);
-
-               do_div(interval, USEC_PER_MSEC);
-
-               /*
-                * differently from hwlat_detector, the osnoise tracer can run
-                * without a pause because preemption is on.
-                */
-               if (interval < 1) {
-                       /* Let synchronize_rcu_tasks() make progress */
-                       cond_resched_tasks_rcu_qs();
-                       continue;
-               }
-
-               if (msleep_interruptible(interval))
-                       break;
+               osnoise_sleep();
        }
 
        return 0;
index 73d9017..80863c6 100644 (file)
@@ -871,15 +871,15 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
        switch (ptype) {
        case PROBE_PRINT_NORMAL:
                fmt = "(%lx)";
-               arg = "REC->" FIELD_STRING_IP;
+               arg = "REC->" FIELD_STRING_IP;
                break;
        case PROBE_PRINT_RETURN:
                fmt = "(%lx <- %lx)";
-               arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP;
+               arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP;
                break;
        case PROBE_PRINT_EVENT:
-               fmt = "(%u)";
-               arg = "REC->" FIELD_STRING_TYPE;
+               fmt = "";
+               arg = "";
                break;
        default:
                WARN_ON_ONCE(1);
@@ -903,7 +903,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
                                        parg->type->fmt);
        }
 
-       pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", arg);
+       pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", arg);
 
        for (i = 0; i < tp->nr_args; i++) {
                parg = tp->args + i;
index 99e7a5d..92cc149 100644 (file)
@@ -38,7 +38,6 @@
 #define FIELD_STRING_IP                "__probe_ip"
 #define FIELD_STRING_RETIP     "__probe_ret_ip"
 #define FIELD_STRING_FUNC      "__probe_func"
-#define FIELD_STRING_TYPE      "__probe_type"
 
 #undef DEFINE_FIELD
 #define DEFINE_FIELD(type, item, name, is_signed)                      \
index afd937a..abcadbe 100644 (file)
@@ -784,9 +784,7 @@ static struct fgraph_ops fgraph_ops __initdata  = {
        .retfunc                = &trace_graph_return,
 };
 
-#if defined(CONFIG_DYNAMIC_FTRACE) && \
-    defined(CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS)
-#define TEST_DIRECT_TRAMP
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 noinline __noclone static void trace_direct_tramp(void) { }
 #endif
 
@@ -849,7 +847,7 @@ trace_selftest_startup_function_graph(struct tracer *trace,
                goto out;
        }
 
-#ifdef TEST_DIRECT_TRAMP
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
        tracing_reset_online_cpus(&tr->array_buffer);
        set_graph_array(tr);
 
index 7b32c35..06ea04d 100644 (file)
@@ -190,6 +190,7 @@ struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid)
                        kfree(new);
                } else {
                        hlist_add_head(&new->node, hashent);
+                       get_user_ns(new->ns);
                        spin_unlock_irq(&ucounts_lock);
                        return new;
                }
@@ -210,6 +211,7 @@ void put_ucounts(struct ucounts *ucounts)
        if (atomic_dec_and_lock_irqsave(&ucounts->count, &ucounts_lock, flags)) {
                hlist_del_init(&ucounts->node);
                spin_unlock_irqrestore(&ucounts_lock, flags);
+               put_user_ns(ucounts->ns);
                kfree(ucounts);
        }
 }
@@ -348,7 +350,8 @@ bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsign
        if (rlimit > LONG_MAX)
                max = LONG_MAX;
        for (iter = ucounts; iter; iter = iter->ns->ucounts) {
-               if (get_ucounts_value(iter, type) > max)
+               long val = get_ucounts_value(iter, type);
+               if (val < 0 || val > max)
                        return true;
                max = READ_ONCE(iter->ns->ucount_max[type]);
        }
index 9364f79..c71c096 100644 (file)
 
 void blake2s_update(struct blake2s_state *state, const u8 *in, size_t inlen)
 {
-       __blake2s_update(state, in, inlen, blake2s_compress);
+       __blake2s_update(state, in, inlen, false);
 }
 EXPORT_SYMBOL(blake2s_update);
 
 void blake2s_final(struct blake2s_state *state, u8 *out)
 {
        WARN_ON(IS_ENABLED(DEBUG) && !out);
-       __blake2s_final(state, out, blake2s_compress);
+       __blake2s_final(state, out, false);
        memzero_explicit(state, sizeof(*state));
 }
 EXPORT_SYMBOL(blake2s_final);
index b0e0acd..6dd5330 100644 (file)
@@ -414,6 +414,7 @@ static size_t copy_page_to_iter_pipe(struct page *page, size_t offset, size_t by
                return 0;
 
        buf->ops = &page_cache_pipe_buf_ops;
+       buf->flags = 0;
        get_page(page);
        buf->page = page;
        buf->offset = offset;
@@ -577,6 +578,7 @@ static size_t push_pipe(struct iov_iter *i, size_t size,
                        break;
 
                buf->ops = &default_pipe_buf_ops;
+               buf->flags = 0;
                buf->page = page;
                buf->offset = 0;
                buf->len = min_t(ssize_t, left, PAGE_SIZE);
index 6220fa6..09d293c 100644 (file)
@@ -488,9 +488,13 @@ void sbitmap_queue_recalculate_wake_batch(struct sbitmap_queue *sbq,
                                            unsigned int users)
 {
        unsigned int wake_batch;
+       unsigned int min_batch;
+       unsigned int depth = (sbq->sb.depth + users - 1) / users;
 
-       wake_batch = clamp_val((sbq->sb.depth + users - 1) /
-                       users, 4, SBQ_WAKE_BATCH);
+       min_batch = sbq->sb.depth >= (4 * SBQ_WAIT_QUEUES) ? 4 : 1;
+
+       wake_batch = clamp_val(depth / SBQ_WAIT_QUEUES,
+                       min_batch, SBQ_WAKE_BATCH);
        __sbitmap_queue_update_wake_batch(sbq, wake_batch);
 }
 EXPORT_SYMBOL_GPL(sbitmap_queue_recalculate_wake_batch);
index 847cdbe..3b413f8 100644 (file)
@@ -492,6 +492,7 @@ static void kmalloc_oob_in_memset(struct kunit *test)
        ptr = kmalloc(size, GFP_KERNEL);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
 
+       OPTIMIZER_HIDE_VAR(ptr);
        OPTIMIZER_HIDE_VAR(size);
        KUNIT_EXPECT_KASAN_FAIL(test,
                                memset(ptr, 0, size + KASAN_GRANULE_SIZE));
@@ -515,6 +516,7 @@ static void kmalloc_memmove_negative_size(struct kunit *test)
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
 
        memset((char *)ptr, 0, 64);
+       OPTIMIZER_HIDE_VAR(ptr);
        OPTIMIZER_HIDE_VAR(invalid_size);
        KUNIT_EXPECT_KASAN_FAIL(test,
                memmove((char *)ptr, (char *)ptr + 4, invalid_size));
@@ -531,6 +533,7 @@ static void kmalloc_memmove_invalid_size(struct kunit *test)
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
 
        memset((char *)ptr, 0, 64);
+       OPTIMIZER_HIDE_VAR(ptr);
        KUNIT_EXPECT_KASAN_FAIL(test,
                memmove((char *)ptr, (char *)ptr + 4, invalid_size));
        kfree(ptr);
@@ -866,11 +869,14 @@ static void kmem_cache_invalid_free(struct kunit *test)
        kmem_cache_destroy(cache);
 }
 
+static void empty_cache_ctor(void *object) { }
+
 static void kmem_cache_double_destroy(struct kunit *test)
 {
        struct kmem_cache *cache;
 
-       cache = kmem_cache_create("test_cache", 200, 0, 0, NULL);
+       /* Provide a constructor to prevent cache merging. */
+       cache = kmem_cache_create("test_cache", 200, 0, 0, empty_cache_ctor);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cache);
        kmem_cache_destroy(cache);
        KUNIT_EXPECT_KASAN_FAIL(test, kmem_cache_destroy(cache));
@@ -893,6 +899,7 @@ static void kasan_memchr(struct kunit *test)
        ptr = kmalloc(size, GFP_KERNEL | __GFP_ZERO);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
 
+       OPTIMIZER_HIDE_VAR(ptr);
        OPTIMIZER_HIDE_VAR(size);
        KUNIT_EXPECT_KASAN_FAIL(test,
                kasan_ptr_result = memchr(ptr, '1', size + 1));
@@ -919,6 +926,7 @@ static void kasan_memcmp(struct kunit *test)
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
        memset(arr, 0, sizeof(arr));
 
+       OPTIMIZER_HIDE_VAR(ptr);
        OPTIMIZER_HIDE_VAR(size);
        KUNIT_EXPECT_KASAN_FAIL(test,
                kasan_int_result = memcmp(ptr, arr, size+1));
index a7ac97c..db2abd9 100644 (file)
@@ -171,6 +171,8 @@ static void __init pte_advanced_tests(struct pgtable_debug_args *args)
        ptep_test_and_clear_young(args->vma, args->vaddr, args->ptep);
        pte = ptep_get(args->ptep);
        WARN_ON(pte_young(pte));
+
+       ptep_get_and_clear_full(args->mm, args->vaddr, args->ptep, 1);
 }
 
 static void __init pte_savedwrite_tests(struct pgtable_debug_args *args)
index f0af462..a9d4d72 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -124,8 +124,8 @@ static inline struct page *try_get_compound_head(struct page *page, int refs)
  * considered failure, and furthermore, a likely bug in the caller, so a warning
  * is also emitted.
  */
-struct page *try_grab_compound_head(struct page *page,
-                                   int refs, unsigned int flags)
+__maybe_unused struct page *try_grab_compound_head(struct page *page,
+                                                  int refs, unsigned int flags)
 {
        if (flags & FOLL_GET)
                return try_get_compound_head(page, refs);
@@ -208,10 +208,35 @@ static void put_compound_head(struct page *page, int refs, unsigned int flags)
  */
 bool __must_check try_grab_page(struct page *page, unsigned int flags)
 {
-       if (!(flags & (FOLL_GET | FOLL_PIN)))
-               return true;
+       WARN_ON_ONCE((flags & (FOLL_GET | FOLL_PIN)) == (FOLL_GET | FOLL_PIN));
 
-       return try_grab_compound_head(page, 1, flags);
+       if (flags & FOLL_GET)
+               return try_get_page(page);
+       else if (flags & FOLL_PIN) {
+               int refs = 1;
+
+               page = compound_head(page);
+
+               if (WARN_ON_ONCE(page_ref_count(page) <= 0))
+                       return false;
+
+               if (hpage_pincount_available(page))
+                       hpage_pincount_add(page, 1);
+               else
+                       refs = GUP_PIN_COUNTING_BIAS;
+
+               /*
+                * Similar to try_grab_compound_head(): even if using the
+                * hpage_pincount_add/_sub() routines, be sure to
+                * *also* increment the normal page refcount field at least
+                * once, so that the page really is pinned.
+                */
+               page_ref_add(page, refs);
+
+               mod_node_page_state(page_pgdat(page), NR_FOLL_PIN_ACQUIRED, 1);
+       }
+
+       return true;
 }
 
 /**
index 61895cc..f294db8 100644 (file)
@@ -4159,10 +4159,10 @@ static int __init hugepages_setup(char *s)
                                pr_warn("HugeTLB: architecture can't support node specific alloc, ignoring!\n");
                                return 0;
                        }
+                       if (tmp >= nr_online_nodes)
+                               goto invalid;
                        node = tmp;
                        p += count + 1;
-                       if (node < 0 || node >= nr_online_nodes)
-                               goto invalid;
                        /* Parse hugepages */
                        if (sscanf(p, "%lu%n", &tmp, &count) != 1)
                                goto invalid;
@@ -4851,14 +4851,13 @@ again:
 }
 
 static void move_huge_pte(struct vm_area_struct *vma, unsigned long old_addr,
-                         unsigned long new_addr, pte_t *src_pte)
+                         unsigned long new_addr, pte_t *src_pte, pte_t *dst_pte)
 {
        struct hstate *h = hstate_vma(vma);
        struct mm_struct *mm = vma->vm_mm;
-       pte_t *dst_pte, pte;
        spinlock_t *src_ptl, *dst_ptl;
+       pte_t pte;
 
-       dst_pte = huge_pte_offset(mm, new_addr, huge_page_size(h));
        dst_ptl = huge_pte_lock(h, mm, dst_pte);
        src_ptl = huge_pte_lockptr(h, mm, src_pte);
 
@@ -4917,7 +4916,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);
+               move_huge_pte(vma, old_addr, new_addr, src_pte, dst_pte);
        }
        flush_tlb_range(vma, old_end - len, old_end);
        mmu_notifier_invalidate_range_end(&range);
index 5ad40e3..13128fa 100644 (file)
@@ -47,7 +47,8 @@
 
 static bool kfence_enabled __read_mostly;
 
-static unsigned long kfence_sample_interval __read_mostly = CONFIG_KFENCE_SAMPLE_INTERVAL;
+unsigned long kfence_sample_interval __read_mostly = CONFIG_KFENCE_SAMPLE_INTERVAL;
+EXPORT_SYMBOL_GPL(kfence_sample_interval); /* Export for test modules. */
 
 #ifdef MODULE_PARAM_PREFIX
 #undef MODULE_PARAM_PREFIX
index a22b1af..50dbb81 100644 (file)
@@ -268,13 +268,13 @@ static void *test_alloc(struct kunit *test, size_t size, gfp_t gfp, enum allocat
         * 100x the sample interval should be more than enough to ensure we get
         * a KFENCE allocation eventually.
         */
-       timeout = jiffies + msecs_to_jiffies(100 * CONFIG_KFENCE_SAMPLE_INTERVAL);
+       timeout = jiffies + msecs_to_jiffies(100 * kfence_sample_interval);
        /*
         * Especially for non-preemption kernels, ensure the allocation-gate
         * timer can catch up: after @resched_after, every failed allocation
         * attempt yields, to ensure the allocation-gate timer is scheduled.
         */
-       resched_after = jiffies + msecs_to_jiffies(CONFIG_KFENCE_SAMPLE_INTERVAL);
+       resched_after = jiffies + msecs_to_jiffies(kfence_sample_interval);
        do {
                if (test_cache)
                        alloc = kmem_cache_alloc(test_cache, gfp);
@@ -608,7 +608,7 @@ static void test_gfpzero(struct kunit *test)
        int i;
 
        /* Skip if we think it'd take too long. */
-       KFENCE_TEST_REQUIRES(test, CONFIG_KFENCE_SAMPLE_INTERVAL <= 100);
+       KFENCE_TEST_REQUIRES(test, kfence_sample_interval <= 100);
 
        setup_test_cache(test, size, 0, NULL);
        buf1 = test_alloc(test, size, GFP_KERNEL, ALLOCATE_ANY);
@@ -739,7 +739,7 @@ static void test_memcache_alloc_bulk(struct kunit *test)
         * 100x the sample interval should be more than enough to ensure we get
         * a KFENCE allocation eventually.
         */
-       timeout = jiffies + msecs_to_jiffies(100 * CONFIG_KFENCE_SAMPLE_INTERVAL);
+       timeout = jiffies + msecs_to_jiffies(100 * kfence_sample_interval);
        do {
                void *objects[100];
                int i, num = kmem_cache_alloc_bulk(test_cache, GFP_ATOMIC, ARRAY_SIZE(objects),
index 35f14d0..131492f 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/hashtable.h>
 #include <linux/userfaultfd_k.h>
 #include <linux/page_idle.h>
+#include <linux/page_table_check.h>
 #include <linux/swapops.h>
 #include <linux/shmem_fs.h>
 
@@ -1416,6 +1417,21 @@ static int khugepaged_add_pte_mapped_thp(struct mm_struct *mm,
        return 0;
 }
 
+static void collapse_and_free_pmd(struct mm_struct *mm, struct vm_area_struct *vma,
+                                 unsigned long addr, pmd_t *pmdp)
+{
+       spinlock_t *ptl;
+       pmd_t pmd;
+
+       mmap_assert_write_locked(mm);
+       ptl = pmd_lock(vma->vm_mm, pmdp);
+       pmd = pmdp_collapse_flush(vma, addr, pmdp);
+       spin_unlock(ptl);
+       mm_dec_nr_ptes(mm);
+       page_table_check_pte_clear_range(mm, addr, pmd);
+       pte_free(mm, pmd_pgtable(pmd));
+}
+
 /**
  * collapse_pte_mapped_thp - Try to collapse a pte-mapped THP for mm at
  * address haddr.
@@ -1433,7 +1449,7 @@ void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr)
        struct vm_area_struct *vma = find_vma(mm, haddr);
        struct page *hpage;
        pte_t *start_pte, *pte;
-       pmd_t *pmd, _pmd;
+       pmd_t *pmd;
        spinlock_t *ptl;
        int count = 0;
        int i;
@@ -1509,12 +1525,7 @@ void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr)
        }
 
        /* step 4: collapse pmd */
-       ptl = pmd_lock(vma->vm_mm, pmd);
-       _pmd = pmdp_collapse_flush(vma, haddr, pmd);
-       spin_unlock(ptl);
-       mm_dec_nr_ptes(mm);
-       pte_free(mm, pmd_pgtable(_pmd));
-
+       collapse_and_free_pmd(mm, vma, haddr, pmd);
 drop_hpage:
        unlock_page(hpage);
        put_page(hpage);
@@ -1552,7 +1563,7 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
        struct vm_area_struct *vma;
        struct mm_struct *mm;
        unsigned long addr;
-       pmd_t *pmd, _pmd;
+       pmd_t *pmd;
 
        i_mmap_lock_write(mapping);
        vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) {
@@ -1591,14 +1602,8 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
                 * reverse order. Trylock is a way to avoid deadlock.
                 */
                if (mmap_write_trylock(mm)) {
-                       if (!khugepaged_test_exit(mm)) {
-                               spinlock_t *ptl = pmd_lock(mm, pmd);
-                               /* assume page table is clear */
-                               _pmd = pmdp_collapse_flush(vma, addr, pmd);
-                               spin_unlock(ptl);
-                               mm_dec_nr_ptes(mm);
-                               pte_free(mm, pmd_pgtable(_pmd));
-                       }
+                       if (!khugepaged_test_exit(mm))
+                               collapse_and_free_pmd(mm, vma, addr, pmd);
                        mmap_write_unlock(mm);
                } else {
                        /* Try again later */
index dc3758f..7580baa 100644 (file)
@@ -1410,7 +1410,8 @@ static void kmemleak_scan(void)
 {
        unsigned long flags;
        struct kmemleak_object *object;
-       int i;
+       struct zone *zone;
+       int __maybe_unused i;
        int new_leaks = 0;
 
        jiffies_last_scan = jiffies;
@@ -1450,9 +1451,9 @@ static void kmemleak_scan(void)
         * Struct page scanning for each node.
         */
        get_online_mems();
-       for_each_online_node(i) {
-               unsigned long start_pfn = node_start_pfn(i);
-               unsigned long end_pfn = node_end_pfn(i);
+       for_each_populated_zone(zone) {
+               unsigned long start_pfn = zone->zone_start_pfn;
+               unsigned long end_pfn = zone_end_pfn(zone);
                unsigned long pfn;
 
                for (pfn = start_pfn; pfn < end_pfn; pfn++) {
@@ -1461,8 +1462,8 @@ static void kmemleak_scan(void)
                        if (!page)
                                continue;
 
-                       /* only scan pages belonging to this node */
-                       if (page_to_nid(page) != i)
+                       /* only scan pages belonging to this zone */
+                       if (page_zone(page) != zone)
                                continue;
                        /* only scan if page is in use */
                        if (page_count(page) == 0)
index 1018e50..b12a364 100644 (file)
@@ -366,14 +366,20 @@ void __init memblock_discard(void)
                addr = __pa(memblock.reserved.regions);
                size = PAGE_ALIGN(sizeof(struct memblock_region) *
                                  memblock.reserved.max);
-               memblock_free_late(addr, size);
+               if (memblock_reserved_in_slab)
+                       kfree(memblock.reserved.regions);
+               else
+                       memblock_free_late(addr, size);
        }
 
        if (memblock.memory.regions != memblock_memory_init_regions) {
                addr = __pa(memblock.memory.regions);
                size = PAGE_ALIGN(sizeof(struct memblock_region) *
                                  memblock.memory.max);
-               memblock_free_late(addr, size);
+               if (memblock_memory_in_slab)
+                       kfree(memblock.memory.regions);
+               else
+                       memblock_free_late(addr, size);
        }
 
        memblock_memory = NULL;
index 09d342c..36e9f38 100644 (file)
@@ -254,7 +254,7 @@ struct mem_cgroup *vmpressure_to_memcg(struct vmpressure *vmpr)
 }
 
 #ifdef CONFIG_MEMCG_KMEM
-extern spinlock_t css_set_lock;
+static DEFINE_SPINLOCK(objcg_lock);
 
 bool mem_cgroup_kmem_disabled(void)
 {
@@ -298,9 +298,9 @@ static void obj_cgroup_release(struct percpu_ref *ref)
        if (nr_pages)
                obj_cgroup_uncharge_pages(objcg, nr_pages);
 
-       spin_lock_irqsave(&css_set_lock, flags);
+       spin_lock_irqsave(&objcg_lock, flags);
        list_del(&objcg->list);
-       spin_unlock_irqrestore(&css_set_lock, flags);
+       spin_unlock_irqrestore(&objcg_lock, flags);
 
        percpu_ref_exit(ref);
        kfree_rcu(objcg, rcu);
@@ -332,7 +332,7 @@ static void memcg_reparent_objcgs(struct mem_cgroup *memcg,
 
        objcg = rcu_replace_pointer(memcg->objcg, NULL, true);
 
-       spin_lock_irq(&css_set_lock);
+       spin_lock_irq(&objcg_lock);
 
        /* 1) Ready to reparent active objcg. */
        list_add(&objcg->list, &memcg->objcg_list);
@@ -342,7 +342,7 @@ static void memcg_reparent_objcgs(struct mem_cgroup *memcg,
        /* 3) Move already reparented objcgs to the parent's list */
        list_splice(&memcg->objcg_list, &parent->objcg_list);
 
-       spin_unlock_irq(&css_set_lock);
+       spin_unlock_irq(&objcg_lock);
 
        percpu_ref_kill(&objcg->refcnt);
 }
index 14ae5c1..97a9ed8 100644 (file)
@@ -1595,6 +1595,12 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
                goto out;
        }
 
+       /*
+        * Pages instantiated by device-dax (not filesystem-dax)
+        * may be compound pages.
+        */
+       page = compound_head(page);
+
        /*
         * Prevent the inode from being freed while we are interrogating
         * the address_space, typically this would be handled by
index 1e8fdb0..d445c1b 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -3186,6 +3186,7 @@ void exit_mmap(struct mm_struct *mm)
                vma = remove_vma(vma);
                cond_resched();
        }
+       mm->mmap = NULL;
        mmap_write_unlock(mm);
        vm_unacct_memory(nr_accounted);
 }
index 0138dfc..5ca3fbc 100644 (file)
@@ -94,7 +94,7 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
 
                                /* Also skip shared copy-on-write pages */
                                if (is_cow_mapping(vma->vm_flags) &&
-                                   page_mapcount(page) != 1)
+                                   page_count(page) != 1)
                                        continue;
 
                                /*
index 6a0ddda..f67c4c7 100644 (file)
@@ -115,7 +115,7 @@ static void unset_migratetype_isolate(struct page *page, unsigned migratetype)
         * onlining - just onlined memory won't immediately be considered for
         * allocation.
         */
-       if (!isolated_page && PageBuddy(page)) {
+       if (!isolated_page) {
                nr_pages = move_freepages_block(zone, page, migratetype, NULL);
                __mod_zone_freepage_state(zone, nr_pages, migratetype);
        }
index 7504e7c..3763bd0 100644 (file)
@@ -86,8 +86,8 @@ static void page_table_check_clear(struct mm_struct *mm, unsigned long addr,
 {
        struct page_ext *page_ext;
        struct page *page;
+       unsigned long i;
        bool anon;
-       int i;
 
        if (!pfn_valid(pfn))
                return;
@@ -121,8 +121,8 @@ static void page_table_check_set(struct mm_struct *mm, unsigned long addr,
 {
        struct page_ext *page_ext;
        struct page *page;
+       unsigned long i;
        bool anon;
-       int i;
 
        if (!pfn_valid(pfn))
                return;
@@ -152,10 +152,10 @@ static void page_table_check_set(struct mm_struct *mm, unsigned long addr,
 void __page_table_check_zero(struct page *page, unsigned int order)
 {
        struct page_ext *page_ext = lookup_page_ext(page);
-       int i;
+       unsigned long i;
 
        BUG_ON(!page_ext);
-       for (i = 0; i < (1 << order); i++) {
+       for (i = 0; i < (1ul << order); i++) {
                struct page_table_check *ptc = get_page_table_check(page_ext);
 
                BUG_ON(atomic_read(&ptc->anon_map_count));
@@ -206,17 +206,10 @@ EXPORT_SYMBOL(__page_table_check_pud_clear);
 void __page_table_check_pte_set(struct mm_struct *mm, unsigned long addr,
                                pte_t *ptep, pte_t pte)
 {
-       pte_t old_pte;
-
        if (&init_mm == mm)
                return;
 
-       old_pte = *ptep;
-       if (pte_user_accessible_page(old_pte)) {
-               page_table_check_clear(mm, addr, pte_pfn(old_pte),
-                                      PAGE_SIZE >> PAGE_SHIFT);
-       }
-
+       __page_table_check_pte_clear(mm, addr, *ptep);
        if (pte_user_accessible_page(pte)) {
                page_table_check_set(mm, addr, pte_pfn(pte),
                                     PAGE_SIZE >> PAGE_SHIFT,
@@ -228,17 +221,10 @@ EXPORT_SYMBOL(__page_table_check_pte_set);
 void __page_table_check_pmd_set(struct mm_struct *mm, unsigned long addr,
                                pmd_t *pmdp, pmd_t pmd)
 {
-       pmd_t old_pmd;
-
        if (&init_mm == mm)
                return;
 
-       old_pmd = *pmdp;
-       if (pmd_user_accessible_page(old_pmd)) {
-               page_table_check_clear(mm, addr, pmd_pfn(old_pmd),
-                                      PMD_PAGE_SIZE >> PAGE_SHIFT);
-       }
-
+       __page_table_check_pmd_clear(mm, addr, *pmdp);
        if (pmd_user_accessible_page(pmd)) {
                page_table_check_set(mm, addr, pmd_pfn(pmd),
                                     PMD_PAGE_SIZE >> PAGE_SHIFT,
@@ -250,17 +236,10 @@ EXPORT_SYMBOL(__page_table_check_pmd_set);
 void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr,
                                pud_t *pudp, pud_t pud)
 {
-       pud_t old_pud;
-
        if (&init_mm == mm)
                return;
 
-       old_pud = *pudp;
-       if (pud_user_accessible_page(old_pud)) {
-               page_table_check_clear(mm, addr, pud_pfn(old_pud),
-                                      PUD_PAGE_SIZE >> PAGE_SHIFT);
-       }
-
+       __page_table_check_pud_clear(mm, addr, *pudp);
        if (pud_user_accessible_page(pud)) {
                page_table_check_set(mm, addr, pud_pfn(pud),
                                     PUD_PAGE_SIZE >> PAGE_SHIFT,
@@ -268,3 +247,23 @@ void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr,
        }
 }
 EXPORT_SYMBOL(__page_table_check_pud_set);
+
+void __page_table_check_pte_clear_range(struct mm_struct *mm,
+                                       unsigned long addr,
+                                       pmd_t pmd)
+{
+       if (&init_mm == mm)
+               return;
+
+       if (!pmd_bad(pmd) && !pmd_leaf(pmd)) {
+               pte_t *ptep = pte_offset_map(&pmd, addr);
+               unsigned long i;
+
+               pte_unmap(ptep);
+               for (i = 0; i < PTRS_PER_PTE; i++) {
+                       __page_table_check_pte_clear(mm, addr, *ptep);
+                       addr += PAGE_SIZE;
+                       ptep++;
+               }
+       }
+}
index 090bfb6..59b14e0 100644 (file)
@@ -1066,8 +1066,10 @@ void reclaim_throttle(pg_data_t *pgdat, enum vmscan_throttle_state reason)
         * forward progress (e.g. journalling workqueues or kthreads).
         */
        if (!current_is_kswapd() &&
-           current->flags & (PF_IO_WORKER|PF_KTHREAD))
+           current->flags & (PF_IO_WORKER|PF_KTHREAD)) {
+               cond_resched();
                return;
+       }
 
        /*
         * These figures are pulled out of thin air.
index 1a705a4..5eaf388 100644 (file)
@@ -129,6 +129,7 @@ void vlan_dev_set_ingress_priority(const struct net_device *dev,
                                   u32 skb_prio, u16 vlan_prio);
 int vlan_dev_set_egress_priority(const struct net_device *dev,
                                 u32 skb_prio, u16 vlan_prio);
+void vlan_dev_free_egress_priority(const struct net_device *dev);
 int vlan_dev_change_flags(const struct net_device *dev, u32 flag, u32 mask);
 void vlan_dev_get_realdev_name(const struct net_device *dev, char *result,
                               size_t size);
@@ -139,7 +140,6 @@ int vlan_check_real_dev(struct net_device *real_dev,
 void vlan_setup(struct net_device *dev);
 int register_vlan_dev(struct net_device *dev, struct netlink_ext_ack *extack);
 void unregister_vlan_dev(struct net_device *dev, struct list_head *head);
-void vlan_dev_uninit(struct net_device *dev);
 bool vlan_dev_inherit_address(struct net_device *dev,
                              struct net_device *real_dev);
 
index 26d031a..d190282 100644 (file)
@@ -622,7 +622,7 @@ static int vlan_dev_init(struct net_device *dev)
 }
 
 /* Note: this function might be called multiple times for the same device. */
-void vlan_dev_uninit(struct net_device *dev)
+void vlan_dev_free_egress_priority(const struct net_device *dev)
 {
        struct vlan_priority_tci_mapping *pm;
        struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
@@ -636,6 +636,16 @@ void vlan_dev_uninit(struct net_device *dev)
        }
 }
 
+static void vlan_dev_uninit(struct net_device *dev)
+{
+       struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
+
+       vlan_dev_free_egress_priority(dev);
+
+       /* Get rid of the vlan's reference to real_dev */
+       dev_put_track(vlan->real_dev, &vlan->dev_tracker);
+}
+
 static netdev_features_t vlan_dev_fix_features(struct net_device *dev,
        netdev_features_t features)
 {
@@ -846,9 +856,6 @@ static void vlan_dev_free(struct net_device *dev)
 
        free_percpu(vlan->vlan_pcpu_stats);
        vlan->vlan_pcpu_stats = NULL;
-
-       /* Get rid of the vlan's reference to real_dev */
-       dev_put_track(vlan->real_dev, &vlan->dev_tracker);
 }
 
 void vlan_setup(struct net_device *dev)
index 0db85ae..53b1955 100644 (file)
@@ -183,10 +183,11 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev,
                return -EINVAL;
 
        err = vlan_changelink(dev, tb, data, extack);
-       if (!err)
-               err = register_vlan_dev(dev, extack);
        if (err)
-               vlan_dev_uninit(dev);
+               return err;
+       err = register_vlan_dev(dev, extack);
+       if (err)
+               vlan_dev_free_egress_priority(dev);
        return err;
 }
 
index 02f43f3..d53cbb4 100644 (file)
@@ -77,6 +77,7 @@ static void ax25_kill_by_device(struct net_device *dev)
 {
        ax25_dev *ax25_dev;
        ax25_cb *s;
+       struct sock *sk;
 
        if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
                return;
@@ -85,13 +86,17 @@ static void ax25_kill_by_device(struct net_device *dev)
 again:
        ax25_for_each(s, &ax25_list) {
                if (s->ax25_dev == ax25_dev) {
+                       sk = s->sk;
+                       sock_hold(sk);
                        spin_unlock_bh(&ax25_list_lock);
-                       lock_sock(s->sk);
+                       lock_sock(sk);
                        s->ax25_dev = NULL;
-                       release_sock(s->sk);
+                       dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker);
+                       ax25_dev_put(ax25_dev);
                        ax25_disconnect(s, ENETUNREACH);
+                       release_sock(sk);
                        spin_lock_bh(&ax25_list_lock);
-
+                       sock_put(sk);
                        /* The entry could have been deleted from the
                         * list meanwhile and thus the next pointer is
                         * no longer valid.  Play it safe and restart
@@ -355,21 +360,25 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg)
        if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl)))
                return -EFAULT;
 
-       if ((ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr)) == NULL)
-               return -ENODEV;
-
        if (ax25_ctl.digi_count > AX25_MAX_DIGIS)
                return -EINVAL;
 
        if (ax25_ctl.arg > ULONG_MAX / HZ && ax25_ctl.cmd != AX25_KILL)
                return -EINVAL;
 
+       ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr);
+       if (!ax25_dev)
+               return -ENODEV;
+
        digi.ndigi = ax25_ctl.digi_count;
        for (k = 0; k < digi.ndigi; k++)
                digi.calls[k] = ax25_ctl.digi_addr[k];
 
-       if ((ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev)) == NULL)
+       ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev);
+       if (!ax25) {
+               ax25_dev_put(ax25_dev);
                return -ENOTCONN;
+       }
 
        switch (ax25_ctl.cmd) {
        case AX25_KILL:
@@ -436,6 +445,7 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg)
          }
 
 out_put:
+       ax25_dev_put(ax25_dev);
        ax25_cb_put(ax25);
        return ret;
 
@@ -1107,8 +1117,10 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                }
        }
 
-       if (ax25_dev != NULL)
+       if (ax25_dev) {
                ax25_fillin_cb(ax25, ax25_dev);
+               dev_hold_track(ax25_dev->dev, &ax25_dev->dev_tracker, GFP_ATOMIC);
+       }
 
 done:
        ax25_cb_add(ax25);
index 256fadb..d2a244e 100644 (file)
@@ -37,6 +37,7 @@ ax25_dev *ax25_addr_ax25dev(ax25_address *addr)
        for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
                if (ax25cmp(addr, (const ax25_address *)ax25_dev->dev->dev_addr) == 0) {
                        res = ax25_dev;
+                       ax25_dev_hold(ax25_dev);
                }
        spin_unlock_bh(&ax25_dev_lock);
 
@@ -56,6 +57,7 @@ void ax25_dev_device_up(struct net_device *dev)
                return;
        }
 
+       refcount_set(&ax25_dev->refcount, 1);
        dev->ax25_ptr     = ax25_dev;
        ax25_dev->dev     = dev;
        dev_hold_track(dev, &ax25_dev->dev_tracker, GFP_ATOMIC);
@@ -84,6 +86,7 @@ void ax25_dev_device_up(struct net_device *dev)
        ax25_dev->next = ax25_dev_list;
        ax25_dev_list  = ax25_dev;
        spin_unlock_bh(&ax25_dev_lock);
+       ax25_dev_hold(ax25_dev);
 
        ax25_register_dev_sysctl(ax25_dev);
 }
@@ -113,9 +116,10 @@ void ax25_dev_device_down(struct net_device *dev)
        if ((s = ax25_dev_list) == ax25_dev) {
                ax25_dev_list = s->next;
                spin_unlock_bh(&ax25_dev_lock);
+               ax25_dev_put(ax25_dev);
                dev->ax25_ptr = NULL;
                dev_put_track(dev, &ax25_dev->dev_tracker);
-               kfree(ax25_dev);
+               ax25_dev_put(ax25_dev);
                return;
        }
 
@@ -123,9 +127,10 @@ void ax25_dev_device_down(struct net_device *dev)
                if (s->next == ax25_dev) {
                        s->next = ax25_dev->next;
                        spin_unlock_bh(&ax25_dev_lock);
+                       ax25_dev_put(ax25_dev);
                        dev->ax25_ptr = NULL;
                        dev_put_track(dev, &ax25_dev->dev_tracker);
-                       kfree(ax25_dev);
+                       ax25_dev_put(ax25_dev);
                        return;
                }
 
@@ -133,6 +138,7 @@ void ax25_dev_device_down(struct net_device *dev)
        }
        spin_unlock_bh(&ax25_dev_lock);
        dev->ax25_ptr = NULL;
+       ax25_dev_put(ax25_dev);
 }
 
 int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
@@ -144,20 +150,32 @@ int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
 
        switch (cmd) {
        case SIOCAX25ADDFWD:
-               if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL)
+               fwd_dev = ax25_addr_ax25dev(&fwd->port_to);
+               if (!fwd_dev) {
+                       ax25_dev_put(ax25_dev);
                        return -EINVAL;
-               if (ax25_dev->forward != NULL)
+               }
+               if (ax25_dev->forward) {
+                       ax25_dev_put(fwd_dev);
+                       ax25_dev_put(ax25_dev);
                        return -EINVAL;
+               }
                ax25_dev->forward = fwd_dev->dev;
+               ax25_dev_put(fwd_dev);
+               ax25_dev_put(ax25_dev);
                break;
 
        case SIOCAX25DELFWD:
-               if (ax25_dev->forward == NULL)
+               if (!ax25_dev->forward) {
+                       ax25_dev_put(ax25_dev);
                        return -EINVAL;
+               }
                ax25_dev->forward = NULL;
+               ax25_dev_put(ax25_dev);
                break;
 
        default:
+               ax25_dev_put(ax25_dev);
                return -EINVAL;
        }
 
index d0b2e09..9751207 100644 (file)
@@ -75,11 +75,13 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
        ax25_dev *ax25_dev;
        int i;
 
-       if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
-               return -EINVAL;
        if (route->digi_count > AX25_MAX_DIGIS)
                return -EINVAL;
 
+       ax25_dev = ax25_addr_ax25dev(&route->port_addr);
+       if (!ax25_dev)
+               return -EINVAL;
+
        write_lock_bh(&ax25_route_lock);
 
        ax25_rt = ax25_route_list;
@@ -91,6 +93,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
                        if (route->digi_count != 0) {
                                if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
                                        write_unlock_bh(&ax25_route_lock);
+                                       ax25_dev_put(ax25_dev);
                                        return -ENOMEM;
                                }
                                ax25_rt->digipeat->lastrepeat = -1;
@@ -101,6 +104,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
                                }
                        }
                        write_unlock_bh(&ax25_route_lock);
+                       ax25_dev_put(ax25_dev);
                        return 0;
                }
                ax25_rt = ax25_rt->next;
@@ -108,6 +112,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
 
        if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) {
                write_unlock_bh(&ax25_route_lock);
+               ax25_dev_put(ax25_dev);
                return -ENOMEM;
        }
 
@@ -120,6 +125,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
                if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
                        write_unlock_bh(&ax25_route_lock);
                        kfree(ax25_rt);
+                       ax25_dev_put(ax25_dev);
                        return -ENOMEM;
                }
                ax25_rt->digipeat->lastrepeat = -1;
@@ -132,6 +138,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route)
        ax25_rt->next   = ax25_route_list;
        ax25_route_list = ax25_rt;
        write_unlock_bh(&ax25_route_lock);
+       ax25_dev_put(ax25_dev);
 
        return 0;
 }
@@ -173,6 +180,7 @@ static int ax25_rt_del(struct ax25_routes_struct *route)
                }
        }
        write_unlock_bh(&ax25_route_lock);
+       ax25_dev_put(ax25_dev);
 
        return 0;
 }
@@ -215,6 +223,7 @@ static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option)
 
 out:
        write_unlock_bh(&ax25_route_lock);
+       ax25_dev_put(ax25_dev);
        return err;
 }
 
index de24098..db4f264 100644 (file)
@@ -82,6 +82,9 @@ static void br_multicast_find_del_pg(struct net_bridge *br,
                                     struct net_bridge_port_group *pg);
 static void __br_multicast_stop(struct net_bridge_mcast *brmctx);
 
+static int br_mc_disabled_update(struct net_device *dev, bool value,
+                                struct netlink_ext_ack *extack);
+
 static struct net_bridge_port_group *
 br_sg_port_find(struct net_bridge *br,
                struct net_bridge_port_group_sg_key *sg_p)
@@ -1156,6 +1159,7 @@ struct net_bridge_mdb_entry *br_multicast_new_group(struct net_bridge *br,
                return mp;
 
        if (atomic_read(&br->mdb_hash_tbl.nelems) >= br->hash_max) {
+               br_mc_disabled_update(br->dev, false, NULL);
                br_opt_toggle(br, BROPT_MULTICAST_ENABLED, false);
                return ERR_PTR(-E2BIG);
        }
index 84ba456..1402d5c 100644 (file)
@@ -560,10 +560,10 @@ static bool __allowed_ingress(const struct net_bridge *br,
                    !br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) {
                        if (*state == BR_STATE_FORWARDING) {
                                *state = br_vlan_get_pvid_state(vg);
-                               return br_vlan_state_allowed(*state, true);
-                       } else {
-                               return true;
+                               if (!br_vlan_state_allowed(*state, true))
+                                       goto drop;
                        }
+                       return true;
                }
        }
        v = br_vlan_find(vg, *vid);
@@ -2020,7 +2020,8 @@ static int br_vlan_rtm_dump(struct sk_buff *skb, struct netlink_callback *cb)
                        goto out_err;
                }
                err = br_vlan_dump_dev(dev, skb, cb, dump_flags);
-               if (err && err != -EMSGSIZE)
+               /* if the dump completed without an error we return 0 here */
+               if (err != -EMSGSIZE)
                        goto out_err;
        } else {
                for_each_netdev_rcu(net, dev) {
index eba0efe..fbf858d 100644 (file)
@@ -49,7 +49,7 @@ static void nft_reject_br_send_v4_tcp_reset(struct net *net,
 {
        struct sk_buff *nskb;
 
-       nskb = nf_reject_skb_v4_tcp_reset(net, oldskb, dev, hook);
+       nskb = nf_reject_skb_v4_tcp_reset(net, oldskb, NULL, hook);
        if (!nskb)
                return;
 
@@ -65,7 +65,7 @@ static void nft_reject_br_send_v4_unreach(struct net *net,
 {
        struct sk_buff *nskb;
 
-       nskb = nf_reject_skb_v4_unreach(net, oldskb, dev, hook, code);
+       nskb = nf_reject_skb_v4_unreach(net, oldskb, NULL, hook, code);
        if (!nskb)
                return;
 
@@ -81,7 +81,7 @@ static void nft_reject_br_send_v6_tcp_reset(struct net *net,
 {
        struct sk_buff *nskb;
 
-       nskb = nf_reject_skb_v6_tcp_reset(net, oldskb, dev, hook);
+       nskb = nf_reject_skb_v6_tcp_reset(net, oldskb, NULL, hook);
        if (!nskb)
                return;
 
@@ -98,7 +98,7 @@ static void nft_reject_br_send_v6_unreach(struct net *net,
 {
        struct sk_buff *nskb;
 
-       nskb = nf_reject_skb_v6_unreach(net, oldskb, dev, hook, code);
+       nskb = nf_reject_skb_v6_unreach(net, oldskb, NULL, hook, code);
        if (!nskb)
                return;
 
index 02cbcb2..d2a430b 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/spinlock.h>
 #include <linux/hrtimer.h>
 #include <linux/wait.h>
 #include <linux/uio.h>
@@ -145,6 +146,7 @@ struct isotp_sock {
        struct tpcon rx, tx;
        struct list_head notifier;
        wait_queue_head_t wait;
+       spinlock_t rx_lock; /* protect single thread state machine */
 };
 
 static LIST_HEAD(isotp_notifier_list);
@@ -615,11 +617,17 @@ static void isotp_rcv(struct sk_buff *skb, void *data)
 
        n_pci_type = cf->data[ae] & 0xF0;
 
+       /* Make sure the state changes and data structures stay consistent at
+        * CAN frame reception time. This locking is not needed in real world
+        * use cases but the inconsistency can be triggered with syzkaller.
+        */
+       spin_lock(&so->rx_lock);
+
        if (so->opt.flags & CAN_ISOTP_HALF_DUPLEX) {
                /* check rx/tx path half duplex expectations */
                if ((so->tx.state != ISOTP_IDLE && n_pci_type != N_PCI_FC) ||
                    (so->rx.state != ISOTP_IDLE && n_pci_type == N_PCI_FC))
-                       return;
+                       goto out_unlock;
        }
 
        switch (n_pci_type) {
@@ -668,6 +676,9 @@ static void isotp_rcv(struct sk_buff *skb, void *data)
                isotp_rcv_cf(sk, cf, ae, skb);
                break;
        }
+
+out_unlock:
+       spin_unlock(&so->rx_lock);
 }
 
 static void isotp_fill_dataframe(struct canfd_frame *cf, struct isotp_sock *so,
@@ -876,7 +887,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 
        if (!size || size > MAX_MSG_LENGTH) {
                err = -EINVAL;
-               goto err_out;
+               goto err_out_drop;
        }
 
        /* take care of a potential SF_DL ESC offset for TX_DL > 8 */
@@ -886,24 +897,24 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
        if ((so->opt.flags & CAN_ISOTP_SF_BROADCAST) &&
            (size > so->tx.ll_dl - SF_PCI_SZ4 - ae - off)) {
                err = -EINVAL;
-               goto err_out;
+               goto err_out_drop;
        }
 
        err = memcpy_from_msg(so->tx.buf, msg, size);
        if (err < 0)
-               goto err_out;
+               goto err_out_drop;
 
        dev = dev_get_by_index(sock_net(sk), so->ifindex);
        if (!dev) {
                err = -ENXIO;
-               goto err_out;
+               goto err_out_drop;
        }
 
        skb = sock_alloc_send_skb(sk, so->ll.mtu + sizeof(struct can_skb_priv),
                                  msg->msg_flags & MSG_DONTWAIT, &err);
        if (!skb) {
                dev_put(dev);
-               goto err_out;
+               goto err_out_drop;
        }
 
        can_skb_reserve(skb);
@@ -965,7 +976,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
        if (err) {
                pr_notice_once("can-isotp: %s: can_send_ret %pe\n",
                               __func__, ERR_PTR(err));
-               goto err_out;
+               goto err_out_drop;
        }
 
        if (wait_tx_done) {
@@ -978,6 +989,9 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 
        return size;
 
+err_out_drop:
+       /* drop this PDU and unlock a potential wait queue */
+       old_state = ISOTP_IDLE;
 err_out:
        so->tx.state = old_state;
        if (so->tx.state == ISOTP_IDLE)
@@ -1444,6 +1458,7 @@ static int isotp_init(struct sock *sk)
        so->txtimer.function = isotp_tx_timer_handler;
 
        init_waitqueue_head(&so->wait);
+       spin_lock_init(&so->rx_lock);
 
        spin_lock(&isotp_notifier_lock);
        list_add_tail(&so->notifier, &isotp_notifier_list);
index a271688..307ee11 100644 (file)
@@ -2006,7 +2006,7 @@ struct j1939_session *j1939_tp_send(struct j1939_priv *priv,
                /* set the end-packet for broadcast */
                session->pkt.last = session->pkt.total;
 
-       skcb->tskey = session->sk->sk_tskey++;
+       skcb->tskey = atomic_inc_return(&session->sk->sk_tskey) - 1;
        session->tskey = skcb->tskey;
 
        return session;
index ecc400a..4c64415 100644 (file)
@@ -246,6 +246,7 @@ enum {
        Opt_cephx_sign_messages,
        Opt_tcp_nodelay,
        Opt_abort_on_full,
+       Opt_rxbounce,
 };
 
 enum {
@@ -295,6 +296,7 @@ static const struct fs_parameter_spec ceph_parameters[] = {
        fsparam_u32     ("osdkeepalive",                Opt_osdkeepalivetimeout),
        fsparam_enum    ("read_from_replica",           Opt_read_from_replica,
                         ceph_param_read_from_replica),
+       fsparam_flag    ("rxbounce",                    Opt_rxbounce),
        fsparam_enum    ("ms_mode",                     Opt_ms_mode,
                         ceph_param_ms_mode),
        fsparam_string  ("secret",                      Opt_secret),
@@ -584,6 +586,9 @@ int ceph_parse_param(struct fs_parameter *param, struct ceph_options *opt,
        case Opt_abort_on_full:
                opt->flags |= CEPH_OPT_ABORT_ON_FULL;
                break;
+       case Opt_rxbounce:
+               opt->flags |= CEPH_OPT_RXBOUNCE;
+               break;
 
        default:
                BUG();
@@ -660,6 +665,8 @@ int ceph_print_client_options(struct seq_file *m, struct ceph_client *client,
                seq_puts(m, "notcp_nodelay,");
        if (show_all && (opt->flags & CEPH_OPT_ABORT_ON_FULL))
                seq_puts(m, "abort_on_full,");
+       if (opt->flags & CEPH_OPT_RXBOUNCE)
+               seq_puts(m, "rxbounce,");
 
        if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT)
                seq_printf(m, "mount_timeout=%d,",
index 45eba2d..d3bb656 100644 (file)
@@ -515,6 +515,10 @@ static void ceph_con_reset_protocol(struct ceph_connection *con)
                ceph_msg_put(con->out_msg);
                con->out_msg = NULL;
        }
+       if (con->bounce_page) {
+               __free_page(con->bounce_page);
+               con->bounce_page = NULL;
+       }
 
        if (ceph_msgr2(from_msgr(con->msgr)))
                ceph_con_v2_reset_protocol(con);
index 2cb5ffd..6b014ec 100644 (file)
@@ -992,8 +992,7 @@ static int read_partial_message_section(struct ceph_connection *con,
 
 static int read_partial_msg_data(struct ceph_connection *con)
 {
-       struct ceph_msg *msg = con->in_msg;
-       struct ceph_msg_data_cursor *cursor = &msg->cursor;
+       struct ceph_msg_data_cursor *cursor = &con->in_msg->cursor;
        bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC);
        struct page *page;
        size_t page_offset;
@@ -1001,9 +1000,6 @@ static int read_partial_msg_data(struct ceph_connection *con)
        u32 crc = 0;
        int ret;
 
-       if (!msg->num_data_items)
-               return -EIO;
-
        if (do_datacrc)
                crc = con->in_data_crc;
        while (cursor->total_resid) {
@@ -1031,6 +1027,46 @@ static int read_partial_msg_data(struct ceph_connection *con)
        return 1;       /* must return > 0 to indicate success */
 }
 
+static int read_partial_msg_data_bounce(struct ceph_connection *con)
+{
+       struct ceph_msg_data_cursor *cursor = &con->in_msg->cursor;
+       struct page *page;
+       size_t off, len;
+       u32 crc;
+       int ret;
+
+       if (unlikely(!con->bounce_page)) {
+               con->bounce_page = alloc_page(GFP_NOIO);
+               if (!con->bounce_page) {
+                       pr_err("failed to allocate bounce page\n");
+                       return -ENOMEM;
+               }
+       }
+
+       crc = con->in_data_crc;
+       while (cursor->total_resid) {
+               if (!cursor->resid) {
+                       ceph_msg_data_advance(cursor, 0);
+                       continue;
+               }
+
+               page = ceph_msg_data_next(cursor, &off, &len, NULL);
+               ret = ceph_tcp_recvpage(con->sock, con->bounce_page, 0, len);
+               if (ret <= 0) {
+                       con->in_data_crc = crc;
+                       return ret;
+               }
+
+               crc = crc32c(crc, page_address(con->bounce_page), ret);
+               memcpy_to_page(page, off, page_address(con->bounce_page), ret);
+
+               ceph_msg_data_advance(cursor, ret);
+       }
+       con->in_data_crc = crc;
+
+       return 1;       /* must return > 0 to indicate success */
+}
+
 /*
  * read (part of) a message.
  */
@@ -1141,7 +1177,13 @@ static int read_partial_message(struct ceph_connection *con)
 
        /* (page) data */
        if (data_len) {
-               ret = read_partial_msg_data(con);
+               if (!m->num_data_items)
+                       return -EIO;
+
+               if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE))
+                       ret = read_partial_msg_data_bounce(con);
+               else
+                       ret = read_partial_msg_data(con);
                if (ret <= 0)
                        return ret;
        }
index c4099b6..c81379f 100644 (file)
@@ -57,8 +57,9 @@
 #define IN_S_HANDLE_CONTROL_REMAINDER  3
 #define IN_S_PREPARE_READ_DATA         4
 #define IN_S_PREPARE_READ_DATA_CONT    5
-#define IN_S_HANDLE_EPILOGUE           6
-#define IN_S_FINISH_SKIP               7
+#define IN_S_PREPARE_READ_ENC_PAGE     6
+#define IN_S_HANDLE_EPILOGUE           7
+#define IN_S_FINISH_SKIP               8
 
 #define OUT_S_QUEUE_DATA               1
 #define OUT_S_QUEUE_DATA_CONT          2
@@ -1032,22 +1033,41 @@ static int decrypt_control_remainder(struct ceph_connection *con)
                         padded_len(rem_len) + CEPH_GCM_TAG_LEN);
 }
 
-static int decrypt_message(struct ceph_connection *con)
+static int decrypt_tail(struct ceph_connection *con)
 {
+       struct sg_table enc_sgt = {};
        struct sg_table sgt = {};
+       int tail_len;
        int ret;
 
+       tail_len = tail_onwire_len(con->in_msg, true);
+       ret = sg_alloc_table_from_pages(&enc_sgt, con->v2.in_enc_pages,
+                                       con->v2.in_enc_page_cnt, 0, tail_len,
+                                       GFP_NOIO);
+       if (ret)
+               goto out;
+
        ret = setup_message_sgs(&sgt, con->in_msg, FRONT_PAD(con->v2.in_buf),
                        MIDDLE_PAD(con->v2.in_buf), DATA_PAD(con->v2.in_buf),
                        con->v2.in_buf, true);
        if (ret)
                goto out;
 
-       ret = gcm_crypt(con, false, sgt.sgl, sgt.sgl,
-                       tail_onwire_len(con->in_msg, true));
+       dout("%s con %p msg %p enc_page_cnt %d sg_cnt %d\n", __func__, con,
+            con->in_msg, con->v2.in_enc_page_cnt, sgt.orig_nents);
+       ret = gcm_crypt(con, false, enc_sgt.sgl, sgt.sgl, tail_len);
+       if (ret)
+               goto out;
+
+       WARN_ON(!con->v2.in_enc_page_cnt);
+       ceph_release_page_vector(con->v2.in_enc_pages,
+                                con->v2.in_enc_page_cnt);
+       con->v2.in_enc_pages = NULL;
+       con->v2.in_enc_page_cnt = 0;
 
 out:
        sg_free_table(&sgt);
+       sg_free_table(&enc_sgt);
        return ret;
 }
 
@@ -1733,54 +1753,157 @@ static int prepare_read_control_remainder(struct ceph_connection *con)
        return 0;
 }
 
-static void prepare_read_data(struct ceph_connection *con)
+static int prepare_read_data(struct ceph_connection *con)
 {
        struct bio_vec bv;
 
-       if (!con_secure(con))
-               con->in_data_crc = -1;
+       con->in_data_crc = -1;
        ceph_msg_data_cursor_init(&con->v2.in_cursor, con->in_msg,
                                  data_len(con->in_msg));
 
        get_bvec_at(&con->v2.in_cursor, &bv);
-       set_in_bvec(con, &bv);
+       if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) {
+               if (unlikely(!con->bounce_page)) {
+                       con->bounce_page = alloc_page(GFP_NOIO);
+                       if (!con->bounce_page) {
+                               pr_err("failed to allocate bounce page\n");
+                               return -ENOMEM;
+                       }
+               }
+
+               bv.bv_page = con->bounce_page;
+               bv.bv_offset = 0;
+               set_in_bvec(con, &bv);
+       } else {
+               set_in_bvec(con, &bv);
+       }
        con->v2.in_state = IN_S_PREPARE_READ_DATA_CONT;
+       return 0;
 }
 
 static void prepare_read_data_cont(struct ceph_connection *con)
 {
        struct bio_vec bv;
 
-       if (!con_secure(con))
+       if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) {
+               con->in_data_crc = crc32c(con->in_data_crc,
+                                         page_address(con->bounce_page),
+                                         con->v2.in_bvec.bv_len);
+
+               get_bvec_at(&con->v2.in_cursor, &bv);
+               memcpy_to_page(bv.bv_page, bv.bv_offset,
+                              page_address(con->bounce_page),
+                              con->v2.in_bvec.bv_len);
+       } else {
                con->in_data_crc = ceph_crc32c_page(con->in_data_crc,
                                                    con->v2.in_bvec.bv_page,
                                                    con->v2.in_bvec.bv_offset,
                                                    con->v2.in_bvec.bv_len);
+       }
 
        ceph_msg_data_advance(&con->v2.in_cursor, con->v2.in_bvec.bv_len);
        if (con->v2.in_cursor.total_resid) {
                get_bvec_at(&con->v2.in_cursor, &bv);
-               set_in_bvec(con, &bv);
+               if (ceph_test_opt(from_msgr(con->msgr), RXBOUNCE)) {
+                       bv.bv_page = con->bounce_page;
+                       bv.bv_offset = 0;
+                       set_in_bvec(con, &bv);
+               } else {
+                       set_in_bvec(con, &bv);
+               }
                WARN_ON(con->v2.in_state != IN_S_PREPARE_READ_DATA_CONT);
                return;
        }
 
        /*
-        * We've read all data.  Prepare to read data padding (if any)
-        * and epilogue.
+        * We've read all data.  Prepare to read epilogue.
         */
        reset_in_kvecs(con);
-       if (con_secure(con)) {
-               if (need_padding(data_len(con->in_msg)))
-                       add_in_kvec(con, DATA_PAD(con->v2.in_buf),
-                                   padding_len(data_len(con->in_msg)));
-               add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_SECURE_LEN);
+       add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_PLAIN_LEN);
+       con->v2.in_state = IN_S_HANDLE_EPILOGUE;
+}
+
+static int prepare_read_tail_plain(struct ceph_connection *con)
+{
+       struct ceph_msg *msg = con->in_msg;
+
+       if (!front_len(msg) && !middle_len(msg)) {
+               WARN_ON(!data_len(msg));
+               return prepare_read_data(con);
+       }
+
+       reset_in_kvecs(con);
+       if (front_len(msg)) {
+               add_in_kvec(con, msg->front.iov_base, front_len(msg));
+               WARN_ON(msg->front.iov_len != front_len(msg));
+       }
+       if (middle_len(msg)) {
+               add_in_kvec(con, msg->middle->vec.iov_base, middle_len(msg));
+               WARN_ON(msg->middle->vec.iov_len != middle_len(msg));
+       }
+
+       if (data_len(msg)) {
+               con->v2.in_state = IN_S_PREPARE_READ_DATA;
        } else {
                add_in_kvec(con, con->v2.in_buf, CEPH_EPILOGUE_PLAIN_LEN);
+               con->v2.in_state = IN_S_HANDLE_EPILOGUE;
        }
+       return 0;
+}
+
+static void prepare_read_enc_page(struct ceph_connection *con)
+{
+       struct bio_vec bv;
+
+       dout("%s con %p i %d resid %d\n", __func__, con, con->v2.in_enc_i,
+            con->v2.in_enc_resid);
+       WARN_ON(!con->v2.in_enc_resid);
+
+       bv.bv_page = con->v2.in_enc_pages[con->v2.in_enc_i];
+       bv.bv_offset = 0;
+       bv.bv_len = min(con->v2.in_enc_resid, (int)PAGE_SIZE);
+
+       set_in_bvec(con, &bv);
+       con->v2.in_enc_i++;
+       con->v2.in_enc_resid -= bv.bv_len;
+
+       if (con->v2.in_enc_resid) {
+               con->v2.in_state = IN_S_PREPARE_READ_ENC_PAGE;
+               return;
+       }
+
+       /*
+        * We are set to read the last piece of ciphertext (ending
+        * with epilogue) + auth tag.
+        */
+       WARN_ON(con->v2.in_enc_i != con->v2.in_enc_page_cnt);
        con->v2.in_state = IN_S_HANDLE_EPILOGUE;
 }
 
+static int prepare_read_tail_secure(struct ceph_connection *con)
+{
+       struct page **enc_pages;
+       int enc_page_cnt;
+       int tail_len;
+
+       tail_len = tail_onwire_len(con->in_msg, true);
+       WARN_ON(!tail_len);
+
+       enc_page_cnt = calc_pages_for(0, tail_len);
+       enc_pages = ceph_alloc_page_vector(enc_page_cnt, GFP_NOIO);
+       if (IS_ERR(enc_pages))
+               return PTR_ERR(enc_pages);
+
+       WARN_ON(con->v2.in_enc_pages || con->v2.in_enc_page_cnt);
+       con->v2.in_enc_pages = enc_pages;
+       con->v2.in_enc_page_cnt = enc_page_cnt;
+       con->v2.in_enc_resid = tail_len;
+       con->v2.in_enc_i = 0;
+
+       prepare_read_enc_page(con);
+       return 0;
+}
+
 static void __finish_skip(struct ceph_connection *con)
 {
        con->in_seq++;
@@ -2589,47 +2712,26 @@ static int __handle_control(struct ceph_connection *con, void *p)
        }
 
        msg = con->in_msg;  /* set in process_message_header() */
-       if (!front_len(msg) && !middle_len(msg)) {
-               if (!data_len(msg))
-                       return process_message(con);
-
-               prepare_read_data(con);
-               return 0;
-       }
-
-       reset_in_kvecs(con);
        if (front_len(msg)) {
                WARN_ON(front_len(msg) > msg->front_alloc_len);
-               add_in_kvec(con, msg->front.iov_base, front_len(msg));
                msg->front.iov_len = front_len(msg);
-
-               if (con_secure(con) && need_padding(front_len(msg)))
-                       add_in_kvec(con, FRONT_PAD(con->v2.in_buf),
-                                   padding_len(front_len(msg)));
        } else {
                msg->front.iov_len = 0;
        }
        if (middle_len(msg)) {
                WARN_ON(middle_len(msg) > msg->middle->alloc_len);
-               add_in_kvec(con, msg->middle->vec.iov_base, middle_len(msg));
                msg->middle->vec.iov_len = middle_len(msg);
-
-               if (con_secure(con) && need_padding(middle_len(msg)))
-                       add_in_kvec(con, MIDDLE_PAD(con->v2.in_buf),
-                                   padding_len(middle_len(msg)));
        } else if (msg->middle) {
                msg->middle->vec.iov_len = 0;
        }
 
-       if (data_len(msg)) {
-               con->v2.in_state = IN_S_PREPARE_READ_DATA;
-       } else {
-               add_in_kvec(con, con->v2.in_buf,
-                           con_secure(con) ? CEPH_EPILOGUE_SECURE_LEN :
-                                             CEPH_EPILOGUE_PLAIN_LEN);
-               con->v2.in_state = IN_S_HANDLE_EPILOGUE;
-       }
-       return 0;
+       if (!front_len(msg) && !middle_len(msg) && !data_len(msg))
+               return process_message(con);
+
+       if (con_secure(con))
+               return prepare_read_tail_secure(con);
+
+       return prepare_read_tail_plain(con);
 }
 
 static int handle_preamble(struct ceph_connection *con)
@@ -2717,7 +2819,7 @@ static int handle_epilogue(struct ceph_connection *con)
        int ret;
 
        if (con_secure(con)) {
-               ret = decrypt_message(con);
+               ret = decrypt_tail(con);
                if (ret) {
                        if (ret == -EBADMSG)
                                con->error_msg = "integrity error, bad epilogue auth tag";
@@ -2785,13 +2887,16 @@ static int populate_in_iter(struct ceph_connection *con)
                        ret = handle_control_remainder(con);
                        break;
                case IN_S_PREPARE_READ_DATA:
-                       prepare_read_data(con);
-                       ret = 0;
+                       ret = prepare_read_data(con);
                        break;
                case IN_S_PREPARE_READ_DATA_CONT:
                        prepare_read_data_cont(con);
                        ret = 0;
                        break;
+               case IN_S_PREPARE_READ_ENC_PAGE:
+                       prepare_read_enc_page(con);
+                       ret = 0;
+                       break;
                case IN_S_HANDLE_EPILOGUE:
                        ret = handle_epilogue(con);
                        break;
@@ -3326,20 +3431,16 @@ void ceph_con_v2_revoke(struct ceph_connection *con)
 
 static void revoke_at_prepare_read_data(struct ceph_connection *con)
 {
-       int remaining;  /* data + [data padding] + epilogue */
+       int remaining;
        int resid;
 
+       WARN_ON(con_secure(con));
        WARN_ON(!data_len(con->in_msg));
        WARN_ON(!iov_iter_is_kvec(&con->v2.in_iter));
        resid = iov_iter_count(&con->v2.in_iter);
        WARN_ON(!resid);
 
-       if (con_secure(con))
-               remaining = padded_len(data_len(con->in_msg)) +
-                           CEPH_EPILOGUE_SECURE_LEN;
-       else
-               remaining = data_len(con->in_msg) + CEPH_EPILOGUE_PLAIN_LEN;
-
+       remaining = data_len(con->in_msg) + CEPH_EPILOGUE_PLAIN_LEN;
        dout("%s con %p resid %d remaining %d\n", __func__, con, resid,
             remaining);
        con->v2.in_iter.count -= resid;
@@ -3350,8 +3451,9 @@ static void revoke_at_prepare_read_data(struct ceph_connection *con)
 static void revoke_at_prepare_read_data_cont(struct ceph_connection *con)
 {
        int recved, resid;  /* current piece of data */
-       int remaining;  /* [data padding] + epilogue */
+       int remaining;
 
+       WARN_ON(con_secure(con));
        WARN_ON(!data_len(con->in_msg));
        WARN_ON(!iov_iter_is_bvec(&con->v2.in_iter));
        resid = iov_iter_count(&con->v2.in_iter);
@@ -3363,12 +3465,7 @@ static void revoke_at_prepare_read_data_cont(struct ceph_connection *con)
                ceph_msg_data_advance(&con->v2.in_cursor, recved);
        WARN_ON(resid > con->v2.in_cursor.total_resid);
 
-       if (con_secure(con))
-               remaining = padding_len(data_len(con->in_msg)) +
-                           CEPH_EPILOGUE_SECURE_LEN;
-       else
-               remaining = CEPH_EPILOGUE_PLAIN_LEN;
-
+       remaining = CEPH_EPILOGUE_PLAIN_LEN;
        dout("%s con %p total_resid %zu remaining %d\n", __func__, con,
             con->v2.in_cursor.total_resid, remaining);
        con->v2.in_iter.count -= resid;
@@ -3376,11 +3473,26 @@ static void revoke_at_prepare_read_data_cont(struct ceph_connection *con)
        con->v2.in_state = IN_S_FINISH_SKIP;
 }
 
+static void revoke_at_prepare_read_enc_page(struct ceph_connection *con)
+{
+       int resid;  /* current enc page (not necessarily data) */
+
+       WARN_ON(!con_secure(con));
+       WARN_ON(!iov_iter_is_bvec(&con->v2.in_iter));
+       resid = iov_iter_count(&con->v2.in_iter);
+       WARN_ON(!resid || resid > con->v2.in_bvec.bv_len);
+
+       dout("%s con %p resid %d enc_resid %d\n", __func__, con, resid,
+            con->v2.in_enc_resid);
+       con->v2.in_iter.count -= resid;
+       set_in_skip(con, resid + con->v2.in_enc_resid);
+       con->v2.in_state = IN_S_FINISH_SKIP;
+}
+
 static void revoke_at_handle_epilogue(struct ceph_connection *con)
 {
        int resid;
 
-       WARN_ON(!iov_iter_is_kvec(&con->v2.in_iter));
        resid = iov_iter_count(&con->v2.in_iter);
        WARN_ON(!resid);
 
@@ -3399,6 +3511,9 @@ void ceph_con_v2_revoke_incoming(struct ceph_connection *con)
        case IN_S_PREPARE_READ_DATA_CONT:
                revoke_at_prepare_read_data_cont(con);
                break;
+       case IN_S_PREPARE_READ_ENC_PAGE:
+               revoke_at_prepare_read_enc_page(con);
+               break;
        case IN_S_HANDLE_EPILOGUE:
                revoke_at_handle_epilogue(con);
                break;
@@ -3432,6 +3547,13 @@ void ceph_con_v2_reset_protocol(struct ceph_connection *con)
        clear_out_sign_kvecs(con);
        free_conn_bufs(con);
 
+       if (con->v2.in_enc_pages) {
+               WARN_ON(!con->v2.in_enc_page_cnt);
+               ceph_release_page_vector(con->v2.in_enc_pages,
+                                        con->v2.in_enc_page_cnt);
+               con->v2.in_enc_pages = NULL;
+               con->v2.in_enc_page_cnt = 0;
+       }
        if (con->v2.out_enc_pages) {
                WARN_ON(!con->v2.out_enc_page_cnt);
                ceph_release_page_vector(con->v2.out_enc_pages,
index 7b288a1..d5dc6be 100644 (file)
@@ -283,13 +283,17 @@ static void trace_napi_poll_hit(void *ignore, struct napi_struct *napi,
 
        rcu_read_lock();
        list_for_each_entry_rcu(new_stat, &hw_stats_list, list) {
+               struct net_device *dev;
+
                /*
                 * only add a note to our monitor buffer if:
                 * 1) this is the dev we received on
                 * 2) its after the last_rx delta
                 * 3) our rx_dropped count has gone up
                 */
-               if ((new_stat->dev == napi->dev)  &&
+               /* Paired with WRITE_ONCE() in dropmon_net_event() */
+               dev = READ_ONCE(new_stat->dev);
+               if ((dev == napi->dev)  &&
                    (time_after(jiffies, new_stat->last_rx + dm_hw_check_delta)) &&
                    (napi->dev->stats.rx_dropped != new_stat->last_drop_val)) {
                        trace_drop_common(NULL, NULL);
@@ -1576,7 +1580,10 @@ static int dropmon_net_event(struct notifier_block *ev_block,
                mutex_lock(&net_dm_mutex);
                list_for_each_entry_safe(new_stat, tmp, &hw_stats_list, list) {
                        if (new_stat->dev == dev) {
-                               new_stat->dev = NULL;
+
+                               /* Paired with READ_ONCE() in trace_napi_poll_hit() */
+                               WRITE_ONCE(new_stat->dev, NULL);
+
                                if (trace_state == TRACE_OFF) {
                                        list_del_rcu(&new_stat->list);
                                        kfree_rcu(new_stat, rcu);
index 4603b7c..9eb7858 100644 (file)
@@ -2710,6 +2710,9 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start,
        if (unlikely(flags))
                return -EINVAL;
 
+       if (unlikely(len == 0))
+               return 0;
+
        /* First find the starting scatterlist element */
        i = msg->sg.start;
        do {
index 6c2016f..ec0bf73 100644 (file)
@@ -1133,7 +1133,8 @@ out:
        neigh_release(neigh);
 }
 
-int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
+int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb,
+                      const bool immediate_ok)
 {
        int rc;
        bool immediate_probe = false;
@@ -1154,12 +1155,17 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
                        atomic_set(&neigh->probes,
                                   NEIGH_VAR(neigh->parms, UCAST_PROBES));
                        neigh_del_timer(neigh);
-                       neigh->nud_state     = NUD_INCOMPLETE;
+                       neigh->nud_state = NUD_INCOMPLETE;
                        neigh->updated = now;
-                       next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
-                                        HZ/100);
+                       if (!immediate_ok) {
+                               next = now + 1;
+                       } else {
+                               immediate_probe = true;
+                               next = now + max(NEIGH_VAR(neigh->parms,
+                                                          RETRANS_TIME),
+                                                HZ / 100);
+                       }
                        neigh_add_timer(neigh, next);
-                       immediate_probe = true;
                } else {
                        neigh->nud_state = NUD_FAILED;
                        neigh->updated = jiffies;
@@ -1571,7 +1577,7 @@ static void neigh_managed_work(struct work_struct *work)
 
        write_lock_bh(&tbl->lock);
        list_for_each_entry(neigh, &tbl->managed_list, managed_list)
-               neigh_event_send(neigh, NULL);
+               neigh_event_send_probe(neigh, NULL, false);
        queue_delayed_work(system_power_efficient_wq, &tbl->managed_work,
                           NEIGH_VAR(&tbl->parms, DELAY_PROBE_TIME));
        write_unlock_bh(&tbl->lock);
index d8b9dba..88cc0ad 100644 (file)
@@ -190,12 +190,23 @@ static const struct seq_operations softnet_seq_ops = {
        .show  = softnet_seq_show,
 };
 
-static void *ptype_get_idx(loff_t pos)
+static void *ptype_get_idx(struct seq_file *seq, loff_t pos)
 {
+       struct list_head *ptype_list = NULL;
        struct packet_type *pt = NULL;
+       struct net_device *dev;
        loff_t i = 0;
        int t;
 
+       for_each_netdev_rcu(seq_file_net(seq), dev) {
+               ptype_list = &dev->ptype_all;
+               list_for_each_entry_rcu(pt, ptype_list, list) {
+                       if (i == pos)
+                               return pt;
+                       ++i;
+               }
+       }
+
        list_for_each_entry_rcu(pt, &ptype_all, list) {
                if (i == pos)
                        return pt;
@@ -216,22 +227,40 @@ static void *ptype_seq_start(struct seq_file *seq, loff_t *pos)
        __acquires(RCU)
 {
        rcu_read_lock();
-       return *pos ? ptype_get_idx(*pos - 1) : SEQ_START_TOKEN;
+       return *pos ? ptype_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
 }
 
 static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
+       struct net_device *dev;
        struct packet_type *pt;
        struct list_head *nxt;
        int hash;
 
        ++*pos;
        if (v == SEQ_START_TOKEN)
-               return ptype_get_idx(0);
+               return ptype_get_idx(seq, 0);
 
        pt = v;
        nxt = pt->list.next;
+       if (pt->dev) {
+               if (nxt != &pt->dev->ptype_all)
+                       goto found;
+
+               dev = pt->dev;
+               for_each_netdev_continue_rcu(seq_file_net(seq), dev) {
+                       if (!list_empty(&dev->ptype_all)) {
+                               nxt = dev->ptype_all.next;
+                               goto found;
+                       }
+               }
+
+               nxt = ptype_all.next;
+               goto ptype_all;
+       }
+
        if (pt->type == htons(ETH_P_ALL)) {
+ptype_all:
                if (nxt != &ptype_all)
                        goto found;
                hash = 0;
@@ -260,7 +289,8 @@ static int ptype_seq_show(struct seq_file *seq, void *v)
 
        if (v == SEQ_START_TOKEN)
                seq_puts(seq, "Type Device      Function\n");
-       else if (pt->dev == NULL || dev_net(pt->dev) == seq_file_net(seq)) {
+       else if ((!pt->af_packet_net || net_eq(pt->af_packet_net, seq_file_net(seq))) &&
+                (!pt->dev || net_eq(dev_net(pt->dev), seq_file_net(seq)))) {
                if (pt->type == htons(ETH_P_ALL))
                        seq_puts(seq, "ALL ");
                else
index 53ea262..fbddf96 100644 (file)
@@ -213,7 +213,7 @@ static ssize_t speed_show(struct device *dev,
        if (!rtnl_trylock())
                return restart_syscall();
 
-       if (netif_running(netdev)) {
+       if (netif_running(netdev) && netif_device_present(netdev)) {
                struct ethtool_link_ksettings cmd;
 
                if (!__ethtool_get_link_ksettings(netdev, &cmd))
index e476403..2fb8eb6 100644 (file)
@@ -1699,6 +1699,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,
 {
        struct ifinfomsg *ifm;
        struct nlmsghdr *nlh;
+       struct Qdisc *qdisc;
 
        ASSERT_RTNL();
        nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
@@ -1716,6 +1717,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,
        if (tgt_netnsid >= 0 && nla_put_s32(skb, IFLA_TARGET_NETNSID, tgt_netnsid))
                goto nla_put_failure;
 
+       qdisc = rtnl_dereference(dev->qdisc);
        if (nla_put_string(skb, IFLA_IFNAME, dev->name) ||
            nla_put_u32(skb, IFLA_TXQLEN, dev->tx_queue_len) ||
            nla_put_u8(skb, IFLA_OPERSTATE,
@@ -1735,8 +1737,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,
 #endif
            put_master_ifindex(skb, dev) ||
            nla_put_u8(skb, IFLA_CARRIER, netif_carrier_ok(dev)) ||
-           (dev->qdisc &&
-            nla_put_string(skb, IFLA_QDISC, dev->qdisc->ops->id)) ||
+           (qdisc &&
+            nla_put_string(skb, IFLA_QDISC, qdisc->ops->id)) ||
            nla_put_ifalias(skb, dev) ||
            nla_put_u32(skb, IFLA_CARRIER_CHANGES,
                        atomic_read(&dev->carrier_up_count) +
@@ -3275,8 +3277,8 @@ static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
        struct nlattr *slave_attr[RTNL_SLAVE_MAX_TYPE + 1];
        unsigned char name_assign_type = NET_NAME_USER;
        struct nlattr *linkinfo[IFLA_INFO_MAX + 1];
-       const struct rtnl_link_ops *m_ops = NULL;
-       struct net_device *master_dev = NULL;
+       const struct rtnl_link_ops *m_ops;
+       struct net_device *master_dev;
        struct net *net = sock_net(skb->sk);
        const struct rtnl_link_ops *ops;
        struct nlattr *tb[IFLA_MAX + 1];
@@ -3314,6 +3316,8 @@ replay:
        else
                dev = NULL;
 
+       master_dev = NULL;
+       m_ops = NULL;
        if (dev) {
                master_dev = netdev_master_upper_dev_get(dev);
                if (master_dev)
index 0118f0a..b8138c3 100644 (file)
@@ -681,7 +681,7 @@ exit:
         * while trying to recycle fragments on __skb_frag_unref() we need
         * to make one SKB responsible for triggering the recycle path.
         * So disable the recycling bit if an SKB is cloned and we have
-        * additional references to to the fragmented part of the SKB.
+        * additional references to the fragmented part of the SKB.
         * Eventually the last SKB will have the recycling bit set and it's
         * dataref set to 0, which will trigger the recycling
         */
@@ -2276,7 +2276,7 @@ void *__pskb_pull_tail(struct sk_buff *skb, int delta)
                /* Free pulled out fragments. */
                while ((list = skb_shinfo(skb)->frag_list) != insp) {
                        skb_shinfo(skb)->frag_list = list->next;
-                       kfree_skb(list);
+                       consume_skb(list);
                }
                /* And insert new clone at head. */
                if (clone) {
@@ -4730,7 +4730,7 @@ static void __skb_complete_tx_timestamp(struct sk_buff *skb,
        if (sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) {
                serr->ee.ee_data = skb_shinfo(skb)->tskey;
                if (sk_is_tcp(sk))
-                       serr->ee.ee_data -= sk->sk_tskey;
+                       serr->ee.ee_data -= atomic_read(&sk->sk_tskey);
        }
 
        err = sock_queue_err_skb(sk, skb);
@@ -6105,7 +6105,7 @@ static int pskb_carve_frag_list(struct sk_buff *skb,
        /* Free pulled out fragments. */
        while ((list = shinfo->frag_list) != insp) {
                shinfo->frag_list = list->next;
-               kfree_skb(list);
+               consume_skb(list);
        }
        /* And insert new clone at head. */
        if (clone) {
index 4ff806d..6eb1748 100644 (file)
@@ -879,9 +879,9 @@ int sock_set_timestamping(struct sock *sk, int optname,
                        if ((1 << sk->sk_state) &
                            (TCPF_CLOSE | TCPF_LISTEN))
                                return -EINVAL;
-                       sk->sk_tskey = tcp_sk(sk)->snd_una;
+                       atomic_set(&sk->sk_tskey, tcp_sk(sk)->snd_una);
                } else {
-                       sk->sk_tskey = 0;
+                       atomic_set(&sk->sk_tskey, 0);
                }
        }
 
index d9d0d22..c43f744 100644 (file)
@@ -349,6 +349,7 @@ void dsa_flush_workqueue(void)
 {
        flush_workqueue(dsa_owq);
 }
+EXPORT_SYMBOL_GPL(dsa_flush_workqueue);
 
 int dsa_devlink_param_get(struct devlink *dl, u32 id,
                          struct devlink_param_gset_ctx *ctx)
index 3d21521..dcad310 100644 (file)
@@ -1718,7 +1718,6 @@ EXPORT_SYMBOL_GPL(dsa_unregister_switch);
 void dsa_switch_shutdown(struct dsa_switch *ds)
 {
        struct net_device *master, *slave_dev;
-       LIST_HEAD(unregister_list);
        struct dsa_port *dp;
 
        mutex_lock(&dsa2_mutex);
@@ -1729,25 +1728,13 @@ void dsa_switch_shutdown(struct dsa_switch *ds)
                slave_dev = dp->slave;
 
                netdev_upper_dev_unlink(master, slave_dev);
-               /* Just unlinking ourselves as uppers of the master is not
-                * sufficient. When the master net device unregisters, that will
-                * also call dev_close, which we will catch as NETDEV_GOING_DOWN
-                * and trigger a dev_close on our own devices (dsa_slave_close).
-                * In turn, that will call dev_mc_unsync on the master's net
-                * device. If the master is also a DSA switch port, this will
-                * trigger dsa_slave_set_rx_mode which will call dev_mc_sync on
-                * its own master. Lockdep will complain about the fact that
-                * all cascaded masters have the same dsa_master_addr_list_lock_key,
-                * which it normally would not do if the cascaded masters would
-                * be in a proper upper/lower relationship, which we've just
-                * destroyed.
-                * To suppress the lockdep warnings, let's actually unregister
-                * the DSA slave interfaces too, to avoid the nonsensical
-                * multicast address list synchronization on shutdown.
-                */
-               unregister_netdevice_queue(slave_dev, &unregister_list);
        }
-       unregister_netdevice_many(&unregister_list);
+
+       /* Disconnect from further netdevice notifiers on the master,
+        * since netdev_uses_dsa() will now return false.
+        */
+       dsa_switch_for_each_cpu_port(dp, ds)
+               dp->master->dsa_ptr = NULL;
 
        rtnl_unlock();
        mutex_unlock(&dsa2_mutex);
index 760306f..23c79e9 100644 (file)
@@ -147,7 +147,6 @@ void dsa_tag_driver_put(const struct dsa_device_ops *ops);
 const struct dsa_device_ops *dsa_find_tagger_by_name(const char *buf);
 
 bool dsa_schedule_work(struct work_struct *work);
-void dsa_flush_workqueue(void);
 const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops);
 
 static inline int dsa_tag_protocol_overhead(const struct dsa_device_ops *ops)
index 2199104..880f910 100644 (file)
@@ -260,11 +260,16 @@ static void dsa_netdev_ops_set(struct net_device *dev,
        dev->dsa_ptr->netdev_ops = ops;
 }
 
+/* Keep the master always promiscuous if the tagging protocol requires that
+ * (garbles MAC DA) or if it doesn't support unicast filtering, case in which
+ * it would revert to promiscuous mode as soon as we call dev_uc_add() on it
+ * anyway.
+ */
 static void dsa_master_set_promiscuity(struct net_device *dev, int inc)
 {
        const struct dsa_device_ops *ops = dev->dsa_ptr->tag_ops;
 
-       if (!ops->promisc_on_master)
+       if ((dev->priv_flags & IFF_UNICAST_FLT) && !ops->promisc_on_master)
                return;
 
        ASSERT_RTNL();
index bd78192..1a40c52 100644 (file)
@@ -395,10 +395,17 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
                .tree_index = dp->ds->dst->index,
                .sw_index = dp->ds->index,
                .port = dp->index,
-               .bridge = *dp->bridge,
        };
        int err;
 
+       /* If the port could not be offloaded to begin with, then
+        * there is nothing to do.
+        */
+       if (!dp->bridge)
+               return;
+
+       info.bridge = *dp->bridge;
+
        /* Here the port is already unbridged. Reflect the current configuration
         * so that drivers can program their chips accordingly.
         */
@@ -781,9 +788,15 @@ int dsa_port_host_fdb_add(struct dsa_port *dp, const unsigned char *addr,
        struct dsa_port *cpu_dp = dp->cpu_dp;
        int err;
 
-       err = dev_uc_add(cpu_dp->master, addr);
-       if (err)
-               return err;
+       /* Avoid a call to __dev_set_promiscuity() on the master, which
+        * requires rtnl_lock(), since we can't guarantee that is held here,
+        * and we can't take it either.
+        */
+       if (cpu_dp->master->priv_flags & IFF_UNICAST_FLT) {
+               err = dev_uc_add(cpu_dp->master, addr);
+               if (err)
+                       return err;
+       }
 
        return dsa_port_notify(dp, DSA_NOTIFIER_HOST_FDB_ADD, &info);
 }
@@ -800,9 +813,11 @@ int dsa_port_host_fdb_del(struct dsa_port *dp, const unsigned char *addr,
        struct dsa_port *cpu_dp = dp->cpu_dp;
        int err;
 
-       err = dev_uc_del(cpu_dp->master, addr);
-       if (err)
-               return err;
+       if (cpu_dp->master->priv_flags & IFF_UNICAST_FLT) {
+               err = dev_uc_del(cpu_dp->master, addr);
+               if (err)
+                       return err;
+       }
 
        return dsa_port_notify(dp, DSA_NOTIFIER_HOST_FDB_DEL, &info);
 }
index cb54818..98d7d71 100644 (file)
@@ -77,7 +77,6 @@ static struct sk_buff *lan9303_xmit(struct sk_buff *skb, struct net_device *dev)
 
 static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev)
 {
-       __be16 *lan9303_tag;
        u16 lan9303_tag1;
        unsigned int source_port;
 
@@ -87,14 +86,15 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev)
                return NULL;
        }
 
-       lan9303_tag = dsa_etype_header_pos_rx(skb);
-
-       if (lan9303_tag[0] != htons(ETH_P_8021Q)) {
-               dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid VLAN marker\n");
-               return NULL;
+       if (skb_vlan_tag_present(skb)) {
+               lan9303_tag1 = skb_vlan_tag_get(skb);
+               __vlan_hwaccel_clear_tag(skb);
+       } else {
+               skb_push_rcsum(skb, ETH_HLEN);
+               __skb_vlan_pop(skb, &lan9303_tag1);
+               skb_pull_rcsum(skb, ETH_HLEN);
        }
 
-       lan9303_tag1 = ntohs(lan9303_tag[1]);
        source_port = lan9303_tag1 & 0x3;
 
        skb->dev = dsa_master_find_slave(dev, 0, source_port);
@@ -103,13 +103,6 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev)
                return NULL;
        }
 
-       /* remove the special VLAN tag between the MAC addresses
-        * and the current ethertype field.
-        */
-       skb_pull_rcsum(skb, 2 + 2);
-
-       dsa_strip_etype_header(skb, LAN9303_TAG_LEN);
-
        if (!(lan9303_tag1 & LAN9303_TAG_RX_TRAPPED_TO_CPU))
                dsa_default_offload_fwd_mark(skb);
 
index 277124f..e0b072a 100644 (file)
@@ -1441,7 +1441,7 @@ static int nl802154_send_key(struct sk_buff *msg, u32 cmd, u32 portid,
 
        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
        if (!hdr)
-               return -1;
+               return -ENOBUFS;
 
        if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
                goto nla_put_failure;
@@ -1634,7 +1634,7 @@ static int nl802154_send_device(struct sk_buff *msg, u32 cmd, u32 portid,
 
        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
        if (!hdr)
-               return -1;
+               return -ENOBUFS;
 
        if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
                goto nla_put_failure;
@@ -1812,7 +1812,7 @@ static int nl802154_send_devkey(struct sk_buff *msg, u32 cmd, u32 portid,
 
        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
        if (!hdr)
-               return -1;
+               return -ENOBUFS;
 
        if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
                goto nla_put_failure;
@@ -1988,7 +1988,7 @@ static int nl802154_send_seclevel(struct sk_buff *msg, u32 cmd, u32 portid,
 
        hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
        if (!hdr)
-               return -1;
+               return -ENOBUFS;
 
        if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
                goto nla_put_failure;
index 9c465ba..72fde28 100644 (file)
@@ -1376,8 +1376,11 @@ struct sk_buff *inet_gso_segment(struct sk_buff *skb,
        }
 
        ops = rcu_dereference(inet_offloads[proto]);
-       if (likely(ops && ops->callbacks.gso_segment))
+       if (likely(ops && ops->callbacks.gso_segment)) {
                segs = ops->callbacks.gso_segment(skb, features);
+               if (!segs)
+                       skb->network_header = skb_mac_header(skb) + nhoff - skb->head;
+       }
 
        if (IS_ERR_OR_NULL(segs))
                goto out;
index 4d61ddd..85117b4 100644 (file)
@@ -436,6 +436,9 @@ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
                if (net->ipv4.fib_has_custom_local_routes ||
                    fib4_has_custom_rules(net))
                        goto full_check;
+               /* Within the same container, it is regarded as a martian source,
+                * and the same host but different containers are not.
+                */
                if (inet_lookup_ifaddr_rcu(net, src))
                        return -EINVAL;
 
index e184bcb..78e40ea 100644 (file)
@@ -16,10 +16,9 @@ struct fib_alias {
        u8                      fa_slen;
        u32                     tb_id;
        s16                     fa_default;
-       u8                      offload:1,
-                               trap:1,
-                               offload_failed:1,
-                               unused:5;
+       u8                      offload;
+       u8                      trap;
+       u8                      offload_failed;
        struct rcu_head         rcu;
 };
 
index b458986..2dd375f 100644 (file)
@@ -525,9 +525,9 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
        fri.dst_len = dst_len;
        fri.tos = fa->fa_tos;
        fri.type = fa->fa_type;
-       fri.offload = fa->offload;
-       fri.trap = fa->trap;
-       fri.offload_failed = fa->offload_failed;
+       fri.offload = READ_ONCE(fa->offload);
+       fri.trap = READ_ONCE(fa->trap);
+       fri.offload_failed = READ_ONCE(fa->offload_failed);
        err = fib_dump_info(skb, info->portid, seq, event, &fri, nlm_flags);
        if (err < 0) {
                /* -EMSGSIZE implies BUG in fib_nlmsg_size() */
index 8060524..f7f74d5 100644 (file)
@@ -1047,19 +1047,23 @@ void fib_alias_hw_flags_set(struct net *net, const struct fib_rt_info *fri)
        if (!fa_match)
                goto out;
 
-       if (fa_match->offload == fri->offload && fa_match->trap == fri->trap &&
-           fa_match->offload_failed == fri->offload_failed)
+       /* These are paired with the WRITE_ONCE() happening in this function.
+        * The reason is that we are only protected by RCU at this point.
+        */
+       if (READ_ONCE(fa_match->offload) == fri->offload &&
+           READ_ONCE(fa_match->trap) == fri->trap &&
+           READ_ONCE(fa_match->offload_failed) == fri->offload_failed)
                goto out;
 
-       fa_match->offload = fri->offload;
-       fa_match->trap = fri->trap;
+       WRITE_ONCE(fa_match->offload, fri->offload);
+       WRITE_ONCE(fa_match->trap, fri->trap);
 
        /* 2 means send notifications only if offload_failed was changed. */
        if (net->ipv4.sysctl_fib_notify_on_flag_change == 2 &&
-           fa_match->offload_failed == fri->offload_failed)
+           READ_ONCE(fa_match->offload_failed) == fri->offload_failed)
                goto out;
 
-       fa_match->offload_failed = fri->offload_failed;
+       WRITE_ONCE(fa_match->offload_failed, fri->offload_failed);
 
        if (!net->ipv4.sysctl_fib_notify_on_flag_change)
                goto out;
@@ -2297,9 +2301,9 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb,
                                fri.dst_len = KEYLENGTH - fa->fa_slen;
                                fri.tos = fa->fa_tos;
                                fri.type = fa->fa_type;
-                               fri.offload = fa->offload;
-                               fri.trap = fa->trap;
-                               fri.offload_failed = fa->offload_failed;
+                               fri.offload = READ_ONCE(fa->offload);
+                               fri.trap = READ_ONCE(fa->trap);
+                               fri.offload_failed = READ_ONCE(fa->offload_failed);
                                err = fib_dump_info(skb,
                                                    NETLINK_CB(cb->skb).portid,
                                                    cb->nlh->nlmsg_seq,
index 57c1d84..7911916 100644 (file)
@@ -162,12 +162,19 @@ int ip_build_and_send_pkt(struct sk_buff *skb, const struct sock *sk,
        iph->daddr    = (opt && opt->opt.srr ? opt->opt.faddr : daddr);
        iph->saddr    = saddr;
        iph->protocol = sk->sk_protocol;
-       if (ip_dont_fragment(sk, &rt->dst)) {
+       /* Do not bother generating IPID for small packets (eg SYNACK) */
+       if (skb->len <= IPV4_MIN_MTU || ip_dont_fragment(sk, &rt->dst)) {
                iph->frag_off = htons(IP_DF);
                iph->id = 0;
        } else {
                iph->frag_off = 0;
-               __ip_select_ident(net, iph, 1);
+               /* TCP packets here are SYNACK with fat IPv4/TCP options.
+                * Avoid using the hashed IP ident generator.
+                */
+               if (sk->sk_protocol == IPPROTO_TCP)
+                       iph->id = (__force __be16)prandom_u32();
+               else
+                       __ip_select_ident(net, iph, 1);
        }
 
        if (opt && opt->opt.optlen) {
@@ -825,15 +832,24 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
                /* Everything is OK. Generate! */
                ip_fraglist_init(skb, iph, hlen, &iter);
 
-               if (iter.frag)
-                       ip_options_fragment(iter.frag);
-
                for (;;) {
                        /* Prepare header of the next frame,
                         * before previous one went down. */
                        if (iter.frag) {
+                               bool first_frag = (iter.offset == 0);
+
                                IPCB(iter.frag)->flags = IPCB(skb)->flags;
                                ip_fraglist_prepare(skb, &iter);
+                               if (first_frag && IPCB(skb)->opt.optlen) {
+                                       /* ipcb->opt is not populated for frags
+                                        * coming from __ip_make_skb(),
+                                        * ip_options_fragment() needs optlen
+                                        */
+                                       IPCB(iter.frag)->opt.optlen =
+                                               IPCB(skb)->opt.optlen;
+                                       ip_options_fragment(iter.frag);
+                                       ip_send_check(iter.iph);
+                               }
                        }
 
                        skb->tstamp = tstamp;
@@ -975,7 +991,7 @@ static int __ip_append_data(struct sock *sk,
 
        if (cork->tx_flags & SKBTX_ANY_SW_TSTAMP &&
            sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)
-               tskey = sk->sk_tskey++;
+               tskey = atomic_inc_return(&sk->sk_tskey) - 1;
 
        hh_len = LL_RESERVED_SPACE(rt->dst.dev);
 
index 0727461..29bbe2b 100644 (file)
@@ -256,7 +256,9 @@ static int __net_init ipmr_rules_init(struct net *net)
        return 0;
 
 err2:
+       rtnl_lock();
        ipmr_free_table(mrt);
+       rtnl_unlock();
 err1:
        fib_rules_unregister(ops);
        return err;
index 67087f9..aab3841 100644 (file)
@@ -58,10 +58,6 @@ config NF_TABLES_ARP
 
 endif # NF_TABLES
 
-config NF_FLOW_TABLE_IPV4
-       tristate
-       select NF_FLOW_TABLE_INET
-
 config NF_DUP_IPV4
        tristate "Netfilter IPv4 packet duplication to alternate destination"
        depends on !NF_CONNTRACK || NF_CONNTRACK
index 0e56df3..3ee9475 100644 (file)
@@ -172,16 +172,22 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
        struct sock *sk = NULL;
        struct inet_sock *isk;
        struct hlist_nulls_node *hnode;
-       int dif = skb->dev->ifindex;
+       int dif, sdif;
 
        if (skb->protocol == htons(ETH_P_IP)) {
+               dif = inet_iif(skb);
+               sdif = inet_sdif(skb);
                pr_debug("try to find: num = %d, daddr = %pI4, dif = %d\n",
                         (int)ident, &ip_hdr(skb)->daddr, dif);
 #if IS_ENABLED(CONFIG_IPV6)
        } else if (skb->protocol == htons(ETH_P_IPV6)) {
+               dif = inet6_iif(skb);
+               sdif = inet6_sdif(skb);
                pr_debug("try to find: num = %d, daddr = %pI6c, dif = %d\n",
                         (int)ident, &ipv6_hdr(skb)->daddr, dif);
 #endif
+       } else {
+               return NULL;
        }
 
        read_lock_bh(&ping_table.lock);
@@ -220,7 +226,8 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
                        continue;
                }
 
-               if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)
+               if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif &&
+                   sk->sk_bound_dev_if != sdif)
                        continue;
 
                sock_hold(sk);
index 9eb5fc2..9f97b9c 100644 (file)
@@ -722,6 +722,7 @@ static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        int ret = -EINVAL;
        int chk_addr_ret;
 
+       lock_sock(sk);
        if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in))
                goto out;
 
@@ -741,7 +742,9 @@ static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                inet->inet_saddr = 0;  /* Use device */
        sk_dst_reset(sk);
        ret = 0;
-out:   return ret;
+out:
+       release_sock(sk);
+       return ret;
 }
 
 /*
index ff6f91c..f33ad1f 100644 (file)
@@ -3395,8 +3395,8 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
                                    fa->fa_tos == fri.tos &&
                                    fa->fa_info == res.fi &&
                                    fa->fa_type == fri.type) {
-                                       fri.offload = fa->offload;
-                                       fri.trap = fa->trap;
+                                       fri.offload = READ_ONCE(fa->offload);
+                                       fri.trap = READ_ONCE(fa->trap);
                                        break;
                                }
                        }
index 3b75836..02cb275 100644 (file)
@@ -842,6 +842,7 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos,
        }
 
        release_sock(sk);
+       sk_defer_free_flush(sk);
 
        if (spliced)
                return spliced;
@@ -936,6 +937,22 @@ void tcp_remove_empty_skb(struct sock *sk)
        }
 }
 
+/* skb changing from pure zc to mixed, must charge zc */
+static int tcp_downgrade_zcopy_pure(struct sock *sk, struct sk_buff *skb)
+{
+       if (unlikely(skb_zcopy_pure(skb))) {
+               u32 extra = skb->truesize -
+                           SKB_TRUESIZE(skb_end_offset(skb));
+
+               if (!sk_wmem_schedule(sk, extra))
+                       return -ENOMEM;
+
+               sk_mem_charge(sk, extra);
+               skb_shinfo(skb)->flags &= ~SKBFL_PURE_ZEROCOPY;
+       }
+       return 0;
+}
+
 static struct sk_buff *tcp_build_frag(struct sock *sk, int size_goal, int flags,
                                      struct page *page, int offset, size_t *size)
 {
@@ -971,7 +988,7 @@ new_segment:
                tcp_mark_push(tp, skb);
                goto new_segment;
        }
-       if (!sk_wmem_schedule(sk, copy))
+       if (tcp_downgrade_zcopy_pure(sk, skb) || !sk_wmem_schedule(sk, copy))
                return NULL;
 
        if (can_coalesce) {
@@ -1319,16 +1336,8 @@ new_segment:
 
                        copy = min_t(int, copy, pfrag->size - pfrag->offset);
 
-                       /* skb changing from pure zc to mixed, must charge zc */
-                       if (unlikely(skb_zcopy_pure(skb))) {
-                               if (!sk_wmem_schedule(sk, skb->data_len))
-                                       goto wait_for_space;
-
-                               sk_mem_charge(sk, skb->data_len);
-                               skb_shinfo(skb)->flags &= ~SKBFL_PURE_ZEROCOPY;
-                       }
-
-                       if (!sk_wmem_schedule(sk, copy))
+                       if (tcp_downgrade_zcopy_pure(sk, skb) ||
+                           !sk_wmem_schedule(sk, copy))
                                goto wait_for_space;
 
                        err = skb_copy_to_page_nocache(sk, &msg->msg_iter, skb,
index dc49a3d..bfe4112 100644 (file)
@@ -1660,6 +1660,8 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,
            (mss != tcp_skb_seglen(skb)))
                goto out;
 
+       if (!tcp_skb_can_collapse(prev, skb))
+               goto out;
        len = skb->len;
        pcount = tcp_skb_pcount(skb);
        if (tcp_skb_shift(prev, skb, pcount, len))
index b53476e..fec656f 100644 (file)
@@ -2095,7 +2095,7 @@ process:
        nf_reset_ct(skb);
 
        if (tcp_filter(sk, skb)) {
-               drop_reason = SKB_DROP_REASON_TCP_FILTER;
+               drop_reason = SKB_DROP_REASON_SOCKET_FILTER;
                goto discard_and_relse;
        }
        th = (const struct tcphdr *)skb->data;
index b910035..bc3a043 100644 (file)
@@ -846,7 +846,7 @@ udp_tunnel_nic_unregister(struct net_device *dev, struct udp_tunnel_nic *utn)
                list_for_each_entry(node, &info->shared->devices, list)
                        if (node->dev == dev)
                                break;
-               if (node->dev != dev)
+               if (list_entry_is_head(node, &info->shared->devices, list))
                        return;
 
                list_del(&node->list);
index 3eee177..6c8ab3e 100644 (file)
@@ -1839,8 +1839,8 @@ out:
 }
 EXPORT_SYMBOL(ipv6_dev_get_saddr);
 
-int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr,
-                     u32 banned_flags)
+static int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr,
+                             u32 banned_flags)
 {
        struct inet6_ifaddr *ifp;
        int err = -EADDRNOTAVAIL;
@@ -2589,7 +2589,7 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
                                 __u32 valid_lft, u32 prefered_lft)
 {
        struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);
-       int create = 0;
+       int create = 0, update_lft = 0;
 
        if (!ifp && valid_lft) {
                int max_addresses = in6_dev->cnf.max_addresses;
@@ -2633,19 +2633,32 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
                unsigned long now;
                u32 stored_lft;
 
-               /* Update lifetime (RFC4862 5.5.3 e)
-                * We deviate from RFC4862 by honoring all Valid Lifetimes to
-                * improve the reaction of SLAAC to renumbering events
-                * (draft-gont-6man-slaac-renum-06, Section 4.2)
-                */
+               /* update lifetime (RFC2462 5.5.3 e) */
                spin_lock_bh(&ifp->lock);
                now = jiffies;
                if (ifp->valid_lft > (now - ifp->tstamp) / HZ)
                        stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ;
                else
                        stored_lft = 0;
-
                if (!create && stored_lft) {
+                       const u32 minimum_lft = min_t(u32,
+                               stored_lft, MIN_VALID_LIFETIME);
+                       valid_lft = max(valid_lft, minimum_lft);
+
+                       /* RFC4862 Section 5.5.3e:
+                        * "Note that the preferred lifetime of the
+                        *  corresponding address is always reset to
+                        *  the Preferred Lifetime in the received
+                        *  Prefix Information option, regardless of
+                        *  whether the valid lifetime is also reset or
+                        *  ignored."
+                        *
+                        * So we should always update prefered_lft here.
+                        */
+                       update_lft = 1;
+               }
+
+               if (update_lft) {
                        ifp->valid_lft = valid_lft;
                        ifp->prefered_lft = prefered_lft;
                        ifp->tstamp = now;
@@ -4985,6 +4998,7 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
            nla_put_s32(skb, IFA_TARGET_NETNSID, args->netnsid))
                goto error;
 
+       spin_lock_bh(&ifa->lock);
        if (!((ifa->flags&IFA_F_PERMANENT) &&
              (ifa->prefered_lft == INFINITY_LIFE_TIME))) {
                preferred = ifa->prefered_lft;
@@ -5006,6 +5020,7 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
                preferred = INFINITY_LIFE_TIME;
                valid = INFINITY_LIFE_TIME;
        }
+       spin_unlock_bh(&ifa->lock);
 
        if (!ipv6_addr_any(&ifa->peer_addr)) {
                if (nla_put_in6_addr(skb, IFA_LOCAL, &ifa->addr) < 0 ||
index 463c37d..413f667 100644 (file)
@@ -112,7 +112,7 @@ void fib6_update_sernum(struct net *net, struct fib6_info *f6i)
        fn = rcu_dereference_protected(f6i->fib6_node,
                        lockdep_is_held(&f6i->fib6_table->tb6_lock));
        if (fn)
-               fn->fn_sernum = fib6_new_sernum(net);
+               WRITE_ONCE(fn->fn_sernum, fib6_new_sernum(net));
 }
 
 /*
@@ -590,12 +590,13 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
                spin_unlock_bh(&table->tb6_lock);
                if (res > 0) {
                        cb->args[4] = 1;
-                       cb->args[5] = w->root->fn_sernum;
+                       cb->args[5] = READ_ONCE(w->root->fn_sernum);
                }
        } else {
-               if (cb->args[5] != w->root->fn_sernum) {
+               int sernum = READ_ONCE(w->root->fn_sernum);
+               if (cb->args[5] != sernum) {
                        /* Begin at the root if the tree changed */
-                       cb->args[5] = w->root->fn_sernum;
+                       cb->args[5] = sernum;
                        w->state = FWS_INIT;
                        w->node = w->root;
                        w->skip = w->count;
@@ -1345,7 +1346,7 @@ static void __fib6_update_sernum_upto_root(struct fib6_info *rt,
        /* paired with smp_rmb() in fib6_get_cookie_safe() */
        smp_wmb();
        while (fn) {
-               fn->fn_sernum = sernum;
+               WRITE_ONCE(fn->fn_sernum, sernum);
                fn = rcu_dereference_protected(fn->parent,
                                lockdep_is_held(&rt->fib6_table->tb6_lock));
        }
@@ -2174,8 +2175,8 @@ static int fib6_clean_node(struct fib6_walker *w)
        };
 
        if (c->sernum != FIB6_NO_SERNUM_CHANGE &&
-           w->node->fn_sernum != c->sernum)
-               w->node->fn_sernum = c->sernum;
+           READ_ONCE(w->node->fn_sernum) != c->sernum)
+               WRITE_ONCE(w->node->fn_sernum, c->sernum);
 
        if (!c->func) {
                WARN_ON_ONCE(c->sernum == FIB6_NO_SERNUM_CHANGE);
@@ -2543,7 +2544,7 @@ static void ipv6_route_seq_setup_walk(struct ipv6_route_iter *iter,
        iter->w.state = FWS_INIT;
        iter->w.node = iter->w.root;
        iter->w.args = iter;
-       iter->sernum = iter->w.root->fn_sernum;
+       iter->sernum = READ_ONCE(iter->w.root->fn_sernum);
        INIT_LIST_HEAD(&iter->w.lh);
        fib6_walker_link(net, &iter->w);
 }
@@ -2571,8 +2572,10 @@ static struct fib6_table *ipv6_route_seq_next_table(struct fib6_table *tbl,
 
 static void ipv6_route_check_sernum(struct ipv6_route_iter *iter)
 {
-       if (iter->sernum != iter->w.root->fn_sernum) {
-               iter->sernum = iter->w.root->fn_sernum;
+       int sernum = READ_ONCE(iter->w.root->fn_sernum);
+
+       if (iter->sernum != sernum) {
+               iter->sernum = sernum;
                iter->w.state = FWS_INIT;
                iter->w.node = iter->w.root;
                WARN_ON(iter->w.skip);
index aa673a6..ceb85c6 100644 (file)
@@ -450,8 +450,10 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
                err = -EINVAL;
                goto done;
        }
-       if (fl_shared_exclusive(fl) || fl->opt)
+       if (fl_shared_exclusive(fl) || fl->opt) {
+               WRITE_ONCE(sock_net(sk)->ipv6.flowlabel_has_excl, 1);
                static_branch_deferred_inc(&ipv6_flowlabel_exclusive);
+       }
        return fl;
 
 done:
index b29e9ba..5f577e2 100644 (file)
@@ -114,6 +114,8 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
        if (likely(ops && ops->callbacks.gso_segment)) {
                skb_reset_transport_header(skb);
                segs = ops->callbacks.gso_segment(skb, features);
+               if (!segs)
+                       skb->network_header = skb_mac_header(skb) + nhoff - skb->head;
        }
 
        if (IS_ERR_OR_NULL(segs))
index 2995f8d..304a295 100644 (file)
@@ -1465,7 +1465,7 @@ static int __ip6_append_data(struct sock *sk,
 
        if (cork->tx_flags & SKBTX_ANY_SW_TSTAMP &&
            sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)
-               tskey = sk->sk_tskey++;
+               tskey = atomic_inc_return(&sk->sk_tskey) - 1;
 
        hh_len = LL_RESERVED_SPACE(rt->dst.dev);
 
index fe786df..97ade83 100644 (file)
@@ -1036,14 +1036,14 @@ int ip6_tnl_xmit_ctl(struct ip6_tnl *t,
 
                if (unlikely(!ipv6_chk_addr_and_flags(net, laddr, ldev, false,
                                                      0, IFA_F_TENTATIVE)))
-                       pr_warn("%s xmit: Local address not yet configured!\n",
-                               p->name);
+                       pr_warn_ratelimited("%s xmit: Local address not yet configured!\n",
+                                           p->name);
                else if (!(p->flags & IP6_TNL_F_ALLOW_LOCAL_REMOTE) &&
                         !ipv6_addr_is_multicast(raddr) &&
                         unlikely(ipv6_chk_addr_and_flags(net, raddr, ldev,
                                                          true, 0, IFA_F_TENTATIVE)))
-                       pr_warn("%s xmit: Routing loop! Remote address found on this node!\n",
-                               p->name);
+                       pr_warn_ratelimited("%s xmit: Routing loop! Remote address found on this node!\n",
+                                           p->name);
                else
                        ret = 1;
                rcu_read_unlock();
index 7cf73e6..8a2db92 100644 (file)
@@ -243,7 +243,9 @@ static int __net_init ip6mr_rules_init(struct net *net)
        return 0;
 
 err2:
+       rtnl_lock();
        ip6mr_free_table(mrt);
+       rtnl_unlock();
 err1:
        fib_rules_unregister(ops);
        return err;
index bed8155..a8861db 100644 (file)
@@ -1759,7 +1759,7 @@ static struct sk_buff *mld_newpack(struct inet6_dev *idev, unsigned int mtu)
        skb_reserve(skb, hlen);
        skb_tailroom_reserve(skb, mtu, tlen);
 
-       if (__ipv6_get_lladdr(idev, &addr_buf, IFA_F_TENTATIVE)) {
+       if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) {
                /* <draft-ietf-magma-mld-source-05.txt>:
                 * use unspecified address as the source address
                 * when a valid link-local address is not available.
index 97d3d1b..0ba62f4 100644 (file)
@@ -47,10 +47,6 @@ config NFT_FIB_IPV6
 endif # NF_TABLES_IPV6
 endif # NF_TABLES
 
-config NF_FLOW_TABLE_IPV6
-       tristate
-       select NF_FLOW_TABLE_INET
-
 config NF_DUP_IPV6
        tristate "Netfilter IPv6 packet duplication to alternate destination"
        depends on !NF_CONNTRACK || NF_CONNTRACK
index b853836..b8d6dc9 100644 (file)
@@ -28,9 +28,6 @@ obj-$(CONFIG_NFT_REJECT_IPV6) += nft_reject_ipv6.o
 obj-$(CONFIG_NFT_DUP_IPV6) += nft_dup_ipv6.o
 obj-$(CONFIG_NFT_FIB_IPV6) += nft_fib_ipv6.o
 
-# flow table support
-obj-$(CONFIG_NF_FLOW_TABLE_IPV6) += nf_flow_table_ipv6.o
-
 # matches
 obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
 obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
diff --git a/net/ipv6/netfilter/nf_flow_table_ipv6.c b/net/ipv6/netfilter/nf_flow_table_ipv6.c
deleted file mode 100644 (file)
index e69de29..0000000
index e6de942..ea1cf41 100644 (file)
@@ -2802,7 +2802,7 @@ static void ip6_link_failure(struct sk_buff *skb)
                        if (from) {
                                fn = rcu_dereference(from->fib6_node);
                                if (fn && (rt->rt6i_flags & RTF_DEFAULT))
-                                       fn->fn_sernum = -1;
+                                       WRITE_ONCE(fn->fn_sernum, -1);
                        }
                }
                rcu_read_unlock();
@@ -5753,11 +5753,11 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
        }
 
        if (!dst) {
-               if (rt->offload)
+               if (READ_ONCE(rt->offload))
                        rtm->rtm_flags |= RTM_F_OFFLOAD;
-               if (rt->trap)
+               if (READ_ONCE(rt->trap))
                        rtm->rtm_flags |= RTM_F_TRAP;
-               if (rt->offload_failed)
+               if (READ_ONCE(rt->offload_failed))
                        rtm->rtm_flags |= RTM_F_OFFLOAD_FAILED;
        }
 
@@ -6215,19 +6215,20 @@ void fib6_info_hw_flags_set(struct net *net, struct fib6_info *f6i,
        struct sk_buff *skb;
        int err;
 
-       if (f6i->offload == offload && f6i->trap == trap &&
-           f6i->offload_failed == offload_failed)
+       if (READ_ONCE(f6i->offload) == offload &&
+           READ_ONCE(f6i->trap) == trap &&
+           READ_ONCE(f6i->offload_failed) == offload_failed)
                return;
 
-       f6i->offload = offload;
-       f6i->trap = trap;
+       WRITE_ONCE(f6i->offload, offload);
+       WRITE_ONCE(f6i->trap, trap);
 
        /* 2 means send notifications only if offload_failed was changed. */
        if (net->ipv6.sysctl.fib_notify_on_flag_change == 2 &&
-           f6i->offload_failed == offload_failed)
+           READ_ONCE(f6i->offload_failed) == offload_failed)
                return;
 
-       f6i->offload_failed = offload_failed;
+       WRITE_ONCE(f6i->offload_failed, offload_failed);
 
        if (!rcu_access_pointer(f6i->fib6_node))
                /* The route was removed from the tree, do not send
index 1eeabdf..e5ccf17 100644 (file)
@@ -666,7 +666,7 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
        ieee80211_ie_build_he_6ghz_cap(sdata, skb);
 }
 
-static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
+static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -686,6 +686,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif);
        const struct ieee80211_sband_iftype_data *iftd;
        struct ieee80211_prep_tx_info info = {};
+       int ret;
 
        /* we know it's writable, cast away the const */
        if (assoc_data->ie_len)
@@ -699,7 +700,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
        if (WARN_ON(!chanctx_conf)) {
                rcu_read_unlock();
-               return;
+               return -EINVAL;
        }
        chan = chanctx_conf->def.chan;
        rcu_read_unlock();
@@ -750,7 +751,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                        (iftd ? iftd->vendor_elems.len : 0),
                        GFP_KERNEL);
        if (!skb)
-               return;
+               return -ENOMEM;
 
        skb_reserve(skb, local->hw.extra_tx_headroom);
 
@@ -1031,15 +1032,22 @@ skip_rates:
                skb_put_data(skb, assoc_data->ie + offset, noffset - offset);
        }
 
-       if (assoc_data->fils_kek_len &&
-           fils_encrypt_assoc_req(skb, assoc_data) < 0) {
-               dev_kfree_skb(skb);
-               return;
+       if (assoc_data->fils_kek_len) {
+               ret = fils_encrypt_assoc_req(skb, assoc_data);
+               if (ret < 0) {
+                       dev_kfree_skb(skb);
+                       return ret;
+               }
        }
 
        pos = skb_tail_pointer(skb);
        kfree(ifmgd->assoc_req_ies);
        ifmgd->assoc_req_ies = kmemdup(ie_start, pos - ie_start, GFP_ATOMIC);
+       if (!ifmgd->assoc_req_ies) {
+               dev_kfree_skb(skb);
+               return -ENOMEM;
+       }
+
        ifmgd->assoc_req_ies_len = pos - ie_start;
 
        drv_mgd_prepare_tx(local, sdata, &info);
@@ -1049,6 +1057,8 @@ skip_rates:
                IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS |
                                                IEEE80211_TX_INTFL_MLME_CONN_TX;
        ieee80211_tx_skb(sdata, skb);
+
+       return 0;
 }
 
 void ieee80211_send_pspoll(struct ieee80211_local *local,
@@ -4497,6 +4507,7 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data;
        struct ieee80211_local *local = sdata->local;
+       int ret;
 
        sdata_assert_lock(sdata);
 
@@ -4517,7 +4528,9 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
        sdata_info(sdata, "associate with %pM (try %d/%d)\n",
                   assoc_data->bss->bssid, assoc_data->tries,
                   IEEE80211_ASSOC_MAX_TRIES);
-       ieee80211_send_assoc(sdata);
+       ret = ieee80211_send_assoc(sdata);
+       if (ret)
+               return ret;
 
        if (!ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
                assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
index 8d9f4ff..e52cef7 100644 (file)
@@ -412,13 +412,14 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
                         * this function.
                         */
                        rc = mctp_key_add(key, msk);
-                       if (rc)
+                       if (rc) {
                                kfree(key);
+                       } else {
+                               trace_mctp_key_acquire(key);
 
-                       trace_mctp_key_acquire(key);
-
-                       /* we don't need to release key->lock on exit */
-                       mctp_key_unref(key);
+                               /* we don't need to release key->lock on exit */
+                               mctp_key_unref(key);
+                       }
                        key = NULL;
 
                } else {
index 48f75a5..d6fdc57 100644 (file)
@@ -1607,6 +1607,7 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
        struct mpls_dev *mdev;
        unsigned int flags;
+       int err;
 
        if (event == NETDEV_REGISTER) {
                mdev = mpls_add_dev(dev);
@@ -1621,7 +1622,6 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
                return NOTIFY_OK;
 
        switch (event) {
-               int err;
 
        case NETDEV_DOWN:
                err = mpls_ifdown(dev, event);
index 3240b72..7558802 100644 (file)
@@ -35,12 +35,14 @@ static const struct snmp_mib mptcp_snmp_list[] = {
        SNMP_MIB_ITEM("AddAddr", MPTCP_MIB_ADDADDR),
        SNMP_MIB_ITEM("EchoAdd", MPTCP_MIB_ECHOADD),
        SNMP_MIB_ITEM("PortAdd", MPTCP_MIB_PORTADD),
+       SNMP_MIB_ITEM("AddAddrDrop", MPTCP_MIB_ADDADDRDROP),
        SNMP_MIB_ITEM("MPJoinPortSynRx", MPTCP_MIB_JOINPORTSYNRX),
        SNMP_MIB_ITEM("MPJoinPortSynAckRx", MPTCP_MIB_JOINPORTSYNACKRX),
        SNMP_MIB_ITEM("MPJoinPortAckRx", MPTCP_MIB_JOINPORTACKRX),
        SNMP_MIB_ITEM("MismatchPortSynRx", MPTCP_MIB_MISMATCHPORTSYNRX),
        SNMP_MIB_ITEM("MismatchPortAckRx", MPTCP_MIB_MISMATCHPORTACKRX),
        SNMP_MIB_ITEM("RmAddr", MPTCP_MIB_RMADDR),
+       SNMP_MIB_ITEM("RmAddrDrop", MPTCP_MIB_RMADDRDROP),
        SNMP_MIB_ITEM("RmSubflow", MPTCP_MIB_RMSUBFLOW),
        SNMP_MIB_ITEM("MPPrioTx", MPTCP_MIB_MPPRIOTX),
        SNMP_MIB_ITEM("MPPrioRx", MPTCP_MIB_MPPRIORX),
index ecd3d8b..2966fcb 100644 (file)
@@ -28,12 +28,14 @@ enum linux_mptcp_mib_field {
        MPTCP_MIB_ADDADDR,              /* Received ADD_ADDR with echo-flag=0 */
        MPTCP_MIB_ECHOADD,              /* Received ADD_ADDR with echo-flag=1 */
        MPTCP_MIB_PORTADD,              /* Received ADD_ADDR with a port-number */
+       MPTCP_MIB_ADDADDRDROP,          /* Dropped incoming ADD_ADDR */
        MPTCP_MIB_JOINPORTSYNRX,        /* Received a SYN MP_JOIN with a different port-number */
        MPTCP_MIB_JOINPORTSYNACKRX,     /* Received a SYNACK MP_JOIN with a different port-number */
        MPTCP_MIB_JOINPORTACKRX,        /* Received an ACK MP_JOIN with a different port-number */
        MPTCP_MIB_MISMATCHPORTSYNRX,    /* Received a SYN MP_JOIN with a mismatched port-number */
        MPTCP_MIB_MISMATCHPORTACKRX,    /* Received an ACK MP_JOIN with a mismatched port-number */
        MPTCP_MIB_RMADDR,               /* Received RM_ADDR */
+       MPTCP_MIB_RMADDRDROP,           /* Dropped incoming RM_ADDR */
        MPTCP_MIB_RMSUBFLOW,            /* Remove a subflow */
        MPTCP_MIB_MPPRIOTX,             /* Transmit a MP_PRIO */
        MPTCP_MIB_MPPRIORX,             /* Received a MP_PRIO */
index 696b2c4..7bea318 100644 (file)
@@ -213,6 +213,8 @@ void mptcp_pm_add_addr_received(struct mptcp_sock *msk,
                mptcp_pm_add_addr_send_ack(msk);
        } else if (mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_RECEIVED)) {
                pm->remote = *addr;
+       } else {
+               __MPTCP_INC_STATS(sock_net((struct sock *)msk), MPTCP_MIB_ADDADDRDROP);
        }
 
        spin_unlock_bh(&pm->lock);
@@ -253,8 +255,10 @@ void mptcp_pm_rm_addr_received(struct mptcp_sock *msk,
                mptcp_event_addr_removed(msk, rm_list->ids[i]);
 
        spin_lock_bh(&pm->lock);
-       mptcp_pm_schedule_work(msk, MPTCP_PM_RM_ADDR_RECEIVED);
-       pm->rm_list_rx = *rm_list;
+       if (mptcp_pm_schedule_work(msk, MPTCP_PM_RM_ADDR_RECEIVED))
+               pm->rm_list_rx = *rm_list;
+       else
+               __MPTCP_INC_STATS(sock_net((struct sock *)msk), MPTCP_MIB_RMADDRDROP);
        spin_unlock_bh(&pm->lock);
 }
 
index 75af1f7..4b5d795 100644 (file)
@@ -478,6 +478,20 @@ __lookup_addr_by_id(struct pm_nl_pernet *pernet, unsigned int id)
        return NULL;
 }
 
+static struct mptcp_pm_addr_entry *
+__lookup_addr(struct pm_nl_pernet *pernet, const struct mptcp_addr_info *info,
+             bool lookup_by_id)
+{
+       struct mptcp_pm_addr_entry *entry;
+
+       list_for_each_entry(entry, &pernet->local_addr_list, list) {
+               if ((!lookup_by_id && addresses_equal(&entry->addr, info, true)) ||
+                   (lookup_by_id && entry->addr.id == info->id))
+                       return entry;
+       }
+       return NULL;
+}
+
 static int
 lookup_id_by_addr(struct pm_nl_pernet *pernet, const struct mptcp_addr_info *addr)
 {
@@ -532,6 +546,16 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
        if (msk->pm.add_addr_signaled < add_addr_signal_max) {
                local = select_signal_address(pernet, msk);
 
+               /* due to racing events on both ends we can reach here while
+                * previous add address is still running: if we invoke now
+                * mptcp_pm_announce_addr(), that will fail and the
+                * corresponding id will be marked as used.
+                * Instead let the PM machinery reschedule us when the
+                * current address announce will be completed.
+                */
+               if (msk->pm.addr_signal & BIT(MPTCP_ADD_ADDR_SIGNAL))
+                       return;
+
                if (local) {
                        if (mptcp_pm_alloc_anno_list(msk, local)) {
                                __clear_bit(local->addr.id, msk->pm.id_avail_bitmap);
@@ -636,6 +660,7 @@ static void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk)
        unsigned int add_addr_accept_max;
        struct mptcp_addr_info remote;
        unsigned int subflows_max;
+       bool reset_port = false;
        int i, nr;
 
        add_addr_accept_max = mptcp_pm_get_add_addr_accept_max(msk);
@@ -645,15 +670,19 @@ static void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk)
                 msk->pm.add_addr_accepted, add_addr_accept_max,
                 msk->pm.remote.family);
 
-       if (lookup_subflow_by_daddr(&msk->conn_list, &msk->pm.remote))
+       remote = msk->pm.remote;
+       if (lookup_subflow_by_daddr(&msk->conn_list, &remote))
                goto add_addr_echo;
 
+       /* pick id 0 port, if none is provided the remote address */
+       if (!remote.port) {
+               reset_port = true;
+               remote.port = sk->sk_dport;
+       }
+
        /* connect to the specified remote address, using whatever
         * local address the routing configuration will pick.
         */
-       remote = msk->pm.remote;
-       if (!remote.port)
-               remote.port = sk->sk_dport;
        nr = fill_local_addresses_vec(msk, addrs);
 
        msk->pm.add_addr_accepted++;
@@ -666,8 +695,12 @@ static void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk)
                __mptcp_subflow_connect(sk, &addrs[i], &remote);
        spin_lock_bh(&msk->pm.lock);
 
+       /* be sure to echo exactly the received address */
+       if (reset_port)
+               remote.port = 0;
+
 add_addr_echo:
-       mptcp_pm_announce_addr(msk, &msk->pm.remote, true);
+       mptcp_pm_announce_addr(msk, &remote, true);
        mptcp_pm_nl_addr_send_ack(msk);
 }
 
@@ -777,7 +810,7 @@ static void mptcp_pm_nl_rm_addr_or_subflow(struct mptcp_sock *msk,
                        removed = true;
                        __MPTCP_INC_STATS(sock_net(sk), rm_type);
                }
-               __set_bit(rm_list->ids[1], msk->pm.id_avail_bitmap);
+               __set_bit(rm_list->ids[i], msk->pm.id_avail_bitmap);
                if (!removed)
                        continue;
 
@@ -911,6 +944,7 @@ out:
 static int mptcp_pm_nl_create_listen_socket(struct sock *sk,
                                            struct mptcp_pm_addr_entry *entry)
 {
+       int addrlen = sizeof(struct sockaddr_in);
        struct sockaddr_storage addr;
        struct mptcp_sock *msk;
        struct socket *ssock;
@@ -935,8 +969,11 @@ static int mptcp_pm_nl_create_listen_socket(struct sock *sk,
        }
 
        mptcp_info2sockaddr(&entry->addr, &addr, entry->addr.family);
-       err = kernel_bind(ssock, (struct sockaddr *)&addr,
-                         sizeof(struct sockaddr_in));
+#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+       if (entry->addr.family == AF_INET6)
+               addrlen = sizeof(struct sockaddr_in6);
+#endif
+       err = kernel_bind(ssock, (struct sockaddr *)&addr, addrlen);
        if (err) {
                pr_warn("kernel_bind error, err=%d", err);
                goto out;
@@ -1763,18 +1800,21 @@ static int mptcp_nl_cmd_set_flags(struct sk_buff *skb, struct genl_info *info)
                        return -EOPNOTSUPP;
        }
 
-       list_for_each_entry(entry, &pernet->local_addr_list, list) {
-               if ((!lookup_by_id && addresses_equal(&entry->addr, &addr.addr, true)) ||
-                   (lookup_by_id && entry->addr.id == addr.addr.id)) {
-                       mptcp_nl_addr_backup(net, &entry->addr, bkup);
-
-                       if (bkup)
-                               entry->flags |= MPTCP_PM_ADDR_FLAG_BACKUP;
-                       else
-                               entry->flags &= ~MPTCP_PM_ADDR_FLAG_BACKUP;
-               }
+       spin_lock_bh(&pernet->lock);
+       entry = __lookup_addr(pernet, &addr.addr, lookup_by_id);
+       if (!entry) {
+               spin_unlock_bh(&pernet->lock);
+               return -EINVAL;
        }
 
+       if (bkup)
+               entry->flags |= MPTCP_PM_ADDR_FLAG_BACKUP;
+       else
+               entry->flags &= ~MPTCP_PM_ADDR_FLAG_BACKUP;
+       addr = *entry;
+       spin_unlock_bh(&pernet->lock);
+
+       mptcp_nl_addr_backup(net, &addr.addr, bkup);
        return 0;
 }
 
index 0e6b42c..85317ce 100644 (file)
@@ -408,7 +408,7 @@ DECLARE_PER_CPU(struct mptcp_delegated_action, mptcp_delegated_actions);
 struct mptcp_subflow_context {
        struct  list_head node;/* conn_list of subflows */
 
-       char    reset_start[0];
+       struct_group(reset,
 
        unsigned long avg_pacing_rate; /* protected by msk socket lock */
        u64     local_key;
@@ -458,7 +458,7 @@ struct mptcp_subflow_context {
 
        long    delegated_status;
 
-       char    reset_end[0];
+       );
 
        struct  list_head delegated_node;   /* link into delegated_action, protected by local BH */
 
@@ -494,7 +494,7 @@ mptcp_subflow_tcp_sock(const struct mptcp_subflow_context *subflow)
 static inline void
 mptcp_subflow_ctx_reset(struct mptcp_subflow_context *subflow)
 {
-       memset(subflow->reset_start, 0, subflow->reset_end - subflow->reset_start);
+       memset(&subflow->reset, 0, sizeof(subflow->reset));
        subflow->request_mptcp = 1;
 }
 
index 894a325..d6aa5b4 100644 (file)
@@ -1924,15 +1924,17 @@ repeat:
                pr_debug("nf_conntrack_in: Can't track with proto module\n");
                nf_ct_put(ct);
                skb->_nfct = 0;
-               NF_CT_STAT_INC_ATOMIC(state->net, invalid);
-               if (ret == -NF_DROP)
-                       NF_CT_STAT_INC_ATOMIC(state->net, drop);
                /* Special case: TCP tracker reports an attempt to reopen a
                 * closed/aborted connection. We have to go back and create a
                 * fresh conntrack.
                 */
                if (ret == -NF_REPEAT)
                        goto repeat;
+
+               NF_CT_STAT_INC_ATOMIC(state->net, invalid);
+               if (ret == -NF_DROP)
+                       NF_CT_STAT_INC_ATOMIC(state->net, drop);
+
                ret = -ret;
                goto out;
        }
index 7f19ee2..55415f0 100644 (file)
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_expect.h>
 
+#define HELPER_NAME    "netbios-ns"
 #define NMBD_PORT      137
 
 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
 MODULE_DESCRIPTION("NetBIOS name service broadcast connection tracking helper");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("ip_conntrack_netbios_ns");
-MODULE_ALIAS_NFCT_HELPER("netbios_ns");
+MODULE_ALIAS_NFCT_HELPER(HELPER_NAME);
 
 static unsigned int timeout __read_mostly = 3;
 module_param(timeout, uint, 0400);
@@ -44,7 +45,7 @@ static int netbios_ns_help(struct sk_buff *skb, unsigned int protoff,
 }
 
 static struct nf_conntrack_helper helper __read_mostly = {
-       .name                   = "netbios-ns",
+       .name                   = HELPER_NAME,
        .tuple.src.l3num        = NFPROTO_IPV4,
        .tuple.src.u.udp.port   = cpu_to_be16(NMBD_PORT),
        .tuple.dst.protonum     = IPPROTO_UDP,
index ac43837..7032402 100644 (file)
@@ -2311,7 +2311,8 @@ ctnetlink_create_conntrack(struct net *net,
                        if (helper->from_nlattr)
                                helper->from_nlattr(helpinfo, ct);
 
-                       /* not in hash table yet so not strictly necessary */
+                       /* disable helper auto-assignment for this entry */
+                       ct->status |= IPS_HELPER;
                        RCU_INIT_POINTER(help->helper, helper);
                }
        } else {
index 2394238..5a93633 100644 (file)
@@ -489,6 +489,15 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
                        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
+                        * port reuse by client or NAT middlebox cannot
+                        * keep entry alive indefinitely (incl. nat info).
+                        */
+                       if (new_state == SCTP_CONNTRACK_CLOSED &&
+                           old_state == SCTP_CONNTRACK_CLOSED &&
+                           nf_ct_is_confirmed(ct))
+                               ignore = true;
                }
 
                ct->proto.sctp.state = new_state;
index af5115e..d1582b8 100644 (file)
@@ -446,6 +446,32 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
        }
 }
 
+static void tcp_init_sender(struct ip_ct_tcp_state *sender,
+                           struct ip_ct_tcp_state *receiver,
+                           const struct sk_buff *skb,
+                           unsigned int dataoff,
+                           const struct tcphdr *tcph,
+                           u32 end, u32 win)
+{
+       /* SYN-ACK in reply to a SYN
+        * or SYN from reply direction in simultaneous open.
+        */
+       sender->td_end =
+       sender->td_maxend = end;
+       sender->td_maxwin = (win == 0 ? 1 : win);
+
+       tcp_options(skb, dataoff, tcph, sender);
+       /* RFC 1323:
+        * Both sides must send the Window Scale option
+        * to enable window scaling in either direction.
+        */
+       if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE &&
+             receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE)) {
+               sender->td_scale = 0;
+               receiver->td_scale = 0;
+       }
+}
+
 static bool tcp_in_window(struct nf_conn *ct,
                          enum ip_conntrack_dir dir,
                          unsigned int index,
@@ -499,24 +525,9 @@ static bool tcp_in_window(struct nf_conn *ct,
                 * Initialize sender data.
                 */
                if (tcph->syn) {
-                       /*
-                        * SYN-ACK in reply to a SYN
-                        * or SYN from reply direction in simultaneous open.
-                        */
-                       sender->td_end =
-                       sender->td_maxend = end;
-                       sender->td_maxwin = (win == 0 ? 1 : win);
-
-                       tcp_options(skb, dataoff, tcph, sender);
-                       /*
-                        * RFC 1323:
-                        * Both sides must send the Window Scale option
-                        * to enable window scaling in either direction.
-                        */
-                       if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE
-                             && receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE))
-                               sender->td_scale =
-                               receiver->td_scale = 0;
+                       tcp_init_sender(sender, receiver,
+                                       skb, dataoff, tcph,
+                                       end, win);
                        if (!tcph->ack)
                                /* Simultaneous open */
                                return true;
@@ -560,6 +571,18 @@ static bool tcp_in_window(struct nf_conn *ct,
                sender->td_maxwin = (win == 0 ? 1 : win);
 
                tcp_options(skb, dataoff, tcph, sender);
+       } else if (tcph->syn && dir == IP_CT_DIR_REPLY &&
+                  state->state == TCP_CONNTRACK_SYN_SENT) {
+               /* Retransmitted syn-ack, or syn (simultaneous open).
+                *
+                * Re-init state for this direction, just like for the first
+                * syn(-ack) reply, it might differ in seq, ack or tcp options.
+                */
+               tcp_init_sender(sender, receiver,
+                               skb, dataoff, tcph,
+                               end, win);
+               if (!tcph->ack)
+                       return true;
        }
 
        if (!(tcph->ack)) {
index 77938b1..9cd1d7a 100644 (file)
@@ -2011,7 +2011,6 @@ static void nft_last_rule(struct nft_rule_blob *blob, const void *ptr)
 
        prule = (struct nft_rule_dp *)ptr;
        prule->is_last = 1;
-       ptr += offsetof(struct nft_rule_dp, data);
        /* blob size does not include the trailer rule */
 }
 
@@ -6552,12 +6551,15 @@ static int nf_tables_updobj(const struct nft_ctx *ctx,
 {
        struct nft_object *newobj;
        struct nft_trans *trans;
-       int err;
+       int err = -ENOMEM;
+
+       if (!try_module_get(type->owner))
+               return -ENOENT;
 
        trans = nft_trans_alloc(ctx, NFT_MSG_NEWOBJ,
                                sizeof(struct nft_trans_obj));
        if (!trans)
-               return -ENOMEM;
+               goto err_trans;
 
        newobj = nft_obj_init(ctx, type, attr);
        if (IS_ERR(newobj)) {
@@ -6574,6 +6576,8 @@ static int nf_tables_updobj(const struct nft_ctx *ctx,
 
 err_free_trans:
        kfree(trans);
+err_trans:
+       module_put(type->owner);
        return err;
 }
 
@@ -8186,7 +8190,7 @@ static void nft_obj_commit_update(struct nft_trans *trans)
        if (obj->ops->update)
                obj->ops->update(obj, newobj);
 
-       kfree(newobj);
+       nft_obj_destroy(&trans->ctx, newobj);
 }
 
 static void nft_commit_release(struct nft_trans *trans)
@@ -8264,14 +8268,12 @@ static int nf_tables_commit_chain_prepare(struct net *net, struct nft_chain *cha
        void *data, *data_boundary;
        struct nft_rule_dp *prule;
        struct nft_rule *rule;
-       int i;
 
        /* already handled or inactive chain? */
        if (chain->blob_next || !nft_is_active_next(net, chain))
                return 0;
 
        rule = list_entry(&chain->rules, struct nft_rule, list);
-       i = 0;
 
        data_size = 0;
        list_for_each_entry_continue(rule, &chain->rules, list) {
@@ -8301,7 +8303,7 @@ static int nf_tables_commit_chain_prepare(struct net *net, struct nft_chain *cha
                        return -ENOMEM;
 
                size = 0;
-               track.last = last;
+               track.last = nft_expr_last(rule);
                nft_rule_for_each_expr(expr, last, rule) {
                        track.cur = expr;
 
@@ -8979,7 +8981,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
                        break;
                case NFT_MSG_NEWOBJ:
                        if (nft_trans_obj_update(trans)) {
-                               kfree(nft_trans_obj_newobj(trans));
+                               nft_obj_destroy(&trans->ctx, nft_trans_obj_newobj(trans));
                                nft_trans_destroy(trans);
                        } else {
                                trans->ctx.table->use--;
@@ -9639,10 +9641,13 @@ EXPORT_SYMBOL_GPL(__nft_release_basechain);
 
 static void __nft_release_hook(struct net *net, struct nft_table *table)
 {
+       struct nft_flowtable *flowtable;
        struct nft_chain *chain;
 
        list_for_each_entry(chain, &table->chains, list)
                nf_tables_unregister_hook(net, table, chain);
+       list_for_each_entry(flowtable, &table->flowtables, list)
+               nft_unregister_flowtable_net_hooks(net, &flowtable->hook_list);
 }
 
 static void __nft_release_hooks(struct net *net)
index 9656c16..2d36952 100644 (file)
@@ -94,7 +94,8 @@ struct nft_flow_rule *nft_flow_rule_create(struct net *net,
 
        expr = nft_expr_first(rule);
        while (nft_expr_more(rule, expr)) {
-               if (expr->ops->offload_flags & NFT_OFFLOAD_F_ACTION)
+               if (expr->ops->offload_action &&
+                   expr->ops->offload_action(expr))
                        num_actions++;
 
                expr = nft_expr_next(expr);
index 9d5947a..e646e9e 100644 (file)
@@ -167,12 +167,24 @@ nla_put_failure:
        return -1;
 }
 
+static bool nft_byteorder_reduce(struct nft_regs_track *track,
+                                const struct nft_expr *expr)
+{
+       struct nft_byteorder *priv = nft_expr_priv(expr);
+
+       track->regs[priv->dreg].selector = NULL;
+       track->regs[priv->dreg].bitwise = NULL;
+
+       return false;
+}
+
 static const struct nft_expr_ops nft_byteorder_ops = {
        .type           = &nft_byteorder_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_byteorder)),
        .eval           = nft_byteorder_eval,
        .init           = nft_byteorder_init,
        .dump           = nft_byteorder_dump,
+       .reduce         = nft_byteorder_reduce,
 };
 
 struct nft_expr_type nft_byteorder_type __read_mostly = {
index 7d00a14..3362417 100644 (file)
@@ -62,6 +62,7 @@ static int nft_connlimit_do_init(const struct nft_ctx *ctx,
 {
        bool invert = false;
        u32 flags, limit;
+       int err;
 
        if (!tb[NFTA_CONNLIMIT_COUNT])
                return -EINVAL;
@@ -84,7 +85,15 @@ static int nft_connlimit_do_init(const struct nft_ctx *ctx,
        priv->limit     = limit;
        priv->invert    = invert;
 
-       return nf_ct_netns_get(ctx->net, ctx->family);
+       err = nf_ct_netns_get(ctx->net, ctx->family);
+       if (err < 0)
+               goto err_netns;
+
+       return 0;
+err_netns:
+       kfree(priv->list);
+
+       return err;
 }
 
 static void nft_connlimit_do_destroy(const struct nft_ctx *ctx,
index 518d96c..5adf8bb 100644 (file)
@@ -260,9 +260,12 @@ static void nft_ct_set_zone_eval(const struct nft_expr *expr,
        ct = this_cpu_read(nft_ct_pcpu_template);
 
        if (likely(refcount_read(&ct->ct_general.use) == 1)) {
+               refcount_inc(&ct->ct_general.use);
                nf_ct_zone_add(ct, &zone);
        } else {
-               /* previous skb got queued to userspace */
+               /* previous skb got queued to userspace, allocate temporary
+                * one until percpu template can be reused.
+                */
                ct = nf_ct_tmpl_alloc(nft_net(pkt), &zone, GFP_ATOMIC);
                if (!ct) {
                        regs->verdict.code = NF_DROP;
index bbf3fcb..5b5c607 100644 (file)
@@ -67,6 +67,11 @@ static int nft_dup_netdev_offload(struct nft_offload_ctx *ctx,
        return nft_fwd_dup_netdev_offload(ctx, flow, FLOW_ACTION_MIRRED, oif);
 }
 
+static bool nft_dup_netdev_offload_action(const struct nft_expr *expr)
+{
+       return true;
+}
+
 static struct nft_expr_type nft_dup_netdev_type;
 static const struct nft_expr_ops nft_dup_netdev_ops = {
        .type           = &nft_dup_netdev_type,
@@ -75,6 +80,7 @@ static const struct nft_expr_ops nft_dup_netdev_ops = {
        .init           = nft_dup_netdev_init,
        .dump           = nft_dup_netdev_dump,
        .offload        = nft_dup_netdev_offload,
+       .offload_action = nft_dup_netdev_offload_action,
 };
 
 static struct nft_expr_type nft_dup_netdev_type __read_mostly = {
index dbe1f2e..9e927ab 100644 (file)
@@ -167,7 +167,7 @@ nft_tcp_header_pointer(const struct nft_pktinfo *pkt,
 {
        struct tcphdr *tcph;
 
-       if (pkt->tprot != IPPROTO_TCP)
+       if (pkt->tprot != IPPROTO_TCP || pkt->fragoff)
                return NULL;
 
        tcph = skb_header_pointer(pkt->skb, nft_thoff(pkt), sizeof(*tcph), buffer);
index fa9301c..619e394 100644 (file)
@@ -79,6 +79,11 @@ static int nft_fwd_netdev_offload(struct nft_offload_ctx *ctx,
        return nft_fwd_dup_netdev_offload(ctx, flow, FLOW_ACTION_REDIRECT, oif);
 }
 
+static bool nft_fwd_netdev_offload_action(const struct nft_expr *expr)
+{
+       return true;
+}
+
 struct nft_fwd_neigh {
        u8                      sreg_dev;
        u8                      sreg_addr;
@@ -222,6 +227,7 @@ static const struct nft_expr_ops nft_fwd_netdev_ops = {
        .dump           = nft_fwd_netdev_dump,
        .validate       = nft_fwd_validate,
        .offload        = nft_fwd_netdev_offload,
+       .offload_action = nft_fwd_netdev_offload_action,
 };
 
 static const struct nft_expr_ops *
index 90c64d2..d0f67d3 100644 (file)
@@ -213,6 +213,16 @@ static int nft_immediate_offload(struct nft_offload_ctx *ctx,
        return 0;
 }
 
+static bool nft_immediate_offload_action(const struct nft_expr *expr)
+{
+       const struct nft_immediate_expr *priv = nft_expr_priv(expr);
+
+       if (priv->dreg == NFT_REG_VERDICT)
+               return true;
+
+       return false;
+}
+
 static const struct nft_expr_ops nft_imm_ops = {
        .type           = &nft_imm_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)),
@@ -224,7 +234,7 @@ static const struct nft_expr_ops nft_imm_ops = {
        .dump           = nft_immediate_dump,
        .validate       = nft_immediate_validate,
        .offload        = nft_immediate_offload,
-       .offload_flags  = NFT_OFFLOAD_F_ACTION,
+       .offload_action = nft_immediate_offload_action,
 };
 
 struct nft_expr_type nft_imm_type __read_mostly = {
index c4f3084..a726b62 100644 (file)
@@ -340,11 +340,20 @@ static int nft_limit_obj_pkts_dump(struct sk_buff *skb,
        return nft_limit_dump(skb, &priv->limit, NFT_LIMIT_PKTS);
 }
 
+static void nft_limit_obj_pkts_destroy(const struct nft_ctx *ctx,
+                                      struct nft_object *obj)
+{
+       struct nft_limit_priv_pkts *priv = nft_obj_data(obj);
+
+       nft_limit_destroy(ctx, &priv->limit);
+}
+
 static struct nft_object_type nft_limit_obj_type;
 static const struct nft_object_ops nft_limit_obj_pkts_ops = {
        .type           = &nft_limit_obj_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_limit_priv_pkts)),
        .init           = nft_limit_obj_pkts_init,
+       .destroy        = nft_limit_obj_pkts_destroy,
        .eval           = nft_limit_obj_pkts_eval,
        .dump           = nft_limit_obj_pkts_dump,
 };
@@ -378,11 +387,20 @@ static int nft_limit_obj_bytes_dump(struct sk_buff *skb,
        return nft_limit_dump(skb, priv, NFT_LIMIT_PKT_BYTES);
 }
 
+static void nft_limit_obj_bytes_destroy(const struct nft_ctx *ctx,
+                                       struct nft_object *obj)
+{
+       struct nft_limit_priv *priv = nft_obj_data(obj);
+
+       nft_limit_destroy(ctx, priv);
+}
+
 static struct nft_object_type nft_limit_obj_type;
 static const struct nft_object_ops nft_limit_obj_bytes_ops = {
        .type           = &nft_limit_obj_type,
        .size           = sizeof(struct nft_limit_priv),
        .init           = nft_limit_obj_bytes_init,
+       .destroy        = nft_limit_obj_bytes_destroy,
        .eval           = nft_limit_obj_bytes_eval,
        .dump           = nft_limit_obj_bytes_dump,
 };
index 940fed9..5cc06ae 100644 (file)
@@ -83,7 +83,7 @@ static int __nft_payload_inner_offset(struct nft_pktinfo *pkt)
 {
        unsigned int thoff = nft_thoff(pkt);
 
-       if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
+       if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff)
                return -1;
 
        switch (pkt->tprot) {
@@ -147,7 +147,7 @@ void nft_payload_eval(const struct nft_expr *expr,
                offset = skb_network_offset(skb);
                break;
        case NFT_PAYLOAD_TRANSPORT_HEADER:
-               if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
+               if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff)
                        goto err;
                offset = nft_thoff(pkt);
                break;
@@ -688,7 +688,7 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
                offset = skb_network_offset(skb);
                break;
        case NFT_PAYLOAD_TRANSPORT_HEADER:
-               if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
+               if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff)
                        goto err;
                offset = nft_thoff(pkt);
                break;
@@ -728,7 +728,8 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
        if (priv->csum_type == NFT_PAYLOAD_CSUM_SCTP &&
            pkt->tprot == IPPROTO_SCTP &&
            skb->ip_summed != CHECKSUM_PARTIAL) {
-               if (nft_payload_csum_sctp(skb, nft_thoff(pkt)))
+               if (pkt->fragoff == 0 &&
+                   nft_payload_csum_sctp(skb, nft_thoff(pkt)))
                        goto err;
        }
 
index a0109fa..1133e06 100644 (file)
@@ -191,8 +191,10 @@ static int nft_synproxy_do_init(const struct nft_ctx *ctx,
                if (err)
                        goto nf_ct_failure;
                err = nf_synproxy_ipv6_init(snet, ctx->net);
-               if (err)
+               if (err) {
+                       nf_synproxy_ipv4_fini(snet, ctx->net);
                        goto nf_ct_failure;
+               }
                break;
        }
 
index 5e6459e..7013f55 100644 (file)
@@ -220,8 +220,10 @@ static void socket_mt_destroy(const struct xt_mtdtor_param *par)
 {
        if (par->family == NFPROTO_IPV4)
                nf_defrag_ipv4_disable(par->net);
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
        else if (par->family == NFPROTO_IPV6)
-               nf_defrag_ipv4_disable(par->net);
+               nf_defrag_ipv6_disable(par->net);
+#endif
 }
 
 static struct xt_match socket_mt_reg[] __read_mostly = {
index 0767740..780d9e2 100644 (file)
@@ -423,12 +423,43 @@ static void set_ipv6_addr(struct sk_buff *skb, u8 l4_proto,
        memcpy(addr, new_addr, sizeof(__be32[4]));
 }
 
-static void set_ipv6_fl(struct ipv6hdr *nh, u32 fl, u32 mask)
+static void set_ipv6_dsfield(struct sk_buff *skb, struct ipv6hdr *nh, u8 ipv6_tclass, u8 mask)
 {
+       u8 old_ipv6_tclass = ipv6_get_dsfield(nh);
+
+       ipv6_tclass = OVS_MASKED(old_ipv6_tclass, ipv6_tclass, mask);
+
+       if (skb->ip_summed == CHECKSUM_COMPLETE)
+               csum_replace(&skb->csum, (__force __wsum)(old_ipv6_tclass << 12),
+                            (__force __wsum)(ipv6_tclass << 12));
+
+       ipv6_change_dsfield(nh, ~mask, ipv6_tclass);
+}
+
+static void set_ipv6_fl(struct sk_buff *skb, struct ipv6hdr *nh, u32 fl, u32 mask)
+{
+       u32 ofl;
+
+       ofl = nh->flow_lbl[0] << 16 |  nh->flow_lbl[1] << 8 |  nh->flow_lbl[2];
+       fl = OVS_MASKED(ofl, fl, mask);
+
        /* Bits 21-24 are always unmasked, so this retains their values. */
-       OVS_SET_MASKED(nh->flow_lbl[0], (u8)(fl >> 16), (u8)(mask >> 16));
-       OVS_SET_MASKED(nh->flow_lbl[1], (u8)(fl >> 8), (u8)(mask >> 8));
-       OVS_SET_MASKED(nh->flow_lbl[2], (u8)fl, (u8)mask);
+       nh->flow_lbl[0] = (u8)(fl >> 16);
+       nh->flow_lbl[1] = (u8)(fl >> 8);
+       nh->flow_lbl[2] = (u8)fl;
+
+       if (skb->ip_summed == CHECKSUM_COMPLETE)
+               csum_replace(&skb->csum, (__force __wsum)htonl(ofl), (__force __wsum)htonl(fl));
+}
+
+static void set_ipv6_ttl(struct sk_buff *skb, struct ipv6hdr *nh, u8 new_ttl, u8 mask)
+{
+       new_ttl = OVS_MASKED(nh->hop_limit, new_ttl, mask);
+
+       if (skb->ip_summed == CHECKSUM_COMPLETE)
+               csum_replace(&skb->csum, (__force __wsum)(nh->hop_limit << 8),
+                            (__force __wsum)(new_ttl << 8));
+       nh->hop_limit = new_ttl;
 }
 
 static void set_ip_ttl(struct sk_buff *skb, struct iphdr *nh, u8 new_ttl,
@@ -546,18 +577,17 @@ static int set_ipv6(struct sk_buff *skb, struct sw_flow_key *flow_key,
                }
        }
        if (mask->ipv6_tclass) {
-               ipv6_change_dsfield(nh, ~mask->ipv6_tclass, key->ipv6_tclass);
+               set_ipv6_dsfield(skb, nh, key->ipv6_tclass, mask->ipv6_tclass);
                flow_key->ip.tos = ipv6_get_dsfield(nh);
        }
        if (mask->ipv6_label) {
-               set_ipv6_fl(nh, ntohl(key->ipv6_label),
+               set_ipv6_fl(skb, nh, ntohl(key->ipv6_label),
                            ntohl(mask->ipv6_label));
                flow_key->ipv6.label =
                    *(__be32 *)nh & htonl(IPV6_FLOWINFO_FLOWLABEL);
        }
        if (mask->ipv6_hlimit) {
-               OVS_SET_MASKED(nh->hop_limit, key->ipv6_hlimit,
-                              mask->ipv6_hlimit);
+               set_ipv6_ttl(skb, nh, key->ipv6_hlimit, mask->ipv6_hlimit);
                flow_key->ip.ttl = nh->hop_limit;
        }
        return 0;
index 5bd409a..ab87f22 100644 (file)
@@ -1774,6 +1774,7 @@ static int fanout_add(struct sock *sk, struct fanout_args *args)
                match->prot_hook.dev = po->prot_hook.dev;
                match->prot_hook.func = packet_rcv_fanout;
                match->prot_hook.af_packet_priv = match;
+               match->prot_hook.af_packet_net = read_pnet(&match->net);
                match->prot_hook.id_match = match_fanout_group;
                match->max_num_members = args->max_num_members;
                list_add(&match->list, &fanout_list);
@@ -1788,7 +1789,10 @@ static int fanout_add(struct sock *sk, struct fanout_args *args)
                err = -ENOSPC;
                if (refcount_read(&match->sk_ref) < match->max_num_members) {
                        __dev_remove_pack(&po->prot_hook);
-                       po->fanout = match;
+
+                       /* Paired with packet_setsockopt(PACKET_FANOUT_DATA) */
+                       WRITE_ONCE(po->fanout, match);
+
                        po->rollover = rollover;
                        rollover = NULL;
                        refcount_set(&match->sk_ref, refcount_read(&match->sk_ref) + 1);
@@ -3353,6 +3357,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol,
                po->prot_hook.func = packet_rcv_spkt;
 
        po->prot_hook.af_packet_priv = sk;
+       po->prot_hook.af_packet_net = sock_net(sk);
 
        if (proto) {
                po->prot_hook.type = proto;
@@ -3932,7 +3937,8 @@ packet_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval,
        }
        case PACKET_FANOUT_DATA:
        {
-               if (!po->fanout)
+               /* Paired with the WRITE_ONCE() in fanout_add() */
+               if (!READ_ONCE(po->fanout))
                        return -EINVAL;
 
                return fanout_set_data(po, optval, optlen);
index 6be2672..df864e6 100644 (file)
@@ -157,7 +157,7 @@ static void rxrpc_congestion_timeout(struct rxrpc_call *call)
 static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
 {
        struct sk_buff *skb;
-       unsigned long resend_at, rto_j;
+       unsigned long resend_at;
        rxrpc_seq_t cursor, seq, top;
        ktime_t now, max_age, oldest, ack_ts;
        int ix;
@@ -165,10 +165,8 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
 
        _enter("{%d,%d}", call->tx_hard_ack, call->tx_top);
 
-       rto_j = call->peer->rto_j;
-
        now = ktime_get_real();
-       max_age = ktime_sub(now, jiffies_to_usecs(rto_j));
+       max_age = ktime_sub(now, jiffies_to_usecs(call->peer->rto_j));
 
        spin_lock_bh(&call->lock);
 
@@ -213,7 +211,7 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
        }
 
        resend_at = nsecs_to_jiffies(ktime_to_ns(ktime_sub(now, oldest)));
-       resend_at += jiffies + rto_j;
+       resend_at += jiffies + rxrpc_get_rto_backoff(call->peer, retrans);
        WRITE_ONCE(call->resend_at, resend_at);
 
        if (unacked)
index 10f2bf2..a45c83f 100644 (file)
@@ -468,7 +468,7 @@ done:
                        if (call->peer->rtt_count > 1) {
                                unsigned long nowj = jiffies, ack_lost_at;
 
-                               ack_lost_at = rxrpc_get_rto_backoff(call->peer, retrans);
+                               ack_lost_at = rxrpc_get_rto_backoff(call->peer, false);
                                ack_lost_at += nowj;
                                WRITE_ONCE(call->ack_lost_at, ack_lost_at);
                                rxrpc_reduce_call_timer(call, ack_lost_at, nowj,
index 32563ce..ca03e72 100644 (file)
@@ -274,7 +274,7 @@ static int tcf_action_offload_add_ex(struct tc_action *action,
        err = tc_setup_action(&fl_action->action, actions);
        if (err) {
                NL_SET_ERR_MSG_MOD(extack,
-                                  "Failed to setup tc actions for offload\n");
+                                  "Failed to setup tc actions for offload");
                goto fl_err;
        }
 
@@ -1037,6 +1037,7 @@ int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
 restart_act_graph:
        for (i = 0; i < nr_actions; i++) {
                const struct tc_action *a = actions[i];
+               int repeat_ttl;
 
                if (jmp_prgcnt > 0) {
                        jmp_prgcnt -= 1;
@@ -1045,11 +1046,17 @@ restart_act_graph:
 
                if (tc_act_skip_sw(a->tcfa_flags))
                        continue;
+
+               repeat_ttl = 32;
 repeat:
                ret = a->ops->act(skb, a, res);
-               if (ret == TC_ACT_REPEAT)
-                       goto repeat;    /* we need a ttl - JHS */
-
+               if (unlikely(ret == TC_ACT_REPEAT)) {
+                       if (--repeat_ttl != 0)
+                               goto repeat;
+                       /* suspicious opcode, stop pipeline */
+                       net_warn_ratelimited("TC_ACT_REPEAT abuse ?\n");
+                       return TC_ACT_OK;
+               }
                if (TC_ACT_EXT_CMP(ret, TC_ACT_JUMP)) {
                        jmp_prgcnt = ret & TCA_ACT_MAX_PRIO_MASK;
                        if (!jmp_prgcnt || (jmp_prgcnt > nr_actions)) {
index f99247f..33e70d6 100644 (file)
@@ -533,11 +533,6 @@ static bool tcf_ct_flow_table_lookup(struct tcf_ct_params *p,
        struct nf_conn *ct;
        u8 dir;
 
-       /* Previously seen or loopback */
-       ct = nf_ct_get(skb, &ctinfo);
-       if ((ct && !nf_ct_is_template(ct)) || ctinfo == IP_CT_UNTRACKED)
-               return false;
-
        switch (family) {
        case NFPROTO_IPV4:
                if (!tcf_ct_flow_table_fill_tuple_ipv4(skb, &tuple, &tcph))
index d4e27c6..5ce1208 100644 (file)
@@ -1044,7 +1044,7 @@ static int __tcf_qdisc_find(struct net *net, struct Qdisc **q,
 
        /* Find qdisc */
        if (!*parent) {
-               *q = dev->qdisc;
+               *q = rcu_dereference(dev->qdisc);
                *parent = (*q)->handle;
        } else {
                *q = qdisc_lookup_rcu(dev, TC_H_MAJ(*parent));
@@ -1945,9 +1945,9 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
        bool prio_allocate;
        u32 parent;
        u32 chain_index;
-       struct Qdisc *q = NULL;
+       struct Qdisc *q;
        struct tcf_chain_info chain_info;
-       struct tcf_chain *chain = NULL;
+       struct tcf_chain *chain;
        struct tcf_block *block;
        struct tcf_proto *tp;
        unsigned long cl;
@@ -1976,6 +1976,8 @@ replay:
        tp = NULL;
        cl = 0;
        block = NULL;
+       q = NULL;
+       chain = NULL;
        flags = 0;
 
        if (prio == 0) {
@@ -2585,7 +2587,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
 
                parent = tcm->tcm_parent;
                if (!parent)
-                       q = dev->qdisc;
+                       q = rtnl_dereference(dev->qdisc);
                else
                        q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent));
                if (!q)
@@ -2798,8 +2800,8 @@ static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n,
        struct tcmsg *t;
        u32 parent;
        u32 chain_index;
-       struct Qdisc *q = NULL;
-       struct tcf_chain *chain = NULL;
+       struct Qdisc *q;
+       struct tcf_chain *chain;
        struct tcf_block *block;
        unsigned long cl;
        int err;
@@ -2809,6 +2811,7 @@ static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n,
                return -EPERM;
 
 replay:
+       q = NULL;
        err = nlmsg_parse_deprecated(n, sizeof(*t), tca, TCA_MAX,
                                     rtm_tca_policy, extack);
        if (err < 0)
@@ -2959,7 +2962,7 @@ static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb)
                        return skb->len;
 
                if (!tcm->tcm_parent)
-                       q = dev->qdisc;
+                       q = rtnl_dereference(dev->qdisc);
                else
                        q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent));
 
index 2cb496c..e3c0e8e 100644 (file)
@@ -301,7 +301,7 @@ struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
 
        if (!handle)
                return NULL;
-       q = qdisc_match_from_root(dev->qdisc, handle);
+       q = qdisc_match_from_root(rtnl_dereference(dev->qdisc), handle);
        if (q)
                goto out;
 
@@ -320,7 +320,7 @@ struct Qdisc *qdisc_lookup_rcu(struct net_device *dev, u32 handle)
 
        if (!handle)
                return NULL;
-       q = qdisc_match_from_root(dev->qdisc, handle);
+       q = qdisc_match_from_root(rcu_dereference(dev->qdisc), handle);
        if (q)
                goto out;
 
@@ -1082,10 +1082,10 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
 skip:
                if (!ingress) {
                        notify_and_destroy(net, skb, n, classid,
-                                          dev->qdisc, new);
+                                          rtnl_dereference(dev->qdisc), new);
                        if (new && !new->ops->attach)
                                qdisc_refcount_inc(new);
-                       dev->qdisc = new ? : &noop_qdisc;
+                       rcu_assign_pointer(dev->qdisc, new ? : &noop_qdisc);
 
                        if (new && new->ops->attach)
                                new->ops->attach(new);
@@ -1204,7 +1204,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
 
        err = -ENOENT;
        if (!ops) {
-               NL_SET_ERR_MSG(extack, "Specified qdisc not found");
+               NL_SET_ERR_MSG(extack, "Specified qdisc kind is unknown");
                goto err_out;
        }
 
@@ -1451,7 +1451,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
                                q = dev_ingress_queue(dev)->qdisc_sleeping;
                        }
                } else {
-                       q = dev->qdisc;
+                       q = rtnl_dereference(dev->qdisc);
                }
                if (!q) {
                        NL_SET_ERR_MSG(extack, "Cannot find specified qdisc on specified device");
@@ -1540,7 +1540,7 @@ replay:
                                q = dev_ingress_queue(dev)->qdisc_sleeping;
                        }
                } else {
-                       q = dev->qdisc;
+                       q = rtnl_dereference(dev->qdisc);
                }
 
                /* It may be default qdisc, ignore it */
@@ -1762,7 +1762,8 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
                        s_q_idx = 0;
                q_idx = 0;
 
-               if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx,
+               if (tc_dump_qdisc_root(rtnl_dereference(dev->qdisc),
+                                      skb, cb, &q_idx, s_q_idx,
                                       true, tca[TCA_DUMP_INVISIBLE]) < 0)
                        goto done;
 
@@ -2033,7 +2034,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n,
                } else if (qid1) {
                        qid = qid1;
                } else if (qid == 0)
-                       qid = dev->qdisc->handle;
+                       qid = rtnl_dereference(dev->qdisc)->handle;
 
                /* Now qid is genuine qdisc handle consistent
                 * both with parent and child.
@@ -2044,7 +2045,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n,
                        portid = TC_H_MAKE(qid, portid);
        } else {
                if (qid == 0)
-                       qid = dev->qdisc->handle;
+                       qid = rtnl_dereference(dev->qdisc)->handle;
        }
 
        /* OK. Locate qdisc */
@@ -2205,7 +2206,8 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
        s_t = cb->args[0];
        t = 0;
 
-       if (tc_dump_tclass_root(dev->qdisc, skb, tcm, cb, &t, s_t, true) < 0)
+       if (tc_dump_tclass_root(rtnl_dereference(dev->qdisc),
+                               skb, tcm, cb, &t, s_t, true) < 0)
                goto done;
 
        dev_queue = dev_ingress_queue(dev);
index f893d9a..5bab9f8 100644 (file)
@@ -1164,30 +1164,33 @@ static void attach_default_qdiscs(struct net_device *dev)
        if (!netif_is_multiqueue(dev) ||
            dev->priv_flags & IFF_NO_QUEUE) {
                netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL);
-               dev->qdisc = txq->qdisc_sleeping;
-               qdisc_refcount_inc(dev->qdisc);
+               qdisc = txq->qdisc_sleeping;
+               rcu_assign_pointer(dev->qdisc, qdisc);
+               qdisc_refcount_inc(qdisc);
        } else {
                qdisc = qdisc_create_dflt(txq, &mq_qdisc_ops, TC_H_ROOT, NULL);
                if (qdisc) {
-                       dev->qdisc = qdisc;
+                       rcu_assign_pointer(dev->qdisc, qdisc);
                        qdisc->ops->attach(qdisc);
                }
        }
+       qdisc = rtnl_dereference(dev->qdisc);
 
        /* Detect default qdisc setup/init failed and fallback to "noqueue" */
-       if (dev->qdisc == &noop_qdisc) {
+       if (qdisc == &noop_qdisc) {
                netdev_warn(dev, "default qdisc (%s) fail, fallback to %s\n",
                            default_qdisc_ops->id, noqueue_qdisc_ops.id);
                dev->priv_flags |= IFF_NO_QUEUE;
                netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL);
-               dev->qdisc = txq->qdisc_sleeping;
-               qdisc_refcount_inc(dev->qdisc);
+               qdisc = txq->qdisc_sleeping;
+               rcu_assign_pointer(dev->qdisc, qdisc);
+               qdisc_refcount_inc(qdisc);
                dev->priv_flags ^= IFF_NO_QUEUE;
        }
 
 #ifdef CONFIG_NET_SCHED
-       if (dev->qdisc != &noop_qdisc)
-               qdisc_hash_add(dev->qdisc, false);
+       if (qdisc != &noop_qdisc)
+               qdisc_hash_add(qdisc, false);
 #endif
 }
 
@@ -1217,7 +1220,7 @@ void dev_activate(struct net_device *dev)
         * and noqueue_qdisc for virtual interfaces
         */
 
-       if (dev->qdisc == &noop_qdisc)
+       if (rtnl_dereference(dev->qdisc) == &noop_qdisc)
                attach_default_qdiscs(dev);
 
        if (!netif_carrier_ok(dev))
@@ -1383,7 +1386,7 @@ static int qdisc_change_tx_queue_len(struct net_device *dev,
 void dev_qdisc_change_real_num_tx(struct net_device *dev,
                                  unsigned int new_real_tx)
 {
-       struct Qdisc *qdisc = dev->qdisc;
+       struct Qdisc *qdisc = rtnl_dereference(dev->qdisc);
 
        if (qdisc->ops->change_real_num_tx)
                qdisc->ops->change_real_num_tx(qdisc, new_real_tx);
@@ -1447,7 +1450,7 @@ static void dev_init_scheduler_queue(struct net_device *dev,
 
 void dev_init_scheduler(struct net_device *dev)
 {
-       dev->qdisc = &noop_qdisc;
+       rcu_assign_pointer(dev->qdisc, &noop_qdisc);
        netdev_for_each_tx_queue(dev, dev_init_scheduler_queue, &noop_qdisc);
        if (dev_ingress_queue(dev))
                dev_init_scheduler_queue(dev, dev_ingress_queue(dev), &noop_qdisc);
@@ -1475,8 +1478,8 @@ void dev_shutdown(struct net_device *dev)
        netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc);
        if (dev_ingress_queue(dev))
                shutdown_scheduler_queue(dev, dev_ingress_queue(dev), &noop_qdisc);
-       qdisc_put(dev->qdisc);
-       dev->qdisc = &noop_qdisc;
+       qdisc_put(rtnl_dereference(dev->qdisc));
+       rcu_assign_pointer(dev->qdisc, &noop_qdisc);
 
        WARN_ON(timer_pending(&dev->watchdog_timer));
 }
index 9267922..23a9d62 100644 (file)
@@ -1810,6 +1810,26 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
        if (!hopt->rate.rate || !hopt->ceil.rate)
                goto failure;
 
+       if (q->offload) {
+               /* Options not supported by the offload. */
+               if (hopt->rate.overhead || hopt->ceil.overhead) {
+                       NL_SET_ERR_MSG(extack, "HTB offload doesn't support the overhead parameter");
+                       goto failure;
+               }
+               if (hopt->rate.mpu || hopt->ceil.mpu) {
+                       NL_SET_ERR_MSG(extack, "HTB offload doesn't support the mpu parameter");
+                       goto failure;
+               }
+               if (hopt->quantum) {
+                       NL_SET_ERR_MSG(extack, "HTB offload doesn't support the quantum parameter");
+                       goto failure;
+               }
+               if (hopt->prio) {
+                       NL_SET_ERR_MSG(extack, "HTB offload doesn't support the prio parameter");
+                       goto failure;
+               }
+       }
+
        /* Keeping backward compatible with rate_table based iproute2 tc */
        if (hopt->rate.linklayer == TC_LINKLAYER_UNAWARE)
                qdisc_put_rtab(qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB],
index 961854e..306d9e8 100644 (file)
@@ -566,12 +566,118 @@ static void smc_stat_fallback(struct smc_sock *smc)
        mutex_unlock(&net->smc.mutex_fback_rsn);
 }
 
-static void smc_switch_to_fallback(struct smc_sock *smc, int reason_code)
+/* must be called under rcu read lock */
+static void smc_fback_wakeup_waitqueue(struct smc_sock *smc, void *key)
 {
-       wait_queue_head_t *smc_wait = sk_sleep(&smc->sk);
-       wait_queue_head_t *clc_wait = sk_sleep(smc->clcsock->sk);
-       unsigned long flags;
+       struct socket_wq *wq;
+       __poll_t flags;
 
+       wq = rcu_dereference(smc->sk.sk_wq);
+       if (!skwq_has_sleeper(wq))
+               return;
+
+       /* wake up smc sk->sk_wq */
+       if (!key) {
+               /* sk_state_change */
+               wake_up_interruptible_all(&wq->wait);
+       } else {
+               flags = key_to_poll(key);
+               if (flags & (EPOLLIN | EPOLLOUT))
+                       /* sk_data_ready or sk_write_space */
+                       wake_up_interruptible_sync_poll(&wq->wait, flags);
+               else if (flags & EPOLLERR)
+                       /* sk_error_report */
+                       wake_up_interruptible_poll(&wq->wait, flags);
+       }
+}
+
+static int smc_fback_mark_woken(wait_queue_entry_t *wait,
+                               unsigned int mode, int sync, void *key)
+{
+       struct smc_mark_woken *mark =
+               container_of(wait, struct smc_mark_woken, wait_entry);
+
+       mark->woken = true;
+       mark->key = key;
+       return 0;
+}
+
+static void smc_fback_forward_wakeup(struct smc_sock *smc, struct sock *clcsk,
+                                    void (*clcsock_callback)(struct sock *sk))
+{
+       struct smc_mark_woken mark = { .woken = false };
+       struct socket_wq *wq;
+
+       init_waitqueue_func_entry(&mark.wait_entry,
+                                 smc_fback_mark_woken);
+       rcu_read_lock();
+       wq = rcu_dereference(clcsk->sk_wq);
+       if (!wq)
+               goto out;
+       add_wait_queue(sk_sleep(clcsk), &mark.wait_entry);
+       clcsock_callback(clcsk);
+       remove_wait_queue(sk_sleep(clcsk), &mark.wait_entry);
+
+       if (mark.woken)
+               smc_fback_wakeup_waitqueue(smc, mark.key);
+out:
+       rcu_read_unlock();
+}
+
+static void smc_fback_state_change(struct sock *clcsk)
+{
+       struct smc_sock *smc =
+               smc_clcsock_user_data(clcsk);
+
+       if (!smc)
+               return;
+       smc_fback_forward_wakeup(smc, clcsk, smc->clcsk_state_change);
+}
+
+static void smc_fback_data_ready(struct sock *clcsk)
+{
+       struct smc_sock *smc =
+               smc_clcsock_user_data(clcsk);
+
+       if (!smc)
+               return;
+       smc_fback_forward_wakeup(smc, clcsk, smc->clcsk_data_ready);
+}
+
+static void smc_fback_write_space(struct sock *clcsk)
+{
+       struct smc_sock *smc =
+               smc_clcsock_user_data(clcsk);
+
+       if (!smc)
+               return;
+       smc_fback_forward_wakeup(smc, clcsk, smc->clcsk_write_space);
+}
+
+static void smc_fback_error_report(struct sock *clcsk)
+{
+       struct smc_sock *smc =
+               smc_clcsock_user_data(clcsk);
+
+       if (!smc)
+               return;
+       smc_fback_forward_wakeup(smc, clcsk, smc->clcsk_error_report);
+}
+
+static int smc_switch_to_fallback(struct smc_sock *smc, int reason_code)
+{
+       struct sock *clcsk;
+       int rc = 0;
+
+       mutex_lock(&smc->clcsock_release_lock);
+       if (!smc->clcsock) {
+               rc = -EBADF;
+               goto out;
+       }
+       clcsk = smc->clcsock->sk;
+
+       if (smc->use_fallback)
+               goto out;
        smc->use_fallback = true;
        smc->fallback_rsn = reason_code;
        smc_stat_fallback(smc);
@@ -582,22 +688,41 @@ static void smc_switch_to_fallback(struct smc_sock *smc, int reason_code)
                smc->clcsock->wq.fasync_list =
                        smc->sk.sk_socket->wq.fasync_list;
 
-               /* There may be some entries remaining in
-                * smc socket->wq, which should be removed
-                * to clcsocket->wq during the fallback.
+               /* There might be some wait entries remaining
+                * in smc sk->sk_wq and they should be woken up
+                * as clcsock's wait queue is woken up.
                 */
-               spin_lock_irqsave(&smc_wait->lock, flags);
-               spin_lock_nested(&clc_wait->lock, SINGLE_DEPTH_NESTING);
-               list_splice_init(&smc_wait->head, &clc_wait->head);
-               spin_unlock(&clc_wait->lock);
-               spin_unlock_irqrestore(&smc_wait->lock, flags);
+               smc->clcsk_state_change = clcsk->sk_state_change;
+               smc->clcsk_data_ready = clcsk->sk_data_ready;
+               smc->clcsk_write_space = clcsk->sk_write_space;
+               smc->clcsk_error_report = clcsk->sk_error_report;
+
+               clcsk->sk_state_change = smc_fback_state_change;
+               clcsk->sk_data_ready = smc_fback_data_ready;
+               clcsk->sk_write_space = smc_fback_write_space;
+               clcsk->sk_error_report = smc_fback_error_report;
+
+               smc->clcsock->sk->sk_user_data =
+                       (void *)((uintptr_t)smc | SK_USER_DATA_NOCOPY);
        }
+out:
+       mutex_unlock(&smc->clcsock_release_lock);
+       return rc;
 }
 
 /* fall back during connect */
 static int smc_connect_fallback(struct smc_sock *smc, int reason_code)
 {
-       smc_switch_to_fallback(smc, reason_code);
+       struct net *net = sock_net(&smc->sk);
+       int rc = 0;
+
+       rc = smc_switch_to_fallback(smc, reason_code);
+       if (rc) { /* fallback fails */
+               this_cpu_inc(net->smc.smc_stats->clnt_hshake_err_cnt);
+               if (smc->sk.sk_state == SMC_INIT)
+                       sock_put(&smc->sk); /* passive closing */
+               return rc;
+       }
        smc_copy_sock_settings_to_clc(smc);
        smc->connect_nonblock = 0;
        if (smc->sk.sk_state == SMC_INIT)
@@ -1518,11 +1643,12 @@ static void smc_listen_decline(struct smc_sock *new_smc, int reason_code,
 {
        /* RDMA setup failed, switch back to TCP */
        smc_conn_abort(new_smc, local_first);
-       if (reason_code < 0) { /* error, no fallback possible */
+       if (reason_code < 0 ||
+           smc_switch_to_fallback(new_smc, reason_code)) {
+               /* error, no fallback possible */
                smc_listen_out_err(new_smc);
                return;
        }
-       smc_switch_to_fallback(new_smc, reason_code);
        if (reason_code && reason_code != SMC_CLC_DECL_PEERDECL) {
                if (smc_clc_send_decline(new_smc, reason_code, version) < 0) {
                        smc_listen_out_err(new_smc);
@@ -1964,8 +2090,11 @@ static void smc_listen_work(struct work_struct *work)
 
        /* check if peer is smc capable */
        if (!tcp_sk(newclcsock->sk)->syn_smc) {
-               smc_switch_to_fallback(new_smc, SMC_CLC_DECL_PEERNOSMC);
-               smc_listen_out_connected(new_smc);
+               rc = smc_switch_to_fallback(new_smc, SMC_CLC_DECL_PEERNOSMC);
+               if (rc)
+                       smc_listen_out_err(new_smc);
+               else
+                       smc_listen_out_connected(new_smc);
                return;
        }
 
@@ -2094,10 +2223,9 @@ out:
 
 static void smc_clcsock_data_ready(struct sock *listen_clcsock)
 {
-       struct smc_sock *lsmc;
+       struct smc_sock *lsmc =
+               smc_clcsock_user_data(listen_clcsock);
 
-       lsmc = (struct smc_sock *)
-              ((uintptr_t)listen_clcsock->sk_user_data & ~SK_USER_DATA_NOCOPY);
        if (!lsmc)
                return;
        lsmc->clcsk_data_ready(listen_clcsock);
@@ -2254,7 +2382,9 @@ static int smc_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
 
        if (msg->msg_flags & MSG_FASTOPEN) {
                if (sk->sk_state == SMC_INIT && !smc->connect_nonblock) {
-                       smc_switch_to_fallback(smc, SMC_CLC_DECL_OPTUNSUPP);
+                       rc = smc_switch_to_fallback(smc, SMC_CLC_DECL_OPTUNSUPP);
+                       if (rc)
+                               goto out;
                } else {
                        rc = -EINVAL;
                        goto out;
@@ -2447,6 +2577,11 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
        /* generic setsockopts reaching us here always apply to the
         * CLC socket
         */
+       mutex_lock(&smc->clcsock_release_lock);
+       if (!smc->clcsock) {
+               mutex_unlock(&smc->clcsock_release_lock);
+               return -EBADF;
+       }
        if (unlikely(!smc->clcsock->ops->setsockopt))
                rc = -EOPNOTSUPP;
        else
@@ -2456,6 +2591,7 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
                sk->sk_err = smc->clcsock->sk->sk_err;
                sk_error_report(sk);
        }
+       mutex_unlock(&smc->clcsock_release_lock);
 
        if (optlen < sizeof(int))
                return -EINVAL;
@@ -2472,7 +2608,7 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
        case TCP_FASTOPEN_NO_COOKIE:
                /* option not supported by SMC */
                if (sk->sk_state == SMC_INIT && !smc->connect_nonblock) {
-                       smc_switch_to_fallback(smc, SMC_CLC_DECL_OPTUNSUPP);
+                       rc = smc_switch_to_fallback(smc, SMC_CLC_DECL_OPTUNSUPP);
                } else {
                        rc = -EINVAL;
                }
@@ -2515,13 +2651,23 @@ static int smc_getsockopt(struct socket *sock, int level, int optname,
                          char __user *optval, int __user *optlen)
 {
        struct smc_sock *smc;
+       int rc;
 
        smc = smc_sk(sock->sk);
+       mutex_lock(&smc->clcsock_release_lock);
+       if (!smc->clcsock) {
+               mutex_unlock(&smc->clcsock_release_lock);
+               return -EBADF;
+       }
        /* socket options apply to the CLC socket */
-       if (unlikely(!smc->clcsock->ops->getsockopt))
+       if (unlikely(!smc->clcsock->ops->getsockopt)) {
+               mutex_unlock(&smc->clcsock_release_lock);
                return -EOPNOTSUPP;
-       return smc->clcsock->ops->getsockopt(smc->clcsock, level, optname,
-                                            optval, optlen);
+       }
+       rc = smc->clcsock->ops->getsockopt(smc->clcsock, level, optname,
+                                          optval, optlen);
+       mutex_unlock(&smc->clcsock_release_lock);
+       return rc;
 }
 
 static int smc_ioctl(struct socket *sock, unsigned int cmd,
index 3d0b8e3..37b2001 100644 (file)
@@ -139,6 +139,12 @@ enum smc_urg_state {
        SMC_URG_READ    = 3,                    /* data was already read */
 };
 
+struct smc_mark_woken {
+       bool woken;
+       void *key;
+       wait_queue_entry_t wait_entry;
+};
+
 struct smc_connection {
        struct rb_node          alert_node;
        struct smc_link_group   *lgr;           /* link group of connection */
@@ -228,8 +234,14 @@ struct smc_connection {
 struct smc_sock {                              /* smc sock container */
        struct sock             sk;
        struct socket           *clcsock;       /* internal tcp socket */
+       void                    (*clcsk_state_change)(struct sock *sk);
+                                               /* original stat_change fct. */
        void                    (*clcsk_data_ready)(struct sock *sk);
-                                               /* original data_ready fct. **/
+                                               /* original data_ready fct. */
+       void                    (*clcsk_write_space)(struct sock *sk);
+                                               /* original write_space fct. */
+       void                    (*clcsk_error_report)(struct sock *sk);
+                                               /* original error_report fct. */
        struct smc_connection   conn;           /* smc connection */
        struct smc_sock         *listen_smc;    /* listen parent */
        struct work_struct      connect_work;   /* handle non-blocking connect*/
@@ -264,6 +276,12 @@ static inline struct smc_sock *smc_sk(const struct sock *sk)
        return (struct smc_sock *)sk;
 }
 
+static inline struct smc_sock *smc_clcsock_user_data(struct sock *clcsk)
+{
+       return (struct smc_sock *)
+              ((uintptr_t)clcsk->sk_user_data & ~SK_USER_DATA_NOCOPY);
+}
+
 extern struct workqueue_struct *smc_hs_wq;     /* wq for handshake work */
 extern struct workqueue_struct *smc_close_wq;  /* wq for close work */
 
index b8898c7..1fca2f9 100644 (file)
@@ -146,13 +146,11 @@ static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb,
            (req->diag_ext & (1 << (SMC_DIAG_LGRINFO - 1))) &&
            !list_empty(&smc->conn.lgr->list)) {
                struct smc_link *link = smc->conn.lnk;
-               struct net *net = read_pnet(&link->smcibdev->ibdev->coredev.rdma_net);
 
                struct smc_diag_lgrinfo linfo = {
                        .role = smc->conn.lgr->role,
                        .lnk[0].ibport = link->ibport,
                        .lnk[0].link_id = link->link_id,
-                       .lnk[0].net_cookie = net->net_cookie,
                };
 
                memcpy(linfo.lnk[0].ibname,
index 291f148..29f0a55 100644 (file)
@@ -113,7 +113,7 @@ static int smc_pnet_remove_by_pnetid(struct net *net, char *pnet_name)
        pnettable = &sn->pnettable;
 
        /* remove table entry */
-       write_lock(&pnettable->lock);
+       mutex_lock(&pnettable->lock);
        list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist,
                                 list) {
                if (!pnet_name ||
@@ -131,7 +131,7 @@ static int smc_pnet_remove_by_pnetid(struct net *net, char *pnet_name)
                        rc = 0;
                }
        }
-       write_unlock(&pnettable->lock);
+       mutex_unlock(&pnettable->lock);
 
        /* if this is not the initial namespace, stop here */
        if (net != &init_net)
@@ -192,7 +192,7 @@ static int smc_pnet_add_by_ndev(struct net_device *ndev)
        sn = net_generic(net, smc_net_id);
        pnettable = &sn->pnettable;
 
-       write_lock(&pnettable->lock);
+       mutex_lock(&pnettable->lock);
        list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) {
                if (pnetelem->type == SMC_PNET_ETH && !pnetelem->ndev &&
                    !strncmp(pnetelem->eth_name, ndev->name, IFNAMSIZ)) {
@@ -206,7 +206,7 @@ static int smc_pnet_add_by_ndev(struct net_device *ndev)
                        break;
                }
        }
-       write_unlock(&pnettable->lock);
+       mutex_unlock(&pnettable->lock);
        return rc;
 }
 
@@ -224,7 +224,7 @@ static int smc_pnet_remove_by_ndev(struct net_device *ndev)
        sn = net_generic(net, smc_net_id);
        pnettable = &sn->pnettable;
 
-       write_lock(&pnettable->lock);
+       mutex_lock(&pnettable->lock);
        list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) {
                if (pnetelem->type == SMC_PNET_ETH && pnetelem->ndev == ndev) {
                        dev_put_track(pnetelem->ndev, &pnetelem->dev_tracker);
@@ -237,7 +237,7 @@ static int smc_pnet_remove_by_ndev(struct net_device *ndev)
                        break;
                }
        }
-       write_unlock(&pnettable->lock);
+       mutex_unlock(&pnettable->lock);
        return rc;
 }
 
@@ -368,12 +368,9 @@ static int smc_pnet_add_eth(struct smc_pnettable *pnettable, struct net *net,
        new_pe->type = SMC_PNET_ETH;
        memcpy(new_pe->pnet_name, pnet_name, SMC_MAX_PNETID_LEN);
        strncpy(new_pe->eth_name, eth_name, IFNAMSIZ);
-       new_pe->ndev = ndev;
-       if (ndev)
-               netdev_tracker_alloc(ndev, &new_pe->dev_tracker, GFP_KERNEL);
        rc = -EEXIST;
        new_netdev = true;
-       write_lock(&pnettable->lock);
+       mutex_lock(&pnettable->lock);
        list_for_each_entry(tmp_pe, &pnettable->pnetlist, list) {
                if (tmp_pe->type == SMC_PNET_ETH &&
                    !strncmp(tmp_pe->eth_name, eth_name, IFNAMSIZ)) {
@@ -382,10 +379,15 @@ static int smc_pnet_add_eth(struct smc_pnettable *pnettable, struct net *net,
                }
        }
        if (new_netdev) {
+               if (ndev) {
+                       new_pe->ndev = ndev;
+                       netdev_tracker_alloc(ndev, &new_pe->dev_tracker,
+                                            GFP_ATOMIC);
+               }
                list_add_tail(&new_pe->list, &pnettable->pnetlist);
-               write_unlock(&pnettable->lock);
+               mutex_unlock(&pnettable->lock);
        } else {
-               write_unlock(&pnettable->lock);
+               mutex_unlock(&pnettable->lock);
                kfree(new_pe);
                goto out_put;
        }
@@ -446,7 +448,7 @@ static int smc_pnet_add_ib(struct smc_pnettable *pnettable, char *ib_name,
        new_pe->ib_port = ib_port;
 
        new_ibdev = true;
-       write_lock(&pnettable->lock);
+       mutex_lock(&pnettable->lock);
        list_for_each_entry(tmp_pe, &pnettable->pnetlist, list) {
                if (tmp_pe->type == SMC_PNET_IB &&
                    !strncmp(tmp_pe->ib_name, ib_name, IB_DEVICE_NAME_MAX)) {
@@ -456,9 +458,9 @@ static int smc_pnet_add_ib(struct smc_pnettable *pnettable, char *ib_name,
        }
        if (new_ibdev) {
                list_add_tail(&new_pe->list, &pnettable->pnetlist);
-               write_unlock(&pnettable->lock);
+               mutex_unlock(&pnettable->lock);
        } else {
-               write_unlock(&pnettable->lock);
+               mutex_unlock(&pnettable->lock);
                kfree(new_pe);
        }
        return (new_ibdev) ? 0 : -EEXIST;
@@ -603,7 +605,7 @@ static int _smc_pnet_dump(struct net *net, struct sk_buff *skb, u32 portid,
        pnettable = &sn->pnettable;
 
        /* dump pnettable entries */
-       read_lock(&pnettable->lock);
+       mutex_lock(&pnettable->lock);
        list_for_each_entry(pnetelem, &pnettable->pnetlist, list) {
                if (pnetid && !smc_pnet_match(pnetelem->pnet_name, pnetid))
                        continue;
@@ -618,7 +620,7 @@ static int _smc_pnet_dump(struct net *net, struct sk_buff *skb, u32 portid,
                        break;
                }
        }
-       read_unlock(&pnettable->lock);
+       mutex_unlock(&pnettable->lock);
        return idx;
 }
 
@@ -862,7 +864,7 @@ int smc_pnet_net_init(struct net *net)
        struct smc_pnetids_ndev *pnetids_ndev = &sn->pnetids_ndev;
 
        INIT_LIST_HEAD(&pnettable->pnetlist);
-       rwlock_init(&pnettable->lock);
+       mutex_init(&pnettable->lock);
        INIT_LIST_HEAD(&pnetids_ndev->list);
        rwlock_init(&pnetids_ndev->lock);
 
@@ -942,7 +944,7 @@ static int smc_pnet_find_ndev_pnetid_by_table(struct net_device *ndev,
        sn = net_generic(net, smc_net_id);
        pnettable = &sn->pnettable;
 
-       read_lock(&pnettable->lock);
+       mutex_lock(&pnettable->lock);
        list_for_each_entry(pnetelem, &pnettable->pnetlist, list) {
                if (pnetelem->type == SMC_PNET_ETH && ndev == pnetelem->ndev) {
                        /* get pnetid of netdev device */
@@ -951,7 +953,7 @@ static int smc_pnet_find_ndev_pnetid_by_table(struct net_device *ndev,
                        break;
                }
        }
-       read_unlock(&pnettable->lock);
+       mutex_unlock(&pnettable->lock);
        return rc;
 }
 
@@ -1154,7 +1156,7 @@ int smc_pnetid_by_table_ib(struct smc_ib_device *smcibdev, u8 ib_port)
        sn = net_generic(&init_net, smc_net_id);
        pnettable = &sn->pnettable;
 
-       read_lock(&pnettable->lock);
+       mutex_lock(&pnettable->lock);
        list_for_each_entry(tmp_pe, &pnettable->pnetlist, list) {
                if (tmp_pe->type == SMC_PNET_IB &&
                    !strncmp(tmp_pe->ib_name, ib_name, IB_DEVICE_NAME_MAX) &&
@@ -1164,7 +1166,7 @@ int smc_pnetid_by_table_ib(struct smc_ib_device *smcibdev, u8 ib_port)
                        break;
                }
        }
-       read_unlock(&pnettable->lock);
+       mutex_unlock(&pnettable->lock);
 
        return rc;
 }
@@ -1183,7 +1185,7 @@ int smc_pnetid_by_table_smcd(struct smcd_dev *smcddev)
        sn = net_generic(&init_net, smc_net_id);
        pnettable = &sn->pnettable;
 
-       read_lock(&pnettable->lock);
+       mutex_lock(&pnettable->lock);
        list_for_each_entry(tmp_pe, &pnettable->pnetlist, list) {
                if (tmp_pe->type == SMC_PNET_IB &&
                    !strncmp(tmp_pe->ib_name, ib_name, IB_DEVICE_NAME_MAX)) {
@@ -1192,7 +1194,7 @@ int smc_pnetid_by_table_smcd(struct smcd_dev *smcddev)
                        break;
                }
        }
-       read_unlock(&pnettable->lock);
+       mutex_unlock(&pnettable->lock);
 
        return rc;
 }
index 1403927..80a88ee 100644 (file)
@@ -29,7 +29,7 @@ struct smc_link_group;
  * @pnetlist: List of PNETIDs
  */
 struct smc_pnettable {
-       rwlock_t lock;
+       struct mutex lock;
        struct list_head pnetlist;
 };
 
index 50cf757..982eeca 100644 (file)
@@ -3448,7 +3448,7 @@ EXPORT_SYMBOL(kernel_connect);
  *     @addr: address holder
  *
  *     Fills the @addr pointer with the address which the socket is bound.
- *     Returns 0 or an error code.
+ *     Returns the length of the address in bytes or an error code.
  */
 
 int kernel_getsockname(struct socket *sock, struct sockaddr *addr)
@@ -3463,7 +3463,7 @@ EXPORT_SYMBOL(kernel_getsockname);
  *     @addr: address holder
  *
  *     Fills the @addr pointer with the address which the socket is connected.
- *     Returns 0 or an error code.
+ *     Returns the length of the address in bytes or an error code.
  */
 
 int kernel_getpeername(struct socket *sock, struct sockaddr *addr)
index fe97f31..4a4082b 100644 (file)
@@ -222,10 +222,8 @@ g_verify_token_header(struct xdr_netobj *mech, int *body_size,
        if (ret)
                return ret;
 
-       if (!ret) {
-               *buf_in = buf;
-               *body_size = toksize;
-       }
+       *buf_in = buf;
+       *body_size = toksize;
 
        return ret;
 }
index a312ea2..c83fe61 100644 (file)
@@ -2900,7 +2900,7 @@ int rpc_clnt_add_xprt(struct rpc_clnt *clnt,
        unsigned long connect_timeout;
        unsigned long reconnect_timeout;
        unsigned char resvport, reuseport;
-       int ret = 0;
+       int ret = 0, ident;
 
        rcu_read_lock();
        xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
@@ -2914,8 +2914,11 @@ int rpc_clnt_add_xprt(struct rpc_clnt *clnt,
        reuseport = xprt->reuseport;
        connect_timeout = xprt->connect_timeout;
        reconnect_timeout = xprt->max_reconnect_timeout;
+       ident = xprt->xprt_class->ident;
        rcu_read_unlock();
 
+       if (!xprtargs->ident)
+               xprtargs->ident = ident;
        xprt = xprt_create_transport(xprtargs);
        if (IS_ERR(xprt)) {
                ret = PTR_ERR(xprt);
index ee5336d..35588f0 100644 (file)
@@ -600,9 +600,9 @@ static int __rpc_rmdir(struct inode *dir, struct dentry *dentry)
 
        dget(dentry);
        ret = simple_rmdir(dir, dentry);
+       d_drop(dentry);
        if (!ret)
                fsnotify_rmdir(dir, dentry);
-       d_delete(dentry);
        dput(dentry);
        return ret;
 }
@@ -613,9 +613,9 @@ static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
 
        dget(dentry);
        ret = simple_unlink(dir, dentry);
+       d_drop(dentry);
        if (!ret)
                fsnotify_unlink(dir, dentry);
-       d_delete(dentry);
        dput(dentry);
        return ret;
 }
index 2766dd2..05c758d 100644 (file)
@@ -115,11 +115,14 @@ static ssize_t rpc_sysfs_xprt_srcaddr_show(struct kobject *kobj,
        }
 
        sock = container_of(xprt, struct sock_xprt, xprt);
-       if (kernel_getsockname(sock->sock, (struct sockaddr *)&saddr) < 0)
+       mutex_lock(&sock->recv_mutex);
+       if (sock->sock == NULL ||
+           kernel_getsockname(sock->sock, (struct sockaddr *)&saddr) < 0)
                goto out;
 
        ret = sprintf(buf, "%pISc\n", &saddr);
 out:
+       mutex_unlock(&sock->recv_mutex);
        xprt_put(xprt);
        return ret + 1;
 }
@@ -295,8 +298,10 @@ static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
                online = 1;
        else if (!strncmp(buf, "remove", 6))
                remove = 1;
-       else
-               return -EINVAL;
+       else {
+               count = -EINVAL;
+               goto out_put;
+       }
 
        if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
                count = -EINTR;
@@ -307,25 +312,28 @@ static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
                goto release_tasks;
        }
        if (offline) {
-               set_bit(XPRT_OFFLINE, &xprt->state);
-               spin_lock(&xps->xps_lock);
-               xps->xps_nactive--;
-               spin_unlock(&xps->xps_lock);
+               if (!test_and_set_bit(XPRT_OFFLINE, &xprt->state)) {
+                       spin_lock(&xps->xps_lock);
+                       xps->xps_nactive--;
+                       spin_unlock(&xps->xps_lock);
+               }
        } else if (online) {
-               clear_bit(XPRT_OFFLINE, &xprt->state);
-               spin_lock(&xps->xps_lock);
-               xps->xps_nactive++;
-               spin_unlock(&xps->xps_lock);
+               if (test_and_clear_bit(XPRT_OFFLINE, &xprt->state)) {
+                       spin_lock(&xps->xps_lock);
+                       xps->xps_nactive++;
+                       spin_unlock(&xps->xps_lock);
+               }
        } else if (remove) {
                if (test_bit(XPRT_OFFLINE, &xprt->state)) {
-                       set_bit(XPRT_REMOVE, &xprt->state);
-                       xprt_force_disconnect(xprt);
-                       if (test_bit(XPRT_CONNECTED, &xprt->state)) {
-                               if (!xprt->sending.qlen &&
-                                   !xprt->pending.qlen &&
-                                   !xprt->backlog.qlen &&
-                                   !atomic_long_read(&xprt->queuelen))
-                                       rpc_xprt_switch_remove_xprt(xps, xprt);
+                       if (!test_and_set_bit(XPRT_REMOVE, &xprt->state)) {
+                               xprt_force_disconnect(xprt);
+                               if (test_bit(XPRT_CONNECTED, &xprt->state)) {
+                                       if (!xprt->sending.qlen &&
+                                           !xprt->pending.qlen &&
+                                           !xprt->backlog.qlen &&
+                                           !atomic_long_read(&xprt->queuelen))
+                                               rpc_xprt_switch_remove_xprt(xps, xprt);
+                               }
                        }
                } else {
                        count = -EINVAL;
@@ -422,6 +430,7 @@ static struct attribute *rpc_sysfs_xprt_attrs[] = {
        &rpc_sysfs_xprt_change_state.attr,
        NULL,
 };
+ATTRIBUTE_GROUPS(rpc_sysfs_xprt);
 
 static struct kobj_attribute rpc_sysfs_xprt_switch_info =
        __ATTR(xprt_switch_info, 0444, rpc_sysfs_xprt_switch_info_show, NULL);
@@ -430,6 +439,7 @@ static struct attribute *rpc_sysfs_xprt_switch_attrs[] = {
        &rpc_sysfs_xprt_switch_info.attr,
        NULL,
 };
+ATTRIBUTE_GROUPS(rpc_sysfs_xprt_switch);
 
 static struct kobj_type rpc_sysfs_client_type = {
        .release = rpc_sysfs_client_release,
@@ -439,14 +449,14 @@ static struct kobj_type rpc_sysfs_client_type = {
 
 static struct kobj_type rpc_sysfs_xprt_switch_type = {
        .release = rpc_sysfs_xprt_switch_release,
-       .default_attrs = rpc_sysfs_xprt_switch_attrs,
+       .default_groups = rpc_sysfs_xprt_switch_groups,
        .sysfs_ops = &kobj_sysfs_ops,
        .namespace = rpc_sysfs_xprt_switch_namespace,
 };
 
 static struct kobj_type rpc_sysfs_xprt_type = {
        .release = rpc_sysfs_xprt_release,
-       .default_attrs = rpc_sysfs_xprt_attrs,
+       .default_groups = rpc_sysfs_xprt_groups,
        .sysfs_ops = &kobj_sysfs_ops,
        .namespace = rpc_sysfs_xprt_namespace,
 };
index 17f174d..faba713 100644 (file)
 #include "xprt_rdma.h"
 #include <trace/events/rpcrdma.h>
 
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
-# define RPCDBG_FACILITY       RPCDBG_TRANS
-#endif
-
 #undef RPCRDMA_BACKCHANNEL_DEBUG
 
 /**
index ff69930..515dd7a 100644 (file)
 #include "xprt_rdma.h"
 #include <trace/events/rpcrdma.h>
 
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
-# define RPCDBG_FACILITY       RPCDBG_TRANS
-#endif
-
 static void frwr_cid_init(struct rpcrdma_ep *ep,
                          struct rpcrdma_mr *mr)
 {
index 8035a98..281ddb8 100644 (file)
 #include "xprt_rdma.h"
 #include <trace/events/rpcrdma.h>
 
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
-# define RPCDBG_FACILITY       RPCDBG_TRANS
-#endif
-
 /* Returns size of largest RPC-over-RDMA header in a Call message
  *
  * The largest Call header contains a full-size Read list and a
index 16e5696..42e375d 100644 (file)
 #include "xprt_rdma.h"
 #include <trace/events/rpcrdma.h>
 
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
-# define RPCDBG_FACILITY       RPCDBG_TRANS
-#endif
-
 /*
  * tunables
  */
index 3d3673b..7b5fce2 100644 (file)
 #include "xprt_rdma.h"
 #include <trace/events/rpcrdma.h>
 
-/*
- * Globals/Macros
- */
-
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
-# define RPCDBG_FACILITY       RPCDBG_TRANS
-#endif
-
-/*
- * internal functions
- */
 static int rpcrdma_sendctxs_create(struct rpcrdma_xprt *r_xprt);
 static void rpcrdma_sendctxs_destroy(struct rpcrdma_xprt *r_xprt);
 static void rpcrdma_sendctx_put_locked(struct rpcrdma_xprt *r_xprt,
@@ -274,8 +263,6 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
                ep->re_connect_status = -ENETUNREACH;
                goto wake_connect_worker;
        case RDMA_CM_EVENT_REJECTED:
-               dprintk("rpcrdma: connection to %pISpc rejected: %s\n",
-                       sap, rdma_reject_msg(id, event->status));
                ep->re_connect_status = -ECONNREFUSED;
                if (event->status == IB_CM_REJ_STALE_CONN)
                        ep->re_connect_status = -ENOTCONN;
@@ -291,8 +278,6 @@ disconnected:
                break;
        }
 
-       dprintk("RPC:       %s: %pISpc on %s/frwr: %s\n", __func__, sap,
-               ep->re_id->device->name, rdma_event_msg(event->event));
        return 0;
 }
 
@@ -419,14 +404,6 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
        ep->re_attr.qp_type = IB_QPT_RC;
        ep->re_attr.port_num = ~0;
 
-       dprintk("RPC:       %s: requested max: dtos: send %d recv %d; "
-               "iovs: send %d recv %d\n",
-               __func__,
-               ep->re_attr.cap.max_send_wr,
-               ep->re_attr.cap.max_recv_wr,
-               ep->re_attr.cap.max_send_sge,
-               ep->re_attr.cap.max_recv_sge);
-
        ep->re_send_batch = ep->re_max_requests >> 3;
        ep->re_send_count = ep->re_send_batch;
        init_waitqueue_head(&ep->re_connect_wait);
@@ -436,6 +413,7 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
                                              IB_POLL_WORKQUEUE);
        if (IS_ERR(ep->re_attr.send_cq)) {
                rc = PTR_ERR(ep->re_attr.send_cq);
+               ep->re_attr.send_cq = NULL;
                goto out_destroy;
        }
 
@@ -444,6 +422,7 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
                                              IB_POLL_WORKQUEUE);
        if (IS_ERR(ep->re_attr.recv_cq)) {
                rc = PTR_ERR(ep->re_attr.recv_cq);
+               ep->re_attr.recv_cq = NULL;
                goto out_destroy;
        }
        ep->re_receive_count = 0;
@@ -482,6 +461,7 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
        ep->re_pd = ib_alloc_pd(device, 0);
        if (IS_ERR(ep->re_pd)) {
                rc = PTR_ERR(ep->re_pd);
+               ep->re_pd = NULL;
                goto out_destroy;
        }
 
index d8ee06a..0f39e08 100644 (file)
@@ -1641,7 +1641,12 @@ static int xs_get_srcport(struct sock_xprt *transport)
 unsigned short get_srcport(struct rpc_xprt *xprt)
 {
        struct sock_xprt *sock = container_of(xprt, struct sock_xprt, xprt);
-       return xs_sock_getport(sock->sock);
+       unsigned short ret = 0;
+       mutex_lock(&sock->recv_mutex);
+       if (sock->sock)
+               ret = xs_sock_getport(sock->sock);
+       mutex_unlock(&sock->recv_mutex);
+       return ret;
 }
 EXPORT_SYMBOL(get_srcport);
 
@@ -1910,7 +1915,7 @@ static void xs_local_connect(struct rpc_xprt *xprt, struct rpc_task *task)
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
        int ret;
 
-        if (RPC_IS_ASYNC(task)) {
+       if (RPC_IS_ASYNC(task)) {
                /*
                 * We want the AF_LOCAL connect to be resolved in the
                 * filesystem namespace of the process making the rpc
index 9325479..f09316a 100644 (file)
@@ -2276,7 +2276,7 @@ static bool tipc_crypto_key_rcv(struct tipc_crypto *rx, struct tipc_msg *hdr)
        struct tipc_crypto *tx = tipc_net(rx->net)->crypto_tx;
        struct tipc_aead_key *skey = NULL;
        u16 key_gen = msg_key_gen(hdr);
-       u16 size = msg_data_sz(hdr);
+       u32 size = msg_data_sz(hdr);
        u8 *data = msg_data(hdr);
        unsigned int keylen;
 
index 8d9e09f..1e14d7f 100644 (file)
@@ -2200,7 +2200,7 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
        struct tipc_msg *hdr = buf_msg(skb);
        struct tipc_gap_ack_blks *ga = NULL;
        bool reply = msg_probe(hdr), retransmitted = false;
-       u16 dlen = msg_data_sz(hdr), glen = 0;
+       u32 dlen = msg_data_sz(hdr), glen = 0;
        u16 peers_snd_nxt =  msg_next_sent(hdr);
        u16 peers_tol = msg_link_tolerance(hdr);
        u16 peers_prio = msg_linkprio(hdr);
@@ -2214,6 +2214,10 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
        void *data;
 
        trace_tipc_proto_rcv(skb, false, l->name);
+
+       if (dlen > U16_MAX)
+               goto exit;
+
        if (tipc_link_is_blocked(l) || !xmitq)
                goto exit;
 
@@ -2309,7 +2313,8 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
 
                /* Receive Gap ACK blocks from peer if any */
                glen = tipc_get_gap_ack_blks(&ga, l, hdr, true);
-
+               if(glen > dlen)
+                       break;
                tipc_mon_rcv(l->net, data + glen, dlen - glen, l->addr,
                             &l->mon_state, l->bearer_id);
 
index 4076196..2f4d232 100644 (file)
@@ -496,6 +496,8 @@ void tipc_mon_rcv(struct net *net, void *data, u16 dlen, u32 addr,
        state->probing = false;
 
        /* Sanity check received domain record */
+       if (new_member_cnt > MAX_MON_DOMAIN)
+               return;
        if (dlen < dom_rec_len(arrv_dom, 0))
                return;
        if (dlen != dom_rec_len(arrv_dom, new_member_cnt))
index bda902c..8267b75 100644 (file)
@@ -313,7 +313,7 @@ static bool tipc_update_nametbl(struct net *net, struct distr_item *i,
                pr_warn_ratelimited("Failed to remove binding %u,%u from %u\n",
                                    ua.sr.type, ua.sr.lower, node);
        } else {
-               pr_warn("Unrecognized name table message received\n");
+               pr_warn_ratelimited("Unknown name table message received\n");
        }
        return false;
 }
index 01396dd..1d8ba23 100644 (file)
@@ -967,7 +967,7 @@ static int __tipc_nl_add_nametable_publ(struct tipc_nl_msg *msg,
                list_for_each_entry(p, &sr->all_publ, all_publ)
                        if (p->key == *last_key)
                                break;
-               if (p->key != *last_key)
+               if (list_entry_is_head(p, &sr->all_publ, all_publ))
                        return -EPIPE;
        } else {
                p = list_first_entry(&sr->all_publ,
index 9947b7d..6ef95ce 100644 (file)
@@ -403,7 +403,7 @@ static void tipc_node_write_unlock(struct tipc_node *n)
        u32 flags = n->action_flags;
        struct list_head *publ_list;
        struct tipc_uaddr ua;
-       u32 bearer_id;
+       u32 bearer_id, node;
 
        if (likely(!flags)) {
                write_unlock_bh(&n->lock);
@@ -413,7 +413,8 @@ static void tipc_node_write_unlock(struct tipc_node *n)
        tipc_uaddr(&ua, TIPC_SERVICE_RANGE, TIPC_NODE_SCOPE,
                   TIPC_LINK_STATE, n->addr, n->addr);
        sk.ref = n->link_id;
-       sk.node = n->addr;
+       sk.node = tipc_own_addr(net);
+       node = n->addr;
        bearer_id = n->link_id & 0xffff;
        publ_list = &n->publ_list;
 
@@ -423,17 +424,17 @@ static void tipc_node_write_unlock(struct tipc_node *n)
        write_unlock_bh(&n->lock);
 
        if (flags & TIPC_NOTIFY_NODE_DOWN)
-               tipc_publ_notify(net, publ_list, sk.node, n->capabilities);
+               tipc_publ_notify(net, publ_list, node, n->capabilities);
 
        if (flags & TIPC_NOTIFY_NODE_UP)
-               tipc_named_node_up(net, sk.node, n->capabilities);
+               tipc_named_node_up(net, node, n->capabilities);
 
        if (flags & TIPC_NOTIFY_LINK_UP) {
-               tipc_mon_peer_up(net, sk.node, bearer_id);
+               tipc_mon_peer_up(net, node, bearer_id);
                tipc_nametbl_publish(net, &ua, &sk, sk.ref);
        }
        if (flags & TIPC_NOTIFY_LINK_DOWN) {
-               tipc_mon_peer_down(net, sk.node, bearer_id);
+               tipc_mon_peer_down(net, node, bearer_id);
                tipc_nametbl_withdraw(net, &ua, &sk, sk.ref);
        }
 }
index 3e63c83..7545321 100644 (file)
@@ -3749,7 +3749,7 @@ static int __tipc_nl_list_sk_publ(struct sk_buff *skb,
                        if (p->key == *last_publ)
                                break;
                }
-               if (p->key != *last_publ) {
+               if (list_entry_is_head(p, &tsk->publications, binding_sock)) {
                        /* We never set seq or call nl_dump_check_consistent()
                         * this means that setting prev_seq here will cause the
                         * consistence check to fail in the netlink callback
index 3235261..38baeb1 100644 (file)
@@ -1401,6 +1401,7 @@ static int vsock_connect(struct socket *sock, struct sockaddr *addr,
                        sk->sk_state = sk->sk_state == TCP_ESTABLISHED ? TCP_CLOSING : TCP_CLOSE;
                        sock->state = SS_UNCONNECTED;
                        vsock_transport_cancel_pkt(vsk);
+                       vsock_remove_connected(vsk);
                        goto out_wait;
                } else if (timeout == 0) {
                        err = -ETIMEDOUT;
index 3a54c8e..f08d4b3 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2006-2010         Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2021 Intel Corporation
+ * Copyright (C) 2018-2022 Intel Corporation
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -332,29 +332,20 @@ static void cfg80211_event_work(struct work_struct *work)
 void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev)
 {
        struct wireless_dev *wdev, *tmp;
-       bool found = false;
 
        ASSERT_RTNL();
 
-       list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
+       list_for_each_entry_safe(wdev, tmp, &rdev->wiphy.wdev_list, list) {
                if (wdev->nl_owner_dead) {
                        if (wdev->netdev)
                                dev_close(wdev->netdev);
-                       found = true;
-               }
-       }
-
-       if (!found)
-               return;
 
-       wiphy_lock(&rdev->wiphy);
-       list_for_each_entry_safe(wdev, tmp, &rdev->wiphy.wdev_list, list) {
-               if (wdev->nl_owner_dead) {
+                       wiphy_lock(&rdev->wiphy);
                        cfg80211_leave(rdev, wdev);
                        rdev_del_virtual_intf(rdev, wdev);
+                       wiphy_unlock(&rdev->wiphy);
                }
        }
-       wiphy_unlock(&rdev->wiphy);
 }
 
 static void cfg80211_destroy_iface_wk(struct work_struct *work)
index cc0648e..4bca4b7 100644 (file)
@@ -25,7 +25,7 @@
 #include <sys/prctl.h>
 #include <unistd.h>
 
-static int install_filter(int nr, int arch, int error)
+static int install_filter(int arch, int nr, int error)
 {
        struct sock_filter filter[] = {
                BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
@@ -42,6 +42,10 @@ static int install_filter(int nr, int arch, int error)
                .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])),
                .filter = filter,
        };
+       if (error == -1) {
+               struct sock_filter kill = BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL);
+               filter[4] = kill;
+       }
        if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
                perror("prctl(NO_NEW_PRIVS)");
                return 1;
@@ -57,9 +61,10 @@ int main(int argc, char **argv)
 {
        if (argc < 5) {
                fprintf(stderr, "Usage:\n"
-                       "dropper <syscall_nr> <arch> <errno> <prog> [<args>]\n"
+                       "dropper <arch> <syscall_nr> <errno> <prog> [<args>]\n"
                        "Hint:  AUDIT_ARCH_I386: 0x%X\n"
                        "       AUDIT_ARCH_X86_64: 0x%X\n"
+                       "       errno == -1 means SECCOMP_RET_KILL\n"
                        "\n", AUDIT_ARCH_I386, AUDIT_ARCH_X86_64);
                return 1;
        }
index ecd3aca..ce5aa90 100644 (file)
@@ -25,7 +25,7 @@ HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/x86/include
 HOSTCFLAGS_sorttable.o += -DUNWINDER_ORC_ENABLED
 endif
 
-ifdef CONFIG_DYNAMIC_FTRACE
+ifdef CONFIG_BUILDTIME_MCOUNT_SORT
 HOSTCFLAGS_sorttable.o += -DMCOUNT_SORT_ENABLED
 endif
 
index d538255..8be8928 100644 (file)
@@ -51,6 +51,7 @@ KBUILD_CFLAGS += -Wno-sign-compare
 KBUILD_CFLAGS += -Wno-format-zero-length
 KBUILD_CFLAGS += $(call cc-disable-warning, pointer-to-enum-cast)
 KBUILD_CFLAGS += -Wno-tautological-constant-out-of-range-compare
+KBUILD_CFLAGS += $(call cc-disable-warning, unaligned-access)
 endif
 
 endif
index 59717be..d3c3a61 100644 (file)
@@ -979,10 +979,10 @@ static int conf_write_autoconf_cmd(const char *autoconf_name)
 
        fprintf(out, "\n$(deps_config): ;\n");
 
-       if (ferror(out)) /* error check for all fprintf() calls */
-               return -1;
-
+       ret = ferror(out); /* error check for all fprintf() calls */
        fclose(out);
+       if (ret)
+               return -1;
 
        if (rename(tmp, name)) {
                perror("rename");
@@ -994,14 +994,19 @@ static int conf_write_autoconf_cmd(const char *autoconf_name)
 
 static int conf_touch_deps(void)
 {
-       const char *name;
+       const char *name, *tmp;
        struct symbol *sym;
        int res, i;
 
-       strcpy(depfile_path, "include/config/");
-       depfile_prefix_len = strlen(depfile_path);
-
        name = conf_get_autoconfig_name();
+       tmp = strrchr(name, '/');
+       depfile_prefix_len = tmp ? tmp - name + 1 : 0;
+       if (depfile_prefix_len + 1 > sizeof(depfile_path))
+               return -1;
+
+       strncpy(depfile_path, name, depfile_prefix_len);
+       depfile_path[depfile_prefix_len] = 0;
+
        conf_read_simple(name, S_DEF_AUTO);
        sym_calc_value(modules_sym);
 
@@ -1093,10 +1098,10 @@ static int __conf_write_autoconf(const char *filename,
                        print_symbol(file, sym);
 
        /* check possible errors in conf_write_heading() and print_symbol() */
-       if (ferror(file))
-               return -1;
-
+       ret = ferror(file);
        fclose(file);
+       if (ret)
+               return -1;
 
        if (rename(tmp, filename)) {
                perror("rename");
index 0590f86..748da57 100644 (file)
@@ -141,7 +141,7 @@ static char *do_lineno(int argc, char *argv[])
 static char *do_shell(int argc, char *argv[])
 {
        FILE *p;
-       char buf[256];
+       char buf[4096];
        char *cmd;
        size_t nread;
        int i;
index 23240d7..895f4b9 100644 (file)
@@ -109,22 +109,25 @@ int asymmetric_verify(struct key *keyring, const char *sig,
 
        pk = asymmetric_key_public_key(key);
        pks.pkey_algo = pk->pkey_algo;
-       if (!strcmp(pk->pkey_algo, "rsa"))
+       if (!strcmp(pk->pkey_algo, "rsa")) {
                pks.encoding = "pkcs1";
-       else if (!strncmp(pk->pkey_algo, "ecdsa-", 6))
+       } else if (!strncmp(pk->pkey_algo, "ecdsa-", 6)) {
                /* edcsa-nist-p192 etc. */
                pks.encoding = "x962";
-       else if (!strcmp(pk->pkey_algo, "ecrdsa") ||
-                  !strcmp(pk->pkey_algo, "sm2"))
+       else if (!strcmp(pk->pkey_algo, "ecrdsa") ||
+                  !strcmp(pk->pkey_algo, "sm2")) {
                pks.encoding = "raw";
-       else
-               return -ENOPKG;
+       } else {
+               ret = -ENOPKG;
+               goto out;
+       }
 
        pks.digest = (u8 *)data;
        pks.digest_size = datalen;
        pks.s = hdr->sig;
        pks.s_size = siglen;
        ret = verify_signature(key, &pks);
+out:
        key_put(key);
        pr_debug("%s() = %d\n", __func__, ret);
        return ret;
index 3d8e9d5..3ad8f77 100644 (file)
@@ -496,12 +496,12 @@ int __init ima_fs_init(void)
 
        return 0;
 out:
+       securityfs_remove(ima_policy);
        securityfs_remove(violations);
        securityfs_remove(runtime_measurements_count);
        securityfs_remove(ascii_runtime_measurements);
        securityfs_remove(binary_runtime_measurements);
        securityfs_remove(ima_symlink);
        securityfs_remove(ima_dir);
-       securityfs_remove(ima_policy);
        return -1;
 }
index 320ca80..2a1f641 100644 (file)
@@ -1967,6 +1967,14 @@ int ima_policy_show(struct seq_file *m, void *v)
 
        rcu_read_lock();
 
+       /* Do not print rules with inactive LSM labels */
+       for (i = 0; i < MAX_LSM_RULES; i++) {
+               if (entry->lsm[i].args_p && !entry->lsm[i].rule) {
+                       rcu_read_unlock();
+                       return 0;
+               }
+       }
+
        if (entry->action & MEASURE)
                seq_puts(m, pt(Opt_measure));
        if (entry->action & DONT_MEASURE)
index 6945603..db1ad6d 100644 (file)
@@ -29,6 +29,7 @@ static struct ima_template_desc builtin_templates[] = {
 
 static LIST_HEAD(defined_templates);
 static DEFINE_SPINLOCK(template_list);
+static int template_setup_done;
 
 static const struct ima_template_field supported_fields[] = {
        {.field_id = "d", .field_init = ima_eventdigest_init,
@@ -101,10 +102,11 @@ static int __init ima_template_setup(char *str)
        struct ima_template_desc *template_desc;
        int template_len = strlen(str);
 
-       if (ima_template)
+       if (template_setup_done)
                return 1;
 
-       ima_init_template_list();
+       if (!ima_template)
+               ima_init_template_list();
 
        /*
         * Verify that a template with the supplied name exists.
@@ -128,6 +130,7 @@ static int __init ima_template_setup(char *str)
        }
 
        ima_template = template_desc;
+       template_setup_done = 1;
        return 1;
 }
 __setup("ima_template=", ima_template_setup);
@@ -136,7 +139,7 @@ static int __init ima_template_fmt_setup(char *str)
 {
        int num_templates = ARRAY_SIZE(builtin_templates);
 
-       if (ima_template)
+       if (template_setup_done)
                return 1;
 
        if (template_desc_init_fields(str, NULL, NULL) < 0) {
@@ -147,6 +150,7 @@ static int __init ima_template_fmt_setup(char *str)
 
        builtin_templates[num_templates - 1].fmt = str;
        ima_template = builtin_templates + num_templates - 1;
+       template_setup_done = 1;
 
        return 1;
 }
index 2922005..0ec5e4c 100644 (file)
@@ -45,6 +45,8 @@ void integrity_audit_message(int audit_msgno, struct inode *inode,
                return;
 
        ab = audit_log_start(audit_context(), GFP_KERNEL, audit_msgno);
+       if (!ab)
+               return;
        audit_log_format(ab, "pid=%d uid=%u auid=%u ses=%u",
                         task_pid_nr(current),
                         from_kuid(&init_user_ns, current_uid()),
index 3d4eb47..22261d7 100644 (file)
@@ -1048,8 +1048,19 @@ int security_dentry_init_security(struct dentry *dentry, int mode,
                                  const char **xattr_name, void **ctx,
                                  u32 *ctxlen)
 {
-       return call_int_hook(dentry_init_security, -EOPNOTSUPP, dentry, mode,
-                               name, xattr_name, ctx, ctxlen);
+       struct security_hook_list *hp;
+       int rc;
+
+       /*
+        * Only one module will provide a security context.
+        */
+       hlist_for_each_entry(hp, &security_hook_heads.dentry_init_security, list) {
+               rc = hp->hook.dentry_init_security(dentry, mode, name,
+                                                  xattr_name, ctx, ctxlen);
+               if (rc != LSM_RET_DEFAULT(dentry_init_security))
+                       return rc;
+       }
+       return LSM_RET_DEFAULT(dentry_init_security);
 }
 EXPORT_SYMBOL(security_dentry_init_security);
 
index 727c4e4..ff7aea6 100644 (file)
@@ -77,7 +77,7 @@ void selinux_ima_measure_state_locked(struct selinux_state *state)
        size_t policy_len;
        int rc = 0;
 
-       WARN_ON(!mutex_is_locked(&state->policy_mutex));
+       lockdep_assert_held(&state->policy_mutex);
 
        state_str = selinux_ima_collect_state(state);
        if (!state_str) {
@@ -117,7 +117,7 @@ void selinux_ima_measure_state_locked(struct selinux_state *state)
  */
 void selinux_ima_measure_state(struct selinux_state *state)
 {
-       WARN_ON(mutex_is_locked(&state->policy_mutex));
+       lockdep_assert_not_held(&state->policy_mutex);
 
        mutex_lock(&state->policy_mutex);
        selinux_ima_measure_state_locked(state);
index 2ec6e5c..feb206f 100644 (file)
@@ -152,6 +152,8 @@ static void cond_list_destroy(struct policydb *p)
        for (i = 0; i < p->cond_list_len; i++)
                cond_node_destroy(&p->cond_list[i]);
        kfree(p->cond_list);
+       p->cond_list = NULL;
+       p->cond_list_len = 0;
 }
 
 void cond_policydb_destroy(struct policydb *p)
@@ -441,7 +443,6 @@ int cond_read_list(struct policydb *p, void *fp)
        return 0;
 err:
        cond_list_destroy(p);
-       p->cond_list = NULL;
        return rc;
 }
 
index d1fcd1d..6fd763d 100644 (file)
@@ -511,7 +511,8 @@ static void *snd_dma_noncontig_alloc(struct snd_dma_buffer *dmab, size_t size)
                                      DEFAULT_GFP, 0);
        if (!sgt)
                return NULL;
-       dmab->dev.need_sync = dma_need_sync(dmab->dev.dev, dmab->dev.dir);
+       dmab->dev.need_sync = dma_need_sync(dmab->dev.dev,
+                                           sg_dma_address(sgt->sgl));
        p = dma_vmap_noncontiguous(dmab->dev.dev, size, sgt);
        if (p)
                dmab->private_data = sgt;
@@ -540,9 +541,9 @@ static void snd_dma_noncontig_sync(struct snd_dma_buffer *dmab,
        if (mode == SNDRV_DMA_SYNC_CPU) {
                if (dmab->dev.dir == DMA_TO_DEVICE)
                        return;
+               invalidate_kernel_vmap_range(dmab->area, dmab->bytes);
                dma_sync_sgtable_for_cpu(dmab->dev.dev, dmab->private_data,
                                         dmab->dev.dir);
-               invalidate_kernel_vmap_range(dmab->area, dmab->bytes);
        } else {
                if (dmab->dev.dir == DMA_FROM_DEVICE)
                        return;
@@ -671,9 +672,13 @@ static const struct snd_malloc_ops snd_dma_sg_wc_ops = {
  */
 static void *snd_dma_noncoherent_alloc(struct snd_dma_buffer *dmab, size_t size)
 {
-       dmab->dev.need_sync = dma_need_sync(dmab->dev.dev, dmab->dev.dir);
-       return dma_alloc_noncoherent(dmab->dev.dev, size, &dmab->addr,
-                                    dmab->dev.dir, DEFAULT_GFP);
+       void *p;
+
+       p = dma_alloc_noncoherent(dmab->dev.dev, size, &dmab->addr,
+                                 dmab->dev.dir, DEFAULT_GFP);
+       if (p)
+               dmab->dev.need_sync = dma_need_sync(dmab->dev.dev, dmab->addr);
+       return p;
 }
 
 static void snd_dma_noncoherent_free(struct snd_dma_buffer *dmab)
index 621883e..a056b3e 100644 (file)
@@ -172,6 +172,19 @@ unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream)
 }
 EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave);
 
+unsigned long _snd_pcm_stream_lock_irqsave_nested(struct snd_pcm_substream *substream)
+{
+       unsigned long flags = 0;
+       if (substream->pcm->nonatomic)
+               mutex_lock_nested(&substream->self_group.mutex,
+                                 SINGLE_DEPTH_NESTING);
+       else
+               spin_lock_irqsave_nested(&substream->self_group.lock, flags,
+                                        SINGLE_DEPTH_NESTING);
+       return flags;
+}
+EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave_nested);
+
 /**
  * snd_pcm_stream_unlock_irqrestore - Unlock the PCM stream
  * @substream: PCM substream
index b7758db..5cb92f7 100644 (file)
@@ -50,11 +50,11 @@ static bool is_link_enabled(struct fwnode_handle *fw_node, int i)
 static int
 sdw_intel_scan_controller(struct sdw_intel_acpi_info *info)
 {
-       struct acpi_device *adev;
+       struct acpi_device *adev = acpi_fetch_acpi_dev(info->handle);
        int ret, i;
        u8 count;
 
-       if (acpi_bus_get_device(info->handle, &adev))
+       if (!adev)
                return -EINVAL;
 
        /* Found controller, find links supported */
@@ -119,7 +119,6 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
                                     void *cdata, void **return_value)
 {
        struct sdw_intel_acpi_info *info = cdata;
-       struct acpi_device *adev;
        acpi_status status;
        u64 adr;
 
@@ -127,7 +126,7 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
        if (ACPI_FAILURE(status))
                return AE_OK; /* keep going */
 
-       if (acpi_bus_get_device(handle, &adev)) {
+       if (!acpi_fetch_acpi_dev(handle)) {
                pr_err("%s: Couldn't find ACPI handle\n", __func__);
                return AE_NOT_FOUND;
        }
index 82c492b..cd1db94 100644 (file)
@@ -981,7 +981,7 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
        int id = HDA_FIXUP_ID_NOT_SET;
        const char *name = NULL;
        const char *type = NULL;
-       int vendor, device;
+       unsigned int vendor, device;
 
        if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET)
                return;
index 7016b48..f552785 100644 (file)
@@ -3000,6 +3000,10 @@ void snd_hda_codec_shutdown(struct hda_codec *codec)
 {
        struct hda_pcm *cpcm;
 
+       /* Skip the shutdown if codec is not registered */
+       if (!codec->registered)
+               return;
+
        list_for_each_entry(cpcm, &codec->pcm_list_head, list)
                snd_pcm_suspend_all(cpcm->pcm);
 
index 3bf5e34..fc114e5 100644 (file)
@@ -91,6 +91,12 @@ static void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
        free_kctls(spec);
        snd_array_free(&spec->paths);
        snd_array_free(&spec->loopback_list);
+#ifdef CONFIG_SND_HDA_GENERIC_LEDS
+       if (spec->led_cdevs[LED_AUDIO_MUTE])
+               led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MUTE]);
+       if (spec->led_cdevs[LED_AUDIO_MICMUTE])
+               led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MICMUTE]);
+#endif
 }
 
 /*
@@ -3922,7 +3928,10 @@ static int create_mute_led_cdev(struct hda_codec *codec,
                                                enum led_brightness),
                                bool micmute)
 {
+       struct hda_gen_spec *spec = codec->spec;
        struct led_classdev *cdev;
+       int idx = micmute ? LED_AUDIO_MICMUTE : LED_AUDIO_MUTE;
+       int err;
 
        cdev = devm_kzalloc(&codec->core.dev, sizeof(*cdev), GFP_KERNEL);
        if (!cdev)
@@ -3932,10 +3941,14 @@ static int create_mute_led_cdev(struct hda_codec *codec,
        cdev->max_brightness = 1;
        cdev->default_trigger = micmute ? "audio-micmute" : "audio-mute";
        cdev->brightness_set_blocking = callback;
-       cdev->brightness = ledtrig_audio_get(micmute ? LED_AUDIO_MICMUTE : LED_AUDIO_MUTE);
+       cdev->brightness = ledtrig_audio_get(idx);
        cdev->flags = LED_CORE_SUSPENDRESUME;
 
-       return devm_led_classdev_register(&codec->core.dev, cdev);
+       err = led_classdev_register(&codec->core.dev, cdev);
+       if (err < 0)
+               return err;
+       spec->led_cdevs[idx] = cdev;
+       return 0;
 }
 
 /**
index 8e1bc8e..34eba40 100644 (file)
@@ -294,6 +294,9 @@ struct hda_gen_spec {
                                   struct hda_jack_callback *cb);
        void (*mic_autoswitch_hook)(struct hda_codec *codec,
                                    struct hda_jack_callback *cb);
+
+       /* leds */
+       struct led_classdev *led_cdevs[NUM_AUDIO_LEDS];
 };
 
 /* values for add_stereo_mix_input flag */
index 4b0338c..572ff0d 100644 (file)
@@ -1615,6 +1615,7 @@ static const struct snd_pci_quirk probe_mask_list[] = {
        /* forced codec slots */
        SND_PCI_QUIRK(0x1043, 0x1262, "ASUS W5Fm", 0x103),
        SND_PCI_QUIRK(0x1046, 0x1262, "ASUS W5F", 0x103),
+       SND_PCI_QUIRK(0x1558, 0x0351, "Schenker Dock 15", 0x105),
        /* WinFast VP200 H (Teradici) user reported broken communication */
        SND_PCI_QUIRK(0x3a21, 0x040d, "WinFast VP200 H", 0x101),
        {}
@@ -1798,8 +1799,6 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
 
        assign_position_fix(chip, check_position_fix(chip, position_fix[dev]));
 
-       check_probe_mask(chip, dev);
-
        if (single_cmd < 0) /* allow fallback to single_cmd at errors */
                chip->fallback_to_single_cmd = 1;
        else /* explicitly set to single_cmd or not */
@@ -1825,6 +1824,8 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
                chip->bus.core.needs_damn_long_delay = 1;
        }
 
+       check_probe_mask(chip, dev);
+
        err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
        if (err < 0) {
                dev_err(card->dev, "Error creating device [card]!\n");
@@ -1940,6 +1941,7 @@ static int azx_first_init(struct azx *chip)
                dma_bits = 32;
        if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(dma_bits)))
                dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32));
+       dma_set_max_seg_size(&pci->dev, UINT_MAX);
 
        /* read number of streams from GCAP register instead of using
         * hardcoded value
index 668274e..3a42457 100644 (file)
@@ -98,6 +98,7 @@ struct alc_spec {
        unsigned int gpio_mic_led_mask;
        struct alc_coef_led mute_led_coef;
        struct alc_coef_led mic_led_coef;
+       struct mutex coef_mutex;
 
        hda_nid_t headset_mic_pin;
        hda_nid_t headphone_mic_pin;
@@ -137,8 +138,24 @@ struct alc_spec {
  * COEF access helper functions
  */
 
-static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-                              unsigned int coef_idx)
+static void coef_mutex_lock(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       snd_hda_power_up_pm(codec);
+       mutex_lock(&spec->coef_mutex);
+}
+
+static void coef_mutex_unlock(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       mutex_unlock(&spec->coef_mutex);
+       snd_hda_power_down_pm(codec);
+}
+
+static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                unsigned int coef_idx)
 {
        unsigned int val;
 
@@ -147,28 +164,56 @@ static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
        return val;
 }
 
+static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                              unsigned int coef_idx)
+{
+       unsigned int val;
+
+       coef_mutex_lock(codec);
+       val = __alc_read_coefex_idx(codec, nid, coef_idx);
+       coef_mutex_unlock(codec);
+       return val;
+}
+
 #define alc_read_coef_idx(codec, coef_idx) \
        alc_read_coefex_idx(codec, 0x20, coef_idx)
 
-static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-                                unsigned int coef_idx, unsigned int coef_val)
+static void __alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                  unsigned int coef_idx, unsigned int coef_val)
 {
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val);
 }
 
+static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                unsigned int coef_idx, unsigned int coef_val)
+{
+       coef_mutex_lock(codec);
+       __alc_write_coefex_idx(codec, nid, coef_idx, coef_val);
+       coef_mutex_unlock(codec);
+}
+
 #define alc_write_coef_idx(codec, coef_idx, coef_val) \
        alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val)
 
+static void __alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                   unsigned int coef_idx, unsigned int mask,
+                                   unsigned int bits_set)
+{
+       unsigned int val = __alc_read_coefex_idx(codec, nid, coef_idx);
+
+       if (val != -1)
+               __alc_write_coefex_idx(codec, nid, coef_idx,
+                                      (val & ~mask) | bits_set);
+}
+
 static void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
                                  unsigned int coef_idx, unsigned int mask,
                                  unsigned int bits_set)
 {
-       unsigned int val = alc_read_coefex_idx(codec, nid, coef_idx);
-
-       if (val != -1)
-               alc_write_coefex_idx(codec, nid, coef_idx,
-                                    (val & ~mask) | bits_set);
+       coef_mutex_lock(codec);
+       __alc_update_coefex_idx(codec, nid, coef_idx, mask, bits_set);
+       coef_mutex_unlock(codec);
 }
 
 #define alc_update_coef_idx(codec, coef_idx, mask, bits_set)   \
@@ -201,13 +246,15 @@ struct coef_fw {
 static void alc_process_coef_fw(struct hda_codec *codec,
                                const struct coef_fw *fw)
 {
+       coef_mutex_lock(codec);
        for (; fw->nid; fw++) {
                if (fw->mask == (unsigned short)-1)
-                       alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
+                       __alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
                else
-                       alc_update_coefex_idx(codec, fw->nid, fw->idx,
-                                             fw->mask, fw->val);
+                       __alc_update_coefex_idx(codec, fw->nid, fw->idx,
+                                               fw->mask, fw->val);
        }
+       coef_mutex_unlock(codec);
 }
 
 /*
@@ -1153,6 +1200,7 @@ static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
        codec->spdif_status_reset = 1;
        codec->forced_resume = 1;
        codec->patch_ops = alc_patch_ops;
+       mutex_init(&spec->coef_mutex);
 
        err = alc_codec_rename_from_preset(codec);
        if (err < 0) {
@@ -2125,6 +2173,7 @@ static void alc1220_fixup_gb_x570(struct hda_codec *codec,
 {
        static const hda_nid_t conn1[] = { 0x0c };
        static const struct coef_fw gb_x570_coefs[] = {
+               WRITE_COEF(0x07, 0x03c0),
                WRITE_COEF(0x1a, 0x01c1),
                WRITE_COEF(0x1b, 0x0202),
                WRITE_COEF(0x43, 0x3005),
@@ -2551,7 +2600,8 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
        SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
        SND_PCI_QUIRK(0x1458, 0xa0cd, "Gigabyte X570 Aorus Master", ALC1220_FIXUP_GB_X570),
-       SND_PCI_QUIRK(0x1458, 0xa0ce, "Gigabyte X570 Aorus Xtreme", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1458, 0xa0ce, "Gigabyte X570 Aorus Xtreme", ALC1220_FIXUP_GB_X570),
+       SND_PCI_QUIRK(0x1458, 0xa0d5, "Gigabyte X570S Aorus Master", ALC1220_FIXUP_GB_X570),
        SND_PCI_QUIRK(0x1462, 0x11f7, "MSI-GE63", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1228, "MSI-GP63", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1229, "MSI-GP73", ALC1220_FIXUP_CLEVO_P950),
@@ -2626,6 +2676,7 @@ static const struct hda_model_fixup alc882_fixup_models[] = {
        {.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"},
        {.id = ALC887_FIXUP_ASUS_BASS, .name = "asus-bass"},
        {.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"},
+       {.id = ALC1220_FIXUP_GB_X570, .name = "gb-x570"},
        {.id = ALC1220_FIXUP_CLEVO_P950, .name = "clevo-p950"},
        {}
 };
@@ -8969,6 +9020,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1e51, "ASUS Zephyrus M15", ALC294_FIXUP_ASUS_GU502_PINS),
        SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401),
        SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401),
+       SND_PCI_QUIRK(0x1043, 0x16b2, "ASUS GU603", ALC289_FIXUP_ASUS_GA401),
        SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2),
        SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
@@ -9127,6 +9179,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x3824, "Legion Y9000X 2020", ALC285_FIXUP_LEGION_Y9000X_SPEAKERS),
        SND_PCI_QUIRK(0x17aa, 0x3827, "Ideapad S740", ALC285_FIXUP_IDEAPAD_S740_COEF),
        SND_PCI_QUIRK(0x17aa, 0x3834, "Lenovo IdeaPad Slim 9i 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
+       SND_PCI_QUIRK(0x17aa, 0x383d, "Legion Y9000X 2019", ALC285_FIXUP_LEGION_Y9000X_SPEAKERS),
        SND_PCI_QUIRK(0x17aa, 0x3843, "Yoga 9i", ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP),
        SND_PCI_QUIRK(0x17aa, 0x3847, "Legion 7 16ACHG6", ALC287_FIXUP_LEGION_16ACHG6),
        SND_PCI_QUIRK(0x17aa, 0x384a, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
index c9caade..cd05ee2 100644 (file)
@@ -303,11 +303,11 @@ static const struct snd_soc_dapm_route rt1019_map_lr[] = {
 
 static struct snd_soc_codec_conf rt1019_conf[] = {
        {
-                .dlc = COMP_CODEC_CONF("i2c-10EC1019:00"),
+                .dlc = COMP_CODEC_CONF("i2c-10EC1019:01"),
                 .name_prefix = "Left",
        },
        {
-                .dlc = COMP_CODEC_CONF("i2c-10EC1019:01"),
+                .dlc = COMP_CODEC_CONF("i2c-10EC1019:00"),
                 .name_prefix = "Right",
        },
 };
index fd62998..c855f50 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/gpio/consumer.h>
 
 #define EN_SPKR_GPIO_GB                0x11F
-#define EN_SPKR_GPIO_NK                0x146
 #define EN_SPKR_GPIO_NONE      -EINVAL
 
 enum be_id {
index 07de461..4cc431e 100644 (file)
@@ -37,7 +37,7 @@ static struct acp_card_drvdata sof_rt5682_max_data = {
        .hs_codec_id = RT5682,
        .amp_codec_id = MAX98360A,
        .dmic_codec_id = DMIC,
-       .gpio_spkr_en = EN_SPKR_GPIO_NK,
+       .gpio_spkr_en = EN_SPKR_GPIO_NONE,
 };
 
 static struct acp_card_drvdata sof_rt5682s_max_data = {
@@ -47,7 +47,7 @@ static struct acp_card_drvdata sof_rt5682s_max_data = {
        .hs_codec_id = RT5682S,
        .amp_codec_id = MAX98360A,
        .dmic_codec_id = DMIC,
-       .gpio_spkr_en = EN_SPKR_GPIO_NK,
+       .gpio_spkr_en = EN_SPKR_GPIO_NONE,
 };
 
 static const struct snd_kcontrol_new acp_controls[] = {
index 598e090..ffdf8b6 100644 (file)
@@ -1667,6 +1667,8 @@ static int cpcap_codec_probe(struct platform_device *pdev)
 {
        struct device_node *codec_node =
                of_get_child_by_name(pdev->dev.parent->of_node, "audio-codec");
+       if (!codec_node)
+               return -ENODEV;
 
        pdev->dev.of_node = codec_node;
 
index b61f980..b07607a 100644 (file)
@@ -277,7 +277,7 @@ struct hdmi_codec_priv {
        bool busy;
        struct snd_soc_jack *jack;
        unsigned int jack_status;
-       u8 iec_status[5];
+       u8 iec_status[AES_IEC958_STATUS_SIZE];
 };
 
 static const struct snd_soc_dapm_widget hdmi_widgets[] = {
index aec5127..6ffe883 100644 (file)
@@ -2688,8 +2688,8 @@ static uint32_t get_iir_band_coeff(struct snd_soc_component *component,
        int reg, b2_reg;
 
        /* Address does not automatically update if reading */
-       reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx;
-       b2_reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx;
+       reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx;
+       b2_reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx;
 
        snd_soc_component_write(component, reg,
                                ((band_idx * BAND_MAX + coeff_idx) *
@@ -2718,7 +2718,7 @@ static uint32_t get_iir_band_coeff(struct snd_soc_component *component,
 static void set_iir_band_coeff(struct snd_soc_component *component,
                               int iir_idx, int band_idx, uint32_t value)
 {
-       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx;
+       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx;
 
        snd_soc_component_write(component, reg, (value & 0xFF));
        snd_soc_component_write(component, reg, (value >> 8) & 0xFF);
@@ -2739,7 +2739,7 @@ static int rx_macro_put_iir_band_audio_mixer(
        int iir_idx = ctl->iir_idx;
        int band_idx = ctl->band_idx;
        u32 coeff[BAND_MAX];
-       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx;
+       int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx;
 
        memcpy(&coeff[0], ucontrol->value.bytes.data, params->max);
 
index d75fd61..bc57d76 100644 (file)
@@ -64,7 +64,8 @@ static int speaker_gain_control_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
        struct max9759 *priv = snd_soc_component_get_drvdata(c);
 
-       if (ucontrol->value.integer.value[0] > 3)
+       if (ucontrol->value.integer.value[0] < 0 ||
+           ucontrol->value.integer.value[0] > 3)
                return -EINVAL;
 
        priv->gain = ucontrol->value.integer.value[0];
index fb09715..5b12cbf 100644 (file)
@@ -1022,11 +1022,13 @@ static void rt5668_jack_detect_handler(struct work_struct *work)
                container_of(work, struct rt5668_priv, jack_detect_work.work);
        int val, btn_type;
 
-       while (!rt5668->component)
-               usleep_range(10000, 15000);
-
-       while (!rt5668->component->card->instantiated)
-               usleep_range(10000, 15000);
+       if (!rt5668->component || !rt5668->component->card ||
+           !rt5668->component->card->instantiated) {
+               /* card not yet ready, try later */
+               mod_delayed_work(system_power_efficient_wq,
+                                &rt5668->jack_detect_work, msecs_to_jiffies(15));
+               return;
+       }
 
        mutex_lock(&rt5668->calibrate_mutex);
 
index 20e0f90..20fc0f3 100644 (file)
@@ -59,18 +59,12 @@ static void rt5682_jd_check_handler(struct work_struct *work)
        struct rt5682_priv *rt5682 = container_of(work, struct rt5682_priv,
                jd_check_work.work);
 
-       if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL)
-               & RT5682_JDH_RS_MASK) {
+       if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL) & RT5682_JDH_RS_MASK)
                /* jack out */
-               rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0);
-
-               snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
-                       SND_JACK_HEADSET |
-                       SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                       SND_JACK_BTN_2 | SND_JACK_BTN_3);
-       } else {
+               mod_delayed_work(system_power_efficient_wq,
+                                &rt5682->jack_detect_work, 0);
+       else
                schedule_delayed_work(&rt5682->jd_check_work, 500);
-       }
 }
 
 static irqreturn_t rt5682_irq(int irq, void *data)
@@ -198,7 +192,6 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
        }
 
        mutex_init(&rt5682->calibrate_mutex);
-       mutex_init(&rt5682->jdet_mutex);
        rt5682_calibrate(rt5682);
 
        rt5682_apply_patch_list(rt5682, &i2c->dev);
index 415ec56..be68d57 100644 (file)
@@ -922,15 +922,13 @@ static void rt5682_enable_push_button_irq(struct snd_soc_component *component,
  *
  * Returns detect status.
  */
-int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
+static int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
 {
        struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
        struct snd_soc_dapm_context *dapm = &component->dapm;
        unsigned int val, count;
 
        if (jack_insert) {
-               snd_soc_dapm_mutex_lock(dapm);
-
                snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1,
                        RT5682_PWR_VREF2 | RT5682_PWR_MB,
                        RT5682_PWR_VREF2 | RT5682_PWR_MB);
@@ -981,8 +979,6 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
                snd_soc_component_update_bits(component, RT5682_MICBIAS_2,
                        RT5682_PWR_CLK25M_MASK | RT5682_PWR_CLK1M_MASK,
                        RT5682_PWR_CLK25M_PU | RT5682_PWR_CLK1M_PU);
-
-               snd_soc_dapm_mutex_unlock(dapm);
        } else {
                rt5682_enable_push_button_irq(component, false);
                snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
@@ -1011,7 +1007,6 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
        dev_dbg(component->dev, "jack_type = %d\n", rt5682->jack_type);
        return rt5682->jack_type;
 }
-EXPORT_SYMBOL_GPL(rt5682_headset_detect);
 
 static int rt5682_set_jack_detect(struct snd_soc_component *component,
                struct snd_soc_jack *hs_jack, void *data)
@@ -1094,15 +1089,20 @@ void rt5682_jack_detect_handler(struct work_struct *work)
 {
        struct rt5682_priv *rt5682 =
                container_of(work, struct rt5682_priv, jack_detect_work.work);
+       struct snd_soc_dapm_context *dapm;
        int val, btn_type;
 
-       while (!rt5682->component)
-               usleep_range(10000, 15000);
+       if (!rt5682->component || !rt5682->component->card ||
+           !rt5682->component->card->instantiated) {
+               /* card not yet ready, try later */
+               mod_delayed_work(system_power_efficient_wq,
+                                &rt5682->jack_detect_work, msecs_to_jiffies(15));
+               return;
+       }
 
-       while (!rt5682->component->card->instantiated)
-               usleep_range(10000, 15000);
+       dapm = snd_soc_component_get_dapm(rt5682->component);
 
-       mutex_lock(&rt5682->jdet_mutex);
+       snd_soc_dapm_mutex_lock(dapm);
        mutex_lock(&rt5682->calibrate_mutex);
 
        val = snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL)
@@ -1162,6 +1162,9 @@ void rt5682_jack_detect_handler(struct work_struct *work)
                rt5682->irq_work_delay_time = 50;
        }
 
+       mutex_unlock(&rt5682->calibrate_mutex);
+       snd_soc_dapm_mutex_unlock(dapm);
+
        snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
                SND_JACK_HEADSET |
                SND_JACK_BTN_0 | SND_JACK_BTN_1 |
@@ -1174,9 +1177,6 @@ void rt5682_jack_detect_handler(struct work_struct *work)
                else
                        cancel_delayed_work_sync(&rt5682->jd_check_work);
        }
-
-       mutex_unlock(&rt5682->calibrate_mutex);
-       mutex_unlock(&rt5682->jdet_mutex);
 }
 EXPORT_SYMBOL_GPL(rt5682_jack_detect_handler);
 
@@ -1526,7 +1526,6 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_component *component =
                snd_soc_dapm_to_component(w->dapm);
-       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -1538,17 +1537,12 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
                        RT5682_DEPOP_1, 0x60, 0x60);
                snd_soc_component_update_bits(component,
                        RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0080);
-
-               mutex_lock(&rt5682->jdet_mutex);
-
                snd_soc_component_update_bits(component, RT5682_HP_CTRL_2,
                        RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN,
                        RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN);
                usleep_range(5000, 10000);
                snd_soc_component_update_bits(component, RT5682_CHARGE_PUMP_1,
                        RT5682_CP_SW_SIZE_MASK, RT5682_CP_SW_SIZE_L);
-
-               mutex_unlock(&rt5682->jdet_mutex);
                break;
 
        case SND_SOC_DAPM_POST_PMD:
index c917c76..52ff0d9 100644 (file)
@@ -1463,7 +1463,6 @@ struct rt5682_priv {
 
        int jack_type;
        int irq_work_delay_time;
-       struct mutex jdet_mutex;
 };
 
 extern const char *rt5682_supply_names[RT5682_NUM_SUPPLIES];
@@ -1473,7 +1472,6 @@ int rt5682_sel_asrc_clk_src(struct snd_soc_component *component,
 
 void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev);
 
-int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert);
 void rt5682_jack_detect_handler(struct work_struct *work);
 
 bool rt5682_volatile_register(struct device *dev, unsigned int reg);
index efa1016..1e662d1 100644 (file)
@@ -824,11 +824,13 @@ static void rt5682s_jack_detect_handler(struct work_struct *work)
                container_of(work, struct rt5682s_priv, jack_detect_work.work);
        int val, btn_type;
 
-       while (!rt5682s->component)
-               usleep_range(10000, 15000);
-
-       while (!rt5682s->component->card->instantiated)
-               usleep_range(10000, 15000);
+       if (!rt5682s->component || !rt5682s->component->card ||
+           !rt5682s->component->card->instantiated) {
+               /* card not yet ready, try later */
+               mod_delayed_work(system_power_efficient_wq,
+                                &rt5682s->jack_detect_work, msecs_to_jiffies(15));
+               return;
+       }
 
        mutex_lock(&rt5682s->jdet_mutex);
        mutex_lock(&rt5682s->calibrate_mutex);
index 6549e7f..c5ea3b1 100644 (file)
@@ -38,10 +38,12 @@ static void tas2770_reset(struct tas2770_priv *tas2770)
                gpiod_set_value_cansleep(tas2770->reset_gpio, 0);
                msleep(20);
                gpiod_set_value_cansleep(tas2770->reset_gpio, 1);
+               usleep_range(1000, 2000);
        }
 
        snd_soc_component_write(tas2770->component, TAS2770_SW_RST,
                TAS2770_RST);
+       usleep_range(1000, 2000);
 }
 
 static int tas2770_set_bias_level(struct snd_soc_component *component,
@@ -110,6 +112,7 @@ static int tas2770_codec_resume(struct snd_soc_component *component)
 
        if (tas2770->sdz_gpio) {
                gpiod_set_value_cansleep(tas2770->sdz_gpio, 1);
+               usleep_range(1000, 2000);
        } else {
                ret = snd_soc_component_update_bits(component, TAS2770_PWR_CTRL,
                                                    TAS2770_PWR_CTRL_MASK,
@@ -510,8 +513,10 @@ static int tas2770_codec_probe(struct snd_soc_component *component)
 
        tas2770->component = component;
 
-       if (tas2770->sdz_gpio)
+       if (tas2770->sdz_gpio) {
                gpiod_set_value_cansleep(tas2770->sdz_gpio, 1);
+               usleep_range(1000, 2000);
+       }
 
        tas2770_reset(tas2770);
 
index eff200a..36cbc66 100644 (file)
@@ -1432,14 +1432,10 @@ static int wcd938x_sdw_connect_port(struct wcd938x_sdw_ch_info *ch_info,
        return 0;
 }
 
-static int wcd938x_connect_port(struct wcd938x_sdw_priv *wcd, u8 ch_id, u8 enable)
+static int wcd938x_connect_port(struct wcd938x_sdw_priv *wcd, u8 port_num, u8 ch_id, u8 enable)
 {
-       u8 port_num;
-
-       port_num = wcd->ch_info[ch_id].port_num;
-
        return wcd938x_sdw_connect_port(&wcd->ch_info[ch_id],
-                                       &wcd->port_config[port_num],
+                                       &wcd->port_config[port_num - 1],
                                        enable);
 }
 
@@ -2563,7 +2559,7 @@ static int wcd938x_ear_pa_put_gain(struct snd_kcontrol *kcontrol,
                                      WCD938X_EAR_GAIN_MASK,
                                      ucontrol->value.integer.value[0]);
 
-       return 0;
+       return 1;
 }
 
 static int wcd938x_get_compander(struct snd_kcontrol *kcontrol,
@@ -2593,6 +2589,7 @@ static int wcd938x_set_compander(struct snd_kcontrol *kcontrol,
        struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
        struct wcd938x_sdw_priv *wcd;
        int value = ucontrol->value.integer.value[0];
+       int portidx;
        struct soc_mixer_control *mc;
        bool hphr;
 
@@ -2606,12 +2603,14 @@ static int wcd938x_set_compander(struct snd_kcontrol *kcontrol,
        else
                wcd938x->comp1_enable = value;
 
+       portidx = wcd->ch_info[mc->reg].port_num;
+
        if (value)
-               wcd938x_connect_port(wcd, mc->reg, true);
+               wcd938x_connect_port(wcd, portidx, mc->reg, true);
        else
-               wcd938x_connect_port(wcd, mc->reg, false);
+               wcd938x_connect_port(wcd, portidx, mc->reg, false);
 
-       return 0;
+       return 1;
 }
 
 static int wcd938x_ldoh_get(struct snd_kcontrol *kcontrol,
@@ -2882,9 +2881,11 @@ static int wcd938x_get_swr_port(struct snd_kcontrol *kcontrol,
        struct wcd938x_sdw_priv *wcd;
        struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
        int dai_id = mixer->shift;
-       int portidx = mixer->reg;
+       int portidx, ch_idx = mixer->reg;
+
 
        wcd = wcd938x->sdw_priv[dai_id];
+       portidx = wcd->ch_info[ch_idx].port_num;
 
        ucontrol->value.integer.value[0] = wcd->port_enable[portidx];
 
@@ -2899,12 +2900,14 @@ static int wcd938x_set_swr_port(struct snd_kcontrol *kcontrol,
        struct wcd938x_sdw_priv *wcd;
        struct soc_mixer_control *mixer =
                (struct soc_mixer_control *)kcontrol->private_value;
-       int portidx = mixer->reg;
+       int ch_idx = mixer->reg;
+       int portidx;
        int dai_id = mixer->shift;
        bool enable;
 
        wcd = wcd938x->sdw_priv[dai_id];
 
+       portidx = wcd->ch_info[ch_idx].port_num;
        if (ucontrol->value.integer.value[0])
                enable = true;
        else
@@ -2912,9 +2915,9 @@ static int wcd938x_set_swr_port(struct snd_kcontrol *kcontrol,
 
        wcd->port_enable[portidx] = enable;
 
-       wcd938x_connect_port(wcd, portidx, enable);
+       wcd938x_connect_port(wcd, portidx, ch_idx, enable);
 
-       return 0;
+       return 1;
 
 }
 
index f3672e3..0582585 100644 (file)
@@ -1441,7 +1441,8 @@ static int wm_adsp_buffer_parse_coeff(struct cs_dsp_coeff_ctl *cs_ctl)
        int ret, i;
 
        for (i = 0; i < 5; ++i) {
-               ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, &coeff_v1, sizeof(coeff_v1));
+               ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, &coeff_v1,
+                                            min(cs_ctl->len, sizeof(coeff_v1)));
                if (ret < 0)
                        return ret;
 
index af3c3b9..83b4a22 100644 (file)
@@ -93,16 +93,21 @@ static int pcm030_fabric_probe(struct platform_device *op)
                dev_err(&op->dev, "platform_device_alloc() failed\n");
 
        ret = platform_device_add(pdata->codec_device);
-       if (ret)
+       if (ret) {
                dev_err(&op->dev, "platform_device_add() failed: %d\n", ret);
+               platform_device_put(pdata->codec_device);
+       }
 
        ret = snd_soc_register_card(card);
-       if (ret)
+       if (ret) {
                dev_err(&op->dev, "snd_soc_register_card() failed: %d\n", ret);
+               platform_device_del(pdata->codec_device);
+               platform_device_put(pdata->codec_device);
+       }
 
        platform_set_drvdata(op, pdata);
-
        return ret;
+
 }
 
 static int pcm030_fabric_remove(struct platform_device *op)
index a89d1cf..78419e1 100644 (file)
@@ -28,6 +28,30 @@ static const struct snd_soc_ops simple_ops = {
        .hw_params      = asoc_simple_hw_params,
 };
 
+static int asoc_simple_parse_platform(struct device_node *node,
+                                     struct snd_soc_dai_link_component *dlc)
+{
+       struct of_phandle_args args;
+       int ret;
+
+       if (!node)
+               return 0;
+
+       /*
+        * Get node via "sound-dai = <&phandle port>"
+        * it will be used as xxx_of_node on soc_bind_dai_link()
+        */
+       ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
+       if (ret)
+               return ret;
+
+       /* dai_name is not required and may not exist for plat component */
+
+       dlc->of_node = args.np;
+
+       return 0;
+}
+
 static int asoc_simple_parse_dai(struct device_node *node,
                                 struct snd_soc_dai_link_component *dlc,
                                 int *is_single_link)
@@ -289,7 +313,7 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv,
        if (ret < 0)
                goto dai_link_of_err;
 
-       ret = asoc_simple_parse_dai(plat, platforms, NULL);
+       ret = asoc_simple_parse_platform(plat, platforms);
        if (ret < 0)
                goto dai_link_of_err;
 
index 148ddf4..aeca582 100644 (file)
@@ -952,6 +952,7 @@ static int skl_first_init(struct hdac_bus *bus)
        /* allow 64bit DMA address if supported by H/W */
        if (dma_set_mask_and_coherent(bus->dev, DMA_BIT_MASK(64)))
                dma_set_mask_and_coherent(bus->dev, DMA_BIT_MASK(32));
+       dma_set_max_seg_size(bus->dev, UINT_MAX);
 
        /* initialize streams */
        snd_hdac_ext_stream_init_all
index 9306b7c..0d15435 100644 (file)
@@ -216,7 +216,7 @@ config SND_SOC_MT8195_MT6359_RT1019_RT5682
 
 config SND_SOC_MT8195_MT6359_RT1011_RT5682
        tristate "ASoC Audio driver for MT8195 with MT6359 RT1011 RT5682 codec"
-       depends on I2C
+       depends on I2C && GPIOLIB
        depends on SND_SOC_MT8195 && MTK_PMIC_WRAP
        select SND_SOC_MT6359
        select SND_SOC_RT1011
index a59e9d2..4b1773c 100644 (file)
@@ -524,7 +524,7 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
                        return -EINVAL;
                }
 
-               ret = regmap_update_bits(map, reg_irqclr, val_irqclr, val_irqclr);
+               ret = regmap_write_bits(map, reg_irqclr, val_irqclr, val_irqclr);
                if (ret) {
                        dev_err(soc_runtime->dev, "error writing to irqclear reg: %d\n", ret);
                        return ret;
@@ -665,7 +665,7 @@ static irqreturn_t lpass_dma_interrupt_handler(
        return -EINVAL;
        }
        if (interrupts & LPAIF_IRQ_PER(chan)) {
-               rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_PER(chan) | val));
+               rv = regmap_write_bits(map, reg, mask, (LPAIF_IRQ_PER(chan) | val));
                if (rv) {
                        dev_err(soc_runtime->dev,
                                "error writing to irqclear reg: %d\n", rv);
@@ -676,7 +676,7 @@ static irqreturn_t lpass_dma_interrupt_handler(
        }
 
        if (interrupts & LPAIF_IRQ_XRUN(chan)) {
-               rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_XRUN(chan) | val));
+               rv = regmap_write_bits(map, reg, mask, (LPAIF_IRQ_XRUN(chan) | val));
                if (rv) {
                        dev_err(soc_runtime->dev,
                                "error writing to irqclear reg: %d\n", rv);
@@ -688,7 +688,7 @@ static irqreturn_t lpass_dma_interrupt_handler(
        }
 
        if (interrupts & LPAIF_IRQ_ERR(chan)) {
-               rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_ERR(chan) | val));
+               rv = regmap_write_bits(map, reg, mask, (LPAIF_IRQ_ERR(chan) | val));
                if (rv) {
                        dev_err(soc_runtime->dev,
                                "error writing to irqclear reg: %d\n", rv);
index eb1c3ae..19c4a90 100644 (file)
@@ -308,8 +308,11 @@ static int q6apm_dai_close(struct snd_soc_component *component,
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct q6apm_dai_rtd *prtd = runtime->private_data;
 
-       q6apm_graph_stop(prtd->graph);
-       q6apm_unmap_memory_regions(prtd->graph, substream->stream);
+       if (prtd->state) { /* only stop graph that is started */
+               q6apm_graph_stop(prtd->graph);
+               q6apm_unmap_memory_regions(prtd->graph, substream->stream);
+       }
+
        q6apm_graph_close(prtd->graph);
        prtd->graph = NULL;
        kfree(prtd);
index cbd7ea4..142476f 100644 (file)
@@ -55,16 +55,13 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_find_machine);
 static acpi_status snd_soc_acpi_find_package(acpi_handle handle, u32 level,
                                             void *context, void **ret)
 {
-       struct acpi_device *adev;
+       struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
        acpi_status status;
        struct snd_soc_acpi_package_context *pkg_ctx = context;
 
        pkg_ctx->data_valid = false;
 
-       if (acpi_bus_get_device(handle, &adev))
-               return AE_OK;
-
-       if (adev->status.present && adev->status.functional) {
+       if (adev && adev->status.present && adev->status.functional) {
                struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
                union acpi_object  *myobj = NULL;
 
index 08eaa9d..03ea959 100644 (file)
@@ -308,7 +308,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
        unsigned int sign_bit = mc->sign_bit;
        unsigned int mask = (1 << fls(max)) - 1;
        unsigned int invert = mc->invert;
-       int err;
+       int err, ret;
        bool type_2r = false;
        unsigned int val2 = 0;
        unsigned int val, val_mask;
@@ -316,13 +316,27 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
        if (sign_bit)
                mask = BIT(sign_bit + 1) - 1;
 
-       val = ((ucontrol->value.integer.value[0] + min) & mask);
+       if (ucontrol->value.integer.value[0] < 0)
+               return -EINVAL;
+       val = ucontrol->value.integer.value[0];
+       if (mc->platform_max && val > mc->platform_max)
+               return -EINVAL;
+       if (val > max - min)
+               return -EINVAL;
+       val = (val + min) & mask;
        if (invert)
                val = max - val;
        val_mask = mask << shift;
        val = val << shift;
        if (snd_soc_volsw_is_stereo(mc)) {
-               val2 = ((ucontrol->value.integer.value[1] + min) & mask);
+               if (ucontrol->value.integer.value[1] < 0)
+                       return -EINVAL;
+               val2 = ucontrol->value.integer.value[1];
+               if (mc->platform_max && val2 > mc->platform_max)
+                       return -EINVAL;
+               if (val2 > max - min)
+                       return -EINVAL;
+               val2 = (val2 + min) & mask;
                if (invert)
                        val2 = max - val2;
                if (reg == reg2) {
@@ -336,12 +350,18 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
        err = snd_soc_component_update_bits(component, reg, val_mask, val);
        if (err < 0)
                return err;
+       ret = err;
 
-       if (type_2r)
+       if (type_2r) {
                err = snd_soc_component_update_bits(component, reg2, val_mask,
-                       val2);
+                                                   val2);
+               /* Don't discard any error code or drop change flag */
+               if (ret == 0 || err < 0) {
+                       ret = err;
+               }
+       }
 
-       return err;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
 
@@ -407,15 +427,24 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
        int min = mc->min;
        unsigned int mask = (1U << (fls(min + max) - 1)) - 1;
        int err = 0;
+       int ret;
        unsigned int val, val_mask;
 
+       if (ucontrol->value.integer.value[0] < 0)
+               return -EINVAL;
+       val = ucontrol->value.integer.value[0];
+       if (mc->platform_max && val > mc->platform_max)
+               return -EINVAL;
+       if (val > max - min)
+               return -EINVAL;
        val_mask = mask << shift;
-       val = (ucontrol->value.integer.value[0] + min) & mask;
+       val = (val + min) & mask;
        val = val << shift;
 
        err = snd_soc_component_update_bits(component, reg, val_mask, val);
        if (err < 0)
                return err;
+       ret = err;
 
        if (snd_soc_volsw_is_stereo(mc)) {
                unsigned int val2;
@@ -426,6 +455,11 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
 
                err = snd_soc_component_update_bits(component, reg2, val_mask,
                        val2);
+
+               /* Don't discard any error code or drop change flag */
+               if (ret == 0 || err < 0) {
+                       ret = err;
+               }
        }
        return err;
 }
@@ -485,7 +519,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
        unsigned int mask = (1 << fls(max)) - 1;
        unsigned int invert = mc->invert;
        unsigned int val, val_mask;
-       int ret;
+       int err, ret;
 
        if (invert)
                val = (max - ucontrol->value.integer.value[0]) & mask;
@@ -494,9 +528,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
        val_mask = mask << shift;
        val = val << shift;
 
-       ret = snd_soc_component_update_bits(component, reg, val_mask, val);
-       if (ret < 0)
-               return ret;
+       err = snd_soc_component_update_bits(component, reg, val_mask, val);
+       if (err < 0)
+               return err;
+       ret = err;
 
        if (snd_soc_volsw_is_stereo(mc)) {
                if (invert)
@@ -506,8 +541,12 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
                val_mask = mask << shift;
                val = val << shift;
 
-               ret = snd_soc_component_update_bits(component, rreg, val_mask,
+               err = snd_soc_component_update_bits(component, rreg, val_mask,
                        val);
+               /* Don't discard any error code or drop change flag */
+               if (ret == 0 || err < 0) {
+                       ret = err;
+               }
        }
 
        return ret;
@@ -856,8 +895,11 @@ int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
        unsigned long mask = (1UL<<mc->nbits)-1;
        long max = mc->max;
        long val = ucontrol->value.integer.value[0];
+       int ret = 0;
        unsigned int i;
 
+       if (val < mc->min || val > mc->max)
+               return -EINVAL;
        if (invert)
                val = max - val;
        val &= mask;
@@ -868,9 +910,11 @@ int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
                                                        regmask, regval);
                if (err < 0)
                        return err;
+               if (err > 0)
+                       ret = err;
        }
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx);
 
index 7abfc48..9a95468 100644 (file)
@@ -46,8 +46,8 @@ static inline void snd_soc_dpcm_stream_lock_irq(struct snd_soc_pcm_runtime *rtd,
        snd_pcm_stream_lock_irq(snd_soc_dpcm_get_substream(rtd, stream));
 }
 
-#define snd_soc_dpcm_stream_lock_irqsave(rtd, stream, flags) \
-       snd_pcm_stream_lock_irqsave(snd_soc_dpcm_get_substream(rtd, stream), flags)
+#define snd_soc_dpcm_stream_lock_irqsave_nested(rtd, stream, flags) \
+       snd_pcm_stream_lock_irqsave_nested(snd_soc_dpcm_get_substream(rtd, stream), flags)
 
 static inline void snd_soc_dpcm_stream_unlock_irq(struct snd_soc_pcm_runtime *rtd,
                                                  int stream)
@@ -1268,6 +1268,7 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
 void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
 {
        struct snd_soc_dpcm *dpcm, *d;
+       LIST_HEAD(deleted_dpcms);
 
        snd_soc_dpcm_mutex_assert_held(fe);
 
@@ -1287,13 +1288,18 @@ void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
                /* BEs still alive need new FE */
                dpcm_be_reparent(fe, dpcm->be, stream);
 
-               dpcm_remove_debugfs_state(dpcm);
-
                list_del(&dpcm->list_be);
+               list_move(&dpcm->list_fe, &deleted_dpcms);
+       }
+       snd_soc_dpcm_stream_unlock_irq(fe, stream);
+
+       while (!list_empty(&deleted_dpcms)) {
+               dpcm = list_first_entry(&deleted_dpcms, struct snd_soc_dpcm,
+                                       list_fe);
                list_del(&dpcm->list_fe);
+               dpcm_remove_debugfs_state(dpcm);
                kfree(dpcm);
        }
-       snd_soc_dpcm_stream_unlock_irq(fe, stream);
 }
 
 /* get BE for DAI widget and stream */
@@ -2094,7 +2100,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
                be = dpcm->be;
                be_substream = snd_soc_dpcm_get_substream(be, stream);
 
-               snd_soc_dpcm_stream_lock_irqsave(be, stream, flags);
+               snd_soc_dpcm_stream_lock_irqsave_nested(be, stream, flags);
 
                /* is this op for this BE ? */
                if (!snd_soc_dpcm_be_can_update(fe, be, stream))
index c8fb082..1385695 100644 (file)
@@ -956,6 +956,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
                dev_dbg(sdev->dev, "DMA mask is 32 bit\n");
                dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32));
        }
+       dma_set_max_seg_size(&pci->dev, UINT_MAX);
 
        /* init streams */
        ret = hda_dsp_stream_init(sdev);
index 91afea9..ce19a60 100644 (file)
@@ -37,6 +37,7 @@
 #define XLNX_AUD_XFER_COUNT    0x28
 #define XLNX_AUD_CH_STS_START  0x2C
 #define XLNX_BYTES_PER_CH      0x44
+#define XLNX_AUD_ALIGN_BYTES   64
 
 #define AUD_STS_IOC_IRQ_MASK   BIT(31)
 #define AUD_STS_CH_STS_MASK    BIT(29)
@@ -368,12 +369,32 @@ static int xlnx_formatter_pcm_open(struct snd_soc_component *component,
        snd_soc_set_runtime_hwparams(substream, &xlnx_pcm_hardware);
        runtime->private_data = stream_data;
 
-       /* Resize the period size divisible by 64 */
+       /* Resize the period bytes as divisible by 64 */
        err = snd_pcm_hw_constraint_step(runtime, 0,
-                                        SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);
+                                        SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+                                        XLNX_AUD_ALIGN_BYTES);
        if (err) {
                dev_err(component->dev,
-                       "unable to set constraint on period bytes\n");
+                       "Unable to set constraint on period bytes\n");
+               return err;
+       }
+
+       /* Resize the buffer bytes as divisible by 64 */
+       err = snd_pcm_hw_constraint_step(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+                                        XLNX_AUD_ALIGN_BYTES);
+       if (err) {
+               dev_err(component->dev,
+                       "Unable to set constraint on buffer bytes\n");
+               return err;
+       }
+
+       /* Set periods as integer multiple */
+       err = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (err < 0) {
+               dev_err(component->dev,
+                       "Unable to set constraint on periods to be integer\n");
                return err;
        }
 
index 70319c8..2d444ec 100644 (file)
@@ -47,13 +47,13 @@ struct snd_usb_implicit_fb_match {
 static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = {
        /* Generic matching */
        IMPLICIT_FB_GENERIC_DEV(0x0499, 0x1509), /* Steinberg UR22 */
-       IMPLICIT_FB_GENERIC_DEV(0x0763, 0x2080), /* M-Audio FastTrack Ultra */
-       IMPLICIT_FB_GENERIC_DEV(0x0763, 0x2081), /* M-Audio FastTrack Ultra */
        IMPLICIT_FB_GENERIC_DEV(0x0763, 0x2030), /* M-Audio Fast Track C400 */
        IMPLICIT_FB_GENERIC_DEV(0x0763, 0x2031), /* M-Audio Fast Track C600 */
 
        /* Fixed EP */
        /* FIXME: check the availability of generic matching */
+       IMPLICIT_FB_FIXED_DEV(0x0763, 0x2080, 0x81, 2), /* M-Audio FastTrack Ultra */
+       IMPLICIT_FB_FIXED_DEV(0x0763, 0x2081, 0x81, 2), /* M-Audio FastTrack Ultra */
        IMPLICIT_FB_FIXED_DEV(0x2466, 0x8010, 0x81, 2), /* Fractal Audio Axe-Fx III */
        IMPLICIT_FB_FIXED_DEV(0x31e9, 0x0001, 0x81, 2), /* Solid State Logic SSL2 */
        IMPLICIT_FB_FIXED_DEV(0x31e9, 0x0002, 0x81, 2), /* Solid State Logic SSL2+ */
index e8f3f8d..a564195 100644 (file)
@@ -1527,6 +1527,10 @@ error:
                usb_audio_err(chip,
                        "cannot get connectors status: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
                        UAC_GET_CUR, validx, idx, cval->val_type);
+
+               if (val)
+                       *val = 0;
+
                return filter_error(cval, ret);
        }
 
@@ -3674,17 +3678,14 @@ static int restore_mixer_value(struct usb_mixer_elem_list *list)
                                err = snd_usb_set_cur_mix_value(cval, c + 1, idx,
                                                        cval->cache_val[idx]);
                                if (err < 0)
-                                       return err;
+                                       break;
                        }
                        idx++;
                }
        } else {
                /* master */
-               if (cval->cached) {
-                       err = snd_usb_set_cur_mix_value(cval, 0, 0, *cval->cache_val);
-                       if (err < 0)
-                               return err;
-               }
+               if (cval->cached)
+                       snd_usb_set_cur_mix_value(cval, 0, 0, *cval->cache_val);
        }
 
        return 0;
index b1522e4..0ea3956 100644 (file)
@@ -84,7 +84,7 @@
  * combination.
  */
 {
-       USB_DEVICE(0x041e, 0x4095),
+       USB_AUDIO_DEVICE(0x041e, 0x4095),
        .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
                .ifnum = QUIRK_ANY_INTERFACE,
                .type = QUIRK_COMPOSITE,
index 18de5f7..6db4e29 100644 (file)
 /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
 #define X86_FEATURE_AVX_VNNI           (12*32+ 4) /* AVX VNNI instructions */
 #define X86_FEATURE_AVX512_BF16                (12*32+ 5) /* AVX512 BFLOAT16 instructions */
+#define X86_FEATURE_AMX_BF16           (18*32+22) /* AMX bf16 Support */
 #define X86_FEATURE_AMX_TILE           (18*32+24) /* AMX tile Support */
+#define X86_FEATURE_AMX_INT8           (18*32+25) /* AMX int8 Support */
 
 /* AMD-defined CPU features, CPUID level 0x80000008 (EBX), word 13 */
 #define X86_FEATURE_CLZERO             (13*32+ 0) /* CLZERO instruction */
index 3faf0f9..a4a39c3 100644 (file)
 #define MSR_AMD64_ICIBSEXTDCTL         0xc001103c
 #define MSR_AMD64_IBSOPDATA4           0xc001103d
 #define MSR_AMD64_IBS_REG_COUNT_MAX    8 /* includes MSR_AMD64_IBSBRTARGET */
+#define MSR_AMD64_SVM_AVIC_DOORBELL    0xc001011b
 #define MSR_AMD64_VM_PAGE_FLUSH                0xc001011e
 #define MSR_AMD64_SEV_ES_GHCB          0xc0010130
 #define MSR_AMD64_SEV                  0xc0010131
index 2da3316..bf6e960 100644 (file)
@@ -452,6 +452,9 @@ struct kvm_sync_regs {
 
 #define KVM_STATE_VMX_PREEMPTION_TIMER_DEADLINE        0x00000001
 
+/* attributes for system fd (group 0) */
+#define KVM_X86_XCOMP_GUEST_SUPP       0
+
 struct kvm_vmx_nested_state_data {
        __u8 vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
        __u8 shadow_vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE];
index 9ddeca9..320a88a 100644 (file)
@@ -9,7 +9,11 @@ ifeq ($(V),1)
   msg =
 else
   Q = @
-  msg = @printf '  %-8s %s%s\n' "$(1)" "$(notdir $(2))" "$(if $(3), $(3))";
+  ifeq ($(silent),1)
+    msg =
+  else
+    msg = @printf '  %-8s %s%s\n' "$(1)" "$(notdir $(2))" "$(if $(3), $(3))";
+  endif
   MAKEFLAGS=--no-print-directory
 endif
 
index ab9353f..9a5c1f0 100644 (file)
@@ -68,7 +68,7 @@ int handle__sched_switch(u64 *ctx)
         */
        struct task_struct *prev = (struct task_struct *)ctx[1];
        struct task_struct *next = (struct task_struct *)ctx[2];
-       struct event event = {};
+       struct runq_event event = {};
        u64 *tsp, delta_us;
        long state;
        u32 pid;
index 2414cc7..d78f414 100644 (file)
@@ -100,7 +100,7 @@ static int bump_memlock_rlimit(void)
 
 void handle_event(void *ctx, int cpu, void *data, __u32 data_sz)
 {
-       const struct event *e = data;
+       const struct runq_event *e = data;
        struct tm *tm;
        char ts[32];
        time_t t;
index 9db2254..4f70f07 100644 (file)
@@ -4,7 +4,7 @@
 
 #define TASK_COMM_LEN 16
 
-struct event {
+struct runq_event {
        char task[TASK_COMM_LEN];
        __u64 delta_us;
        pid_t pid;
index 1600b17..1d3a90d 100644 (file)
@@ -11,7 +11,7 @@ from drgn.helpers.linux import list_for_each_entry, list_empty
 from drgn.helpers.linux import for_each_page
 from drgn.helpers.linux.cpumask import for_each_online_cpu
 from drgn.helpers.linux.percpu import per_cpu_ptr
-from drgn import container_of, FaultError, Object
+from drgn import container_of, FaultError, Object, cast
 
 
 DESC = """
@@ -69,15 +69,15 @@ def oo_objects(s):
 
 
 def count_partial(n, fn):
-    nr_pages = 0
-    for page in list_for_each_entry('struct page', n.partial.address_of_(),
-                                    'lru'):
-         nr_pages += fn(page)
-    return nr_pages
+    nr_objs = 0
+    for slab in list_for_each_entry('struct slab', n.partial.address_of_(),
+                                    'slab_list'):
+         nr_objs += fn(slab)
+    return nr_objs
 
 
-def count_free(page):
-    return page.objects - page.inuse
+def count_free(slab):
+    return slab.objects - slab.inuse
 
 
 def slub_get_slabinfo(s, cfg):
@@ -145,14 +145,14 @@ def detect_kernel_config():
     return cfg
 
 
-def for_each_slab_page(prog):
+def for_each_slab(prog):
     PGSlab = 1 << prog.constant('PG_slab')
     PGHead = 1 << prog.constant('PG_head')
 
     for page in for_each_page(prog):
         try:
             if page.flags.value_() & PGSlab:
-                yield page
+                yield cast('struct slab *', page)
         except FaultError:
             pass
 
@@ -190,13 +190,13 @@ def main():
                                        'list'):
             obj_cgroups.add(ptr.value_())
 
-        # look over all slab pages, belonging to non-root memcgs
-        # and look for objects belonging to the given memory cgroup
-        for page in for_each_slab_page(prog):
-            objcg_vec_raw = page.memcg_data.value_()
+        # look over all slab folios and look for objects belonging
+        # to the given memory cgroup
+        for slab in for_each_slab(prog):
+            objcg_vec_raw = slab.memcg_data.value_()
             if objcg_vec_raw == 0:
                 continue
-            cache = page.slab_cache
+            cache = slab.slab_cache
             if not cache:
                 continue
             addr = cache.value_()
index 9563d29..507ee1f 100644 (file)
@@ -1133,6 +1133,8 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM 206
 #define KVM_CAP_VM_GPA_BITS 207
 #define KVM_CAP_XSAVE2 208
+#define KVM_CAP_SYS_ATTRIBUTES 209
+#define KVM_CAP_PPC_AIL_MODE_3 210
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -1623,9 +1625,6 @@ struct kvm_enc_region {
 #define KVM_S390_NORMAL_RESET  _IO(KVMIO,   0xc3)
 #define KVM_S390_CLEAR_RESET   _IO(KVMIO,   0xc4)
 
-/* Available with KVM_CAP_XSAVE2 */
-#define KVM_GET_XSAVE2           _IOR(KVMIO,  0xcf, struct kvm_xsave)
-
 struct kvm_s390_pv_sec_parm {
        __u64 origin;
        __u64 length;
@@ -2047,4 +2046,7 @@ struct kvm_stats_desc {
 
 #define KVM_GET_STATS_FD  _IO(KVMIO,  0xce)
 
+/* Available with KVM_CAP_XSAVE2 */
+#define KVM_GET_XSAVE2           _IOR(KVMIO,  0xcf, struct kvm_xsave)
+
 #endif /* __LINUX_KVM_H */
diff --git a/tools/include/uapi/linux/lirc.h b/tools/include/uapi/linux/lirc.h
deleted file mode 100644 (file)
index 45fcbf9..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * lirc.h - linux infrared remote control header file
- * last modified 2010/07/13 by Jarod Wilson
- */
-
-#ifndef _LINUX_LIRC_H
-#define _LINUX_LIRC_H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-
-#define PULSE_BIT       0x01000000
-#define PULSE_MASK      0x00FFFFFF
-
-#define LIRC_MODE2_SPACE     0x00000000
-#define LIRC_MODE2_PULSE     0x01000000
-#define LIRC_MODE2_FREQUENCY 0x02000000
-#define LIRC_MODE2_TIMEOUT   0x03000000
-
-#define LIRC_VALUE_MASK      0x00FFFFFF
-#define LIRC_MODE2_MASK      0xFF000000
-
-#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE)
-#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE)
-#define LIRC_FREQUENCY(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_FREQUENCY)
-#define LIRC_TIMEOUT(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT)
-
-#define LIRC_VALUE(val) ((val)&LIRC_VALUE_MASK)
-#define LIRC_MODE2(val) ((val)&LIRC_MODE2_MASK)
-
-#define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE)
-#define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE)
-#define LIRC_IS_FREQUENCY(val) (LIRC_MODE2(val) == LIRC_MODE2_FREQUENCY)
-#define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT)
-
-/* used heavily by lirc userspace */
-#define lirc_t int
-
-/*** lirc compatible hardware features ***/
-
-#define LIRC_MODE2SEND(x) (x)
-#define LIRC_SEND2MODE(x) (x)
-#define LIRC_MODE2REC(x) ((x) << 16)
-#define LIRC_REC2MODE(x) ((x) >> 16)
-
-#define LIRC_MODE_RAW                  0x00000001
-#define LIRC_MODE_PULSE                0x00000002
-#define LIRC_MODE_MODE2                0x00000004
-#define LIRC_MODE_SCANCODE             0x00000008
-#define LIRC_MODE_LIRCCODE             0x00000010
-
-
-#define LIRC_CAN_SEND_RAW              LIRC_MODE2SEND(LIRC_MODE_RAW)
-#define LIRC_CAN_SEND_PULSE            LIRC_MODE2SEND(LIRC_MODE_PULSE)
-#define LIRC_CAN_SEND_MODE2            LIRC_MODE2SEND(LIRC_MODE_MODE2)
-#define LIRC_CAN_SEND_LIRCCODE         LIRC_MODE2SEND(LIRC_MODE_LIRCCODE)
-
-#define LIRC_CAN_SEND_MASK             0x0000003f
-
-#define LIRC_CAN_SET_SEND_CARRIER      0x00000100
-#define LIRC_CAN_SET_SEND_DUTY_CYCLE   0x00000200
-#define LIRC_CAN_SET_TRANSMITTER_MASK  0x00000400
-
-#define LIRC_CAN_REC_RAW               LIRC_MODE2REC(LIRC_MODE_RAW)
-#define LIRC_CAN_REC_PULSE             LIRC_MODE2REC(LIRC_MODE_PULSE)
-#define LIRC_CAN_REC_MODE2             LIRC_MODE2REC(LIRC_MODE_MODE2)
-#define LIRC_CAN_REC_SCANCODE          LIRC_MODE2REC(LIRC_MODE_SCANCODE)
-#define LIRC_CAN_REC_LIRCCODE          LIRC_MODE2REC(LIRC_MODE_LIRCCODE)
-
-#define LIRC_CAN_REC_MASK              LIRC_MODE2REC(LIRC_CAN_SEND_MASK)
-
-#define LIRC_CAN_SET_REC_CARRIER       (LIRC_CAN_SET_SEND_CARRIER << 16)
-#define LIRC_CAN_SET_REC_DUTY_CYCLE    (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16)
-
-#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000
-#define LIRC_CAN_SET_REC_CARRIER_RANGE    0x80000000
-#define LIRC_CAN_GET_REC_RESOLUTION       0x20000000
-#define LIRC_CAN_SET_REC_TIMEOUT          0x10000000
-#define LIRC_CAN_SET_REC_FILTER           0x08000000
-
-#define LIRC_CAN_MEASURE_CARRIER          0x02000000
-#define LIRC_CAN_USE_WIDEBAND_RECEIVER    0x04000000
-
-#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK)
-#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK)
-
-#define LIRC_CAN_NOTIFY_DECODE            0x01000000
-
-/*** IOCTL commands for lirc driver ***/
-
-#define LIRC_GET_FEATURES              _IOR('i', 0x00000000, __u32)
-
-#define LIRC_GET_SEND_MODE             _IOR('i', 0x00000001, __u32)
-#define LIRC_GET_REC_MODE              _IOR('i', 0x00000002, __u32)
-#define LIRC_GET_REC_RESOLUTION        _IOR('i', 0x00000007, __u32)
-
-#define LIRC_GET_MIN_TIMEOUT           _IOR('i', 0x00000008, __u32)
-#define LIRC_GET_MAX_TIMEOUT           _IOR('i', 0x00000009, __u32)
-
-/* code length in bits, currently only for LIRC_MODE_LIRCCODE */
-#define LIRC_GET_LENGTH                _IOR('i', 0x0000000f, __u32)
-
-#define LIRC_SET_SEND_MODE             _IOW('i', 0x00000011, __u32)
-#define LIRC_SET_REC_MODE              _IOW('i', 0x00000012, __u32)
-/* Note: these can reset the according pulse_width */
-#define LIRC_SET_SEND_CARRIER          _IOW('i', 0x00000013, __u32)
-#define LIRC_SET_REC_CARRIER           _IOW('i', 0x00000014, __u32)
-#define LIRC_SET_SEND_DUTY_CYCLE       _IOW('i', 0x00000015, __u32)
-#define LIRC_SET_TRANSMITTER_MASK      _IOW('i', 0x00000017, __u32)
-
-/*
- * when a timeout != 0 is set the driver will send a
- * LIRC_MODE2_TIMEOUT data packet, otherwise LIRC_MODE2_TIMEOUT is
- * never sent, timeout is disabled by default
- */
-#define LIRC_SET_REC_TIMEOUT           _IOW('i', 0x00000018, __u32)
-
-/* 1 enables, 0 disables timeout reports in MODE2 */
-#define LIRC_SET_REC_TIMEOUT_REPORTS   _IOW('i', 0x00000019, __u32)
-
-/*
- * if enabled from the next key press on the driver will send
- * LIRC_MODE2_FREQUENCY packets
- */
-#define LIRC_SET_MEASURE_CARRIER_MODE  _IOW('i', 0x0000001d, __u32)
-
-/*
- * to set a range use LIRC_SET_REC_CARRIER_RANGE with the
- * lower bound first and later LIRC_SET_REC_CARRIER with the upper bound
- */
-#define LIRC_SET_REC_CARRIER_RANGE     _IOW('i', 0x0000001f, __u32)
-
-#define LIRC_SET_WIDEBAND_RECEIVER     _IOW('i', 0x00000023, __u32)
-
-/*
- * Return the recording timeout, which is either set by
- * the ioctl LIRC_SET_REC_TIMEOUT or by the kernel after setting the protocols.
- */
-#define LIRC_GET_REC_TIMEOUT          _IOR('i', 0x00000024, __u32)
-
-/*
- * struct lirc_scancode - decoded scancode with protocol for use with
- *     LIRC_MODE_SCANCODE
- *
- * @timestamp: Timestamp in nanoseconds using CLOCK_MONOTONIC when IR
- *     was decoded.
- * @flags: should be 0 for transmit. When receiving scancodes,
- *     LIRC_SCANCODE_FLAG_TOGGLE or LIRC_SCANCODE_FLAG_REPEAT can be set
- *     depending on the protocol
- * @rc_proto: see enum rc_proto
- * @keycode: the translated keycode. Set to 0 for transmit.
- * @scancode: the scancode received or to be sent
- */
-struct lirc_scancode {
-       __u64   timestamp;
-       __u16   flags;
-       __u16   rc_proto;
-       __u32   keycode;
-       __u64   scancode;
-};
-
-/* Set if the toggle bit of rc-5 or rc-6 is enabled */
-#define LIRC_SCANCODE_FLAG_TOGGLE      1
-/* Set if this is a nec or sanyo repeat */
-#define LIRC_SCANCODE_FLAG_REPEAT      2
-
-/**
- * enum rc_proto - the Remote Controller protocol
- *
- * @RC_PROTO_UNKNOWN: Protocol not known
- * @RC_PROTO_OTHER: Protocol known but proprietary
- * @RC_PROTO_RC5: Philips RC5 protocol
- * @RC_PROTO_RC5X_20: Philips RC5x 20 bit protocol
- * @RC_PROTO_RC5_SZ: StreamZap variant of RC5
- * @RC_PROTO_JVC: JVC protocol
- * @RC_PROTO_SONY12: Sony 12 bit protocol
- * @RC_PROTO_SONY15: Sony 15 bit protocol
- * @RC_PROTO_SONY20: Sony 20 bit protocol
- * @RC_PROTO_NEC: NEC protocol
- * @RC_PROTO_NECX: Extended NEC protocol
- * @RC_PROTO_NEC32: NEC 32 bit protocol
- * @RC_PROTO_SANYO: Sanyo protocol
- * @RC_PROTO_MCIR2_KBD: RC6-ish MCE keyboard
- * @RC_PROTO_MCIR2_MSE: RC6-ish MCE mouse
- * @RC_PROTO_RC6_0: Philips RC6-0-16 protocol
- * @RC_PROTO_RC6_6A_20: Philips RC6-6A-20 protocol
- * @RC_PROTO_RC6_6A_24: Philips RC6-6A-24 protocol
- * @RC_PROTO_RC6_6A_32: Philips RC6-6A-32 protocol
- * @RC_PROTO_RC6_MCE: MCE (Philips RC6-6A-32 subtype) protocol
- * @RC_PROTO_SHARP: Sharp protocol
- * @RC_PROTO_XMP: XMP protocol
- * @RC_PROTO_CEC: CEC protocol
- * @RC_PROTO_IMON: iMon Pad protocol
- * @RC_PROTO_RCMM12: RC-MM protocol 12 bits
- * @RC_PROTO_RCMM24: RC-MM protocol 24 bits
- * @RC_PROTO_RCMM32: RC-MM protocol 32 bits
- */
-enum rc_proto {
-       RC_PROTO_UNKNOWN        = 0,
-       RC_PROTO_OTHER          = 1,
-       RC_PROTO_RC5            = 2,
-       RC_PROTO_RC5X_20        = 3,
-       RC_PROTO_RC5_SZ         = 4,
-       RC_PROTO_JVC            = 5,
-       RC_PROTO_SONY12         = 6,
-       RC_PROTO_SONY15         = 7,
-       RC_PROTO_SONY20         = 8,
-       RC_PROTO_NEC            = 9,
-       RC_PROTO_NECX           = 10,
-       RC_PROTO_NEC32          = 11,
-       RC_PROTO_SANYO          = 12,
-       RC_PROTO_MCIR2_KBD      = 13,
-       RC_PROTO_MCIR2_MSE      = 14,
-       RC_PROTO_RC6_0          = 15,
-       RC_PROTO_RC6_6A_20      = 16,
-       RC_PROTO_RC6_6A_24      = 17,
-       RC_PROTO_RC6_6A_32      = 18,
-       RC_PROTO_RC6_MCE        = 19,
-       RC_PROTO_SHARP          = 20,
-       RC_PROTO_XMP            = 21,
-       RC_PROTO_CEC            = 22,
-       RC_PROTO_IMON           = 23,
-       RC_PROTO_RCMM12         = 24,
-       RC_PROTO_RCMM24         = 25,
-       RC_PROTO_RCMM32         = 26,
-};
-
-#endif
index 4cd39aa..82858b6 100644 (file)
@@ -465,6 +465,8 @@ struct perf_event_attr {
        /*
         * User provided data if sigtrap=1, passed back to user via
         * siginfo_t::si_perf_data, e.g. to permit user to identify the event.
+        * Note, siginfo_t::si_perf_data is long-sized, and sig_data will be
+        * truncated accordingly on 32 bit architectures.
         */
        __u64   sig_data;
 };
@@ -1332,9 +1334,9 @@ union perf_mem_data_src {
 
 /* hop level */
 #define PERF_MEM_HOPS_0                0x01 /* remote core, same node */
-#define PERF_MEM_HOPS_1         0x02 /* remote node, same socket */
-#define PERF_MEM_HOPS_2         0x03 /* remote socket, same board */
-#define PERF_MEM_HOPS_3         0x04 /* remote board */
+#define PERF_MEM_HOPS_1                0x02 /* remote node, same socket */
+#define PERF_MEM_HOPS_2                0x03 /* remote socket, same board */
+#define PERF_MEM_HOPS_3                0x04 /* remote board */
 /* 5-7 available */
 #define PERF_MEM_HOPS_SHIFT    43
 
index bb73e9a..e998764 100644 (file)
@@ -272,4 +272,7 @@ struct prctl_mm_map {
 # define PR_SCHED_CORE_SCOPE_THREAD_GROUP      1
 # define PR_SCHED_CORE_SCOPE_PROCESS_GROUP     2
 
+#define PR_SET_VMA             0x53564d41
+# define PR_SET_VMA_ANON_NAME          0
+
 #endif /* _LINUX_PRCTL_H */
index 5fbb79e..2d3e5df 100644 (file)
  *                                                                          *
  ****************************************************************************/
 
+#define AES_IEC958_STATUS_SIZE         24
+
 struct snd_aes_iec958 {
-       unsigned char status[24];       /* AES/IEC958 channel status bits */
+       unsigned char status[AES_IEC958_STATUS_SIZE]; /* AES/IEC958 channel status bits */
        unsigned char subcode[147];     /* AES/IEC958 subcode bits */
        unsigned char pad;              /* nothing */
        unsigned char dig_subframe[4];  /* AES/IEC958 subframe bits */
@@ -202,6 +204,11 @@ typedef int __bitwise snd_pcm_format_t;
 #define        SNDRV_PCM_FORMAT_S24_BE ((__force snd_pcm_format_t) 7) /* low three bytes */
 #define        SNDRV_PCM_FORMAT_U24_LE ((__force snd_pcm_format_t) 8) /* low three bytes */
 #define        SNDRV_PCM_FORMAT_U24_BE ((__force snd_pcm_format_t) 9) /* low three bytes */
+/*
+ * For S32/U32 formats, 'msbits' hardware parameter is often used to deliver information about the
+ * available bit count in most significant bit. It's for the case of so-called 'left-justified' or
+ * `right-padding` sample which has less width than 32 bit.
+ */
 #define        SNDRV_PCM_FORMAT_S32_LE ((__force snd_pcm_format_t) 10)
 #define        SNDRV_PCM_FORMAT_S32_BE ((__force snd_pcm_format_t) 11)
 #define        SNDRV_PCM_FORMAT_U32_LE ((__force snd_pcm_format_t) 12)
@@ -300,7 +307,7 @@ typedef int __bitwise snd_pcm_subformat_t;
 #define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME    0x04000000  /* report estimated link audio time */
 #define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000  /* report synchronized audio/system time */
 #define SNDRV_PCM_INFO_EXPLICIT_SYNC   0x10000000      /* needs explicit sync of pointers and data */
-
+#define SNDRV_PCM_INFO_NO_REWINDS      0x20000000      /* hardware can only support monotonic changes of appl_ptr */
 #define SNDRV_PCM_INFO_DRAIN_TRIGGER   0x40000000              /* internal kernel flag - trigger in drain */
 #define SNDRV_PCM_INFO_FIFO_IN_FRAMES  0x80000000      /* internal kernel flag - FIFO size is in frames */
 
index 581f9ff..1973a18 100644 (file)
@@ -3,11 +3,7 @@
 #define __LIBPERF_INTERNAL_CPUMAP_H
 
 #include <linux/refcount.h>
-
-/** A wrapper around a CPU to avoid confusion with the perf_cpu_map's map's indices. */
-struct perf_cpu {
-       int cpu;
-};
+#include <perf/cpumap.h>
 
 /**
  * A sized, reference counted, sorted array of integers representing CPU
index 15b8faa..4a2edbd 100644 (file)
@@ -7,6 +7,11 @@
 #include <stdio.h>
 #include <stdbool.h>
 
+/** A wrapper around a CPU to avoid confusion with the perf_cpu_map's map's indices. */
+struct perf_cpu {
+       int cpu;
+};
+
 LIBPERF_API struct perf_cpu_map *perf_cpu_map__dummy_new(void);
 LIBPERF_API struct perf_cpu_map *perf_cpu_map__default_new(void);
 LIBPERF_API struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list);
index 93696af..6fa0d65 100644 (file)
@@ -2,6 +2,7 @@ LIBPERF_0.0.1 {
        global:
                libperf_init;
                perf_cpu_map__dummy_new;
+               perf_cpu_map__default_new;
                perf_cpu_map__get;
                perf_cpu_map__put;
                perf_cpu_map__new;
index f7ee07c..0d1634c 100644 (file)
@@ -13,6 +13,7 @@
 #include <internal/lib.h>
 #include <linux/kernel.h>
 #include <linux/math64.h>
+#include <linux/stringify.h>
 #include "internal.h"
 
 void perf_mmap__init(struct perf_mmap *map, struct perf_mmap *prev,
@@ -294,6 +295,103 @@ static u64 read_timestamp(void)
 
        return low | ((u64)high) << 32;
 }
+#elif defined(__aarch64__)
+#define read_sysreg(r) ({                                              \
+       u64 __val;                                                      \
+       asm volatile("mrs %0, " __stringify(r) : "=r" (__val));         \
+       __val;                                                          \
+})
+
+static u64 read_pmccntr(void)
+{
+       return read_sysreg(pmccntr_el0);
+}
+
+#define PMEVCNTR_READ(idx)                                     \
+       static u64 read_pmevcntr_##idx(void) {                  \
+               return read_sysreg(pmevcntr##idx##_el0);        \
+       }
+
+PMEVCNTR_READ(0);
+PMEVCNTR_READ(1);
+PMEVCNTR_READ(2);
+PMEVCNTR_READ(3);
+PMEVCNTR_READ(4);
+PMEVCNTR_READ(5);
+PMEVCNTR_READ(6);
+PMEVCNTR_READ(7);
+PMEVCNTR_READ(8);
+PMEVCNTR_READ(9);
+PMEVCNTR_READ(10);
+PMEVCNTR_READ(11);
+PMEVCNTR_READ(12);
+PMEVCNTR_READ(13);
+PMEVCNTR_READ(14);
+PMEVCNTR_READ(15);
+PMEVCNTR_READ(16);
+PMEVCNTR_READ(17);
+PMEVCNTR_READ(18);
+PMEVCNTR_READ(19);
+PMEVCNTR_READ(20);
+PMEVCNTR_READ(21);
+PMEVCNTR_READ(22);
+PMEVCNTR_READ(23);
+PMEVCNTR_READ(24);
+PMEVCNTR_READ(25);
+PMEVCNTR_READ(26);
+PMEVCNTR_READ(27);
+PMEVCNTR_READ(28);
+PMEVCNTR_READ(29);
+PMEVCNTR_READ(30);
+
+/*
+ * Read a value direct from PMEVCNTR<idx>
+ */
+static u64 read_perf_counter(unsigned int counter)
+{
+       static u64 (* const read_f[])(void) = {
+               read_pmevcntr_0,
+               read_pmevcntr_1,
+               read_pmevcntr_2,
+               read_pmevcntr_3,
+               read_pmevcntr_4,
+               read_pmevcntr_5,
+               read_pmevcntr_6,
+               read_pmevcntr_7,
+               read_pmevcntr_8,
+               read_pmevcntr_9,
+               read_pmevcntr_10,
+               read_pmevcntr_11,
+               read_pmevcntr_13,
+               read_pmevcntr_12,
+               read_pmevcntr_14,
+               read_pmevcntr_15,
+               read_pmevcntr_16,
+               read_pmevcntr_17,
+               read_pmevcntr_18,
+               read_pmevcntr_19,
+               read_pmevcntr_20,
+               read_pmevcntr_21,
+               read_pmevcntr_22,
+               read_pmevcntr_23,
+               read_pmevcntr_24,
+               read_pmevcntr_25,
+               read_pmevcntr_26,
+               read_pmevcntr_27,
+               read_pmevcntr_28,
+               read_pmevcntr_29,
+               read_pmevcntr_30,
+               read_pmccntr
+       };
+
+       if (counter < ARRAY_SIZE(read_f))
+               return (read_f[counter])();
+
+       return 0;
+}
+
+static u64 read_timestamp(void) { return read_sysreg(cntvct_el0); }
+
 #else
 static u64 read_perf_counter(unsigned int counter __maybe_unused) { return 0; }
 static u64 read_timestamp(void) { return 0; }
index d39378e..87b0510 100644 (file)
@@ -14,6 +14,8 @@ static int libperf_print(enum libperf_print_level level,
 int test_cpumap(int argc, char **argv)
 {
        struct perf_cpu_map *cpus;
+       struct perf_cpu cpu;
+       int idx;
 
        __T_START;
 
@@ -27,6 +29,15 @@ int test_cpumap(int argc, char **argv)
        perf_cpu_map__put(cpus);
        perf_cpu_map__put(cpus);
 
+       cpus = perf_cpu_map__default_new();
+       if (!cpus)
+               return -1;
+
+       perf_cpu_map__for_each_cpu(cpu, idx, cpus)
+               __T("wrong cpu number", cpu.cpu != -1);
+
+       perf_cpu_map__put(cpus);
+
        __T_END;
        return tests_failed == 0 ? 0 : -1;
 }
index b3479df..fa854c8 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #define _GNU_SOURCE // needed for sched.h to get sched_[gs]etaffinity and CPU_(ZERO,SET)
+#include <inttypes.h>
 #include <sched.h>
 #include <stdio.h>
 #include <stdarg.h>
@@ -526,12 +527,12 @@ static int test_stat_multiplexing(void)
 
        min = counts[0].val;
        for (i = 0; i < EVENT_NUM; i++) {
-               __T_VERBOSE("Event %2d -- Raw count = %lu, run = %lu, enable = %lu\n",
+               __T_VERBOSE("Event %2d -- Raw count = %" PRIu64 ", run = %" PRIu64 ", enable = %" PRIu64 "\n",
                            i, counts[i].val, counts[i].run, counts[i].ena);
 
                perf_counts_values__scale(&counts[i], true, &scaled);
                if (scaled == 1) {
-                       __T_VERBOSE("\t Scaled count = %lu (%.2lf%%, %lu/%lu)\n",
+                       __T_VERBOSE("\t Scaled count = %" PRIu64 " (%.2lf%%, %" PRIu64 "/%" PRIu64 ")\n",
                                    counts[i].val,
                                    (double)counts[i].run / (double)counts[i].ena * 100.0,
                                    counts[i].run, counts[i].ena);
index 33ae933..89be89a 100644 (file)
@@ -130,6 +130,9 @@ static int test_stat_user_read(int event)
        struct perf_event_attr attr = {
                .type   = PERF_TYPE_HARDWARE,
                .config = event,
+#ifdef __aarch64__
+               .config1 = 0x2,         /* Request user access */
+#endif
        };
        int err, i;
 
@@ -150,7 +153,7 @@ static int test_stat_user_read(int event)
        pc = perf_evsel__mmap_base(evsel, 0, 0);
        __T("failed to get mmapped address", pc);
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
        __T("userspace counter access not supported", pc->cap_user_rdpmc);
        __T("userspace counter access not enabled", pc->index);
        __T("userspace counter width not set", pc->pmc_width >= 32);
index 794a375..b2aec04 100644 (file)
@@ -50,15 +50,8 @@ static NORETURN inline void die(const char *err, ...)
 static inline void *xrealloc(void *ptr, size_t size)
 {
        void *ret = realloc(ptr, size);
-       if (!ret && !size)
-               ret = realloc(ptr, 1);
-       if (!ret) {
-               ret = realloc(ptr, size);
-               if (!ret && !size)
-                       ret = realloc(ptr, 1);
-               if (!ret)
-                       die("Out of memory, realloc failed");
-       }
+       if (!ret)
+               die("Out of memory, realloc failed");
        return ret;
 }
 
index c2d2ab9..7c33ec6 100644 (file)
@@ -2854,7 +2854,7 @@ static inline bool func_uaccess_safe(struct symbol *func)
 
 static inline const char *call_dest_name(struct instruction *insn)
 {
-       static char pvname[16];
+       static char pvname[19];
        struct reloc *rel;
        int idx;
 
index dec24dc..a8785de 100644 (file)
@@ -1115,6 +1115,7 @@ enum perf_ftrace_subcommand {
 int cmd_ftrace(int argc, const char **argv)
 {
        int ret;
+       int (*cmd_func)(struct perf_ftrace *) = NULL;
        struct perf_ftrace ftrace = {
                .tracer = DEFAULT_TRACER,
                .target = { .uid = UINT_MAX, },
@@ -1221,6 +1222,28 @@ int cmd_ftrace(int argc, const char **argv)
                goto out_delete_filters;
        }
 
+       switch (subcmd) {
+       case PERF_FTRACE_TRACE:
+               if (!argc && target__none(&ftrace.target))
+                       ftrace.target.system_wide = true;
+               cmd_func = __cmd_ftrace;
+               break;
+       case PERF_FTRACE_LATENCY:
+               if (list_empty(&ftrace.filters)) {
+                       pr_err("Should provide a function to measure\n");
+                       parse_options_usage(ftrace_usage, options, "T", 1);
+                       ret = -EINVAL;
+                       goto out_delete_filters;
+               }
+               cmd_func = __cmd_latency;
+               break;
+       case PERF_FTRACE_NONE:
+       default:
+               pr_err("Invalid subcommand\n");
+               ret = -EINVAL;
+               goto out_delete_filters;
+       }
+
        ret = target__validate(&ftrace.target);
        if (ret) {
                char errbuf[512];
@@ -1248,27 +1271,7 @@ int cmd_ftrace(int argc, const char **argv)
                        goto out_delete_evlist;
        }
 
-       switch (subcmd) {
-       case PERF_FTRACE_TRACE:
-               if (!argc && target__none(&ftrace.target))
-                       ftrace.target.system_wide = true;
-               ret = __cmd_ftrace(&ftrace);
-               break;
-       case PERF_FTRACE_LATENCY:
-               if (list_empty(&ftrace.filters)) {
-                       pr_err("Should provide a function to measure\n");
-                       parse_options_usage(ftrace_usage, options, "T", 1);
-                       ret = -EINVAL;
-                       goto out_delete_evlist;
-               }
-               ret = __cmd_latency(&ftrace);
-               break;
-       case PERF_FTRACE_NONE:
-       default:
-               pr_err("Invalid subcommand\n");
-               ret = -EINVAL;
-               break;
-       }
+       ret = cmd_func(&ftrace);
 
 out_delete_evlist:
        evlist__delete(ftrace.evlist);
index abae818..fa478dd 100644 (file)
@@ -463,7 +463,7 @@ static int evsel__check_attr(struct evsel *evsel, struct perf_session *session)
                return -EINVAL;
 
        if (PRINT_FIELD(WEIGHT) &&
-           evsel__check_stype(evsel, PERF_SAMPLE_WEIGHT_TYPE, "WEIGHT", PERF_OUTPUT_WEIGHT))
+           evsel__do_check_stype(evsel, PERF_SAMPLE_WEIGHT_TYPE, "WEIGHT", PERF_OUTPUT_WEIGHT, allow_user_set))
                return -EINVAL;
 
        if (PRINT_FIELD(SYM) &&
index 32844d8..52b137a 100644 (file)
@@ -1536,13 +1536,20 @@ static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
        return fprintf(fp, "         ? ");
 }
 
+static pid_t workload_pid = -1;
 static bool done = false;
 static bool interrupted = false;
 
-static void sig_handler(int sig)
+static void sighandler_interrupt(int sig __maybe_unused)
 {
-       done = true;
-       interrupted = sig == SIGINT;
+       done = interrupted = true;
+}
+
+static void sighandler_chld(int sig __maybe_unused, siginfo_t *info,
+                           void *context __maybe_unused)
+{
+       if (info->si_pid == workload_pid)
+               done = true;
 }
 
 static size_t trace__fprintf_comm_tid(struct trace *trace, struct thread *thread, FILE *fp)
@@ -3938,7 +3945,6 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
        bool draining = false;
 
        trace->live = true;
-       signal(SIGCHLD, sig_handler);
 
        if (!trace->raw_augmented_syscalls) {
                if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
@@ -4018,6 +4024,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
                        fprintf(trace->output, "Couldn't run the workload!\n");
                        goto out_delete_evlist;
                }
+               workload_pid = evlist->workload.pid;
        }
 
        err = evlist__open(evlist);
@@ -4887,10 +4894,16 @@ int cmd_trace(int argc, const char **argv)
        const char * const trace_subcommands[] = { "record", NULL };
        int err = -1;
        char bf[BUFSIZ];
+       struct sigaction sigchld_act;
 
        signal(SIGSEGV, sighandler_dump_stack);
        signal(SIGFPE, sighandler_dump_stack);
-       signal(SIGINT, sig_handler);
+       signal(SIGINT, sighandler_interrupt);
+
+       memset(&sigchld_act, 0, sizeof(sigchld_act));
+       sigchld_act.sa_flags = SA_SIGINFO;
+       sigchld_act.sa_sigaction = sighandler_chld;
+       sigaction(SIGCHLD, &sigchld_act, NULL);
 
        trace.evlist = evlist__new();
        trace.sctbl = syscalltbl__new();
index a36f49f..1116fc6 100644 (file)
@@ -45,8 +45,10 @@ Following tests are defined (with perf commands):
   perf record -d kill                           (test-record-data)
   perf record -F 100 kill                       (test-record-freq)
   perf record -g kill                           (test-record-graph-default)
+  perf record -g kill                           (test-record-graph-default-aarch64)
   perf record --call-graph dwarf kill          (test-record-graph-dwarf)
   perf record --call-graph fp kill              (test-record-graph-fp)
+  perf record --call-graph fp kill              (test-record-graph-fp-aarch64)
   perf record --group -e cycles,instructions kill (test-record-group)
   perf record -e '{cycles,instructions}' kill   (test-record-group1)
   perf record -e '{cycles/period=1/,instructions/period=2/}:S' kill (test-record-group2)
index 5d8234d..f0a18b4 100644 (file)
@@ -2,6 +2,8 @@
 command = record
 args    = --no-bpf-event -g kill >/dev/null 2>&1
 ret     = 1
+# arm64 enables registers in the default mode (fp)
+arch    = !aarch64
 
 [event:base-record]
 sample_type=295
diff --git a/tools/perf/tests/attr/test-record-graph-default-aarch64 b/tools/perf/tests/attr/test-record-graph-default-aarch64
new file mode 100644 (file)
index 0000000..e98d62e
--- /dev/null
@@ -0,0 +1,9 @@
+[config]
+command = record
+args    = --no-bpf-event -g kill >/dev/null 2>&1
+ret     = 1
+arch    = aarch64
+
+[event:base-record]
+sample_type=4391
+sample_regs_user=1073741824
index 5630521..a6e60e8 100644 (file)
@@ -2,6 +2,8 @@
 command = record
 args    = --no-bpf-event --call-graph fp kill >/dev/null 2>&1
 ret     = 1
+# arm64 enables registers in fp mode
+arch    = !aarch64
 
 [event:base-record]
 sample_type=295
diff --git a/tools/perf/tests/attr/test-record-graph-fp-aarch64 b/tools/perf/tests/attr/test-record-graph-fp-aarch64
new file mode 100644 (file)
index 0000000..cbeea99
--- /dev/null
@@ -0,0 +1,9 @@
+[config]
+command = record
+args    = --no-bpf-event --call-graph fp kill >/dev/null 2>&1
+ret     = 1
+arch    = aarch64
+
+[event:base-record]
+sample_type=4391
+sample_regs_user=1073741824
index 1f147fe..e32ece9 100644 (file)
 #include "tests.h"
 #include "../perf-sys.h"
 
-/*
- * PowerPC and S390 do not support creation of instruction breakpoints using the
- * perf_event interface.
- *
- * Just disable the test for these architectures until these issues are
- * resolved.
- */
-#if defined(__powerpc__) || defined(__s390x__)
-#define BP_ACCOUNT_IS_SUPPORTED 0
-#else
-#define BP_ACCOUNT_IS_SUPPORTED 1
-#endif
-
 #define NUM_THREADS 5
 
 static struct {
@@ -135,7 +122,7 @@ static int test__sigtrap(struct test_suite *test __maybe_unused, int subtest __m
        char sbuf[STRERR_BUFSIZE];
        int i, fd, ret = TEST_FAIL;
 
-       if (!BP_ACCOUNT_IS_SUPPORTED) {
+       if (!BP_SIGNAL_IS_SUPPORTED) {
                pr_debug("Test not supported on this architecture");
                return TEST_SKIP;
        }
index 3109d7b..3d27878 100755 (executable)
@@ -4,7 +4,7 @@
 [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/
 
 printf "static const char *prctl_options[] = {\n"
-regex='^#define[[:space:]]+PR_(\w+)[[:space:]]*([[:xdigit:]]+).*'
+regex='^#define[[:space:]]{1}PR_(\w+)[[:space:]]*([[:xdigit:]]+)([[:space:]]*\/.*)?$'
 egrep $regex ${header_dir}/prctl.h | grep -v PR_SET_PTRACER | \
        sed -r "s/$regex/\2 \1/g"       | \
        sort -n | xargs printf "\t[%s] = \"%s\",\n"
index 0190068..8190a12 100644 (file)
@@ -2036,6 +2036,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
        memset(&objdump_process, 0, sizeof(objdump_process));
        objdump_process.argv = objdump_argv;
        objdump_process.out = -1;
+       objdump_process.err = -1;
        if (start_command(&objdump_process)) {
                pr_err("Failure starting to run %s\n", command);
                err = -1;
index 7ecfaac..16ec605 100644 (file)
@@ -1220,9 +1220,10 @@ bpf__obj_config_map(struct bpf_object *obj,
        pr_debug("ERROR: Invalid map config option '%s'\n", map_opt);
        err = -BPF_LOADER_ERRNO__OBJCONF_MAP_OPT;
 out:
-       free(map_name);
        if (!err)
                *key_scan_pos += strlen(map_opt);
+
+       free(map_name);
        return err;
 }
 
index 631e34a..ac60c08 100644 (file)
@@ -266,7 +266,7 @@ static int bperf_cgrp__read(struct evsel *evsel)
                idx = evsel->core.idx;
                err = bpf_map_lookup_elem(reading_map_fd, &idx, values);
                if (err) {
-                       pr_err("bpf map lookup falied: idx=%u, event=%s, cgrp=%s\n",
+                       pr_err("bpf map lookup failed: idx=%u, event=%s, cgrp=%s\n",
                               idx, evsel__name(evsel), evsel->cgrp->name);
                        goto out;
                }
index 4f672f7..8b95fb3 100644 (file)
@@ -50,8 +50,6 @@ struct cs_etm_auxtrace {
        u8 timeless_decoding;
        u8 snapshot_mode;
        u8 data_queued;
-       u8 sample_branches;
-       u8 sample_instructions;
 
        int num_cpu;
        u64 latest_kernel_timestamp;
@@ -410,8 +408,8 @@ static void cs_etm__packet_swap(struct cs_etm_auxtrace *etm,
 {
        struct cs_etm_packet *tmp;
 
-       if (etm->sample_branches || etm->synth_opts.last_branch ||
-           etm->sample_instructions) {
+       if (etm->synth_opts.branches || etm->synth_opts.last_branch ||
+           etm->synth_opts.instructions) {
                /*
                 * Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for
                 * the next incoming packet.
@@ -1365,7 +1363,6 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm,
                err = cs_etm__synth_event(session, &attr, id);
                if (err)
                        return err;
-               etm->sample_branches = true;
                etm->branches_sample_type = attr.sample_type;
                etm->branches_id = id;
                id += 1;
@@ -1389,7 +1386,6 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm,
                err = cs_etm__synth_event(session, &attr, id);
                if (err)
                        return err;
-               etm->sample_instructions = true;
                etm->instructions_sample_type = attr.sample_type;
                etm->instructions_id = id;
                id += 1;
@@ -1420,7 +1416,7 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
            tidq->prev_packet->last_instr_taken_branch)
                cs_etm__update_last_branch_rb(etmq, tidq);
 
-       if (etm->sample_instructions &&
+       if (etm->synth_opts.instructions &&
            tidq->period_instructions >= etm->instructions_sample_period) {
                /*
                 * Emit instruction sample periodically
@@ -1503,7 +1499,7 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
                }
        }
 
-       if (etm->sample_branches) {
+       if (etm->synth_opts.branches) {
                bool generate_sample = false;
 
                /* Generate sample for tracing on packet */
@@ -1557,6 +1553,7 @@ static int cs_etm__flush(struct cs_etm_queue *etmq,
                goto swap_packet;
 
        if (etmq->etm->synth_opts.last_branch &&
+           etmq->etm->synth_opts.instructions &&
            tidq->prev_packet->sample_type == CS_ETM_RANGE) {
                u64 addr;
 
@@ -1582,7 +1579,7 @@ static int cs_etm__flush(struct cs_etm_queue *etmq,
 
        }
 
-       if (etm->sample_branches &&
+       if (etm->synth_opts.branches &&
            tidq->prev_packet->sample_type == CS_ETM_RANGE) {
                err = cs_etm__synth_branch_sample(etmq, tidq);
                if (err)
@@ -1614,6 +1611,7 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq,
         * the trace.
         */
        if (etmq->etm->synth_opts.last_branch &&
+           etmq->etm->synth_opts.instructions &&
            tidq->prev_packet->sample_type == CS_ETM_RANGE) {
                u64 addr;
 
index f5d260b..15a4547 100644 (file)
@@ -44,10 +44,6 @@ int perf_data__create_dir(struct perf_data *data, int nr)
        if (!files)
                return -ENOMEM;
 
-       data->dir.version = PERF_DIR_VERSION;
-       data->dir.files   = files;
-       data->dir.nr      = nr;
-
        for (i = 0; i < nr; i++) {
                struct perf_data_file *file = &files[i];
 
@@ -62,6 +58,9 @@ int perf_data__create_dir(struct perf_data *data, int nr)
                file->fd = ret;
        }
 
+       data->dir.version = PERF_DIR_VERSION;
+       data->dir.files   = files;
+       data->dir.nr      = nr;
        return 0;
 
 out_err:
index 7f23421..57f02be 100644 (file)
@@ -154,8 +154,8 @@ int evlist__fix_hybrid_cpus(struct evlist *evlist, const char *cpu_list)
                perf_cpu_map__put(matched_cpus);
                perf_cpu_map__put(unmatched_cpus);
        }
-
-       ret = (unmatched_count == events_nr) ? -1 : 0;
+       if (events_nr)
+               ret = (unmatched_count == events_nr) ? -1 : 0;
 out:
        perf_cpu_map__put(cpus);
        return ret;
index f70ba56..3945500 100644 (file)
@@ -2073,6 +2073,7 @@ static void ip__resolve_ams(struct thread *thread,
 
        ams->addr = ip;
        ams->al_addr = al.addr;
+       ams->al_level = al.level;
        ams->ms.maps = al.maps;
        ams->ms.sym = al.sym;
        ams->ms.map = al.map;
@@ -2092,6 +2093,7 @@ static void ip__resolve_data(struct thread *thread,
 
        ams->addr = addr;
        ams->al_addr = al.addr;
+       ams->al_level = al.level;
        ams->ms.maps = al.maps;
        ams->ms.sym = al.sym;
        ams->ms.map = al.map;
index 7d22ade..e08817b 100644 (file)
@@ -18,6 +18,7 @@ struct addr_map_symbol {
        struct map_symbol ms;
        u64           addr;
        u64           al_addr;
+       char          al_level;
        u64           phys_addr;
        u64           data_page_size;
 };
index 47b7531..98af3fa 100644 (file)
@@ -52,7 +52,7 @@ static void __p_branch_sample_type(char *buf, size_t size, u64 value)
                bit_name(ABORT_TX), bit_name(IN_TX), bit_name(NO_TX),
                bit_name(COND), bit_name(CALL_STACK), bit_name(IND_JUMP),
                bit_name(CALL), bit_name(NO_FLAGS), bit_name(NO_CYCLES),
-               bit_name(HW_INDEX),
+               bit_name(TYPE_SAVE), bit_name(HW_INDEX),
                { .name = NULL, }
        };
 #undef bit_name
index 2c0d30f..498b057 100644 (file)
@@ -1503,11 +1503,12 @@ static int machines__deliver_event(struct machines *machines,
                        ++evlist->stats.nr_unknown_id;
                        return 0;
                }
-               dump_sample(evsel, event, sample, perf_env__arch(machine->env));
                if (machine == NULL) {
                        ++evlist->stats.nr_unprocessable_samples;
+                       dump_sample(evsel, event, sample, perf_env__arch(NULL));
                        return 0;
                }
+               dump_sample(evsel, event, sample, perf_env__arch(machine->env));
                return evlist__deliver_sample(evlist, tool, event, sample, evsel, machine);
        case PERF_RECORD_MMAP:
                return tool->mmap(tool, event, sample, machine);
index cfba8c3..2da081e 100644 (file)
@@ -915,7 +915,7 @@ static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
                struct addr_map_symbol *from = &he->branch_info->from;
 
                return _hist_entry__sym_snprintf(&from->ms, from->al_addr,
-                                                he->level, bf, size, width);
+                                                from->al_level, bf, size, width);
        }
 
        return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
@@ -928,7 +928,7 @@ static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
                struct addr_map_symbol *to = &he->branch_info->to;
 
                return _hist_entry__sym_snprintf(&to->ms, to->al_addr,
-                                                he->level, bf, size, width);
+                                                to->al_level, bf, size, width);
        }
 
        return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
index 5db83e5..9cbe351 100644 (file)
@@ -585,15 +585,16 @@ static void collect_all_aliases(struct perf_stat_config *config, struct evsel *c
 
        alias = list_prepare_entry(counter, &(evlist->core.entries), core.node);
        list_for_each_entry_continue (alias, &evlist->core.entries, core.node) {
-               if (strcmp(evsel__name(alias), evsel__name(counter)) ||
-                   alias->scale != counter->scale ||
-                   alias->cgrp != counter->cgrp ||
-                   strcmp(alias->unit, counter->unit) ||
-                   evsel__is_clock(alias) != evsel__is_clock(counter) ||
-                   !strcmp(alias->pmu_name, counter->pmu_name))
-                       break;
-               alias->merged_stat = true;
-               cb(config, alias, data, false);
+               /* Merge events with the same name, etc. but on different PMUs. */
+               if (!strcmp(evsel__name(alias), evsel__name(counter)) &&
+                       alias->scale == counter->scale &&
+                       alias->cgrp == counter->cgrp &&
+                       !strcmp(alias->unit, counter->unit) &&
+                       evsel__is_clock(alias) == evsel__is_clock(counter) &&
+                       strcmp(alias->pmu_name, counter->pmu_name)) {
+                       alias->merged_stat = true;
+                       cb(config, alias, data, false);
+               }
        }
 }
 
index 70f0956..b654de0 100644 (file)
@@ -1784,6 +1784,25 @@ int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too
                                  perf_event__handler_t process, bool needs_mmap,
                                  bool data_mmap, unsigned int nr_threads_synthesize)
 {
+       /*
+        * When perf runs in non-root PID namespace, and the namespace's proc FS
+        * is not mounted, nsinfo__is_in_root_namespace() returns false.
+        * In this case, the proc FS is coming for the parent namespace, thus
+        * perf tool will wrongly gather process info from its parent PID
+        * namespace.
+        *
+        * To avoid the confusion that the perf tool runs in a child PID
+        * namespace but it synthesizes thread info from its parent PID
+        * namespace, returns failure with warning.
+        */
+       if (!nsinfo__is_in_root_namespace()) {
+               pr_err("Perf runs in non-root PID namespace but it tries to ");
+               pr_err("gather process info from its parent PID namespace.\n");
+               pr_err("Please mount the proc file system properly, e.g. ");
+               pr_err("add the option '--mount-proc' for unshare command.\n");
+               return -EPERM;
+       }
+
        if (target__has_task(target))
                return perf_event__synthesize_thread_map(tool, threads, process, machine,
                                                         needs_mmap, data_mmap);
index b0be5f4..79d1023 100644 (file)
@@ -90,7 +90,7 @@ EXTRA_WARNINGS += -Wstrict-aliasing=3
 
 else ifneq ($(CROSS_COMPILE),)
 CLANG_CROSS_FLAGS := --target=$(notdir $(CROSS_COMPILE:%-=%))
-GCC_TOOLCHAIN_DIR := $(dir $(shell which $(CROSS_COMPILE)gcc))
+GCC_TOOLCHAIN_DIR := $(dir $(shell which $(CROSS_COMPILE)gcc 2>/dev/null))
 ifneq ($(GCC_TOOLCHAIN_DIR),)
 CLANG_CROSS_FLAGS += --prefix=$(GCC_TOOLCHAIN_DIR)$(notdir $(CROSS_COMPILE))
 CLANG_CROSS_FLAGS += --sysroot=$(shell $(CROSS_COMPILE)gcc -print-sysroot)
index 44bbe54..3c4196c 100644 (file)
@@ -6,6 +6,7 @@
 # Author: Felix Guo <felixguoxiuping@gmail.com>
 # Author: Brendan Higgins <brendanhiggins@google.com>
 
+import importlib.abc
 import importlib.util
 import logging
 import subprocess
index 4f32133..13d854a 100755 (executable)
@@ -61,7 +61,7 @@ def main(argv: Sequence[str]) -> None:
                elif isinstance(ex, subprocess.CalledProcessError):
                        print(f'{name}: FAILED')
                else:
-                       print('{name}: unexpected exception: {ex}')
+                       print(f'{name}: unexpected exception: {ex}')
                        continue
 
                output = ex.output
index 16ec895..5bd9e6e 100644 (file)
@@ -74,7 +74,7 @@ static inline unsigned long page_to_phys(struct page *page)
              __UNIQUE_ID(min1_), __UNIQUE_ID(min2_),   \
              x, y)
 
-#define preemptible() (1)
+#define pagefault_disabled() (0)
 
 static inline void *kmap(struct page *page)
 {
@@ -127,6 +127,7 @@ kmalloc_array(unsigned int n, unsigned int size, unsigned int flags)
 #define kmemleak_free(a)
 
 #define PageSlab(p) (0)
+#define flush_dcache_page(p)
 
 #define MAX_ERRNO      4095
 
index af798b9..a3c1e67 100644 (file)
@@ -261,7 +261,7 @@ static void ptrace_sve_fpsimd(pid_t child, const struct vec_type *type)
        }
 
        ksft_test_result((sve->flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD,
-                        "Set FPSIMD registers via %s\n", type->name);
+                        "Got FPSIMD registers via %s\n", type->name);
        if ((sve->flags & SVE_PT_REGS_MASK) != SVE_PT_REGS_FPSIMD)
                goto out;
 
@@ -557,7 +557,14 @@ static int do_parent(pid_t child)
                }
 
                /* prctl() flags */
-               ptrace_set_get_inherit(child, &vec_types[i]);
+               if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {
+                       ptrace_set_get_inherit(child, &vec_types[i]);
+               } else {
+                       ksft_test_result_skip("%s SVE_PT_VL_INHERIT set\n",
+                                             vec_types[i].name);
+                       ksft_test_result_skip("%s SVE_PT_VL_INHERIT cleared\n",
+                                             vec_types[i].name);
+               }
 
                /* Step through every possible VQ */
                for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) {
diff --git a/tools/testing/selftests/bpf/prog_tests/timer_crash.c b/tools/testing/selftests/bpf/prog_tests/timer_crash.c
new file mode 100644 (file)
index 0000000..f74b823
--- /dev/null
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <test_progs.h>
+#include "timer_crash.skel.h"
+
+enum {
+       MODE_ARRAY,
+       MODE_HASH,
+};
+
+static void test_timer_crash_mode(int mode)
+{
+       struct timer_crash *skel;
+
+       skel = timer_crash__open_and_load();
+       if (!ASSERT_OK_PTR(skel, "timer_crash__open_and_load"))
+               return;
+       skel->bss->pid = getpid();
+       skel->bss->crash_map = mode;
+       if (!ASSERT_OK(timer_crash__attach(skel), "timer_crash__attach"))
+               goto end;
+       usleep(1);
+end:
+       timer_crash__destroy(skel);
+}
+
+void test_timer_crash(void)
+{
+       if (test__start_subtest("array"))
+               test_timer_crash_mode(MODE_ARRAY);
+       if (test__start_subtest("hash"))
+               test_timer_crash_mode(MODE_HASH);
+}
index 2966564..6c85b00 100644 (file)
@@ -235,7 +235,7 @@ SEC("sk_msg1")
 int bpf_prog4(struct sk_msg_md *msg)
 {
        int *bytes, zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5;
-       int *start, *end, *start_push, *end_push, *start_pop, *pop;
+       int *start, *end, *start_push, *end_push, *start_pop, *pop, err = 0;
 
        bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
        if (bytes)
@@ -249,8 +249,11 @@ int bpf_prog4(struct sk_msg_md *msg)
                bpf_msg_pull_data(msg, *start, *end, 0);
        start_push = bpf_map_lookup_elem(&sock_bytes, &two);
        end_push = bpf_map_lookup_elem(&sock_bytes, &three);
-       if (start_push && end_push)
-               bpf_msg_push_data(msg, *start_push, *end_push, 0);
+       if (start_push && end_push) {
+               err = bpf_msg_push_data(msg, *start_push, *end_push, 0);
+               if (err)
+                       return SK_DROP;
+       }
        start_pop = bpf_map_lookup_elem(&sock_bytes, &four);
        pop = bpf_map_lookup_elem(&sock_bytes, &five);
        if (start_pop && pop)
@@ -263,6 +266,7 @@ int bpf_prog6(struct sk_msg_md *msg)
 {
        int zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5, key = 0;
        int *bytes, *start, *end, *start_push, *end_push, *start_pop, *pop, *f;
+       int err = 0;
        __u64 flags = 0;
 
        bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
@@ -279,8 +283,11 @@ int bpf_prog6(struct sk_msg_md *msg)
 
        start_push = bpf_map_lookup_elem(&sock_bytes, &two);
        end_push = bpf_map_lookup_elem(&sock_bytes, &three);
-       if (start_push && end_push)
-               bpf_msg_push_data(msg, *start_push, *end_push, 0);
+       if (start_push && end_push) {
+               err = bpf_msg_push_data(msg, *start_push, *end_push, 0);
+               if (err)
+                       return SK_DROP;
+       }
 
        start_pop = bpf_map_lookup_elem(&sock_bytes, &four);
        pop = bpf_map_lookup_elem(&sock_bytes, &five);
@@ -338,7 +345,7 @@ SEC("sk_msg5")
 int bpf_prog10(struct sk_msg_md *msg)
 {
        int *bytes, *start, *end, *start_push, *end_push, *start_pop, *pop;
-       int zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5;
+       int zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5, err = 0;
 
        bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero);
        if (bytes)
@@ -352,8 +359,11 @@ int bpf_prog10(struct sk_msg_md *msg)
                bpf_msg_pull_data(msg, *start, *end, 0);
        start_push = bpf_map_lookup_elem(&sock_bytes, &two);
        end_push = bpf_map_lookup_elem(&sock_bytes, &three);
-       if (start_push && end_push)
-               bpf_msg_push_data(msg, *start_push, *end_push, 0);
+       if (start_push && end_push) {
+               err = bpf_msg_push_data(msg, *start_push, *end_push, 0);
+               if (err)
+                       return SK_PASS;
+       }
        start_pop = bpf_map_lookup_elem(&sock_bytes, &four);
        pop = bpf_map_lookup_elem(&sock_bytes, &five);
        if (start_pop && pop)
diff --git a/tools/testing/selftests/bpf/progs/timer_crash.c b/tools/testing/selftests/bpf/progs/timer_crash.c
new file mode 100644 (file)
index 0000000..f8f7944
--- /dev/null
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <vmlinux.h>
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_helpers.h>
+
+struct map_elem {
+       struct bpf_timer timer;
+       struct bpf_spin_lock lock;
+};
+
+struct {
+       __uint(type, BPF_MAP_TYPE_ARRAY);
+       __uint(max_entries, 1);
+       __type(key, int);
+       __type(value, struct map_elem);
+} amap SEC(".maps");
+
+struct {
+       __uint(type, BPF_MAP_TYPE_HASH);
+       __uint(max_entries, 1);
+       __type(key, int);
+       __type(value, struct map_elem);
+} hmap SEC(".maps");
+
+int pid = 0;
+int crash_map = 0; /* 0 for amap, 1 for hmap */
+
+SEC("fentry/do_nanosleep")
+int sys_enter(void *ctx)
+{
+       struct map_elem *e, value = {};
+       void *map = crash_map ? (void *)&hmap : (void *)&amap;
+
+       if (bpf_get_current_task_btf()->tgid != pid)
+               return 0;
+
+       *(void **)&value = (void *)0xdeadcaf3;
+
+       bpf_map_update_elem(map, &(int){0}, &value, 0);
+       /* For array map, doing bpf_map_update_elem will do a
+        * check_and_free_timer_in_array, which will trigger the crash if timer
+        * pointer was overwritten, for hmap we need to use bpf_timer_cancel.
+        */
+       if (crash_map == 1) {
+               e = bpf_map_lookup_elem(map, &(int){0});
+               if (!e)
+                       return 0;
+               bpf_timer_cancel(&e->timer);
+       }
+       return 0;
+}
+
+char _license[] SEC("license") = "GPL";
index ebf68dc..2893e9f 100644 (file)
@@ -28,7 +28,6 @@
 // 5. We can read keycode from same /dev/lirc device
 
 #include <linux/bpf.h>
-#include <linux/lirc.h>
 #include <linux/input.h>
 #include <errno.h>
 #include <stdio.h>
index 076cf43..cd45821 100644 (file)
@@ -126,8 +126,6 @@ static void test_clone3(uint64_t flags, size_t size, int expected,
 
 int main(int argc, char *argv[])
 {
-       pid_t pid;
-
        uid_t uid = getuid();
 
        ksft_print_header();
index 31f8c9a..60ce18e 100755 (executable)
@@ -194,5 +194,5 @@ prerequisite
 
 # Run requested functions
 clear_dumps $OUTFILE
-do_test >> $OUTFILE.txt
+do_test | tee -a $OUTFILE.txt
 dmesg_dumps $OUTFILE
index dd61118..2d7fca4 100644 (file)
@@ -3,9 +3,9 @@ CFLAGS = -Wall
 CFLAGS += -Wno-nonnull
 CFLAGS += -D_GNU_SOURCE
 
-TEST_PROGS := binfmt_script non-regular
-TEST_GEN_PROGS := execveat load_address_4096 load_address_2097152 load_address_16777216
-TEST_GEN_FILES := execveat.symlink execveat.denatured script subdir pipe
+TEST_PROGS := binfmt_script
+TEST_GEN_PROGS := execveat load_address_4096 load_address_2097152 load_address_16777216 non-regular
+TEST_GEN_FILES := execveat.symlink execveat.denatured script subdir
 # Makefile is a run-time dependency, since it's accessed by the execveat test
 TEST_FILES := Makefile
 
index e96e279..25432b8 100644 (file)
@@ -19,7 +19,7 @@ fail() { # mesg
 
 FILTER=set_ftrace_filter
 FUNC1="schedule"
-FUNC2="do_softirq"
+FUNC2="scheduler_tick"
 
 ALL_FUNCS="#### all functions enabled ####"
 
index 12631f0..11e157d 100644 (file)
@@ -11,7 +11,7 @@ all:
        @for DIR in $(SUBDIRS); do              \
                BUILD_TARGET=$(OUTPUT)/$$DIR;   \
                mkdir $$BUILD_TARGET  -p;       \
-               make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
+               $(MAKE) OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
                if [ -e $$DIR/$(TEST_PROGS) ]; then \
                        rsync -a $$DIR/$(TEST_PROGS) $$BUILD_TARGET/; \
                fi \
@@ -32,6 +32,6 @@ override define CLEAN
        @for DIR in $(SUBDIRS); do              \
                BUILD_TARGET=$(OUTPUT)/$$DIR;   \
                mkdir $$BUILD_TARGET  -p;       \
-               make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
+               $(MAKE) OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
        done
 endef
index 06256c9..f4a15cb 100644 (file)
 #define SYSFS_PATH_MAX 256
 #define DNAME_PATH_MAX 256
 
+/*
+ * Support ancient lirc.h which does not have these values. Can be removed
+ * once RHEL 8 is no longer a relevant testing platform.
+ */
+#if RC_PROTO_MAX < 26
+#define RC_PROTO_RCMM12 24
+#define RC_PROTO_RCMM24 25
+#define RC_PROTO_RCMM32 26
+#endif
+
 static const struct {
        enum rc_proto proto;
        const char *name;
index 471eaa7..1177940 100644 (file)
@@ -877,7 +877,8 @@ static void __timeout_handler(int sig, siginfo_t *info, void *ucontext)
        }
 
        t->timed_out = true;
-       kill(t->pid, SIGKILL);
+       // signal process group
+       kill(-(t->pid), SIGKILL);
 }
 
 void __wait_for_test(struct __test_metadata *t)
@@ -987,6 +988,7 @@ void __run_test(struct __fixture_metadata *f,
                ksft_print_msg("ERROR SPAWNING TEST CHILD\n");
                t->passed = 0;
        } else if (t->pid == 0) {
+               setpgrp();
                t->fn(t, variant);
                if (t->skip)
                        _exit(255);
index 81ebf99..17c3f07 100644 (file)
@@ -82,9 +82,9 @@ TEST_GEN_PROGS_x86_64 += x86_64/tsc_msrs_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_pmu_msrs_test
 TEST_GEN_PROGS_x86_64 += x86_64/xen_shinfo_test
 TEST_GEN_PROGS_x86_64 += x86_64/xen_vmcall_test
-TEST_GEN_PROGS_x86_64 += x86_64/vmx_pi_mmio_test
 TEST_GEN_PROGS_x86_64 += x86_64/sev_migrate_tests
 TEST_GEN_PROGS_x86_64 += x86_64/amx_test
+TEST_GEN_PROGS_x86_64 += access_tracking_perf_test
 TEST_GEN_PROGS_x86_64 += demand_paging_test
 TEST_GEN_PROGS_x86_64 += dirty_log_test
 TEST_GEN_PROGS_x86_64 += dirty_log_perf_test
index 66775de..4ed6aa0 100644 (file)
@@ -345,7 +345,6 @@ struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus,
  *   guest_code - The vCPU's entry point
  */
 void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code);
-void vm_xsave_req_perm(void);
 
 bool vm_is_unrestricted_guest(struct kvm_vm *vm);
 
index 423d8a6..8a470da 100644 (file)
@@ -458,6 +458,7 @@ uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2,
 struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void);
 void vcpu_set_hv_cpuid(struct kvm_vm *vm, uint32_t vcpuid);
 struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vm *vm, uint32_t vcpuid);
+void vm_xsave_req_perm(int bit);
 
 enum x86_page_size {
        X86_PAGE_SIZE_4K = 0,
index 8c53f96..d8cf851 100644 (file)
@@ -393,13 +393,6 @@ struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus,
        struct kvm_vm *vm;
        int i;
 
-#ifdef __x86_64__
-       /*
-        * Permission needs to be requested before KVM_SET_CPUID2.
-        */
-       vm_xsave_req_perm();
-#endif
-
        /* Force slot0 memory size not small than DEFAULT_GUEST_PHY_PAGES */
        if (slot0_mem_pages < DEFAULT_GUEST_PHY_PAGES)
                slot0_mem_pages = DEFAULT_GUEST_PHY_PAGES;
index 5f9d7e9..9f000df 100644 (file)
@@ -665,16 +665,31 @@ static bool is_xfd_supported(void)
        return !!(eax & CPUID_XFD_BIT);
 }
 
-void vm_xsave_req_perm(void)
+void vm_xsave_req_perm(int bit)
 {
-       unsigned long bitmask;
+       int kvm_fd;
+       u64 bitmask;
        long rc;
+       struct kvm_device_attr attr = {
+               .group = 0,
+               .attr = KVM_X86_XCOMP_GUEST_SUPP,
+               .addr = (unsigned long) &bitmask
+       };
+
+       kvm_fd = open_kvm_dev_path_or_exit();
+       rc = ioctl(kvm_fd, KVM_GET_DEVICE_ATTR, &attr);
+       close(kvm_fd);
+       if (rc == -1 && (errno == ENXIO || errno == EINVAL))
+               exit(KSFT_SKIP);
+       TEST_ASSERT(rc == 0, "KVM_GET_DEVICE_ATTR(0, KVM_X86_XCOMP_GUEST_SUPP) error: %ld", rc);
+       if (!(bitmask & (1ULL << bit)))
+               exit(KSFT_SKIP);
 
        if (!is_xfd_supported())
-               return;
+               exit(KSFT_SKIP);
+
+       rc = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_GUEST_PERM, bit);
 
-       rc = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_GUEST_PERM,
-                    XSTATE_XTILE_DATA_BIT);
        /*
         * The older kernel version(<5.15) can't support
         * ARCH_REQ_XCOMP_GUEST_PERM and directly return.
@@ -684,7 +699,7 @@ void vm_xsave_req_perm(void)
 
        rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_GUEST_PERM, &bitmask);
        TEST_ASSERT(rc == 0, "prctl(ARCH_GET_XCOMP_GUEST_PERM) error: %ld", rc);
-       TEST_ASSERT(bitmask & XFEATURE_XTILE_MASK,
+       TEST_ASSERT(bitmask & (1ULL << bit),
                    "prctl(ARCH_REQ_XCOMP_GUEST_PERM) failure bitmask=0x%lx",
                    bitmask);
 }
index 523c1e9..52a3ef6 100644 (file)
@@ -329,6 +329,8 @@ int main(int argc, char *argv[])
        u32 amx_offset;
        int stage, ret;
 
+       vm_xsave_req_perm(XSTATE_XTILE_DATA_BIT);
+
        /* Create VM */
        vm = vm_create_default(VCPU_ID, 0, guest_code);
 
index 2da8eb8..a626d40 100644 (file)
@@ -105,7 +105,6 @@ static void guest_code(void *arg)
 
                if (cpu_has_svm()) {
                        run_guest(svm->vmcb, svm->vmcb_gpa);
-                       svm->vmcb->save.rip += 3;
                        run_guest(svm->vmcb, svm->vmcb_gpa);
                } else {
                        vmlaunch();
index a26a3fa..46f39ee 100644 (file)
@@ -3,9 +3,9 @@ CONFIG_DEBUG_LIST=y
 CONFIG_SLAB_FREELIST_HARDENED=y
 CONFIG_FORTIFY_SOURCE=y
 CONFIG_HARDENED_USERCOPY=y
-# CONFIG_HARDENED_USERCOPY_FALLBACK is not set
 CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=y
 CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y
+CONFIG_UBSAN=y
 CONFIG_UBSAN_BOUNDS=y
 CONFIG_UBSAN_TRAP=y
 CONFIG_STACKPROTECTOR_STRONG=y
index 192a289..94df269 100644 (file)
@@ -455,6 +455,7 @@ static void mfd_fail_write(int fd)
                        printf("mmap()+mprotect() didn't fail as expected\n");
                        abort();
                }
+               munmap(p, mfd_def_size);
        }
 
        /* verify PUNCH_HOLE fails */
index e541066..4c88238 100644 (file)
@@ -207,15 +207,21 @@ TEST(check_file_mmap)
 
        errno = 0;
        fd = open(".", O_TMPFILE | O_RDWR, 0600);
-       ASSERT_NE(-1, fd) {
-               TH_LOG("Can't create temporary file: %s",
-                       strerror(errno));
+       if (fd < 0) {
+               ASSERT_EQ(errno, EOPNOTSUPP) {
+                       TH_LOG("Can't create temporary file: %s",
+                              strerror(errno));
+               }
+               SKIP(goto out_free, "O_TMPFILE not supported by filesystem.");
        }
        errno = 0;
        retval = fallocate(fd, 0, 0, FILE_SIZE);
-       ASSERT_EQ(0, retval) {
-               TH_LOG("Error allocating space for the temporary file: %s",
-                       strerror(errno));
+       if (retval) {
+               ASSERT_EQ(errno, EOPNOTSUPP) {
+                       TH_LOG("Error allocating space for the temporary file: %s",
+                              strerror(errno));
+               }
+               SKIP(goto out_close, "fallocate not supported by filesystem.");
        }
 
        /*
@@ -271,7 +277,9 @@ TEST(check_file_mmap)
        }
 
        munmap(addr, FILE_SIZE);
+out_close:
        close(fd);
+out_free:
        free(vec);
 }
 
index f31205f..8c5fea6 100644 (file)
@@ -1236,7 +1236,7 @@ static int get_userns_fd(unsigned long nsid, unsigned long hostid, unsigned long
 }
 
 /**
- * Validate that an attached mount in our mount namespace can be idmapped.
+ * Validate that an attached mount in our mount namespace cannot be idmapped.
  * (The kernel enforces that the mount's mount namespace and the caller's mount
  *  namespace match.)
  */
@@ -1259,7 +1259,7 @@ TEST_F(mount_setattr_idmapped, attached_mount_inside_current_mount_namespace)
 
        attr.userns_fd  = get_userns_fd(0, 10000, 10000);
        ASSERT_GE(attr.userns_fd, 0);
-       ASSERT_EQ(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
+       ASSERT_NE(sys_mount_setattr(open_tree_fd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), 0);
        ASSERT_EQ(close(attr.userns_fd), 0);
        ASSERT_EQ(close(open_tree_fd), 0);
 }
index 8f6997d..d9d1d41 100644 (file)
@@ -240,11 +240,8 @@ static int check_ioam6_data(__u8 **p, struct ioam6_trace_hdr *ioam6h,
                *p += sizeof(__u32);
        }
 
-       if (ioam6h->type.bit6) {
-               if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
-                       return 1;
+       if (ioam6h->type.bit6)
                *p += sizeof(__u32);
-       }
 
        if (ioam6h->type.bit7) {
                if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
index 2674ba2..ff82102 100755 (executable)
@@ -71,6 +71,36 @@ chk_msk_remote_key_nr()
                __chk_nr "grep -c remote_key" $*
 }
 
+# $1: ns, $2: port
+wait_local_port_listen()
+{
+       local listener_ns="${1}"
+       local port="${2}"
+
+       local port_hex i
+
+       port_hex="$(printf "%04X" "${port}")"
+       for i in $(seq 10); do
+               ip netns exec "${listener_ns}" cat /proc/net/tcp | \
+                       awk "BEGIN {rc=1} {if (\$2 ~ /:${port_hex}\$/ && \$4 ~ /0A/) {rc=0; exit}} END {exit rc}" &&
+                       break
+               sleep 0.1
+       done
+}
+
+wait_connected()
+{
+       local listener_ns="${1}"
+       local port="${2}"
+
+       local port_hex i
+
+       port_hex="$(printf "%04X" "${port}")"
+       for i in $(seq 10); do
+               ip netns exec ${listener_ns} grep -q " 0100007F:${port_hex} " /proc/net/tcp && break
+               sleep 0.1
+       done
+}
 
 trap cleanup EXIT
 ip netns add $ns
@@ -81,15 +111,15 @@ echo "a" | \
                ip netns exec $ns \
                        ./mptcp_connect -p 10000 -l -t ${timeout_poll} \
                                0.0.0.0 >/dev/null &
-sleep 0.1
+wait_local_port_listen $ns 10000
 chk_msk_nr 0 "no msk on netns creation"
 
 echo "b" | \
        timeout ${timeout_test} \
                ip netns exec $ns \
-                       ./mptcp_connect -p 10000 -j -t ${timeout_poll} \
+                       ./mptcp_connect -p 10000 -r 0 -t ${timeout_poll} \
                                127.0.0.1 >/dev/null &
-sleep 0.1
+wait_connected $ns 10000
 chk_msk_nr 2 "after MPC handshake "
 chk_msk_remote_key_nr 2 "....chk remote_key"
 chk_msk_fallback_nr 0 "....chk no fallback"
@@ -101,13 +131,13 @@ echo "a" | \
                ip netns exec $ns \
                        ./mptcp_connect -p 10001 -l -s TCP -t ${timeout_poll} \
                                0.0.0.0 >/dev/null &
-sleep 0.1
+wait_local_port_listen $ns 10001
 echo "b" | \
        timeout ${timeout_test} \
                ip netns exec $ns \
-                       ./mptcp_connect -p 10001 -j -t ${timeout_poll} \
+                       ./mptcp_connect -p 10001 -r 0 -t ${timeout_poll} \
                                127.0.0.1 >/dev/null &
-sleep 0.1
+wait_connected $ns 10001
 chk_msk_fallback_nr 1 "check fallback"
 flush_pids
 
@@ -119,7 +149,7 @@ for I in `seq 1 $NR_CLIENTS`; do
                                ./mptcp_connect -p $((I+10001)) -l -w 10 \
                                        -t ${timeout_poll} 0.0.0.0 >/dev/null &
 done
-sleep 0.1
+wait_local_port_listen $ns $((NR_CLIENTS + 10001))
 
 for I in `seq 1 $NR_CLIENTS`; do
        echo "b" | \
index 27d0eb9..0c8a2a2 100755 (executable)
@@ -75,6 +75,7 @@ init()
 
                # let $ns2 reach any $ns1 address from any interface
                ip -net "$ns2" route add default via 10.0.$i.1 dev ns2eth$i metric 10$i
+               ip -net "$ns2" route add default via dead:beef:$i::1 dev ns2eth$i metric 10$i
        done
 }
 
@@ -659,6 +660,7 @@ chk_join_nr()
        local ack_nr=$4
        local count
        local dump_stats
+       local with_cookie
 
        printf "%02u %-36s %s" "$TEST_COUNT" "$msg" "syn"
        count=`ip netns exec $ns1 nstat -as | grep MPTcpExtMPJoinSynRx | awk '{print $2}'`
@@ -672,12 +674,20 @@ chk_join_nr()
        fi
 
        echo -n " - synack"
+       with_cookie=`ip netns exec $ns2 sysctl -n net.ipv4.tcp_syncookies`
        count=`ip netns exec $ns2 nstat -as | grep MPTcpExtMPJoinSynAckRx | awk '{print $2}'`
        [ -z "$count" ] && count=0
        if [ "$count" != "$syn_ack_nr" ]; then
-               echo "[fail] got $count JOIN[s] synack expected $syn_ack_nr"
-               ret=1
-               dump_stats=1
+               # simult connections exceeding the limit with cookie enabled could go up to
+               # synack validation as the conn limit can be enforced reliably only after
+               # the subflow creation
+               if [ "$with_cookie" = 2 ] && [ "$count" -gt "$syn_ack_nr" ] && [ "$count" -le "$syn_nr" ]; then
+                       echo -n "[ ok ]"
+               else
+                       echo "[fail] got $count JOIN[s] synack expected $syn_ack_nr"
+                       ret=1
+                       dump_stats=1
+               fi
        else
                echo -n "[ ok ]"
        fi
@@ -751,11 +761,17 @@ chk_add_nr()
        local mis_ack_nr=${8:-0}
        local count
        local dump_stats
+       local timeout
+
+       timeout=`ip netns exec $ns1 sysctl -n net.mptcp.add_addr_timeout`
 
        printf "%-39s %s" " " "add"
-       count=`ip netns exec $ns2 nstat -as | grep MPTcpExtAddAddr | awk '{print $2}'`
+       count=`ip netns exec $ns2 nstat -as MPTcpExtAddAddr | grep MPTcpExtAddAddr | awk '{print $2}'`
        [ -z "$count" ] && count=0
-       if [ "$count" != "$add_nr" ]; then
+
+       # if the test configured a short timeout tolerate greater then expected
+       # add addrs options, due to retransmissions
+       if [ "$count" != "$add_nr" ] && [ "$timeout" -gt 1 -o "$count" -lt "$add_nr" ]; then
                echo "[fail] got $count ADD_ADDR[s] expected $add_nr"
                ret=1
                dump_stats=1
@@ -960,7 +976,7 @@ wait_for_tw()
        local ns=$1
 
        while [ $time -lt $timeout_ms ]; do
-               local cnt=$(ip netns exec $ns ss -t state time-wait |wc -l)
+               local cnt=$(ip netns exec $ns nstat -as TcpAttemptFails | grep TcpAttemptFails | awk '{print $2}')
 
                [ "$cnt" = 1 ] && return 1
                time=$((time + 100))
@@ -1157,7 +1173,11 @@ signal_address_tests()
        ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 flags signal
        ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags signal
        ip netns exec $ns2 ./pm_nl_ctl add 10.0.4.2 flags signal
-       run_tests $ns1 $ns2 10.0.1.1
+
+       # the peer could possibly miss some addr notification, allow retransmission
+       ip netns exec $ns1 sysctl -q net.mptcp.add_addr_timeout=1
+       run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow
+       chk_join_nr "signal addresses race test" 3 3 3
 
        # the server will not signal the address terminating
        # the MPC subflow
@@ -1476,7 +1496,7 @@ ipv6_tests()
        reset
        ip netns exec $ns1 ./pm_nl_ctl limits 0 1
        ip netns exec $ns2 ./pm_nl_ctl limits 0 1
-       ip netns exec $ns2 ./pm_nl_ctl add dead:beef:3::2 flags subflow
+       ip netns exec $ns2 ./pm_nl_ctl add dead:beef:3::2 dev ns2eth3 flags subflow
        run_tests $ns1 $ns2 dead:beef:1::1 0 0 0 slow
        chk_join_nr "single subflow IPv6" 1 1 1
 
@@ -1511,7 +1531,7 @@ ipv6_tests()
        ip netns exec $ns1 ./pm_nl_ctl limits 0 2
        ip netns exec $ns1 ./pm_nl_ctl add dead:beef:2::1 flags signal
        ip netns exec $ns2 ./pm_nl_ctl limits 1 2
-       ip netns exec $ns2 ./pm_nl_ctl add dead:beef:3::2 flags subflow
+       ip netns exec $ns2 ./pm_nl_ctl add dead:beef:3::2 dev ns2eth3 flags subflow
        run_tests $ns1 $ns2 dead:beef:1::1 0 -1 -1 slow
        chk_join_nr "remove subflow and signal IPv6" 2 2 2
        chk_add_nr 1 1
index ffca314..e4f845d 100644 (file)
@@ -6,7 +6,7 @@ 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
+       conntrack_vrf.sh nft_synproxy.sh
 
 LDLIBS = -lmnl
 TEST_GEN_FILES =  nf-queue
index ed61f6c..b35010c 100755 (executable)
@@ -27,7 +27,7 @@ TYPES="net_port port_net net6_port port_proto net6_port_mac net6_port_mac_proto
        net6_port_net6_port net_port_mac_proto_net"
 
 # Reported bugs, also described by TYPE_ variables below
-BUGS="flush_remove_add"
+BUGS="flush_remove_add reload"
 
 # List of possible paths to pktgen script from kernel tree for performance tests
 PKTGEN_SCRIPT_PATHS="
@@ -354,6 +354,23 @@ TYPE_flush_remove_add="
 display                Add two elements, flush, re-add
 "
 
+TYPE_reload="
+display                net,mac with reload
+type_spec      ipv4_addr . ether_addr
+chain_spec     ip daddr . ether saddr
+dst            addr4
+src            mac
+start          1
+count          1
+src_delta      2000
+tools          sendip nc bash
+proto          udp
+
+race_repeat    0
+
+perf_duration  0
+"
+
 # Set template for all tests, types and rules are filled in depending on test
 set_template='
 flush ruleset
@@ -1473,6 +1490,59 @@ test_bug_flush_remove_add() {
        nft flush ruleset
 }
 
+# - add ranged element, check that packets match it
+# - reload the set, check packets still match
+test_bug_reload() {
+       setup veth send_"${proto}" set || return ${KSELFTEST_SKIP}
+       rstart=${start}
+
+       range_size=1
+       for i in $(seq "${start}" $((start + count))); do
+               end=$((start + range_size))
+
+               # Avoid negative or zero-sized port ranges
+               if [ $((end / 65534)) -gt $((start / 65534)) ]; then
+                       start=${end}
+                       end=$((end + 1))
+               fi
+               srcstart=$((start + src_delta))
+               srcend=$((end + src_delta))
+
+               add "$(format)" || return 1
+               range_size=$((range_size + 1))
+               start=$((end + range_size))
+       done
+
+       # check kernel does allocate pcpu sctrach map
+       # for reload with no elemet add/delete
+       ( echo flush set inet filter test ;
+         nft list set inet filter test ) | nft -f -
+
+       start=${rstart}
+       range_size=1
+
+       for i in $(seq "${start}" $((start + count))); do
+               end=$((start + range_size))
+
+               # Avoid negative or zero-sized port ranges
+               if [ $((end / 65534)) -gt $((start / 65534)) ]; then
+                       start=${end}
+                       end=$((end + 1))
+               fi
+               srcstart=$((start + src_delta))
+               srcend=$((end + src_delta))
+
+               for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do
+                       send_match "${j}" $((j + src_delta)) || return 1
+               done
+
+               range_size=$((range_size + 1))
+               start=$((end + range_size))
+       done
+
+       nft flush ruleset
+}
+
 test_reported_issues() {
        eval test_bug_"${subtest}"
 }
@@ -1531,4 +1601,4 @@ for name in ${TESTS}; do
        done
 done
 
-[ ${passed} -eq 0 ] && exit ${KSELFTEST_SKIP}
+[ ${passed} -eq 0 ] && exit ${KSELFTEST_SKIP} || exit 0
index 6caf6ac..695a195 100755 (executable)
@@ -174,6 +174,7 @@ test_ping() {
 ip netns exec ${nsrouter} sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
 ip netns exec ${nsrouter} sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
 ip netns exec ${nsrouter} sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
+ip netns exec ${nsrouter} sysctl net.ipv4.conf.veth0.rp_filter=0 > /dev/null
 
 sleep 3
 
index 349a319..79fe627 100755 (executable)
@@ -899,6 +899,144 @@ EOF
        ip netns exec "$ns0" nft delete table $family nat
 }
 
+test_stateless_nat_ip()
+{
+       local lret=0
+
+       ip netns exec "$ns0" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
+       ip netns exec "$ns0" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
+
+       ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
+       if [ $? -ne 0 ] ; then
+               echo "ERROR: cannot ping $ns1 from $ns2 before loading stateless rules"
+               return 1
+       fi
+
+ip netns exec "$ns0" nft -f /dev/stdin <<EOF
+table ip stateless {
+       map xlate_in {
+               typeof meta iifname . ip saddr . ip daddr : ip daddr
+               elements = {
+                       "veth1" . 10.0.2.99 . 10.0.1.99 : 10.0.2.2,
+               }
+       }
+       map xlate_out {
+               typeof meta iifname . ip saddr . ip daddr : ip daddr
+               elements = {
+                       "veth0" . 10.0.1.99 . 10.0.2.2 : 10.0.2.99
+               }
+       }
+
+       chain prerouting {
+               type filter hook prerouting priority -400; policy accept;
+               ip saddr set meta iifname . ip saddr . ip daddr map @xlate_in
+               ip daddr set meta iifname . ip saddr . ip daddr map @xlate_out
+       }
+}
+EOF
+       if [ $? -ne 0 ]; then
+               echo "SKIP: Could not add ip statless rules"
+               return $ksft_skip
+       fi
+
+       reset_counters
+
+       ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
+       if [ $? -ne 0 ] ; then
+               echo "ERROR: cannot ping $ns1 from $ns2 with stateless rules"
+               lret=1
+       fi
+
+       # ns1 should have seen packets from .2.2, due to stateless rewrite.
+       expect="packets 1 bytes 84"
+       cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0insl | grep -q "$expect")
+       if [ $? -ne 0 ]; then
+               bad_counter "$ns1" ns0insl "$expect" "test_stateless 1"
+               lret=1
+       fi
+
+       for dir in "in" "out" ; do
+               cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect")
+               if [ $? -ne 0 ]; then
+                       bad_counter "$ns2" ns1$dir "$expect" "test_stateless 2"
+                       lret=1
+               fi
+       done
+
+       # ns1 should not have seen packets from ns2, due to masquerade
+       expect="packets 0 bytes 0"
+       for dir in "in" "out" ; do
+               cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect")
+               if [ $? -ne 0 ]; then
+                       bad_counter "$ns1" ns0$dir "$expect" "test_stateless 3"
+                       lret=1
+               fi
+
+               cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect")
+               if [ $? -ne 0 ]; then
+                       bad_counter "$ns0" ns1$dir "$expect" "test_stateless 4"
+                       lret=1
+               fi
+       done
+
+       reset_counters
+
+       socat -h > /dev/null 2>&1
+       if [ $? -ne 0 ];then
+               echo "SKIP: Could not run stateless nat frag test without socat tool"
+               if [ $lret -eq 0 ]; then
+                       return $ksft_skip
+               fi
+
+               ip netns exec "$ns0" nft delete table ip stateless
+               return $lret
+       fi
+
+       local tmpfile=$(mktemp)
+       dd if=/dev/urandom of=$tmpfile bs=4096 count=1 2>/dev/null
+
+       local outfile=$(mktemp)
+       ip netns exec "$ns1" timeout 3 socat -u UDP4-RECV:4233 OPEN:$outfile < /dev/null &
+       sc_r=$!
+
+       sleep 1
+       # re-do with large ping -> ip fragmentation
+       ip netns exec "$ns2" timeout 3 socat - UDP4-SENDTO:"10.0.1.99:4233" < "$tmpfile" > /dev/null
+       if [ $? -ne 0 ] ; then
+               echo "ERROR: failed to test udp $ns1 to $ns2 with stateless ip nat" 1>&2
+               lret=1
+       fi
+
+       wait
+
+       cmp "$tmpfile" "$outfile"
+       if [ $? -ne 0 ]; then
+               ls -l "$tmpfile" "$outfile"
+               echo "ERROR: in and output file mismatch when checking udp with stateless nat" 1>&2
+               lret=1
+       fi
+
+       rm -f "$tmpfile" "$outfile"
+
+       # ns1 should have seen packets from 2.2, due to stateless rewrite.
+       expect="packets 3 bytes 4164"
+       cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0insl | grep -q "$expect")
+       if [ $? -ne 0 ]; then
+               bad_counter "$ns1" ns0insl "$expect" "test_stateless 5"
+               lret=1
+       fi
+
+       ip netns exec "$ns0" nft delete table ip stateless
+       if [ $? -ne 0 ]; then
+               echo "ERROR: Could not delete table ip stateless" 1>&2
+               lret=1
+       fi
+
+       test $lret -eq 0 && echo "PASS: IP statless for $ns2"
+
+       return $lret
+}
+
 # ip netns exec "$ns0" ping -c 1 -q 10.0.$i.99
 for i in 0 1 2; do
 ip netns exec ns$i-$sfx nft -f /dev/stdin <<EOF
@@ -965,6 +1103,19 @@ table inet filter {
 EOF
 done
 
+# special case for stateless nat check, counter needs to
+# be done before (input) ip defragmentation
+ip netns exec ns1-$sfx nft -f /dev/stdin <<EOF
+table inet filter {
+       counter ns0insl {}
+
+       chain pre {
+               type filter hook prerouting priority -400; policy accept;
+               ip saddr 10.0.2.2 counter name "ns0insl"
+       }
+}
+EOF
+
 sleep 3
 # test basic connectivity
 for i in 1 2; do
@@ -1019,6 +1170,7 @@ $test_inet_nat && test_redirect inet
 $test_inet_nat && test_redirect6 inet
 
 test_port_shadowing
+test_stateless_nat_ip
 
 if [ $ret -ne 0 ];then
        echo -n "FAIL: "
diff --git a/tools/testing/selftests/netfilter/nft_synproxy.sh b/tools/testing/selftests/netfilter/nft_synproxy.sh
new file mode 100755 (executable)
index 0000000..b62933b
--- /dev/null
@@ -0,0 +1,117 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+
+# Kselftest framework requirement - SKIP code is 4.
+ksft_skip=4
+ret=0
+
+rnd=$(mktemp -u XXXXXXXX)
+nsr="nsr-$rnd" # synproxy machine
+ns1="ns1-$rnd"  # iperf client
+ns2="ns2-$rnd"  # iperf server
+
+checktool (){
+       if ! $1 > /dev/null 2>&1; then
+               echo "SKIP: Could not $2"
+               exit $ksft_skip
+       fi
+}
+
+checktool "nft --version" "run test without nft tool"
+checktool "ip -Version" "run test without ip tool"
+checktool "iperf3 --version" "run test without iperf3"
+checktool "ip netns add $nsr" "create net namespace"
+
+modprobe -q nf_conntrack
+
+ip netns add $ns1
+ip netns add $ns2
+
+cleanup() {
+       ip netns pids $ns1 | xargs kill 2>/dev/null
+       ip netns pids $ns2 | xargs kill 2>/dev/null
+       ip netns del $ns1
+       ip netns del $ns2
+
+       ip netns del $nsr
+}
+
+trap cleanup EXIT
+
+ip link add veth0 netns $nsr type veth peer name eth0 netns $ns1
+ip link add veth1 netns $nsr type veth peer name eth0 netns $ns2
+
+for dev in lo veth0 veth1; do
+ip -net $nsr link set $dev up
+done
+
+ip -net $nsr addr add 10.0.1.1/24 dev veth0
+ip -net $nsr addr add 10.0.2.1/24 dev veth1
+
+ip netns exec $nsr sysctl -q net.ipv4.conf.veth0.forwarding=1
+ip netns exec $nsr sysctl -q net.ipv4.conf.veth1.forwarding=1
+ip netns exec $nsr sysctl -q net.netfilter.nf_conntrack_tcp_loose=0
+
+for n in $ns1 $ns2; do
+  ip -net $n link set lo up
+  ip -net $n link set eth0 up
+done
+ip -net $ns1 addr add 10.0.1.99/24 dev eth0
+ip -net $ns2 addr add 10.0.2.99/24 dev eth0
+ip -net $ns1 route add default via 10.0.1.1
+ip -net $ns2 route add default via 10.0.2.1
+
+# test basic connectivity
+if ! ip netns exec $ns1 ping -c 1 -q 10.0.2.99 > /dev/null; then
+  echo "ERROR: $ns1 cannot reach $ns2" 1>&2
+  exit 1
+fi
+
+if ! ip netns exec $ns2 ping -c 1 -q 10.0.1.99 > /dev/null; then
+  echo "ERROR: $ns2 cannot reach $ns1" 1>&2
+  exit 1
+fi
+
+ip netns exec $ns2 iperf3 -s > /dev/null 2>&1 &
+# ip netns exec $nsr tcpdump -vvv -n -i veth1 tcp | head -n 10 &
+
+sleep 1
+
+ip netns exec $nsr nft -f - <<EOF
+table inet filter {
+   chain prerouting {
+      type filter hook prerouting priority -300; policy accept;
+      meta iif veth0 tcp flags syn counter notrack
+   }
+
+  chain forward {
+      type filter hook forward priority 0; policy accept;
+
+      ct state new,established counter accept
+
+      meta iif veth0 meta l4proto tcp ct state untracked,invalid synproxy mss 1460 sack-perm timestamp
+
+      ct state invalid counter drop
+
+      # make ns2 unreachable w.o. tcp synproxy
+      tcp flags syn counter drop
+   }
+}
+EOF
+if [ $? -ne 0 ]; then
+       echo "SKIP: Cannot add nft synproxy"
+       exit $ksft_skip
+fi
+
+ip netns exec $ns1 timeout 5 iperf3 -c 10.0.2.99 -n $((1 * 1024 * 1024)) > /dev/null
+
+if [ $? -ne 0 ]; then
+       echo "FAIL: iperf3 returned an error" 1>&2
+       ret=$?
+       ip netns exec $nsr nft list ruleset
+else
+       echo "PASS: synproxy connection successful"
+fi
+
+exit $ret
index 0463311..5a8db0b 100755 (executable)
@@ -9,7 +9,7 @@ ns="ns-$sfx"
 # Kselftest framework requirement - SKIP code is 4.
 ksft_skip=4
 
-zones=20000
+zones=2000
 have_ct_tool=0
 ret=0
 
@@ -75,10 +75,10 @@ EOF
 
        while [ $i -lt $max_zones ]; do
                local start=$(date +%s%3N)
-               i=$((i + 10000))
+               i=$((i + 1000))
                j=$((j + 1))
                # nft rule in output places each packet in a different zone.
-               dd if=/dev/zero of=/dev/stdout bs=8k count=10000 2>/dev/null | ip netns exec "$ns" socat STDIN UDP:127.0.0.1:12345,sourceport=12345
+               dd if=/dev/zero of=/dev/stdout bs=8k count=1000 2>/dev/null | ip netns exec "$ns" socat STDIN UDP:127.0.0.1:12345,sourceport=12345
                if [ $? -ne 0 ] ;then
                        ret=1
                        break
@@ -86,7 +86,7 @@ EOF
 
                stop=$(date +%s%3N)
                local duration=$((stop-start))
-               echo "PASS: added 10000 entries in $duration ms (now $i total, loop $j)"
+               echo "PASS: added 1000 entries in $duration ms (now $i total, loop $j)"
        done
 
        if [ $have_ct_tool -eq 1 ]; then
@@ -128,11 +128,11 @@ test_conntrack_tool() {
                        break
                fi
 
-               if [ $((i%10000)) -eq 0 ];then
+               if [ $((i%1000)) -eq 0 ];then
                        stop=$(date +%s%3N)
 
                        local duration=$((stop-start))
-                       echo "PASS: added 10000 entries in $duration ms (now $i total)"
+                       echo "PASS: added 1000 entries in $duration ms (now $i total)"
                        start=$stop
                fi
        done
index 4b93b14..843ba56 100644 (file)
@@ -5,4 +5,4 @@ TEST_GEN_PROGS := openat2_test resolve_test rename_attack_test
 
 include ../lib.mk
 
-$(TEST_GEN_PROGS): helpers.c
+$(TEST_GEN_PROGS): helpers.c helpers.h
index a6ea273..7056340 100644 (file)
@@ -9,6 +9,7 @@
 
 #define _GNU_SOURCE
 #include <stdint.h>
+#include <stdbool.h>
 #include <errno.h>
 #include <linux/types.h>
 #include "../kselftest.h"
@@ -62,11 +63,12 @@ bool needs_openat2(const struct open_how *how);
                                        (similar to chroot(2)). */
 #endif /* RESOLVE_IN_ROOT */
 
-#define E_func(func, ...)                                              \
-       do {                                                            \
-               if (func(__VA_ARGS__) < 0)                              \
-                       ksft_exit_fail_msg("%s:%d %s failed\n", \
-                                          __FILE__, __LINE__, #func);\
+#define E_func(func, ...)                                                    \
+       do {                                                                  \
+               errno = 0;                                                    \
+               if (func(__VA_ARGS__) < 0)                                    \
+                       ksft_exit_fail_msg("%s:%d %s failed - errno:%d\n",    \
+                                          __FILE__, __LINE__, #func, errno); \
        } while (0)
 
 #define E_asprintf(...)                E_func(asprintf,        __VA_ARGS__)
index 1bddbe9..7fb9020 100644 (file)
@@ -259,6 +259,16 @@ void test_openat2_flags(void)
                unlink(path);
 
                fd = sys_openat2(AT_FDCWD, path, &test->how);
+               if (fd < 0 && fd == -EOPNOTSUPP) {
+                       /*
+                        * Skip the testcase if it failed because not supported
+                        * by FS. (e.g. a valid O_TMPFILE combination on NFS)
+                        */
+                       ksft_test_result_skip("openat2 with %s fails with %d (%s)\n",
+                                             test->name, fd, strerror(-fd));
+                       goto next;
+               }
+
                if (test->err >= 0)
                        failed = (fd < 0);
                else
@@ -303,7 +313,7 @@ skip:
                else
                        resultfn("openat2 with %s fails with %d (%s)\n",
                                 test->name, test->err, strerror(-test->err));
-
+next:
                free(fdpath);
                fflush(stdout);
        }
index 8e83cf9..6d849dc 100644 (file)
@@ -44,9 +44,10 @@ static struct {
 } ctx;
 
 /* Unique value to check si_perf_data is correctly set from perf_event_attr::sig_data. */
-#define TEST_SIG_DATA(addr) (~(unsigned long)(addr))
+#define TEST_SIG_DATA(addr, id) (~(unsigned long)(addr) + id)
 
-static struct perf_event_attr make_event_attr(bool enabled, volatile void *addr)
+static struct perf_event_attr make_event_attr(bool enabled, volatile void *addr,
+                                             unsigned long id)
 {
        struct perf_event_attr attr = {
                .type           = PERF_TYPE_BREAKPOINT,
@@ -60,7 +61,7 @@ static struct perf_event_attr make_event_attr(bool enabled, volatile void *addr)
                .inherit_thread = 1, /* ... but only cloned with CLONE_THREAD. */
                .remove_on_exec = 1, /* Required by sigtrap. */
                .sigtrap        = 1, /* Request synchronous SIGTRAP on event. */
-               .sig_data       = TEST_SIG_DATA(addr),
+               .sig_data       = TEST_SIG_DATA(addr, id),
        };
        return attr;
 }
@@ -110,7 +111,7 @@ FIXTURE(sigtrap_threads)
 
 FIXTURE_SETUP(sigtrap_threads)
 {
-       struct perf_event_attr attr = make_event_attr(false, &ctx.iterate_on);
+       struct perf_event_attr attr = make_event_attr(false, &ctx.iterate_on, 0);
        struct sigaction action = {};
        int i;
 
@@ -165,7 +166,7 @@ TEST_F(sigtrap_threads, enable_event)
        EXPECT_EQ(ctx.tids_want_signal, 0);
        EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
        EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
-       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on));
+       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 0));
 
        /* Check enabled for parent. */
        ctx.iterate_on = 0;
@@ -175,7 +176,7 @@ TEST_F(sigtrap_threads, enable_event)
 /* Test that modification propagates to all inherited events. */
 TEST_F(sigtrap_threads, modify_and_enable_event)
 {
-       struct perf_event_attr new_attr = make_event_attr(true, &ctx.iterate_on);
+       struct perf_event_attr new_attr = make_event_attr(true, &ctx.iterate_on, 42);
 
        EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &new_attr), 0);
        run_test_threads(_metadata, self);
@@ -184,7 +185,7 @@ TEST_F(sigtrap_threads, modify_and_enable_event)
        EXPECT_EQ(ctx.tids_want_signal, 0);
        EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
        EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
-       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on));
+       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 42));
 
        /* Check enabled for parent. */
        ctx.iterate_on = 0;
@@ -204,7 +205,7 @@ TEST_F(sigtrap_threads, signal_stress)
        EXPECT_EQ(ctx.tids_want_signal, 0);
        EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
        EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
-       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on));
+       EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 0));
 }
 
 TEST_HARNESS_MAIN
index 01f8d3c..6922d64 100644 (file)
@@ -68,7 +68,7 @@
 #define PIDFD_SKIP 3
 #define PIDFD_XFAIL 4
 
-int wait_for_pid(pid_t pid)
+static inline int wait_for_pid(pid_t pid)
 {
        int status, ret;
 
@@ -78,13 +78,20 @@ again:
                if (errno == EINTR)
                        goto again;
 
+               ksft_print_msg("waitpid returned -1, errno=%d\n", errno);
                return -1;
        }
 
-       if (!WIFEXITED(status))
+       if (!WIFEXITED(status)) {
+               ksft_print_msg(
+                      "waitpid !WIFEXITED, WIFSIGNALED=%d, WTERMSIG=%d\n",
+                      WIFSIGNALED(status), WTERMSIG(status));
                return -1;
+       }
 
-       return WEXITSTATUS(status);
+       ret = WEXITSTATUS(status);
+       ksft_print_msg("waitpid WEXITSTATUS=%d\n", ret);
+       return ret;
 }
 
 static inline int sys_pidfd_open(pid_t pid, unsigned int flags)
index 2255852..3fd8e90 100644 (file)
@@ -12,6 +12,7 @@
 #include <string.h>
 #include <syscall.h>
 #include <sys/wait.h>
+#include <sys/mman.h>
 
 #include "pidfd.h"
 #include "../kselftest.h"
@@ -80,7 +81,10 @@ static inline int error_check(struct error *err, const char *test_name)
        return err->code;
 }
 
+#define CHILD_STACK_SIZE 8192
+
 struct child {
+       char *stack;
        pid_t pid;
        int   fd;
 };
@@ -89,17 +93,22 @@ static struct child clone_newns(int (*fn)(void *), void *args,
                                struct error *err)
 {
        static int flags = CLONE_PIDFD | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD;
-       size_t stack_size = 1024;
-       char *stack[1024] = { 0 };
        struct child ret;
 
        if (!(flags & CLONE_NEWUSER) && geteuid() != 0)
                flags |= CLONE_NEWUSER;
 
+       ret.stack = mmap(NULL, CHILD_STACK_SIZE, PROT_READ | PROT_WRITE,
+                        MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
+       if (ret.stack == MAP_FAILED) {
+               error_set(err, -1, "mmap of stack failed (errno %d)", errno);
+               return ret;
+       }
+
 #ifdef __ia64__
-       ret.pid = __clone2(fn, stack, stack_size, flags, args, &ret.fd);
+       ret.pid = __clone2(fn, ret.stack, CHILD_STACK_SIZE, flags, args, &ret.fd);
 #else
-       ret.pid = clone(fn, stack + stack_size, flags, args, &ret.fd);
+       ret.pid = clone(fn, ret.stack + CHILD_STACK_SIZE, flags, args, &ret.fd);
 #endif
 
        if (ret.pid < 0) {
@@ -129,6 +138,11 @@ static inline int child_join(struct child *child, struct error *err)
        else if (r > 0)
                error_set(err, r, "child %d reported: %d", child->pid, r);
 
+       if (munmap(child->stack, CHILD_STACK_SIZE)) {
+               error_set(err, -1, "munmap of child stack failed (errno %d)", errno);
+               r = -1;
+       }
+
        return r;
 }
 
index 529eb70..9a2d649 100644 (file)
@@ -441,7 +441,6 @@ static void test_pidfd_poll_exec(int use_waitpid)
 {
        int pid, pidfd = 0;
        int status, ret;
-       pthread_t t1;
        time_t prog_start = time(NULL);
        const char *test_name = "pidfd_poll check for premature notification on child thread exec";
 
@@ -500,13 +499,14 @@ static int child_poll_leader_exit_test(void *args)
         */
        *child_exit_secs = time(NULL);
        syscall(SYS_exit, 0);
+       /* Never reached, but appeases compiler thinking we should return. */
+       exit(0);
 }
 
 static void test_pidfd_poll_leader_exit(int use_waitpid)
 {
        int pid, pidfd = 0;
-       int status, ret;
-       time_t prog_start = time(NULL);
+       int status, ret = 0;
        const char *test_name = "pidfd_poll check for premature notification on non-empty"
                                "group leader exit";
 
index be2943f..17999e0 100644 (file)
@@ -39,7 +39,7 @@ static int sys_waitid(int which, pid_t pid, siginfo_t *info, int options,
 
 TEST(wait_simple)
 {
-       int pidfd = -1, status = 0;
+       int pidfd = -1;
        pid_t parent_tid = -1;
        struct clone_args args = {
                .parent_tid = ptr_to_u64(&parent_tid),
@@ -47,7 +47,6 @@ TEST(wait_simple)
                .flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
                .exit_signal = SIGCHLD,
        };
-       int ret;
        pid_t pid;
        siginfo_t info = {
                .si_signo = 0,
@@ -88,7 +87,7 @@ TEST(wait_simple)
 
 TEST(wait_states)
 {
-       int pidfd = -1, status = 0;
+       int pidfd = -1;
        pid_t parent_tid = -1;
        struct clone_args args = {
                .parent_tid = ptr_to_u64(&parent_tid),
index 0ebfe8b..585f7a0 100644 (file)
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
-CFLAGS += -Wl,-no-as-needed -Wall
+CFLAGS += -Wl,-no-as-needed -Wall -isystem ../../../../usr/include/
 LDFLAGS += -lpthread
 
 TEST_GEN_PROGS := seccomp_bpf seccomp_benchmark
index 3d603f1..883ca85 100644 (file)
@@ -33,110 +33,114 @@ typedef long (*vdso_clock_gettime_t)(clockid_t clk_id, struct timespec *ts);
 typedef long (*vdso_clock_getres_t)(clockid_t clk_id, struct timespec *ts);
 typedef time_t (*vdso_time_t)(time_t *t);
 
-static int vdso_test_gettimeofday(void)
+#define VDSO_TEST_PASS_MSG()   "\n%s(): PASS\n", __func__
+#define VDSO_TEST_FAIL_MSG(x)  "\n%s(): %s FAIL\n", __func__, x
+#define VDSO_TEST_SKIP_MSG(x)  "\n%s(): SKIP: Could not find %s\n", __func__, x
+
+static void vdso_test_gettimeofday(void)
 {
        /* Find gettimeofday. */
        vdso_gettimeofday_t vdso_gettimeofday =
                (vdso_gettimeofday_t)vdso_sym(version, name[0]);
 
        if (!vdso_gettimeofday) {
-               printf("Could not find %s\n", name[0]);
-               return KSFT_SKIP;
+               ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[0]));
+               return;
        }
 
        struct timeval tv;
        long ret = vdso_gettimeofday(&tv, 0);
 
        if (ret == 0) {
-               printf("The time is %lld.%06lld\n",
-                      (long long)tv.tv_sec, (long long)tv.tv_usec);
+               ksft_print_msg("The time is %lld.%06lld\n",
+                              (long long)tv.tv_sec, (long long)tv.tv_usec);
+               ksft_test_result_pass(VDSO_TEST_PASS_MSG());
        } else {
-               printf("%s failed\n", name[0]);
-               return KSFT_FAIL;
+               ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[0]));
        }
-
-       return KSFT_PASS;
 }
 
-static int vdso_test_clock_gettime(clockid_t clk_id)
+static void vdso_test_clock_gettime(clockid_t clk_id)
 {
        /* Find clock_gettime. */
        vdso_clock_gettime_t vdso_clock_gettime =
                (vdso_clock_gettime_t)vdso_sym(version, name[1]);
 
        if (!vdso_clock_gettime) {
-               printf("Could not find %s\n", name[1]);
-               return KSFT_SKIP;
+               ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[1]));
+               return;
        }
 
        struct timespec ts;
        long ret = vdso_clock_gettime(clk_id, &ts);
 
        if (ret == 0) {
-               printf("The time is %lld.%06lld\n",
-                      (long long)ts.tv_sec, (long long)ts.tv_nsec);
+               ksft_print_msg("The time is %lld.%06lld\n",
+                              (long long)ts.tv_sec, (long long)ts.tv_nsec);
+               ksft_test_result_pass(VDSO_TEST_PASS_MSG());
        } else {
-               printf("%s failed\n", name[1]);
-               return KSFT_FAIL;
+               ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[1]));
        }
-
-       return KSFT_PASS;
 }
 
-static int vdso_test_time(void)
+static void vdso_test_time(void)
 {
        /* Find time. */
        vdso_time_t vdso_time =
                (vdso_time_t)vdso_sym(version, name[2]);
 
        if (!vdso_time) {
-               printf("Could not find %s\n", name[2]);
-               return KSFT_SKIP;
+               ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[2]));
+               return;
        }
 
        long ret = vdso_time(NULL);
 
        if (ret > 0) {
-               printf("The time in hours since January 1, 1970 is %lld\n",
+               ksft_print_msg("The time in hours since January 1, 1970 is %lld\n",
                                (long long)(ret / 3600));
+               ksft_test_result_pass(VDSO_TEST_PASS_MSG());
        } else {
-               printf("%s failed\n", name[2]);
-               return KSFT_FAIL;
+               ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[2]));
        }
-
-       return KSFT_PASS;
 }
 
-static int vdso_test_clock_getres(clockid_t clk_id)
+static void vdso_test_clock_getres(clockid_t clk_id)
 {
+       int clock_getres_fail = 0;
+
        /* Find clock_getres. */
        vdso_clock_getres_t vdso_clock_getres =
                (vdso_clock_getres_t)vdso_sym(version, name[3]);
 
        if (!vdso_clock_getres) {
-               printf("Could not find %s\n", name[3]);
-               return KSFT_SKIP;
+               ksft_test_result_skip(VDSO_TEST_SKIP_MSG(name[3]));
+               return;
        }
 
        struct timespec ts, sys_ts;
        long ret = vdso_clock_getres(clk_id, &ts);
 
        if (ret == 0) {
-               printf("The resolution is %lld %lld\n",
-                      (long long)ts.tv_sec, (long long)ts.tv_nsec);
+               ksft_print_msg("The vdso resolution is %lld %lld\n",
+                              (long long)ts.tv_sec, (long long)ts.tv_nsec);
        } else {
-               printf("%s failed\n", name[3]);
-               return KSFT_FAIL;
+               clock_getres_fail++;
        }
 
        ret = syscall(SYS_clock_getres, clk_id, &sys_ts);
 
-       if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec)) {
-               printf("%s failed\n", name[3]);
-               return KSFT_FAIL;
-       }
+       ksft_print_msg("The syscall resolution is %lld %lld\n",
+                       (long long)sys_ts.tv_sec, (long long)sys_ts.tv_nsec);
 
-       return KSFT_PASS;
+       if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec))
+               clock_getres_fail++;
+
+       if (clock_getres_fail > 0) {
+               ksft_test_result_fail(VDSO_TEST_FAIL_MSG(name[3]));
+       } else {
+               ksft_test_result_pass(VDSO_TEST_PASS_MSG());
+       }
 }
 
 const char *vdso_clock_name[12] = {
@@ -158,36 +162,23 @@ const char *vdso_clock_name[12] = {
  * This function calls vdso_test_clock_gettime and vdso_test_clock_getres
  * with different values for clock_id.
  */
-static inline int vdso_test_clock(clockid_t clock_id)
+static inline void vdso_test_clock(clockid_t clock_id)
 {
-       int ret0, ret1;
-
-       ret0 = vdso_test_clock_gettime(clock_id);
-       /* A skipped test is considered passed */
-       if (ret0 == KSFT_SKIP)
-               ret0 = KSFT_PASS;
-
-       ret1 = vdso_test_clock_getres(clock_id);
-       /* A skipped test is considered passed */
-       if (ret1 == KSFT_SKIP)
-               ret1 = KSFT_PASS;
+       ksft_print_msg("\nclock_id: %s\n", vdso_clock_name[clock_id]);
 
-       ret0 += ret1;
+       vdso_test_clock_gettime(clock_id);
 
-       printf("clock_id: %s", vdso_clock_name[clock_id]);
-
-       if (ret0 > 0)
-               printf(" [FAIL]\n");
-       else
-               printf(" [PASS]\n");
-
-       return ret0;
+       vdso_test_clock_getres(clock_id);
 }
 
+#define VDSO_TEST_PLAN 16
+
 int main(int argc, char **argv)
 {
        unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
-       int ret;
+
+       ksft_print_header();
+       ksft_set_plan(VDSO_TEST_PLAN);
 
        if (!sysinfo_ehdr) {
                printf("AT_SYSINFO_EHDR is not present!\n");
@@ -201,44 +192,42 @@ int main(int argc, char **argv)
 
        vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR));
 
-       ret = vdso_test_gettimeofday();
+       vdso_test_gettimeofday();
 
 #if _POSIX_TIMERS > 0
 
 #ifdef CLOCK_REALTIME
-       ret += vdso_test_clock(CLOCK_REALTIME);
+       vdso_test_clock(CLOCK_REALTIME);
 #endif
 
 #ifdef CLOCK_BOOTTIME
-       ret += vdso_test_clock(CLOCK_BOOTTIME);
+       vdso_test_clock(CLOCK_BOOTTIME);
 #endif
 
 #ifdef CLOCK_TAI
-       ret += vdso_test_clock(CLOCK_TAI);
+       vdso_test_clock(CLOCK_TAI);
 #endif
 
 #ifdef CLOCK_REALTIME_COARSE
-       ret += vdso_test_clock(CLOCK_REALTIME_COARSE);
+       vdso_test_clock(CLOCK_REALTIME_COARSE);
 #endif
 
 #ifdef CLOCK_MONOTONIC
-       ret += vdso_test_clock(CLOCK_MONOTONIC);
+       vdso_test_clock(CLOCK_MONOTONIC);
 #endif
 
 #ifdef CLOCK_MONOTONIC_RAW
-       ret += vdso_test_clock(CLOCK_MONOTONIC_RAW);
+       vdso_test_clock(CLOCK_MONOTONIC_RAW);
 #endif
 
 #ifdef CLOCK_MONOTONIC_COARSE
-       ret += vdso_test_clock(CLOCK_MONOTONIC_COARSE);
+       vdso_test_clock(CLOCK_MONOTONIC_COARSE);
 #endif
 
 #endif
 
-       ret += vdso_test_time();
-
-       if (ret > 0)
-               return KSFT_FAIL;
+       vdso_test_time();
 
-       return KSFT_PASS;
+       ksft_print_cnts();
+       return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
 }
index d91bde5..eed4432 100644 (file)
@@ -17,9 +17,6 @@
 #define MAP_FIXED_NOREPLACE 0x100000
 #endif
 
-#define BASE_ADDRESS   (256ul * 1024 * 1024)
-
-
 static void dump_maps(void)
 {
        char cmd[32];
@@ -28,18 +25,46 @@ static void dump_maps(void)
        system(cmd);
 }
 
+static unsigned long find_base_addr(unsigned long size)
+{
+       void *addr;
+       unsigned long flags;
+
+       flags = MAP_PRIVATE | MAP_ANONYMOUS;
+       addr = mmap(NULL, size, PROT_NONE, flags, -1, 0);
+       if (addr == MAP_FAILED) {
+               printf("Error: couldn't map the space we need for the test\n");
+               return 0;
+       }
+
+       if (munmap(addr, size) != 0) {
+               printf("Error: couldn't map the space we need for the test\n");
+               return 0;
+       }
+       return (unsigned long)addr;
+}
+
 int main(void)
 {
+       unsigned long base_addr;
        unsigned long flags, addr, size, page_size;
        char *p;
 
        page_size = sysconf(_SC_PAGE_SIZE);
 
+       //let's find a base addr that is free before we start the tests
+       size = 5 * page_size;
+       base_addr = find_base_addr(size);
+       if (!base_addr) {
+               printf("Error: couldn't map the space we need for the test\n");
+               return 1;
+       }
+
        flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE;
 
        // Check we can map all the areas we need below
        errno = 0;
-       addr = BASE_ADDRESS;
+       addr = base_addr;
        size = 5 * page_size;
        p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
 
@@ -60,7 +85,7 @@ int main(void)
        printf("unmap() successful\n");
 
        errno = 0;
-       addr = BASE_ADDRESS + page_size;
+       addr = base_addr + page_size;
        size = 3 * page_size;
        p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
        printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
@@ -80,7 +105,7 @@ int main(void)
         *     +4 |  free  | new
         */
        errno = 0;
-       addr = BASE_ADDRESS;
+       addr = base_addr;
        size = 5 * page_size;
        p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
        printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
@@ -101,7 +126,7 @@ int main(void)
         *     +4 |  free  |
         */
        errno = 0;
-       addr = BASE_ADDRESS + (2 * page_size);
+       addr = base_addr + (2 * page_size);
        size = page_size;
        p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
        printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
@@ -121,7 +146,7 @@ int main(void)
         *     +4 |  free  | new
         */
        errno = 0;
-       addr = BASE_ADDRESS + (3 * page_size);
+       addr = base_addr + (3 * page_size);
        size = 2 * page_size;
        p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
        printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
@@ -141,7 +166,7 @@ int main(void)
         *     +4 |  free  |
         */
        errno = 0;
-       addr = BASE_ADDRESS;
+       addr = base_addr;
        size = 2 * page_size;
        p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
        printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
@@ -161,7 +186,7 @@ int main(void)
         *     +4 |  free  |
         */
        errno = 0;
-       addr = BASE_ADDRESS;
+       addr = base_addr;
        size = page_size;
        p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
        printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
@@ -181,7 +206,7 @@ int main(void)
         *     +4 |  free  |  new
         */
        errno = 0;
-       addr = BASE_ADDRESS + (4 * page_size);
+       addr = base_addr + (4 * page_size);
        size = page_size;
        p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
        printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
@@ -192,7 +217,7 @@ int main(void)
                return 1;
        }
 
-       addr = BASE_ADDRESS;
+       addr = base_addr;
        size = 5 * page_size;
        if (munmap((void *)addr, size) != 0) {
                dump_maps();
index d3fd24f..2f49c9a 100644 (file)
@@ -1417,6 +1417,7 @@ static void userfaultfd_pagemap_test(unsigned int test_pgsize)
 static int userfaultfd_stress(void)
 {
        void *area;
+       char *tmp_area;
        unsigned long nr;
        struct uffdio_register uffdio_register;
        struct uffd_stats uffd_stats[nr_cpus];
@@ -1527,9 +1528,13 @@ static int userfaultfd_stress(void)
                                            count_verify[nr], nr);
 
                /* prepare next bounce */
-               swap(area_src, area_dst);
+               tmp_area = area_src;
+               area_src = area_dst;
+               area_dst = tmp_area;
 
-               swap(area_src_alias, area_dst_alias);
+               tmp_area = area_src_alias;
+               area_src_alias = area_dst_alias;
+               area_dst_alias = tmp_area;
 
                uffd_stats_report(uffd_stats, nr_cpus);
        }
index 232e958..b0b91d9 100755 (executable)
@@ -2,9 +2,6 @@
 # SPDX-License-Identifier: GPL-2.0
 TCID="zram.sh"
 
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
-
 . ./zram_lib.sh
 
 run_zram () {
@@ -18,14 +15,4 @@ echo ""
 
 check_prereqs
 
-# check zram module exists
-MODULE_PATH=/lib/modules/`uname -r`/kernel/drivers/block/zram/zram.ko
-if [ -f $MODULE_PATH ]; then
-       run_zram
-elif [ -b /dev/zram0 ]; then
-       run_zram
-else
-       echo "$TCID : No zram.ko module or /dev/zram0 device file not found"
-       echo "$TCID : CONFIG_ZRAM is not set"
-       exit $ksft_skip
-fi
+run_zram
index 114863d..8f4affe 100755 (executable)
@@ -33,9 +33,7 @@ zram_algs="lzo"
 
 zram_fill_fs()
 {
-       local mem_free0=$(free -m | awk 'NR==2 {print $4}')
-
-       for i in $(seq 0 $(($dev_num - 1))); do
+       for i in $(seq $dev_start $dev_end); do
                echo "fill zram$i..."
                local b=0
                while [ true ]; do
@@ -45,29 +43,17 @@ zram_fill_fs()
                        b=$(($b + 1))
                done
                echo "zram$i can be filled with '$b' KB"
-       done
 
-       local mem_free1=$(free -m | awk 'NR==2 {print $4}')
-       local used_mem=$(($mem_free0 - $mem_free1))
+               local mem_used_total=`awk '{print $3}' "/sys/block/zram$i/mm_stat"`
+               local v=$((100 * 1024 * $b / $mem_used_total))
+               if [ "$v" -lt 100 ]; then
+                        echo "FAIL compression ratio: 0.$v:1"
+                        ERR_CODE=-1
+                        return
+               fi
 
-       local total_size=0
-       for sm in $zram_sizes; do
-               local s=$(echo $sm | sed 's/M//')
-               total_size=$(($total_size + $s))
+               echo "zram compression ratio: $(echo "scale=2; $v / 100 " | bc):1: OK"
        done
-
-       echo "zram used ${used_mem}M, zram disk sizes ${total_size}M"
-
-       local v=$((100 * $total_size / $used_mem))
-
-       if [ "$v" -lt 100 ]; then
-               echo "FAIL compression ratio: 0.$v:1"
-               ERR_CODE=-1
-               zram_cleanup
-               return
-       fi
-
-       echo "zram compression ratio: $(echo "scale=2; $v / 100 " | bc):1: OK"
 }
 
 check_prereqs
@@ -81,7 +67,6 @@ zram_mount
 
 zram_fill_fs
 zram_cleanup
-zram_unload
 
 if [ $ERR_CODE -ne 0 ]; then
        echo "$TCID : [FAIL]"
index e83b404..2418b0c 100755 (executable)
@@ -36,7 +36,6 @@ zram_set_memlimit
 zram_makeswap
 zram_swapoff
 zram_cleanup
-zram_unload
 
 if [ $ERR_CODE -ne 0 ]; then
        echo "$TCID : [FAIL]"
index 6f872f2..21ec196 100755 (executable)
@@ -5,12 +5,17 @@
 # Author: Alexey Kodanev <alexey.kodanev@oracle.com>
 # Modified: Naresh Kamboju <naresh.kamboju@linaro.org>
 
-MODULE=0
 dev_makeswap=-1
 dev_mounted=-1
-
+dev_start=0
+dev_end=-1
+module_load=-1
+sys_control=-1
 # Kselftest framework requirement - SKIP code is 4.
 ksft_skip=4
+kernel_version=`uname -r | cut -d'.' -f1,2`
+kernel_major=${kernel_version%.*}
+kernel_minor=${kernel_version#*.}
 
 trap INT
 
@@ -25,68 +30,104 @@ check_prereqs()
        fi
 }
 
+kernel_gte()
+{
+       major=${1%.*}
+       minor=${1#*.}
+
+       if [ $kernel_major -gt $major ]; then
+               return 0
+       elif [[ $kernel_major -eq $major && $kernel_minor -ge $minor ]]; then
+               return 0
+       fi
+
+       return 1
+}
+
 zram_cleanup()
 {
        echo "zram cleanup"
        local i=
-       for i in $(seq 0 $dev_makeswap); do
+       for i in $(seq $dev_start $dev_makeswap); do
                swapoff /dev/zram$i
        done
 
-       for i in $(seq 0 $dev_mounted); do
+       for i in $(seq $dev_start $dev_mounted); do
                umount /dev/zram$i
        done
 
-       for i in $(seq 0 $(($dev_num - 1))); do
+       for i in $(seq $dev_start $dev_end); do
                echo 1 > /sys/block/zram${i}/reset
                rm -rf zram$i
        done
 
-}
+       if [ $sys_control -eq 1 ]; then
+               for i in $(seq $dev_start $dev_end); do
+                       echo $i > /sys/class/zram-control/hot_remove
+               done
+       fi
 
-zram_unload()
-{
-       if [ $MODULE -ne 0 ] ; then
-               echo "zram rmmod zram"
+       if [ $module_load -eq 1 ]; then
                rmmod zram > /dev/null 2>&1
        fi
 }
 
 zram_load()
 {
-       # check zram module exists
-       MODULE_PATH=/lib/modules/`uname -r`/kernel/drivers/block/zram/zram.ko
-       if [ -f $MODULE_PATH ]; then
-               MODULE=1
-               echo "create '$dev_num' zram device(s)"
-               modprobe zram num_devices=$dev_num
-               if [ $? -ne 0 ]; then
-                       echo "failed to insert zram module"
-                       exit 1
-               fi
-
-               dev_num_created=$(ls /dev/zram* | wc -w)
+       echo "create '$dev_num' zram device(s)"
+
+       # zram module loaded, new kernel
+       if [ -d "/sys/class/zram-control" ]; then
+               echo "zram modules already loaded, kernel supports" \
+                       "zram-control interface"
+               dev_start=$(ls /dev/zram* | wc -w)
+               dev_end=$(($dev_start + $dev_num - 1))
+               sys_control=1
+
+               for i in $(seq $dev_start $dev_end); do
+                       cat /sys/class/zram-control/hot_add > /dev/null
+               done
+
+               echo "all zram devices (/dev/zram$dev_start~$dev_end" \
+                       "successfully created"
+               return 0
+       fi
 
-               if [ "$dev_num_created" -ne "$dev_num" ]; then
-                       echo "unexpected num of devices: $dev_num_created"
-                       ERR_CODE=-1
+       # detect old kernel or built-in
+       modprobe zram num_devices=$dev_num
+       if [ ! -d "/sys/class/zram-control" ]; then
+               if grep -q '^zram' /proc/modules; then
+                       rmmod zram > /dev/null 2>&1
+                       if [ $? -ne 0 ]; then
+                               echo "zram module is being used on old kernel" \
+                                       "without zram-control interface"
+                               exit $ksft_skip
+                       fi
                else
-                       echo "zram load module successful"
+                       echo "test needs CONFIG_ZRAM=m on old kernel without" \
+                               "zram-control interface"
+                       exit $ksft_skip
                fi
-       elif [ -b /dev/zram0 ]; then
-               echo "/dev/zram0 device file found: OK"
-       else
-               echo "ERROR: No zram.ko module or no /dev/zram0 device found"
-               echo "$TCID : CONFIG_ZRAM is not set"
-               exit 1
+               modprobe zram num_devices=$dev_num
        fi
+
+       module_load=1
+       dev_end=$(($dev_num - 1))
+       echo "all zram devices (/dev/zram0~$dev_end) successfully created"
 }
 
 zram_max_streams()
 {
        echo "set max_comp_streams to zram device(s)"
 
-       local i=0
+       kernel_gte 4.7
+       if [ $? -eq 0 ]; then
+               echo "The device attribute max_comp_streams was"\
+                              "deprecated in 4.7"
+               return 0
+       fi
+
+       local i=$dev_start
        for max_s in $zram_max_streams; do
                local sys_path="/sys/block/zram${i}/max_comp_streams"
                echo $max_s > $sys_path || \
@@ -98,7 +139,7 @@ zram_max_streams()
                        echo "FAIL can't set max_streams '$max_s', get $max_stream"
 
                i=$(($i + 1))
-               echo "$sys_path = '$max_streams' ($i/$dev_num)"
+               echo "$sys_path = '$max_streams'"
        done
 
        echo "zram max streams: OK"
@@ -108,15 +149,16 @@ zram_compress_alg()
 {
        echo "test that we can set compression algorithm"
 
-       local algs=$(cat /sys/block/zram0/comp_algorithm)
+       local i=$dev_start
+       local algs=$(cat /sys/block/zram${i}/comp_algorithm)
        echo "supported algs: $algs"
-       local i=0
+
        for alg in $zram_algs; do
                local sys_path="/sys/block/zram${i}/comp_algorithm"
                echo "$alg" >   $sys_path || \
                        echo "FAIL can't set '$alg' to $sys_path"
                i=$(($i + 1))
-               echo "$sys_path = '$alg' ($i/$dev_num)"
+               echo "$sys_path = '$alg'"
        done
 
        echo "zram set compression algorithm: OK"
@@ -125,14 +167,14 @@ zram_compress_alg()
 zram_set_disksizes()
 {
        echo "set disk size to zram device(s)"
-       local i=0
+       local i=$dev_start
        for ds in $zram_sizes; do
                local sys_path="/sys/block/zram${i}/disksize"
                echo "$ds" >    $sys_path || \
                        echo "FAIL can't set '$ds' to $sys_path"
 
                i=$(($i + 1))
-               echo "$sys_path = '$ds' ($i/$dev_num)"
+               echo "$sys_path = '$ds'"
        done
 
        echo "zram set disksizes: OK"
@@ -142,14 +184,14 @@ zram_set_memlimit()
 {
        echo "set memory limit to zram device(s)"
 
-       local i=0
+       local i=$dev_start
        for ds in $zram_mem_limits; do
                local sys_path="/sys/block/zram${i}/mem_limit"
                echo "$ds" >    $sys_path || \
                        echo "FAIL can't set '$ds' to $sys_path"
 
                i=$(($i + 1))
-               echo "$sys_path = '$ds' ($i/$dev_num)"
+               echo "$sys_path = '$ds'"
        done
 
        echo "zram set memory limit: OK"
@@ -158,8 +200,8 @@ zram_set_memlimit()
 zram_makeswap()
 {
        echo "make swap with zram device(s)"
-       local i=0
-       for i in $(seq 0 $(($dev_num - 1))); do
+       local i=$dev_start
+       for i in $(seq $dev_start $dev_end); do
                mkswap /dev/zram$i > err.log 2>&1
                if [ $? -ne 0 ]; then
                        cat err.log
@@ -182,7 +224,7 @@ zram_makeswap()
 zram_swapoff()
 {
        local i=
-       for i in $(seq 0 $dev_makeswap); do
+       for i in $(seq $dev_start $dev_end); do
                swapoff /dev/zram$i > err.log 2>&1
                if [ $? -ne 0 ]; then
                        cat err.log
@@ -196,7 +238,7 @@ zram_swapoff()
 
 zram_makefs()
 {
-       local i=0
+       local i=$dev_start
        for fs in $zram_filesystems; do
                # if requested fs not supported default it to ext2
                which mkfs.$fs > /dev/null 2>&1 || fs=ext2
@@ -215,7 +257,7 @@ zram_makefs()
 zram_mount()
 {
        local i=0
-       for i in $(seq 0 $(($dev_num - 1))); do
+       for i in $(seq $dev_start $dev_end); do
                echo "mount /dev/zram$i"
                mkdir zram$i
                mount /dev/zram$i zram$i > /dev/null || \
index 87e0ec4..95e485f 100644 (file)
@@ -1,11 +1,11 @@
 # SPDX-License-Identifier: GPL-2.0
 include ../scripts/Makefile.include
 
-all: latency
+all: latency rtla
 
-clean: latency_clean
+clean: latency_clean rtla_clean
 
-install: latency_install
+install: latency_install rtla_install
 
 latency:
        $(call descend,latency)
@@ -16,4 +16,14 @@ latency_install:
 latency_clean:
        $(call descend,latency,clean)
 
-.PHONY: all install clean latency latency_install latency_clean
+rtla:
+       $(call descend,rtla)
+
+rtla_install:
+       $(call descend,rtla,install)
+
+rtla_clean:
+       $(call descend,rtla,clean)
+
+.PHONY: all install clean latency latency_install latency_clean \
+       rtla rtla_install rtla_clean
index 2d52ff0..5a1eda6 100644 (file)
@@ -1,5 +1,6 @@
 NAME   :=      rtla
-VERSION        :=      0.5
+# Follow the kernel version
+VERSION :=     $(shell cat VERSION 2> /dev/null || make -sC ../../.. kernelversion)
 
 # From libtracefs:
 # Makefiles suck: This macro sets a default value of $(2) for the
@@ -59,7 +60,7 @@ endif
 .PHONY:        all
 all:   rtla
 
-rtla: $(OBJ) doc
+rtla: $(OBJ)
        $(CC) -o rtla $(LDFLAGS) $(OBJ) $(LIBS)
 
 static: $(OBJ)
@@ -85,6 +86,7 @@ clean: doc_clean
 
 tarball: clean
        rm -rf $(NAME)-$(VERSION) && mkdir $(NAME)-$(VERSION)
+       echo $(VERSION) > $(NAME)-$(VERSION)/VERSION
        cp -r $(DIRS) $(FILES) $(NAME)-$(VERSION)
        mkdir $(NAME)-$(VERSION)/Documentation/
        cp -rp $(SRCTREE)/../../../Documentation/tools/rtla/* $(NAME)-$(VERSION)/Documentation/
index 7b73d1e..e60f186 100644 (file)
@@ -750,6 +750,9 @@ void osnoise_put_context(struct osnoise_context *context)
  */
 void osnoise_destroy_tool(struct osnoise_tool *top)
 {
+       if (!top)
+               return;
+
        trace_instance_destroy(&top->trace);
 
        if (top->context)
@@ -807,7 +810,7 @@ struct osnoise_tool *osnoise_init_trace_tool(char *tracer)
 
        retval = enable_tracer_by_name(trace->trace.inst, tracer);
        if (retval) {
-               err_msg("Could not enable osnoiser tracer for tracing\n");
+               err_msg("Could not enable %s tracer for tracing\n", tracer);
                goto out_err;
        }
 
index 180fcbe..52c053c 100644 (file)
@@ -426,7 +426,7 @@ static void osnoise_hist_usage(char *usage)
        static const char * const msg[] = {
                "",
                "  usage: rtla osnoise hist [-h] [-D] [-d s] [-p us] [-r us] [-s us] [-S us] [-t[=file]] \\",
-               "         [-c cpu-list] [-P priority] [-b N] [-e N] [--no-header] [--no-summary] \\",
+               "         [-c cpu-list] [-P priority] [-b N] [-E N] [--no-header] [--no-summary] \\",
                "         [--no-index] [--with-zeros]",
                "",
                "         -h/--help: print this menu",
@@ -439,7 +439,7 @@ static void osnoise_hist_usage(char *usage)
                "         -D/--debug: print debug info",
                "         -t/--trace[=file]: save the stopped trace to [file|osnoise_trace.txt]",
                "         -b/--bucket-size N: set the histogram bucket size (default 1)",
-               "         -e/--entries N: set the number of entries of the histogram (default 256)",
+               "         -E/--entries N: set the number of entries of the histogram (default 256)",
                "            --no-header: do not print header",
                "            --no-summary: do not print summary",
                "            --no-index: do not print index",
@@ -486,7 +486,7 @@ static struct osnoise_hist_params
        while (1) {
                static struct option long_options[] = {
                        {"bucket-size",         required_argument,      0, 'b'},
-                       {"entries",             required_argument,      0, 'e'},
+                       {"entries",             required_argument,      0, 'E'},
                        {"cpus",                required_argument,      0, 'c'},
                        {"debug",               no_argument,            0, 'D'},
                        {"duration",            required_argument,      0, 'd'},
@@ -507,7 +507,7 @@ static struct osnoise_hist_params
                /* getopt_long stores the option index here. */
                int option_index = 0;
 
-               c = getopt_long(argc, argv, "c:b:d:e:Dhp:P:r:s:S:t::0123",
+               c = getopt_long(argc, argv, "c:b:d:E:Dhp:P:r:s:S:t::0123",
                                 long_options, &option_index);
 
                /* detect the end of the options. */
@@ -534,7 +534,7 @@ static struct osnoise_hist_params
                        if (!params->duration)
                                osnoise_hist_usage("Invalid -D duration\n");
                        break;
-               case 'e':
+               case 'E':
                        params->entries = get_llong_from_str(optarg);
                        if ((params->entries < 10) || (params->entries > 9999999))
                                osnoise_hist_usage("Entries must be > 10 and < 9999999\n");
@@ -701,9 +701,9 @@ osnoise_hist_set_signals(struct osnoise_hist_params *params)
 int osnoise_hist_main(int argc, char *argv[])
 {
        struct osnoise_hist_params *params;
+       struct osnoise_tool *record = NULL;
+       struct osnoise_tool *tool = NULL;
        struct trace_instance *trace;
-       struct osnoise_tool *record;
-       struct osnoise_tool *tool;
        int return_value = 1;
        int retval;
 
@@ -792,9 +792,8 @@ int osnoise_hist_main(int argc, char *argv[])
 out_hist:
        osnoise_free_histogram(tool->data);
 out_destroy:
+       osnoise_destroy_tool(record);
        osnoise_destroy_tool(tool);
-       if (params->trace_output)
-               osnoise_destroy_tool(record);
        free(params);
 out_exit:
        exit(return_value);
index 332b2ac..7af769b 100644 (file)
@@ -483,9 +483,9 @@ static void osnoise_top_set_signals(struct osnoise_top_params *params)
 int osnoise_top_main(int argc, char **argv)
 {
        struct osnoise_top_params *params;
+       struct osnoise_tool *record = NULL;
+       struct osnoise_tool *tool = NULL;
        struct trace_instance *trace;
-       struct osnoise_tool *record;
-       struct osnoise_tool *tool;
        int return_value = 1;
        int retval;
 
@@ -571,9 +571,9 @@ int osnoise_top_main(int argc, char **argv)
 
 out_top:
        osnoise_free_top(tool->data);
+       osnoise_destroy_tool(record);
        osnoise_destroy_tool(tool);
-       if (params->trace_output)
-               osnoise_destroy_tool(record);
+       free(params);
 out_exit:
        exit(return_value);
 }
index 235f962..237e173 100644 (file)
@@ -429,7 +429,7 @@ static void timerlat_hist_usage(char *usage)
        char *msg[] = {
                "",
                "  usage: [rtla] timerlat hist [-h] [-q] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] [-t[=file]] \\",
-               "         [-c cpu-list] [-P priority] [-e N] [-b N]  [--no-irq] [--no-thread] [--no-header] [--no-summary] \\",
+               "         [-c cpu-list] [-P priority] [-E N] [-b N]  [--no-irq] [--no-thread] [--no-header] [--no-summary] \\",
                "         [--no-index] [--with-zeros]",
                "",
                "         -h/--help: print this menu",
@@ -443,7 +443,7 @@ static void timerlat_hist_usage(char *usage)
                "         -T/--trace[=file]: save the stopped trace to [file|timerlat_trace.txt]",
                "         -n/--nano: display data in nanoseconds",
                "         -b/--bucket-size N: set the histogram bucket size (default 1)",
-               "         -e/--entries N: set the number of entries of the histogram (default 256)",
+               "         -E/--entries N: set the number of entries of the histogram (default 256)",
                "            --no-irq: ignore IRQ latencies",
                "            --no-thread: ignore thread latencies",
                "            --no-header: do not print header",
@@ -494,7 +494,7 @@ static struct timerlat_hist_params
                        {"cpus",                required_argument,      0, 'c'},
                        {"bucket-size",         required_argument,      0, 'b'},
                        {"debug",               no_argument,            0, 'D'},
-                       {"entries",             required_argument,      0, 'e'},
+                       {"entries",             required_argument,      0, 'E'},
                        {"duration",            required_argument,      0, 'd'},
                        {"help",                no_argument,            0, 'h'},
                        {"irq",                 required_argument,      0, 'i'},
@@ -516,7 +516,7 @@ static struct timerlat_hist_params
                /* getopt_long stores the option index here. */
                int option_index = 0;
 
-               c = getopt_long(argc, argv, "c:b:d:e:Dhi:np:P:s:t::T:012345",
+               c = getopt_long(argc, argv, "c:b:d:E:Dhi:np:P:s:t::T:012345",
                                 long_options, &option_index);
 
                /* detect the end of the options. */
@@ -543,7 +543,7 @@ static struct timerlat_hist_params
                        if (!params->duration)
                                timerlat_hist_usage("Invalid -D duration\n");
                        break;
-               case 'e':
+               case 'E':
                        params->entries = get_llong_from_str(optarg);
                        if ((params->entries < 10) || (params->entries > 9999999))
                                        timerlat_hist_usage("Entries must be > 10 and < 9999999\n");
@@ -729,9 +729,9 @@ timerlat_hist_set_signals(struct timerlat_hist_params *params)
 int timerlat_hist_main(int argc, char *argv[])
 {
        struct timerlat_hist_params *params;
+       struct osnoise_tool *record = NULL;
+       struct osnoise_tool *tool = NULL;
        struct trace_instance *trace;
-       struct osnoise_tool *record;
-       struct osnoise_tool *tool;
        int return_value = 1;
        int retval;
 
@@ -813,9 +813,8 @@ int timerlat_hist_main(int argc, char *argv[])
 
 out_hist:
        timerlat_free_histogram(tool->data);
+       osnoise_destroy_tool(record);
        osnoise_destroy_tool(tool);
-       if (params->trace_output)
-               osnoise_destroy_tool(record);
        free(params);
 out_exit:
        exit(return_value);
index 1ebd529..d4187f6 100644 (file)
@@ -521,9 +521,9 @@ timerlat_top_set_signals(struct timerlat_top_params *params)
 int timerlat_top_main(int argc, char *argv[])
 {
        struct timerlat_top_params *params;
+       struct osnoise_tool *record = NULL;
+       struct osnoise_tool *top = NULL;
        struct trace_instance *trace;
-       struct osnoise_tool *record;
-       struct osnoise_tool *top;
        int return_value = 1;
        int retval;
 
@@ -609,9 +609,8 @@ int timerlat_top_main(int argc, char *argv[])
 
 out_top:
        timerlat_free_top(top->data);
+       osnoise_destroy_tool(record);
        osnoise_destroy_tool(top);
-       if (params->trace_output)
-               osnoise_destroy_tool(record);
        free(params);
 out_exit:
        exit(return_value);
index 107a0c6..83de259 100644 (file)
@@ -20,14 +20,14 @@ int enable_tracer_by_name(struct tracefs_instance *inst, const char *tracer_name
 
        tracer = TRACEFS_TRACER_CUSTOM;
 
-       debug_msg("enabling %s tracer\n", tracer_name);
+       debug_msg("Enabling %s tracer\n", tracer_name);
 
        retval = tracefs_tracer_set(inst, tracer, tracer_name);
        if (retval < 0) {
                if (errno == ENODEV)
-                       err_msg("tracer %s not found!\n", tracer_name);
+                       err_msg("Tracer %s not found!\n", tracer_name);
 
-               err_msg("failed to enable the tracer %s\n", tracer_name);
+               err_msg("Failed to enable the %s tracer\n", tracer_name);
                return -1;
        }
 
@@ -44,7 +44,7 @@ void disable_tracer(struct tracefs_instance *inst)
 
        retval = tracefs_tracer_set(inst, t);
        if (retval < 0)
-               err_msg("oops, error disabling tracer\n");
+               err_msg("Oops, error disabling tracer\n");
 }
 
 /*
index 1c9f0ee..ffaf8ec 100644 (file)
@@ -77,11 +77,11 @@ void get_duration(time_t start_time, char *output, int output_size)
        time_t duration;
 
        duration = difftime(now, start_time);
-       tm_info = localtime(&duration);
+       tm_info = gmtime(&duration);
 
        snprintf(output, output_size, "%3d %02d:%02d:%02d",
                        tm_info->tm_yday,
-                       tm_info->tm_hour - 1,
+                       tm_info->tm_hour,
                        tm_info->tm_min,
                        tm_info->tm_sec);
 }
index 7be7468..83822c3 100644 (file)
@@ -28,6 +28,7 @@ no-header-test += linux/am437x-vpfe.h
 no-header-test += linux/android/binder.h
 no-header-test += linux/android/binderfs.h
 no-header-test += linux/coda.h
+no-header-test += linux/cyclades.h
 no-header-test += linux/errqueue.h
 no-header-test += linux/fsmap.h
 no-header-test += linux/hdlc/ioctl.h
index 2ad013b..59b1dd4 100644 (file)
@@ -463,8 +463,8 @@ bool kvm_irq_has_notifier(struct kvm *kvm, unsigned irqchip, unsigned pin)
        idx = srcu_read_lock(&kvm->irq_srcu);
        gsi = kvm_irq_map_chip_pin(kvm, irqchip, pin);
        if (gsi != -1)
-               hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list,
-                                        link)
+               hlist_for_each_entry_srcu(kian, &kvm->irq_ack_notifier_list,
+                                         link, srcu_read_lock_held(&kvm->irq_srcu))
                        if (kian->gsi == gsi) {
                                srcu_read_unlock(&kvm->irq_srcu, idx);
                                return true;
@@ -480,8 +480,8 @@ void kvm_notify_acked_gsi(struct kvm *kvm, int gsi)
 {
        struct kvm_irq_ack_notifier *kian;
 
-       hlist_for_each_entry_rcu(kian, &kvm->irq_ack_notifier_list,
-                                link)
+       hlist_for_each_entry_srcu(kian, &kvm->irq_ack_notifier_list,
+                                 link, srcu_read_lock_held(&kvm->irq_srcu))
                if (kian->gsi == gsi)
                        kian->irq_acked(kian);
 }
index 9a20f22..0afc016 100644 (file)
@@ -2248,7 +2248,6 @@ struct kvm_memory_slot *kvm_vcpu_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn
 
        return NULL;
 }
-EXPORT_SYMBOL_GPL(kvm_vcpu_gfn_to_memslot);
 
 bool kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn)
 {
@@ -2463,9 +2462,8 @@ static int kvm_try_get_pfn(kvm_pfn_t pfn)
 }
 
 static int hva_to_pfn_remapped(struct vm_area_struct *vma,
-                              unsigned long addr, bool *async,
-                              bool write_fault, bool *writable,
-                              kvm_pfn_t *p_pfn)
+                              unsigned long addr, bool write_fault,
+                              bool *writable, kvm_pfn_t *p_pfn)
 {
        kvm_pfn_t pfn;
        pte_t *ptep;
@@ -2575,7 +2573,7 @@ retry:
        if (vma == NULL)
                pfn = KVM_PFN_ERR_FAULT;
        else if (vma->vm_flags & (VM_IO | VM_PFNMAP)) {
-               r = hva_to_pfn_remapped(vma, addr, async, write_fault, writable, &pfn);
+               r = hva_to_pfn_remapped(vma, addr, write_fault, writable, &pfn);
                if (r == -EAGAIN)
                        goto retry;
                if (r < 0)
@@ -5530,9 +5528,7 @@ static int kvm_suspend(void)
 static void kvm_resume(void)
 {
        if (kvm_usage_count) {
-#ifdef CONFIG_LOCKDEP
-               WARN_ON(lockdep_is_held(&kvm_count_lock));
-#endif
+               lockdep_assert_not_held(&kvm_count_lock);
                hardware_enable_nolock(NULL);
        }
 }