Merge branches 'pm-devfreq', 'pm-qos', 'pm-tools' and 'pm-docs'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 29 Jul 2022 17:46:00 +0000 (19:46 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 29 Jul 2022 17:46:00 +0000 (19:46 +0200)
Merge devfreq changes, PM QoS change, and power management tools and
documentation changes for v5.20-rc1:

 - Add new devfreq driver for Mediatek CCI (Cache Coherent
   Interconnect) (Johnson Wang).

 - Convert the Samsung Exynos SoC Bus bindings to DT schema of
   exynos-bus.c (Krzysztof Kozlowski).

 - Address kernel-doc warnings by adding the description for unused
   fucntion parameters in devfreq core (Mauro Carvalho Chehab).

 - Use NULL to pass a null pointer rather than zero according to the
   function propotype in imx-bus.c (Colin Ian King).

 - Print error message instead of error interger value in
   tegra30-devfreq.c (Dmitry Osipenko).

 - Add checks to prevent setting negative frequency QoS limits for
   CPUs (Shivnandan Kumar).

 - Update the pm-graph suite of utilities to the latest revision 5.9
   including multiple improvements (Todd Brandt).

 - Drop pme_interrupt reference from the PCI power management
   documentation (Mario Limonciello).

* pm-devfreq:
  PM / devfreq: tegra30: Add error message for devm_devfreq_add_device()
  PM / devfreq: imx-bus: use NULL to pass a null pointer rather than zero
  PM / devfreq: shut up kernel-doc warnings
  dt-bindings: interconnect: samsung,exynos-bus: convert to dtschema
  PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
  dt-bindings: interconnect: Add MediaTek CCI dt-bindings

* pm-qos:
  PM: QoS: Add check to make sure CPU freq is non-negative

* pm-tools:
  pm-graph v5.9

* pm-docs:
  Documentation: PM: Drop pme_interrupt reference

816 files changed:
.mailmap
CREDITS
Documentation/admin-guide/kernel-parameters.txt
Documentation/core-api/kernel-api.rst
Documentation/core-api/symbol-namespaces.rst
Documentation/devicetree/bindings/devfreq/exynos-bus.txt [deleted file]
Documentation/devicetree/bindings/display/allwinner,sun4i-a10-display-engine.yaml
Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml
Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/interconnect/samsung,exynos-bus.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/net/wireless/qca,ath9k.yaml
Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
Documentation/filesystems/netfs_library.rst
Documentation/filesystems/overlayfs.rst
Documentation/livepatch/module-elf-format.rst
Documentation/networking/dsa/dsa.rst
Documentation/networking/ip-sysctl.rst
Documentation/power/energy-model.rst
Documentation/process/maintainer-netdev.rst
Documentation/sound/soc/dai.rst
Documentation/translations/it_IT/core-api/symbol-namespaces.rst
Documentation/translations/zh_CN/core-api/kernel-api.rst
Documentation/translations/zh_CN/core-api/symbol-namespaces.rst
Documentation/virt/kvm/api.rst
MAINTAINERS
Makefile
arch/Kconfig
arch/arm/boot/dts/at91-sam9x60ek.dts
arch/arm/boot/dts/at91-sama5d2_icp.dts
arch/arm/boot/dts/imx6qdl-ts7970.dtsi
arch/arm/boot/dts/imx6ull-colibri.dtsi
arch/arm/boot/dts/imx7d-smegw01.dts
arch/arm/boot/dts/lan966x-kontron-kswitch-d10-mmt.dtsi
arch/arm/boot/dts/qcom-msm8974.dtsi
arch/arm/boot/dts/sama5d2.dtsi
arch/arm/boot/dts/stm32mp15-scmi.dtsi
arch/arm/boot/dts/stm32mp151.dtsi
arch/arm/boot/dts/stm32mp157a-dk1-scmi.dts
arch/arm/boot/dts/stm32mp157c-dk2-scmi.dts
arch/arm/boot/dts/stm32mp157c-ed1-scmi.dts
arch/arm/boot/dts/stm32mp157c-ev1-scmi.dts
arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts
arch/arm/configs/mxs_defconfig
arch/arm/include/asm/domain.h
arch/arm/include/asm/mach/map.h
arch/arm/include/asm/ptrace.h
arch/arm/kernel/entry-common.S
arch/arm/mach-at91/pm.c
arch/arm/mach-meson/platsmp.c
arch/arm/mach-rockchip/pm.c
arch/arm/mm/Kconfig
arch/arm/mm/alignment.c
arch/arm/mm/mmu.c
arch/arm/mm/proc-v7-bugs.c
arch/arm/probes/decode.h
arch/arm/xen/p2m.c
arch/arm64/boot/dts/broadcom/bcm4908/bcm4906.dtsi
arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
arch/arm64/boot/dts/freescale/imx8mp-evk.dts
arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp-edimm2.2.dts
arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts
arch/arm64/boot/dts/freescale/imx8mp.dtsi
arch/arm64/boot/dts/qcom/msm8992-lg-bullhead.dtsi
arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts
arch/arm64/boot/dts/qcom/msm8994.dtsi
arch/arm64/boot/dts/qcom/sc7180-trogdor-homestar.dtsi
arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor.dtsi
arch/arm64/boot/dts/qcom/sdm845.dtsi
arch/arm64/boot/dts/qcom/sm8450.dtsi
arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi
arch/arm64/boot/dts/rockchip/rk3399.dtsi
arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
arch/arm64/boot/dts/rockchip/rk3566-quartz64-b.dts
arch/csky/include/asm/tlb.h
arch/loongarch/Kconfig
arch/loongarch/include/asm/fpregdef.h
arch/loongarch/include/asm/page.h
arch/loongarch/include/asm/processor.h
arch/loongarch/include/asm/tlb.h
arch/loongarch/kernel/asm-offsets.c
arch/loongarch/kernel/fpu.S
arch/loongarch/kernel/numa.c
arch/loongarch/vdso/Makefile
arch/openrisc/kernel/unwinder.c
arch/powerpc/Kconfig
arch/powerpc/include/asm/tlb.h
arch/powerpc/platforms/powernv/rng.c
arch/riscv/Kconfig
arch/riscv/Makefile
arch/riscv/boot/dts/canaan/canaan_kd233.dts
arch/riscv/boot/dts/canaan/sipeed_maix_bit.dts
arch/riscv/boot/dts/canaan/sipeed_maix_dock.dts
arch/riscv/boot/dts/canaan/sipeed_maix_go.dts
arch/riscv/boot/dts/canaan/sipeed_maixduino.dts
arch/riscv/boot/dts/microchip/mpfs.dtsi
arch/riscv/errata/sifive/errata.c
arch/riscv/include/asm/pgtable-64.h
arch/riscv/include/asm/pgtable.h
arch/riscv/kernel/Makefile
arch/riscv/kernel/elf_kexec.c
arch/riscv/kvm/mmu.c
arch/riscv/kvm/vcpu.c
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/include/asm/nospec-insn.h
arch/s390/include/asm/tlb.h
arch/s390/lib/Makefile
arch/s390/lib/expoline.S [deleted file]
arch/s390/lib/expoline/Makefile [new file with mode: 0644]
arch/s390/lib/expoline/expoline.S [new file with mode: 0644]
arch/sh/include/asm/io.h
arch/sparc/Kconfig
arch/sparc/include/asm/tlb_64.h
arch/um/include/asm/page.h
arch/um/include/shared/mem.h
arch/um/kernel/um_arch.c
arch/um/os-Linux/skas/process.c
arch/x86/Kconfig
arch/x86/Makefile
arch/x86/boot/compressed/ident_map_64.c
arch/x86/entry/Makefile
arch/x86/entry/calling.h
arch/x86/entry/entry.S [new file with mode: 0644]
arch/x86/entry/entry_32.S
arch/x86/entry/entry_64.S
arch/x86/entry/entry_64_compat.S
arch/x86/entry/vdso/Makefile
arch/x86/entry/vsyscall/vsyscall_emu_64.S
arch/x86/events/intel/lbr.c
arch/x86/include/asm/alternative.h
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/disabled-features.h
arch/x86/include/asm/linkage.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/nospec-branch.h
arch/x86/include/asm/setup.h
arch/x86/include/asm/static_call.h
arch/x86/include/asm/tlb.h
arch/x86/include/asm/unwind_hints.h
arch/x86/include/uapi/asm/bootparam.h
arch/x86/kernel/acpi/cppc.c
arch/x86/kernel/alternative.c
arch/x86/kernel/asm-offsets.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpu.h
arch/x86/kernel/cpu/hygon.c
arch/x86/kernel/cpu/scattered.c
arch/x86/kernel/ftrace.c
arch/x86/kernel/head64.c
arch/x86/kernel/head_32.S
arch/x86/kernel/head_64.S
arch/x86/kernel/module.c
arch/x86/kernel/process.c
arch/x86/kernel/relocate_kernel_32.S
arch/x86/kernel/relocate_kernel_64.S
arch/x86/kernel/static_call.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/kvm/emulate.c
arch/x86/kvm/svm/vmenter.S
arch/x86/kvm/vmx/capabilities.h
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/run_flags.h [new file with mode: 0644]
arch/x86/kvm/vmx/vmenter.S
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/vmx/vmx.h
arch/x86/kvm/vmx/vmx_ops.h
arch/x86/kvm/x86.c
arch/x86/lib/memmove_64.S
arch/x86/lib/retpoline.S
arch/x86/mm/init.c
arch/x86/mm/mem_encrypt_boot.S
arch/x86/net/bpf_jit_comp.c
arch/x86/platform/efi/efi_thunk_64.S
arch/x86/xen/enlighten_pv.c
arch/x86/xen/setup.c
arch/x86/xen/xen-asm.S
arch/x86/xen/xen-head.S
arch/x86/xen/xen-ops.h
block/blk-merge.c
certs/Kconfig
crypto/Kconfig
drivers/acpi/acpi_video.c
drivers/acpi/bus.c
drivers/acpi/cppc_acpi.c
drivers/amba/bus.c
drivers/base/core.c
drivers/base/cpu.c
drivers/base/power/domain.c
drivers/base/power/runtime.c
drivers/base/power/wakeup.c
drivers/block/xen-blkfront.c
drivers/char/random.c
drivers/clk/clk-lan966x.c
drivers/cpufreq/Kconfig
drivers/cpufreq/acpi-cpufreq.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/mediatek-cpufreq-hw.c
drivers/cpufreq/mediatek-cpufreq.c
drivers/cpufreq/scmi-cpufreq.c
drivers/cpuidle/governors/haltpoll.c
drivers/crypto/Kconfig
drivers/cxl/core/hdm.c
drivers/cxl/core/mbox.c
drivers/cxl/core/port.c
drivers/cxl/cxl.h
drivers/cxl/cxlmem.h
drivers/cxl/mem.c
drivers/cxl/pmem.c
drivers/devfreq/Kconfig
drivers/devfreq/Makefile
drivers/devfreq/devfreq.c
drivers/devfreq/exynos-bus.c
drivers/devfreq/imx-bus.c
drivers/devfreq/mtk-cci-devfreq.c [new file with mode: 0644]
drivers/devfreq/tegra30-devfreq.c
drivers/dma-buf/dma-resv.c
drivers/dma/at_xdmac.c
drivers/dma/dmatest.c
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
drivers/dma/idxd/device.c
drivers/dma/idxd/init.c
drivers/dma/imx-sdma.c
drivers/dma/lgm/lgm-dma.c
drivers/dma/pl330.c
drivers/dma/qcom/bam_dma.c
drivers/dma/ti/dma-crossbar.c
drivers/firmware/arm_scmi/bus.c
drivers/firmware/arm_scmi/clock.c
drivers/firmware/arm_scmi/driver.c
drivers/firmware/arm_scmi/optee.c
drivers/firmware/arm_scmi/perf.c
drivers/firmware/arm_scmi/protocols.h
drivers/firmware/efi/reboot.c
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-sim.c
drivers/gpio/gpio-vf610.c
drivers/gpio/gpio-xilinx.c
drivers/gpio/gpiolib-cdev.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h [deleted file]
drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
drivers/gpu/drm/amd/amdkfd/kfd_device.c
drivers/gpu/drm/amd/display/Kconfig
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
drivers/gpu/drm/bridge/fsl-ldb.c
drivers/gpu/drm/drm_aperture.c
drivers/gpu/drm/drm_gem_ttm_helper.c
drivers/gpu/drm/drm_panel_orientation_quirks.c
drivers/gpu/drm/i915/display/intel_dp_mst.c
drivers/gpu/drm/i915/gem/i915_gem_region.c
drivers/gpu/drm/i915/gem/i915_gem_ttm.c
drivers/gpu/drm/i915/gem/i915_gem_wait.c
drivers/gpu/drm/i915/gt/intel_context_types.h
drivers/gpu/drm/i915/gt/intel_execlists_submission.c
drivers/gpu/drm/i915/gt/intel_gt.c
drivers/gpu/drm/i915/gt/intel_lrc.h
drivers/gpu/drm/i915/gt/intel_reset.c
drivers/gpu/drm/i915/gt/selftest_lrc.c
drivers/gpu/drm/i915/gt/uc/abi/guc_actions_abi.h
drivers/gpu/drm/i915/gt/uc/intel_guc.h
drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h
drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
drivers/gpu/drm/i915/gt/uc/intel_uc_fw.h
drivers/gpu/drm/i915/gvt/cmd_parser.c
drivers/gpu/drm/i915/i915_scatterlist.c
drivers/gpu/drm/i915/i915_scatterlist.h
drivers/gpu/drm/i915/i915_vma.c
drivers/gpu/drm/i915/intel_region_ttm.c
drivers/gpu/drm/i915/intel_region_ttm.h
drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
drivers/gpu/drm/i915/selftests/intel_memory_region.c
drivers/gpu/drm/i915/selftests/mock_region.c
drivers/gpu/drm/imx/dcss/dcss-dev.c
drivers/gpu/drm/panel/panel-edp.c
drivers/gpu/drm/panfrost/panfrost_drv.c
drivers/gpu/drm/panfrost/panfrost_mmu.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
drivers/gpu/drm/scheduler/sched_entity.c
drivers/gpu/drm/solomon/ssd130x.c
drivers/i2c/busses/i2c-cadence.c
drivers/i2c/busses/i2c-imx.c
drivers/i2c/busses/i2c-mlxcpld.c
drivers/i2c/busses/i2c-piix4.c
drivers/idle/intel_idle.c
drivers/infiniband/hw/irdma/cm.c
drivers/infiniband/hw/irdma/i40iw_hw.c
drivers/infiniband/hw/irdma/icrdma_hw.c
drivers/infiniband/hw/irdma/irdma.h
drivers/infiniband/hw/irdma/verbs.c
drivers/input/touchscreen/goodix.c
drivers/input/touchscreen/usbtouchscreen.c
drivers/input/touchscreen/wm97xx-core.c
drivers/iommu/intel/dmar.c
drivers/iommu/intel/iommu.c
drivers/iommu/intel/pasid.c
drivers/iommu/intel/pasid.h
drivers/irqchip/Kconfig
drivers/irqchip/irq-apple-aic.c
drivers/irqchip/irq-gic-v3.c
drivers/irqchip/irq-or1k-pic.c
drivers/md/raid5.c
drivers/misc/cardreader/rtsx_usb.c
drivers/misc/eeprom/at25.c
drivers/misc/lkdtm/Makefile
drivers/mmc/host/sdhci-omap.c
drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
drivers/net/Kconfig
drivers/net/amt.c
drivers/net/can/grcan.c
drivers/net/can/m_can/m_can.c
drivers/net/can/rcar/rcar_canfd.c
drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
drivers/net/can/spi/mcp251xfd/mcp251xfd-regmap.c
drivers/net/can/usb/gs_usb.c
drivers/net/can/usb/kvaser_usb/kvaser_usb.h
drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
drivers/net/can/xilinx_can.c
drivers/net/dsa/microchip/ksz_common.c
drivers/net/dsa/sja1105/sja1105_main.c
drivers/net/dsa/vitesse-vsc73xx-spi.c
drivers/net/ethernet/aquantia/atlantic/aq_pci_func.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_ptp.c
drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_ethtool.c
drivers/net/ethernet/faraday/ftgmac100.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/intel/e1000e/hw.h
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/e1000e/ich8lan.h
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_register.h
drivers/net/ethernet/intel/i40e/i40e_type.h
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/iavf/iavf.h
drivers/net/ethernet/intel/iavf/iavf_ethtool.c
drivers/net/ethernet/intel/iavf/iavf_main.c
drivers/net/ethernet/intel/iavf/iavf_txrx.c
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
drivers/net/ethernet/intel/ice/ice_devids.h
drivers/net/ethernet/intel/ice/ice_devlink.c
drivers/net/ethernet/intel/ice/ice_fw_update.c
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/igc/igc_main.c
drivers/net/ethernet/intel/igc/igc_regs.h
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
drivers/net/ethernet/marvell/prestera/prestera_flower.c
drivers/net/ethernet/marvell/prestera/prestera_router.c
drivers/net/ethernet/mediatek/mtk_ppe_offload.c
drivers/net/ethernet/mediatek/mtk_wed.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.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/legacy.c
drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
drivers/net/ethernet/microchip/lan966x/lan966x_mac.c
drivers/net/ethernet/microchip/lan966x/lan966x_main.c
drivers/net/ethernet/microchip/lan966x/lan966x_main.h
drivers/net/ethernet/mscc/ocelot_fdma.c
drivers/net/ethernet/netronome/nfp/flower/action.c
drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
drivers/net/ethernet/netronome/nfp/nfdk/dp.c
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/ef10_sriov.c
drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c
drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
drivers/net/ethernet/stmicro/stmmac/dwmac4.h
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
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_platform.c
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
drivers/net/ethernet/sun/sunhme.c
drivers/net/ethernet/ti/am65-cpsw-nuss.c
drivers/net/usb/catc.c
drivers/net/usb/r8152.c
drivers/net/usb/usbnet.c
drivers/net/wireless/ath/ath11k/wmi.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/realtek/rtw88/main.h
drivers/net/wireless/realtek/rtw88/rtw8821c.c
drivers/net/xen-netback/rx.c
drivers/net/xen-netfront.c
drivers/nvme/host/core.c
drivers/nvme/host/pci.c
drivers/nvme/host/trace.h
drivers/opp/of.c
drivers/pinctrl/Kconfig
drivers/pinctrl/aspeed/pinctrl-aspeed.c
drivers/pinctrl/freescale/pinctrl-imx93.c
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
drivers/pinctrl/pinctrl-ocelot.c
drivers/pinctrl/ralink/pinctrl-ralink.c
drivers/pinctrl/stm32/pinctrl-stm32.c
drivers/pinctrl/sunplus/sppctl.c
drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c
drivers/pinctrl/sunxi/pinctrl-sunxi.c
drivers/platform/x86/amd-pmc.c
drivers/platform/x86/asus-nb-wmi.c
drivers/platform/x86/gigabyte-wmi.c
drivers/platform/x86/intel/atomisp2/led.c
drivers/platform/x86/intel/ifs/Kconfig
drivers/platform/x86/x86-android-tablets.c
drivers/power/reset/arm-versatile-reboot.c
drivers/power/supply/ab8500_fg.c
drivers/power/supply/power_supply_core.c
drivers/powercap/dtpm_cpu.c
drivers/powercap/intel_rapl_common.c
drivers/powercap/intel_rapl_msr.c
drivers/s390/crypto/ap_bus.c
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/pm8001/pm8001_hwi.c
drivers/scsi/pm8001/pm8001_init.c
drivers/scsi/pm8001/pm80xx_hwi.c
drivers/soc/atmel/soc.c
drivers/soc/ixp4xx/ixp4xx-npe.c
drivers/soc/qcom/smem.c
drivers/spi/spi-amd.c
drivers/spi/spi-aspeed-smc.c
drivers/spi/spi-bcm2835.c
drivers/spi/spi-cadence-quadspi.c
drivers/spi/spi-cadence.c
drivers/spi/spi-rspi.c
drivers/staging/wlan-ng/hfa384x_usb.c
drivers/target/target_core_file.c
drivers/target/target_core_iblock.c
drivers/target/target_core_sbc.c
drivers/tee/optee/optee_smc.h
drivers/tee/optee/smc_abi.c
drivers/tee/tee_core.c
drivers/thermal/cpufreq_cooling.c
drivers/thermal/devfreq_cooling.c
drivers/tty/pty.c
drivers/tty/serial/8250/8250_core.c
drivers/tty/serial/8250/8250_dma.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/mvebu-uart.c
drivers/tty/serial/samsung_tty.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/stm32-usart.c
drivers/tty/tty.h
drivers/tty/tty_buffer.c
drivers/tty/vt/vt.c
drivers/ufs/core/ufshcd.c
drivers/usb/dwc3/dwc3-am62.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/function/uvc_configfs.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/fsl-mph-dr-of.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/typec/class.c
drivers/vfio/vfio.c
drivers/video/fbdev/core/fbcon.c
drivers/video/fbdev/core/fbmem.c
drivers/virt/coco/sev-guest/sev-guest.c
drivers/xen/gntdev.c
fs/afs/file.c
fs/btrfs/ctree.h
fs/btrfs/delayed-inode.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/inode.c
fs/btrfs/send.c
fs/btrfs/tests/btrfs-tests.c
fs/btrfs/transaction.c
fs/btrfs/zoned.c
fs/cachefiles/ondemand.c
fs/ceph/addr.c
fs/cifs/connect.c
fs/cifs/sess.c
fs/cifs/smb2pdu.c
fs/exec.c
fs/fscache/cookie.c
fs/fscache/volume.c
fs/io_uring.c
fs/lockd/svcsubs.c
fs/netfs/buffered_read.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsd.h
fs/nilfs2/nilfs.h
fs/overlayfs/super.c
fs/remap_range.c
include/acpi/cppc_acpi.h
include/asm-generic/tlb.h
include/drm/gpu_scheduler.h
include/linux/acpi.h
include/linux/cgroup-defs.h
include/linux/cpu.h
include/linux/energy_model.h
include/linux/fbcon.h
include/linux/fscache.h
include/linux/highmem.h
include/linux/intel-iommu.h
include/linux/kexec.h
include/linux/kvm_host.h
include/linux/memregion.h
include/linux/netfs.h
include/linux/nvme.h
include/linux/objtool.h
include/linux/pm_runtime.h
include/linux/pm_wakeup.h
include/linux/reset.h
include/linux/rtsx_usb.h
include/linux/sched/task.h
include/linux/scmi_protocol.h
include/linux/serial_core.h
include/linux/stmmac.h
include/net/amt.h
include/net/cfg80211.h
include/net/flow_offload.h
include/net/inet_hashtables.h
include/net/inet_sock.h
include/net/ip.h
include/net/mac80211.h
include/net/netfilter/nf_tables.h
include/net/protocol.h
include/net/raw.h
include/net/route.h
include/net/sock.h
include/net/tcp.h
include/net/tls.h
include/net/udp.h
include/sound/soc.h
include/trace/events/iocost.h
include/trace/events/power.h
include/trace/events/sock.h
include/uapi/linux/bpf.h
include/uapi/linux/input.h
include/uapi/linux/io_uring.h
include/uapi/linux/kvm.h
include/uapi/linux/tty.h
include/video/of_display_timing.h
ipc/namespace.c
kernel/bpf/core.c
kernel/bpf/helpers.c
kernel/bpf/verifier.c
kernel/cgroup/cgroup.c
kernel/events/core.c
kernel/exit.c
kernel/kexec_file.c
kernel/module/internal.h
kernel/module/kallsyms.c
kernel/module/main.c
kernel/power/energy_model.c
kernel/power/qos.c
kernel/power/user.c
kernel/printk/printk.c
kernel/ptrace.c
kernel/rcu/srcutree.c
kernel/sched/deadline.c
kernel/signal.c
kernel/sysctl.c
kernel/time/posix-timers.c
kernel/trace/Kconfig
kernel/trace/trace.c
kernel/trace/trace_events_hist.c
kernel/watch_queue.c
lib/Kconfig.ubsan
lib/idr.c
mm/damon/vaddr.c
mm/memory.c
mm/rmap.c
mm/sparse-vmemmap.c
mm/userfaultfd.c
net/8021q/vlan_netlink.c
net/bluetooth/hci_core.c
net/bluetooth/hci_sync.c
net/can/bcm.c
net/core/dev.c
net/core/filter.c
net/core/secure_seq.c
net/core/sock_reuseport.c
net/dsa/port.c
net/ipv4/af_inet.c
net/ipv4/ah4.c
net/ipv4/cipso_ipv4.c
net/ipv4/esp4.c
net/ipv4/fib_semantics.c
net/ipv4/fib_trie.c
net/ipv4/icmp.c
net/ipv4/igmp.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_timewait_sock.c
net/ipv4/inetpeer.c
net/ipv4/ip_forward.c
net/ipv4/ip_input.c
net/ipv4/ip_sockglue.c
net/ipv4/netfilter/nf_reject_ipv4.c
net/ipv4/nexthop.c
net/ipv4/proc.c
net/ipv4/route.c
net/ipv4/syncookies.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_fastopen.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_metrics.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_output.c
net/ipv4/tcp_recovery.c
net/ipv4/tcp_timer.c
net/ipv6/af_inet6.c
net/ipv6/icmp.c
net/ipv6/ip6_input.c
net/ipv6/route.c
net/ipv6/seg6_iptunnel.c
net/ipv6/seg6_local.c
net/ipv6/syncookies.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/mac80211/cfg.c
net/mac80211/iface.c
net/mac80211/rx.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wme.c
net/mptcp/options.c
net/mptcp/pm_netlink.c
net/mptcp/pm_userspace.c
net/mptcp/protocol.c
net/mptcp/protocol.h
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_log_syslog.c
net/netfilter/nf_synproxy_core.c
net/netfilter/nf_tables_api.c
net/netfilter/nft_set_pipapo.c
net/rose/rose_route.c
net/sched/act_police.c
net/sched/cls_api.c
net/sctp/protocol.c
net/smc/smc_llc.c
net/tls/tls_device.c
net/tls/tls_main.c
net/tls/tls_sw.c
net/wireless/sme.c
net/xdp/xsk_buff_pool.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
samples/fprobe/fprobe_example.c
samples/kprobes/kprobe_example.c
samples/kprobes/kretprobe_example.c
scripts/Makefile.lib
scripts/Makefile.modinst
scripts/Makefile.vmlinux_o
scripts/clang-tools/gen_compile_commands.py
scripts/gdb/linux/symbols.py
security/Kconfig
security/integrity/evm/evm_crypto.c
security/integrity/ima/ima_appraise.c
security/integrity/ima/ima_crypto.c
security/integrity/ima/ima_efi.c
security/integrity/ima/ima_policy.c
security/integrity/ima/ima_template_lib.c
sound/pci/cs46xx/cs46xx.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/soc/codecs/ak4613.c
sound/soc/codecs/arizona.c
sound/soc/codecs/cs35l41-lib.c
sound/soc/codecs/cs35l41.c
sound/soc/codecs/cs47l15.c
sound/soc/codecs/cs47l92.c
sound/soc/codecs/madera.c
sound/soc/codecs/max98373-sdw.c
sound/soc/codecs/max98396.c
sound/soc/codecs/rt1308-sdw.c
sound/soc/codecs/rt1316-sdw.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5682-sdw.c
sound/soc/codecs/rt700-sdw.c
sound/soc/codecs/rt700.c
sound/soc/codecs/rt711-sdca-sdw.c
sound/soc/codecs/rt711-sdca.c
sound/soc/codecs/rt711-sdw.c
sound/soc/codecs/rt711.c
sound/soc/codecs/rt715-sdca-sdw.c
sound/soc/codecs/rt715-sdw.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sgtl5000.h
sound/soc/codecs/tas2764.c
sound/soc/codecs/tas2764.h
sound/soc/codecs/tlv320adcx140.c
sound/soc/codecs/wcd9335.c
sound/soc/codecs/wcd938x.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8998.c
sound/soc/codecs/wm_adsp.c
sound/soc/generic/audio-graph-card2.c
sound/soc/intel/avs/topology.c
sound/soc/intel/boards/bytcr_wm5102.c
sound/soc/intel/boards/sof_rt5682.c
sound/soc/intel/boards/sof_sdw.c
sound/soc/intel/skylake/skl-nhlt.c
sound/soc/qcom/qdsp6/q6apm-dai.c
sound/soc/qcom/qdsp6/q6apm.c
sound/soc/soc-dapm.c
sound/soc/soc-ops.c
sound/soc/sof/intel/hda-dsp.c
sound/soc/sof/intel/hda-loader.c
sound/soc/sof/intel/hda-pcm.c
sound/soc/sof/intel/hda-stream.c
sound/soc/sof/intel/hda.h
sound/soc/sof/ipc3-topology.c
sound/soc/sof/mediatek/mt8186/mt8186.c
sound/soc/sof/pm.c
sound/soc/sof/sof-priv.h
sound/soc/ti/omap-mcbsp-priv.h
sound/soc/ti/omap-mcbsp-st.c
sound/soc/ti/omap-mcbsp.c
sound/usb/quirks-table.h
sound/usb/quirks.c
tools/arch/x86/include/asm/cpufeatures.h
tools/arch/x86/include/asm/disabled-features.h
tools/arch/x86/include/asm/msr-index.h
tools/include/linux/objtool.h
tools/include/uapi/linux/bpf.h
tools/include/uapi/linux/kvm.h
tools/objtool/arch/x86/decode.c
tools/objtool/builtin-check.c
tools/objtool/check.c
tools/objtool/include/objtool/arch.h
tools/objtool/include/objtool/builtin.h
tools/objtool/include/objtool/check.h
tools/objtool/include/objtool/elf.h
tools/objtool/include/objtool/objtool.h
tools/objtool/objtool.c
tools/perf/builtin-trace.c
tools/perf/tests/perf-time-to-tsc.c
tools/power/pm-graph/README
tools/power/pm-graph/bootgraph.py
tools/power/pm-graph/config/custom-timeline-functions.cfg
tools/power/pm-graph/sleepgraph.py
tools/testing/selftests/bpf/progs/dynptr_fail.c
tools/testing/selftests/bpf/progs/dynptr_success.c
tools/testing/selftests/bpf/verifier/jmp32.c
tools/testing/selftests/bpf/verifier/jump.c
tools/testing/selftests/gpio/Makefile
tools/testing/selftests/kvm/rseq_test.c
tools/testing/selftests/net/.gitignore
tools/testing/selftests/net/Makefile
tools/testing/selftests/net/fib_nexthop_nongw.sh [new file with mode: 0755]
tools/testing/selftests/net/forwarding/Makefile
tools/testing/selftests/net/forwarding/lib.sh
tools/testing/selftests/net/mptcp/Makefile
tools/testing/selftests/net/mptcp/pm_nl_ctl.c
tools/testing/selftests/net/mptcp/userspace_pm.sh
tools/testing/selftests/net/udpgro.sh
tools/testing/selftests/net/udpgro_bench.sh
tools/testing/selftests/net/udpgro_frglist.sh
tools/testing/selftests/net/udpgro_fwd.sh
tools/testing/selftests/net/veth.sh
tools/testing/selftests/wireguard/qemu/Makefile
tools/testing/selftests/wireguard/qemu/arch/arm.config
tools/testing/selftests/wireguard/qemu/arch/armeb.config
tools/testing/selftests/wireguard/qemu/arch/i686.config
tools/testing/selftests/wireguard/qemu/arch/m68k.config
tools/testing/selftests/wireguard/qemu/arch/mips.config
tools/testing/selftests/wireguard/qemu/arch/mipsel.config
tools/testing/selftests/wireguard/qemu/arch/powerpc.config
tools/testing/selftests/wireguard/qemu/arch/x86_64.config
tools/testing/selftests/wireguard/qemu/init.c

index 2ed1cf86917530661aa715c2bdafb798c973797f..13e4f504e17fbb7f91d6f87ae5589b989157ee73 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -64,6 +64,9 @@ Bart Van Assche <bvanassche@acm.org> <bart.vanassche@sandisk.com>
 Bart Van Assche <bvanassche@acm.org> <bart.vanassche@wdc.com>
 Ben Gardner <bgardner@wabtec.com>
 Ben M Cahill <ben.m.cahill@intel.com>
+Ben Widawsky <bwidawsk@kernel.org> <ben@bwidawsk.net>
+Ben Widawsky <bwidawsk@kernel.org> <ben.widawsky@intel.com>
+Ben Widawsky <bwidawsk@kernel.org> <benjamin.widawsky@intel.com>
 Björn Steinbrink <B.Steinbrink@gmx.de>
 Björn Töpel <bjorn@kernel.org> <bjorn.topel@gmail.com>
 Björn Töpel <bjorn@kernel.org> <bjorn.topel@intel.com>
diff --git a/CREDITS b/CREDITS
index 7e85a53b6a880942e9379125bae8ad4c9a08f13b..40d3c655b567a0b914fd9809dabcb8cdf5cc0f3c 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -627,6 +627,10 @@ S: 48287 Sawleaf
 S: Fremont, California 94539
 S: USA
 
+N: Tomas Cech
+E: sleep_walker@suse.com
+D: arm/palm treo support
+
 N: Florent Chabaud
 E: florent.chabaud@polytechnique.org
 D: software suspend
index 2522b11e593f2397840d59541f9befcebed505b1..c0fdb04a0435a6daf88492cbaf76adfb6aeac716 100644 (file)
 
        retain_initrd   [RAM] Keep initrd memory after extraction
 
+       retbleed=       [X86] Control mitigation of RETBleed (Arbitrary
+                       Speculative Code Execution with Return Instructions)
+                       vulnerability.
+
+                       off          - no mitigation
+                       auto         - automatically select a migitation
+                       auto,nosmt   - automatically select a mitigation,
+                                      disabling SMT if necessary for
+                                      the full mitigation (only on Zen1
+                                      and older without STIBP).
+                       ibpb         - mitigate short speculation windows on
+                                      basic block boundaries too. Safe, highest
+                                      perf impact.
+                       unret        - force enable untrained return thunks,
+                                      only effective on AMD f15h-f17h
+                                      based systems.
+                       unret,nosmt  - like unret, will disable SMT when STIBP
+                                      is not available.
+
+                       Selecting 'auto' will choose a mitigation method at run
+                       time according to the CPU.
+
+                       Not specifying this option is equivalent to retbleed=auto.
+
        rfkill.default_state=
                0       "airplane mode".  All wifi, bluetooth, wimax, gps, fm,
                        etc. communication is blocked by default.
                        eibrs             - enhanced IBRS
                        eibrs,retpoline   - enhanced IBRS + Retpolines
                        eibrs,lfence      - enhanced IBRS + LFENCE
+                       ibrs              - use IBRS to protect kernel
 
                        Not specifying this option is equivalent to
                        spectre_v2=auto.
                        expediting.  Set to zero to disable automatic
                        expediting.
 
+       srcutree.srcu_max_nodelay [KNL]
+                       Specifies the number of no-delay instances
+                       per jiffy for which the SRCU grace period
+                       worker thread will be rescheduled with zero
+                       delay. Beyond this limit, worker thread will
+                       be rescheduled with a sleep delay of one jiffy.
+
+       srcutree.srcu_max_nodelay_phase [KNL]
+                       Specifies the per-grace-period phase, number of
+                       non-sleeping polls of readers. Beyond this limit,
+                       grace period worker thread will be rescheduled
+                       with a sleep delay of one jiffy, between each
+                       rescan of the readers, for a grace period phase.
+
+       srcutree.srcu_retry_check_delay [KNL]
+                       Specifies number of microseconds of non-sleeping
+                       delay between each non-sleeping poll of readers.
+
        srcutree.small_contention_lim [KNL]
                        Specifies the number of update-side contention
                        events per jiffy will be tolerated before
index d6b3f94b9f1fb5959f042fe28fbf16068bd67261..0793c400d4b0594af47b5e56f07387ac123e2692 100644 (file)
@@ -223,7 +223,7 @@ Module Loading
 Inter Module support
 --------------------
 
-Refer to the file kernel/module.c for more information.
+Refer to the files in kernel/module/ for more information.
 
 Hardware Interfaces
 ===================
index 5ad9e0abe42cf3debc2bf88f407c5aa27d9bf410..12e4aecdae94522c30929c427410505bef6f3c4b 100644 (file)
@@ -51,8 +51,8 @@ namespace ``USB_STORAGE``, use::
 The corresponding ksymtab entry struct ``kernel_symbol`` will have the member
 ``namespace`` set accordingly. A symbol that is exported without a namespace will
 refer to ``NULL``. There is no default namespace if none is defined. ``modpost``
-and kernel/module.c make use the namespace at build time or module load time,
-respectively.
+and kernel/module/main.c make use the namespace at build time or module load
+time, respectively.
 
 2.2 Using the DEFAULT_SYMBOL_NAMESPACE define
 =============================================
diff --git a/Documentation/devicetree/bindings/devfreq/exynos-bus.txt b/Documentation/devicetree/bindings/devfreq/exynos-bus.txt
deleted file mode 100644 (file)
index bcaa2c0..0000000
+++ /dev/null
@@ -1,488 +0,0 @@
-* Generic Exynos Bus frequency device
-
-The Samsung Exynos SoC has many buses for data transfer between DRAM
-and sub-blocks in SoC. Most Exynos SoCs share the common architecture
-for buses. Generally, each bus of Exynos SoC includes a source clock
-and a power line, which are able to change the clock frequency
-of the bus in runtime. To monitor the usage of each bus in runtime,
-the driver uses the PPMU (Platform Performance Monitoring Unit), which
-is able to measure the current load of sub-blocks.
-
-The Exynos SoC includes the various sub-blocks which have the each AXI bus.
-The each AXI bus has the owned source clock but, has not the only owned
-power line. The power line might be shared among one more sub-blocks.
-So, we can divide into two type of device as the role of each sub-block.
-There are two type of bus devices as following:
-- parent bus device
-- passive bus device
-
-Basically, parent and passive bus device share the same power line.
-The parent bus device can only change the voltage of shared power line
-and the rest bus devices (passive bus device) depend on the decision of
-the parent bus device. If there are three blocks which share the VDD_xxx
-power line, Only one block should be parent device and then the rest blocks
-should depend on the parent device as passive device.
-
-       VDD_xxx |--- A block (parent)
-               |--- B block (passive)
-               |--- C block (passive)
-
-There are a little different composition among Exynos SoC because each Exynos
-SoC has different sub-blocks. Therefore, such difference should be specified
-in devicetree file instead of each device driver. In result, this driver
-is able to support the bus frequency for all Exynos SoCs.
-
-Required properties for all bus devices:
-- compatible: Should be "samsung,exynos-bus".
-- clock-names : the name of clock used by the bus, "bus".
-- clocks : phandles for clock specified in "clock-names" property.
-- operating-points-v2: the OPP table including frequency/voltage information
-  to support DVFS (Dynamic Voltage/Frequency Scaling) feature.
-
-Required properties only for parent bus device:
-- vdd-supply: the regulator to provide the buses with the voltage.
-- devfreq-events: the devfreq-event device to monitor the current utilization
-  of buses.
-
-Required properties only for passive bus device:
-- devfreq: the parent bus device.
-
-Optional properties only for parent bus device:
-- exynos,saturation-ratio: the percentage value which is used to calibrate
-                       the performance count against total cycle count.
-
-Optional properties for the interconnect functionality (QoS frequency
-constraints):
-- #interconnect-cells: should be 0.
-- interconnects: as documented in ../interconnect.txt, describes a path at the
-  higher level interconnects used by this interconnect provider.
-  If this interconnect provider is directly linked to a top level interconnect
-  provider the property contains only one phandle. The provider extends
-  the interconnect graph by linking its node to a node registered by provider
-  pointed to by first phandle in the 'interconnects' property.
-
-- samsung,data-clock-ratio: ratio of the data throughput in B/s to minimum data
-   clock frequency in Hz, default value is 8 when this property is missing.
-
-Detailed correlation between sub-blocks and power line according to Exynos SoC:
-- In case of Exynos3250, there are two power line as following:
-       VDD_MIF |--- DMC
-
-       VDD_INT |--- LEFTBUS (parent device)
-               |--- PERIL
-               |--- MFC
-               |--- G3D
-               |--- RIGHTBUS
-               |--- PERIR
-               |--- FSYS
-               |--- LCD0
-               |--- PERIR
-               |--- ISP
-               |--- CAM
-
-- In case of Exynos4210, there is one power line as following:
-       VDD_INT |--- DMC (parent device)
-               |--- LEFTBUS
-               |--- PERIL
-               |--- MFC(L)
-               |--- G3D
-               |--- TV
-               |--- LCD0
-               |--- RIGHTBUS
-               |--- PERIR
-               |--- MFC(R)
-               |--- CAM
-               |--- FSYS
-               |--- GPS
-               |--- LCD0
-               |--- LCD1
-
-- In case of Exynos4x12, there are two power line as following:
-       VDD_MIF |--- DMC
-
-       VDD_INT |--- LEFTBUS (parent device)
-               |--- PERIL
-               |--- MFC(L)
-               |--- G3D
-               |--- TV
-               |--- IMAGE
-               |--- RIGHTBUS
-               |--- PERIR
-               |--- MFC(R)
-               |--- CAM
-               |--- FSYS
-               |--- GPS
-               |--- LCD0
-               |--- ISP
-
-- In case of Exynos5422, there are two power line as following:
-       VDD_MIF |--- DREX 0 (parent device, DRAM EXpress controller)
-               |--- DREX 1
-
-       VDD_INT |--- NoC_Core (parent device)
-               |--- G2D
-               |--- G3D
-               |--- DISP1
-               |--- NoC_WCORE
-               |--- GSCL
-               |--- MSCL
-               |--- ISP
-               |--- MFC
-               |--- GEN
-               |--- PERIS
-               |--- PERIC
-               |--- FSYS
-               |--- FSYS2
-
-- In case of Exynos5433, there is VDD_INT power line as following:
-       VDD_INT |--- G2D (parent device)
-               |--- MSCL
-               |--- GSCL
-               |--- JPEG
-               |--- MFC
-               |--- HEVC
-               |--- BUS0
-               |--- BUS1
-               |--- BUS2
-               |--- PERIS (Fixed clock rate)
-               |--- PERIC (Fixed clock rate)
-               |--- FSYS  (Fixed clock rate)
-
-Example 1:
-       Show the AXI buses of Exynos3250 SoC. Exynos3250 divides the buses to
-       power line (regulator). The MIF (Memory Interface) AXI bus is used to
-       transfer data between DRAM and CPU and uses the VDD_MIF regulator.
-
-       - MIF (Memory Interface) block
-       : VDD_MIF |--- DMC (Dynamic Memory Controller)
-
-       - INT (Internal) block
-       : VDD_INT |--- LEFTBUS (parent device)
-                 |--- PERIL
-                 |--- MFC
-                 |--- G3D
-                 |--- RIGHTBUS
-                 |--- FSYS
-                 |--- LCD0
-                 |--- PERIR
-                 |--- ISP
-                 |--- CAM
-
-       - MIF bus's frequency/voltage table
-       -----------------------
-       |Lv| Freq   | Voltage |
-       -----------------------
-       |L1| 50000  |800000   |
-       |L2| 100000 |800000   |
-       |L3| 134000 |800000   |
-       |L4| 200000 |825000   |
-       |L5| 400000 |875000   |
-       -----------------------
-
-       - INT bus's frequency/voltage table
-       ----------------------------------------------------------
-       |Block|LEFTBUS|RIGHTBUS|MCUISP |ISP    |PERIL  ||VDD_INT |
-       | name|       |LCD0    |       |       |       ||        |
-       |     |       |FSYS    |       |       |       ||        |
-       |     |       |MFC     |       |       |       ||        |
-       ----------------------------------------------------------
-       |Mode |*parent|passive |passive|passive|passive||        |
-       ----------------------------------------------------------
-       |Lv   |Frequency                               ||Voltage |
-       ----------------------------------------------------------
-       |L1   |50000  |50000   |50000  |50000  |50000  ||900000  |
-       |L2   |80000  |80000   |80000  |80000  |80000  ||900000  |
-       |L3   |100000 |100000  |100000 |100000 |100000 ||1000000 |
-       |L4   |134000 |134000  |200000 |200000 |       ||1000000 |
-       |L5   |200000 |200000  |400000 |300000 |       ||1000000 |
-       ----------------------------------------------------------
-
-Example 2:
-       The bus of DMC (Dynamic Memory Controller) block in exynos3250.dtsi
-       is listed below:
-
-       bus_dmc: bus_dmc {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu_dmc CLK_DIV_DMC>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_dmc_opp_table>;
-               status = "disabled";
-       };
-
-       bus_dmc_opp_table: opp_table1 {
-               compatible = "operating-points-v2";
-               opp-shared;
-
-               opp-50000000 {
-                       opp-hz = /bits/ 64 <50000000>;
-                       opp-microvolt = <800000>;
-               };
-               opp-100000000 {
-                       opp-hz = /bits/ 64 <100000000>;
-                       opp-microvolt = <800000>;
-               };
-               opp-134000000 {
-                       opp-hz = /bits/ 64 <134000000>;
-                       opp-microvolt = <800000>;
-               };
-               opp-200000000 {
-                       opp-hz = /bits/ 64 <200000000>;
-                       opp-microvolt = <825000>;
-               };
-               opp-400000000 {
-                       opp-hz = /bits/ 64 <400000000>;
-                       opp-microvolt = <875000>;
-               };
-       };
-
-       bus_leftbus: bus_leftbus {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu CLK_DIV_GDL>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_leftbus_opp_table>;
-               status = "disabled";
-       };
-
-       bus_rightbus: bus_rightbus {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu CLK_DIV_GDR>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_leftbus_opp_table>;
-               status = "disabled";
-       };
-
-       bus_lcd0: bus_lcd0 {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu CLK_DIV_ACLK_160>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_leftbus_opp_table>;
-               status = "disabled";
-       };
-
-       bus_fsys: bus_fsys {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu CLK_DIV_ACLK_200>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_leftbus_opp_table>;
-               status = "disabled";
-       };
-
-       bus_mcuisp: bus_mcuisp {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu CLK_DIV_ACLK_400_MCUISP>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_mcuisp_opp_table>;
-               status = "disabled";
-       };
-
-       bus_isp: bus_isp {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu CLK_DIV_ACLK_266>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_isp_opp_table>;
-               status = "disabled";
-       };
-
-       bus_peril: bus_peril {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu CLK_DIV_ACLK_100>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_peril_opp_table>;
-               status = "disabled";
-       };
-
-       bus_mfc: bus_mfc {
-               compatible = "samsung,exynos-bus";
-               clocks = <&cmu CLK_SCLK_MFC>;
-               clock-names = "bus";
-               operating-points-v2 = <&bus_leftbus_opp_table>;
-               status = "disabled";
-       };
-
-       bus_leftbus_opp_table: opp_table1 {
-               compatible = "operating-points-v2";
-               opp-shared;
-
-               opp-50000000 {
-                       opp-hz = /bits/ 64 <50000000>;
-                       opp-microvolt = <900000>;
-               };
-               opp-80000000 {
-                       opp-hz = /bits/ 64 <80000000>;
-                       opp-microvolt = <900000>;
-               };
-               opp-100000000 {
-                       opp-hz = /bits/ 64 <100000000>;
-                       opp-microvolt = <1000000>;
-               };
-               opp-134000000 {
-                       opp-hz = /bits/ 64 <134000000>;
-                       opp-microvolt = <1000000>;
-               };
-               opp-200000000 {
-                       opp-hz = /bits/ 64 <200000000>;
-                       opp-microvolt = <1000000>;
-               };
-       };
-
-       bus_mcuisp_opp_table: opp_table2 {
-               compatible = "operating-points-v2";
-               opp-shared;
-
-               opp-50000000 {
-                       opp-hz = /bits/ 64 <50000000>;
-               };
-               opp-80000000 {
-                       opp-hz = /bits/ 64 <80000000>;
-               };
-               opp-100000000 {
-                       opp-hz = /bits/ 64 <100000000>;
-               };
-               opp-200000000 {
-                       opp-hz = /bits/ 64 <200000000>;
-               };
-               opp-400000000 {
-                       opp-hz = /bits/ 64 <400000000>;
-               };
-       };
-
-       bus_isp_opp_table: opp_table3 {
-               compatible = "operating-points-v2";
-               opp-shared;
-
-               opp-50000000 {
-                       opp-hz = /bits/ 64 <50000000>;
-               };
-               opp-80000000 {
-                       opp-hz = /bits/ 64 <80000000>;
-               };
-               opp-100000000 {
-                       opp-hz = /bits/ 64 <100000000>;
-               };
-               opp-200000000 {
-                       opp-hz = /bits/ 64 <200000000>;
-               };
-               opp-300000000 {
-                       opp-hz = /bits/ 64 <300000000>;
-               };
-       };
-
-       bus_peril_opp_table: opp_table4 {
-               compatible = "operating-points-v2";
-               opp-shared;
-
-               opp-50000000 {
-                       opp-hz = /bits/ 64 <50000000>;
-               };
-               opp-80000000 {
-                       opp-hz = /bits/ 64 <80000000>;
-               };
-               opp-100000000 {
-                       opp-hz = /bits/ 64 <100000000>;
-               };
-       };
-
-
-       Usage case to handle the frequency and voltage of bus on runtime
-       in exynos3250-rinato.dts is listed below:
-
-       &bus_dmc {
-               devfreq-events = <&ppmu_dmc0_3>, <&ppmu_dmc1_3>;
-               vdd-supply = <&buck1_reg>;      /* VDD_MIF */
-               status = "okay";
-       };
-
-       &bus_leftbus {
-               devfreq-events = <&ppmu_leftbus_3>, <&ppmu_rightbus_3>;
-               vdd-supply = <&buck3_reg>;
-               status = "okay";
-       };
-
-       &bus_rightbus {
-               devfreq = <&bus_leftbus>;
-               status = "okay";
-       };
-
-       &bus_lcd0 {
-               devfreq = <&bus_leftbus>;
-               status = "okay";
-       };
-
-       &bus_fsys {
-               devfreq = <&bus_leftbus>;
-               status = "okay";
-       };
-
-       &bus_mcuisp {
-               devfreq = <&bus_leftbus>;
-               status = "okay";
-       };
-
-       &bus_isp {
-               devfreq = <&bus_leftbus>;
-               status = "okay";
-       };
-
-       &bus_peril {
-               devfreq = <&bus_leftbus>;
-               status = "okay";
-       };
-
-       &bus_mfc {
-               devfreq = <&bus_leftbus>;
-               status = "okay";
-       };
-
-Example 3:
-       An interconnect path "bus_display -- bus_leftbus -- bus_dmc" on
-       Exynos4412 SoC with video mixer as an interconnect consumer device.
-
-       soc {
-               bus_dmc: bus_dmc {
-                       compatible = "samsung,exynos-bus";
-                       clocks = <&clock CLK_DIV_DMC>;
-                       clock-names = "bus";
-                       operating-points-v2 = <&bus_dmc_opp_table>;
-                       samsung,data-clock-ratio = <4>;
-                       #interconnect-cells = <0>;
-               };
-
-               bus_leftbus: bus_leftbus {
-                       compatible = "samsung,exynos-bus";
-                       clocks = <&clock CLK_DIV_GDL>;
-                       clock-names = "bus";
-                       operating-points-v2 = <&bus_leftbus_opp_table>;
-                       #interconnect-cells = <0>;
-                       interconnects = <&bus_dmc>;
-               };
-
-               bus_display: bus_display {
-                       compatible = "samsung,exynos-bus";
-                       clocks = <&clock CLK_ACLK160>;
-                       clock-names = "bus";
-                       operating-points-v2 = <&bus_display_opp_table>;
-                       #interconnect-cells = <0>;
-                       interconnects = <&bus_leftbus &bus_dmc>;
-               };
-
-               bus_dmc_opp_table: opp_table1 {
-                       compatible = "operating-points-v2";
-                       /* ... */
-               }
-
-               bus_leftbus_opp_table: opp_table3 {
-                       compatible = "operating-points-v2";
-                       /* ... */
-               };
-
-               bus_display_opp_table: opp_table4 {
-                       compatible = "operating-points-v2";
-                       /* .. */
-               };
-
-               &mixer {
-                       compatible = "samsung,exynos4212-mixer";
-                       interconnects = <&bus_display &bus_dmc>;
-                       /* ... */
-               };
-       };
index c388ae5da1e429303944429f790896d1634adf1d..c9c346e6228e9a9bdf9e9ae835f088d136182ac2 100644 (file)
@@ -94,6 +94,7 @@ if:
           - allwinner,sun8i-a83t-display-engine
           - allwinner,sun8i-r40-display-engine
           - allwinner,sun9i-a80-display-engine
+          - allwinner,sun20i-d1-display-engine
           - allwinner,sun50i-a64-display-engine
 
 then:
index ff0a5c58d78ccd6537d98dc20a9d07effc3636aa..e712444abff17776e9138908560551bedec4dd11 100644 (file)
@@ -67,7 +67,7 @@ if:
 then:
   properties:
     clocks:
-      maxItems: 2
+      minItems: 2
 
   required:
     - clock-names
diff --git a/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml b/Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
new file mode 100644 (file)
index 0000000..449c7c9
--- /dev/null
@@ -0,0 +1,141 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interconnect/mediatek,cci.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Cache Coherent Interconnect (CCI) frequency and voltage scaling
+
+maintainers:
+  - Jia-Wei Chang <jia-wei.chang@mediatek.com>
+  - Johnson Wang <johnson.wang@mediatek.com>
+
+description: |
+  MediaTek Cache Coherent Interconnect (CCI) is a hardware engine used by
+  MT8183 and MT8186 SoCs to scale the frequency and adjust the voltage in
+  hardware. It can also optimize the voltage to reduce the power consumption.
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt8183-cci
+      - mediatek,mt8186-cci
+
+  clocks:
+    items:
+      - description:
+          The multiplexer for clock input of the bus.
+      - description:
+          A parent of "bus" clock which is used as an intermediate clock source
+          when the original clock source (PLL) is under transition and not
+          stable yet.
+
+  clock-names:
+    items:
+      - const: cci
+      - const: intermediate
+
+  operating-points-v2: true
+  opp-table: true
+
+  proc-supply:
+    description:
+      Phandle of the regulator for CCI that provides the supply voltage.
+
+  sram-supply:
+    description:
+      Phandle of the regulator for sram of CCI that provides the supply
+      voltage. When it is present, the implementation needs to do
+      "voltage tracking" to step by step scale up/down Vproc and Vsram to fit
+      SoC specific needs. When absent, the voltage scaling flow is handled by
+      hardware, hence no software "voltage tracking" is needed.
+
+required:
+  - compatible
+  - clocks
+  - clock-names
+  - operating-points-v2
+  - proc-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/mt8183-clk.h>
+    cci: cci {
+        compatible = "mediatek,mt8183-cci";
+        clocks = <&mcucfg CLK_MCU_BUS_SEL>,
+                 <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
+        clock-names = "cci", "intermediate";
+        operating-points-v2 = <&cci_opp>;
+        proc-supply = <&mt6358_vproc12_reg>;
+    };
+
+    cci_opp: opp-table-cci {
+        compatible = "operating-points-v2";
+        opp-shared;
+        opp2_00: opp-273000000 {
+            opp-hz = /bits/ 64 <273000000>;
+            opp-microvolt = <650000>;
+        };
+        opp2_01: opp-338000000 {
+            opp-hz = /bits/ 64 <338000000>;
+            opp-microvolt = <687500>;
+        };
+        opp2_02: opp-403000000 {
+            opp-hz = /bits/ 64 <403000000>;
+            opp-microvolt = <718750>;
+        };
+        opp2_03: opp-463000000 {
+            opp-hz = /bits/ 64 <463000000>;
+            opp-microvolt = <756250>;
+        };
+        opp2_04: opp-546000000 {
+            opp-hz = /bits/ 64 <546000000>;
+            opp-microvolt = <800000>;
+        };
+        opp2_05: opp-624000000 {
+            opp-hz = /bits/ 64 <624000000>;
+            opp-microvolt = <818750>;
+        };
+        opp2_06: opp-689000000 {
+            opp-hz = /bits/ 64 <689000000>;
+            opp-microvolt = <850000>;
+        };
+        opp2_07: opp-767000000 {
+            opp-hz = /bits/ 64 <767000000>;
+            opp-microvolt = <868750>;
+        };
+        opp2_08: opp-845000000 {
+            opp-hz = /bits/ 64 <845000000>;
+            opp-microvolt = <893750>;
+        };
+        opp2_09: opp-871000000 {
+            opp-hz = /bits/ 64 <871000000>;
+            opp-microvolt = <906250>;
+        };
+        opp2_10: opp-923000000 {
+            opp-hz = /bits/ 64 <923000000>;
+            opp-microvolt = <931250>;
+        };
+        opp2_11: opp-962000000 {
+            opp-hz = /bits/ 64 <962000000>;
+            opp-microvolt = <943750>;
+        };
+        opp2_12: opp-1027000000 {
+            opp-hz = /bits/ 64 <1027000000>;
+            opp-microvolt = <975000>;
+        };
+        opp2_13: opp-1092000000 {
+            opp-hz = /bits/ 64 <1092000000>;
+            opp-microvolt = <1000000>;
+        };
+        opp2_14: opp-1144000000 {
+            opp-hz = /bits/ 64 <1144000000>;
+            opp-microvolt = <1025000>;
+        };
+        opp2_15: opp-1196000000 {
+            opp-hz = /bits/ 64 <1196000000>;
+            opp-microvolt = <1050000>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/interconnect/samsung,exynos-bus.yaml b/Documentation/devicetree/bindings/interconnect/samsung,exynos-bus.yaml
new file mode 100644 (file)
index 0000000..ad9ed59
--- /dev/null
@@ -0,0 +1,290 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interconnect/samsung,exynos-bus.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung Exynos SoC Bus and Interconnect
+
+maintainers:
+  - Chanwoo Choi <cw00.choi@samsung.com>
+  - Krzysztof Kozlowski <krzk@kernel.org>
+
+description: |
+  The Samsung Exynos SoC has many buses for data transfer between DRAM and
+  sub-blocks in SoC. Most Exynos SoCs share the common architecture for buses.
+  Generally, each bus of Exynos SoC includes a source clock and a power line,
+  which are able to change the clock frequency of the bus in runtime. To
+  monitor the usage of each bus in runtime, the driver uses the PPMU (Platform
+  Performance Monitoring Unit), which is able to measure the current load of
+  sub-blocks.
+
+  The Exynos SoC includes the various sub-blocks which have the each AXI bus.
+  The each AXI bus has the owned source clock but, has not the only owned power
+  line. The power line might be shared among one more sub-blocks.  So, we can
+  divide into two type of device as the role of each sub-block.  There are two
+  type of bus devices as following::
+   - parent bus device
+   - passive bus device
+
+  Basically, parent and passive bus device share the same power line.  The
+  parent bus device can only change the voltage of shared power line and the
+  rest bus devices (passive bus device) depend on the decision of the parent
+  bus device. If there are three blocks which share the VDD_xxx power line,
+  Only one block should be parent device and then the rest blocks should depend
+  on the parent device as passive device.
+
+    VDD_xxx |--- A block (parent)
+      |--- B block (passive)
+      |--- C block (passive)
+
+  There are a little different composition among Exynos SoC because each Exynos
+  SoC has different sub-blocks. Therefore, such difference should be specified
+  in devicetree file instead of each device driver. In result, this driver is
+  able to support the bus frequency for all Exynos SoCs.
+
+  Detailed correlation between sub-blocks and power line according
+  to Exynos SoC::
+   - In case of Exynos3250, there are two power line as following::
+     VDD_MIF |--- DMC (Dynamic Memory Controller)
+
+     VDD_INT |--- LEFTBUS (parent device)
+       |--- PERIL
+       |--- MFC
+       |--- G3D
+       |--- RIGHTBUS
+       |--- PERIR
+       |--- FSYS
+       |--- LCD0
+       |--- PERIR
+       |--- ISP
+       |--- CAM
+
+     - MIF bus's frequency/voltage table
+       -----------------------
+       |Lv| Freq   | Voltage |
+       -----------------------
+       |L1| 50000  |800000   |
+       |L2| 100000 |800000   |
+       |L3| 134000 |800000   |
+       |L4| 200000 |825000   |
+       |L5| 400000 |875000   |
+       -----------------------
+
+     - INT bus's frequency/voltage table
+       ----------------------------------------------------------
+       |Block|LEFTBUS|RIGHTBUS|MCUISP |ISP    |PERIL  ||VDD_INT |
+       | name|       |LCD0    |       |       |       ||        |
+       |     |       |FSYS    |       |       |       ||        |
+       |     |       |MFC     |       |       |       ||        |
+       ----------------------------------------------------------
+       |Mode |*parent|passive |passive|passive|passive||        |
+       ----------------------------------------------------------
+       |Lv   |Frequency                               ||Voltage |
+       ----------------------------------------------------------
+       |L1   |50000  |50000   |50000  |50000  |50000  ||900000  |
+       |L2   |80000  |80000   |80000  |80000  |80000  ||900000  |
+       |L3   |100000 |100000  |100000 |100000 |100000 ||1000000 |
+       |L4   |134000 |134000  |200000 |200000 |       ||1000000 |
+       |L5   |200000 |200000  |400000 |300000 |       ||1000000 |
+       ----------------------------------------------------------
+
+   - In case of Exynos4210, there is one power line as following::
+     VDD_INT |--- DMC (parent device, Dynamic Memory Controller)
+       |--- LEFTBUS
+       |--- PERIL
+       |--- MFC(L)
+       |--- G3D
+       |--- TV
+       |--- LCD0
+       |--- RIGHTBUS
+       |--- PERIR
+       |--- MFC(R)
+       |--- CAM
+       |--- FSYS
+       |--- GPS
+       |--- LCD0
+       |--- LCD1
+
+   - In case of Exynos4x12, there are two power line as following::
+     VDD_MIF |--- DMC (Dynamic Memory Controller)
+
+     VDD_INT |--- LEFTBUS (parent device)
+       |--- PERIL
+       |--- MFC(L)
+       |--- G3D
+       |--- TV
+       |--- IMAGE
+       |--- RIGHTBUS
+       |--- PERIR
+       |--- MFC(R)
+       |--- CAM
+       |--- FSYS
+       |--- GPS
+       |--- LCD0
+       |--- ISP
+
+   - In case of Exynos5422, there are two power line as following::
+     VDD_MIF |--- DREX 0 (parent device, DRAM EXpress controller)
+             |--- DREX 1
+
+     VDD_INT |--- NoC_Core (parent device)
+       |--- G2D
+       |--- G3D
+       |--- DISP1
+       |--- NoC_WCORE
+       |--- GSCL
+       |--- MSCL
+       |--- ISP
+       |--- MFC
+       |--- GEN
+       |--- PERIS
+       |--- PERIC
+       |--- FSYS
+       |--- FSYS2
+
+   - In case of Exynos5433, there is VDD_INT power line as following::
+     VDD_INT |--- G2D (parent device)
+       |--- MSCL
+       |--- GSCL
+       |--- JPEG
+       |--- MFC
+       |--- HEVC
+       |--- BUS0
+       |--- BUS1
+       |--- BUS2
+       |--- PERIS (Fixed clock rate)
+       |--- PERIC (Fixed clock rate)
+       |--- FSYS  (Fixed clock rate)
+
+properties:
+  compatible:
+    enum:
+      - samsung,exynos-bus
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: bus
+
+  devfreq:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Parent bus device. Valid and required only for the passive bus devices.
+
+  devfreq-events:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    minItems: 1
+    maxItems: 4
+    description:
+      Devfreq-event device to monitor the current utilization of buses. Valid
+      and required only for the parent bus devices.
+
+  exynos,saturation-ratio:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Percentage value which is used to calibrate the performance count against
+      total cycle count.  Valid only for the parent bus devices.
+
+  '#interconnect-cells':
+    const: 0
+
+  interconnects:
+    minItems: 1
+    maxItems: 2
+
+  operating-points-v2: true
+
+  samsung,data-clock-ratio:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    default: 8
+    description:
+      Ratio of the data throughput in B/s to minimum data clock frequency in
+      Hz.
+
+  vdd-supply:
+    description:
+      Main bus power rail. Valid and required only for the parent bus devices.
+
+required:
+  - compatible
+  - clocks
+  - clock-names
+  - operating-points-v2
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/exynos3250.h>
+
+    bus-dmc {
+        compatible = "samsung,exynos-bus";
+        clocks = <&cmu_dmc CLK_DIV_DMC>;
+        clock-names = "bus";
+        operating-points-v2 = <&bus_dmc_opp_table>;
+        devfreq-events = <&ppmu_dmc0_3>, <&ppmu_dmc1_3>;
+        vdd-supply = <&buck1_reg>;
+    };
+
+    ppmu_dmc0: ppmu@106a0000 {
+        compatible = "samsung,exynos-ppmu";
+        reg = <0x106a0000 0x2000>;
+        events {
+            ppmu_dmc0_3: ppmu-event3-dmc0 {
+                event-name = "ppmu-event3-dmc0";
+            };
+        };
+    };
+
+    bus_leftbus: bus-leftbus {
+        compatible = "samsung,exynos-bus";
+        clocks = <&cmu CLK_DIV_GDL>;
+        clock-names = "bus";
+        operating-points-v2 = <&bus_leftbus_opp_table>;
+        devfreq-events = <&ppmu_leftbus_3>, <&ppmu_rightbus_3>;
+        vdd-supply = <&buck3_reg>;
+    };
+
+    bus-rightbus {
+        compatible = "samsung,exynos-bus";
+        clocks = <&cmu CLK_DIV_GDR>;
+        clock-names = "bus";
+        operating-points-v2 = <&bus_leftbus_opp_table>;
+        devfreq = <&bus_leftbus>;
+    };
+
+  - |
+    dmc: bus-dmc {
+        compatible = "samsung,exynos-bus";
+        clocks = <&clock CLK_DIV_DMC>;
+        clock-names = "bus";
+        operating-points-v2 = <&bus_dmc_opp_table>;
+        samsung,data-clock-ratio = <4>;
+        #interconnect-cells = <0>;
+        devfreq-events = <&ppmu_dmc0_3>, <&ppmu_dmc1_3>;
+        vdd-supply = <&buck1_reg>;
+    };
+
+    leftbus: bus-leftbus {
+        compatible = "samsung,exynos-bus";
+        clocks = <&clock CLK_DIV_GDL>;
+        clock-names = "bus";
+        operating-points-v2 = <&bus_leftbus_opp_table>;
+        interconnects = <&dmc>;
+        #interconnect-cells = <0>;
+        devfreq-events = <&ppmu_leftbus_3>, <&ppmu_rightbus_3>;
+        vdd-supply = <&buck3_reg>;
+    };
+
+    display: bus-display {
+        compatible = "samsung,exynos-bus";
+        clocks = <&clock CLK_DIV_ACLK_266>;
+        clock-names = "bus";
+        operating-points-v2 = <&bus_display_opp_table>;
+        interconnects = <&leftbus &dmc>;
+        #interconnect-cells = <0>;
+        devfreq = <&leftbus>;
+    };
index 8cd0adbf7021f88fd62243e41f92a6aa9b064cbb..7029cb1f38ffb8a79f9dece86cf35b97bc2687b3 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Qualcomm Atheros ath9k wireless devices Generic Binding
 
 maintainers:
-  - Kalle Valo <kvalo@codeaurora.org>
+  - Toke Høiland-Jørgensen <toke@toke.dk>
 
 description: |
   This node provides properties for configuring the ath9k wireless device.
index 8c01fdba134b922c4e0dea54f32135b1090c1d38..a677b056f11206f8140972a6f9ab02cd92422399 100644 (file)
@@ -9,7 +9,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Qualcomm Technologies ath11k wireless devices Generic Binding
 
 maintainers:
-  - Kalle Valo <kvalo@codeaurora.org>
+  - Kalle Valo <kvalo@kernel.org>
 
 description: |
   These are dt entries for Qualcomm Technologies, Inc. IEEE 802.11ax
index e9a533080b32d530b8a5cf7d31a7005526520f20..ef18a572a1ff385d7ca91726c2e5f2972d1bfb70 100644 (file)
@@ -25,12 +25,12 @@ properties:
       - qcom,sc7280-lpass-cpu
 
   reg:
-    minItems: 2
+    minItems: 1
     maxItems: 6
     description: LPAIF core registers
 
   reg-names:
-    minItems: 2
+    minItems: 1
     maxItems: 6
 
   clocks:
@@ -42,12 +42,12 @@ properties:
     maxItems: 10
 
   interrupts:
-    minItems: 2
+    minItems: 1
     maxItems: 4
     description: LPAIF DMA buffer interrupt
 
   interrupt-names:
-    minItems: 2
+    minItems: 1
     maxItems: 4
 
   qcom,adsp:
index 4d19b19bcc0867a834f81498f73727eac2030508..73a4176144b3b80aff4db87bd4ab3bd8e96c35c4 100644 (file)
@@ -301,7 +301,7 @@ through which it can issue requests and negotiate::
                void (*issue_read)(struct netfs_io_subrequest *subreq);
                bool (*is_still_valid)(struct netfs_io_request *rreq);
                int (*check_write_begin)(struct file *file, loff_t pos, unsigned len,
-                                        struct folio *folio, void **_fsdata);
+                                        struct folio **foliop, void **_fsdata);
                void (*done)(struct netfs_io_request *rreq);
        };
 
@@ -381,8 +381,10 @@ The operations are as follows:
    allocated/grabbed the folio to be modified to allow the filesystem to flush
    conflicting state before allowing it to be modified.
 
-   It should return 0 if everything is now fine, -EAGAIN if the folio should be
-   regrabbed and any other error code to abort the operation.
+   It may unlock and discard the folio it was given and set the caller's folio
+   pointer to NULL.  It should return 0 if everything is now fine (``*foliop``
+   left set) or the op should be retried (``*foliop`` cleared) and any other
+   error code to abort the operation.
 
  * ``done``
 
index 7da6c30ed596ad72a446b5dc81b52b305b77b069..316cfd8b1891e53ddf82f9352779484b42cdc0a8 100644 (file)
@@ -466,6 +466,10 @@ overlay filesystem and the value of st_ino for filesystem objects may not be
 persistent and could change even while the overlay filesystem is mounted, as
 summarized in the `Inode properties`_ table above.
 
+4) "idmapped mounts"
+When the upper or lower layers are idmapped mounts overlayfs will be mounted
+without support for POSIX Access Control Lists (ACLs). This limitation will
+eventually be lifted.
 
 Changes to underlying filesystems
 ---------------------------------
index dbe9b400e39fe041bd36ce038a8ed7fe58e43650..7347638895a00d475348735e503b9d0caa546def 100644 (file)
@@ -210,11 +210,11 @@ module->symtab.
 =====================================
 Normally, a stripped down copy of a module's symbol table (containing only
 "core" symbols) is made available through module->symtab (See layout_symtab()
-in kernel/module.c). For livepatch modules, the symbol table copied into memory
-on module load must be exactly the same as the symbol table produced when the
-patch module was compiled. This is because the relocations in each livepatch
-relocation section refer to their respective symbols with their symbol indices,
-and the original symbol indices (and thus the symtab ordering) must be
+in kernel/module/kallsyms.c). For livepatch modules, the symbol table copied
+into memory on module load must be exactly the same as the symbol table produced
+when the patch module was compiled. This is because the relocations in each
+livepatch relocation section refer to their respective symbols with their symbol
+indices, and the original symbol indices (and thus the symtab ordering) must be
 preserved in order for apply_relocate_add() to find the right symbol.
 
 For example, take this particular rela from a livepatch module:::
index ed7fa76e7a404342f968c6123258b98d80532aec..d742ba6bd21195de7ba1e04aab6cc915f8f333cc 100644 (file)
@@ -503,26 +503,108 @@ per-port PHY specific details: interface connection, MDIO bus location, etc.
 Driver development
 ==================
 
-DSA switch drivers need to implement a dsa_switch_ops structure which will
+DSA switch drivers need to implement a ``dsa_switch_ops`` structure which will
 contain the various members described below.
 
-``register_switch_driver()`` registers this dsa_switch_ops in its internal list
-of drivers to probe for. ``unregister_switch_driver()`` does the exact opposite.
+Probing, registration and device lifetime
+-----------------------------------------
 
-Unless requested differently by setting the priv_size member accordingly, DSA
-does not allocate any driver private context space.
+DSA switches are regular ``device`` structures on buses (be they platform, SPI,
+I2C, MDIO or otherwise). The DSA framework is not involved in their probing
+with the device core.
+
+Switch registration from the perspective of a driver means passing a valid
+``struct dsa_switch`` pointer to ``dsa_register_switch()``, usually from the
+switch driver's probing function. The following members must be valid in the
+provided structure:
+
+- ``ds->dev``: will be used to parse the switch's OF node or platform data.
+
+- ``ds->num_ports``: will be used to create the port list for this switch, and
+  to validate the port indices provided in the OF node.
+
+- ``ds->ops``: a pointer to the ``dsa_switch_ops`` structure holding the DSA
+  method implementations.
+
+- ``ds->priv``: backpointer to a driver-private data structure which can be
+  retrieved in all further DSA method callbacks.
+
+In addition, the following flags in the ``dsa_switch`` structure may optionally
+be configured to obtain driver-specific behavior from the DSA core. Their
+behavior when set is documented through comments in ``include/net/dsa.h``.
+
+- ``ds->vlan_filtering_is_global``
+
+- ``ds->needs_standalone_vlan_filtering``
+
+- ``ds->configure_vlan_while_not_filtering``
+
+- ``ds->untag_bridge_pvid``
+
+- ``ds->assisted_learning_on_cpu_port``
+
+- ``ds->mtu_enforcement_ingress``
+
+- ``ds->fdb_isolation``
+
+Internally, DSA keeps an array of switch trees (group of switches) global to
+the kernel, and attaches a ``dsa_switch`` structure to a tree on registration.
+The tree ID to which the switch is attached is determined by the first u32
+number of the ``dsa,member`` property of the switch's OF node (0 if missing).
+The switch ID within the tree is determined by the second u32 number of the
+same OF property (0 if missing). Registering multiple switches with the same
+switch ID and tree ID is illegal and will cause an error. Using platform data,
+a single switch and a single switch tree is permitted.
+
+In case of a tree with multiple switches, probing takes place asymmetrically.
+The first N-1 callers of ``dsa_register_switch()`` only add their ports to the
+port list of the tree (``dst->ports``), each port having a backpointer to its
+associated switch (``dp->ds``). Then, these switches exit their
+``dsa_register_switch()`` call early, because ``dsa_tree_setup_routing_table()``
+has determined that the tree is not yet complete (not all ports referenced by
+DSA links are present in the tree's port list). The tree becomes complete when
+the last switch calls ``dsa_register_switch()``, and this triggers the effective
+continuation of initialization (including the call to ``ds->ops->setup()``) for
+all switches within that tree, all as part of the calling context of the last
+switch's probe function.
+
+The opposite of registration takes place when calling ``dsa_unregister_switch()``,
+which removes a switch's ports from the port list of the tree. The entire tree
+is torn down when the first switch unregisters.
+
+It is mandatory for DSA switch drivers to implement the ``shutdown()`` callback
+of their respective bus, and call ``dsa_switch_shutdown()`` from it (a minimal
+version of the full teardown performed by ``dsa_unregister_switch()``).
+The reason is that DSA keeps a reference on the master net device, and if the
+driver for the master device decides to unbind on shutdown, DSA's reference
+will block that operation from finalizing.
+
+Either ``dsa_switch_shutdown()`` or ``dsa_unregister_switch()`` must be called,
+but not both, and the device driver model permits the bus' ``remove()`` method
+to be called even if ``shutdown()`` was already called. Therefore, drivers are
+expected to implement a mutual exclusion method between ``remove()`` and
+``shutdown()`` by setting their drvdata to NULL after any of these has run, and
+checking whether the drvdata is NULL before proceeding to take any action.
+
+After ``dsa_switch_shutdown()`` or ``dsa_unregister_switch()`` was called, no
+further callbacks via the provided ``dsa_switch_ops`` may take place, and the
+driver may free the data structures associated with the ``dsa_switch``.
 
 Switch configuration
 --------------------
 
-- ``tag_protocol``: this is to indicate what kind of tagging protocol is supported,
-  should be a valid value from the ``dsa_tag_protocol`` enum
+- ``get_tag_protocol``: this is to indicate what kind of tagging protocol is
+  supported, should be a valid value from the ``dsa_tag_protocol`` enum.
+  The returned information does not have to be static; the driver is passed the
+  CPU port number, as well as the tagging protocol of a possibly stacked
+  upstream switch, in case there are hardware limitations in terms of supported
+  tag formats.
 
-- ``probe``: probe routine which will be invoked by the DSA platform device upon
-  registration to test for the presence/absence of a switch device. For MDIO
-  devices, it is recommended to issue a read towards internal registers using
-  the switch pseudo-PHY and return whether this is a supported device. For other
-  buses, return a non-NULL string
+- ``change_tag_protocol``: when the default tagging protocol has compatibility
+  problems with the master or other issues, the driver may support changing it
+  at runtime, either through a device tree property or through sysfs. In that
+  case, further calls to ``get_tag_protocol`` should report the protocol in
+  current use.
 
 - ``setup``: setup function for the switch, this function is responsible for setting
   up the ``dsa_switch_ops`` private structure with all it needs: register maps,
@@ -535,7 +617,17 @@ Switch configuration
   fully configured and ready to serve any kind of request. It is recommended
   to issue a software reset of the switch during this setup function in order to
   avoid relying on what a previous software agent such as a bootloader/firmware
-  may have previously configured.
+  may have previously configured. The method responsible for undoing any
+  applicable allocations or operations done here is ``teardown``.
+
+- ``port_setup`` and ``port_teardown``: methods for initialization and
+  destruction of per-port data structures. It is mandatory for some operations
+  such as registering and unregistering devlink port regions to be done from
+  these methods, otherwise they are optional. A port will be torn down only if
+  it has been previously set up. It is possible for a port to be set up during
+  probing only to be torn down immediately afterwards, for example in case its
+  PHY cannot be found. In this case, probing of the DSA switch continues
+  without that particular port.
 
 PHY devices and link management
 -------------------------------
@@ -635,26 +727,198 @@ Power management
   ``BR_STATE_DISABLED`` and propagating changes to the hardware if this port is
   disabled while being a bridge member
 
+Address databases
+-----------------
+
+Switching hardware is expected to have a table for FDB entries, however not all
+of them are active at the same time. An address database is the subset (partition)
+of FDB entries that is active (can be matched by address learning on RX, or FDB
+lookup on TX) depending on the state of the port. An address database may
+occasionally be called "FID" (Filtering ID) in this document, although the
+underlying implementation may choose whatever is available to the hardware.
+
+For example, all ports that belong to a VLAN-unaware bridge (which is
+*currently* VLAN-unaware) are expected to learn source addresses in the
+database associated by the driver with that bridge (and not with other
+VLAN-unaware bridges). During forwarding and FDB lookup, a packet received on a
+VLAN-unaware bridge port should be able to find a VLAN-unaware FDB entry having
+the same MAC DA as the packet, which is present on another port member of the
+same bridge. At the same time, the FDB lookup process must be able to not find
+an FDB entry having the same MAC DA as the packet, if that entry points towards
+a port which is a member of a different VLAN-unaware bridge (and is therefore
+associated with a different address database).
+
+Similarly, each VLAN of each offloaded VLAN-aware bridge should have an
+associated address database, which is shared by all ports which are members of
+that VLAN, but not shared by ports belonging to different bridges that are
+members of the same VID.
+
+In this context, a VLAN-unaware database means that all packets are expected to
+match on it irrespective of VLAN ID (only MAC address lookup), whereas a
+VLAN-aware database means that packets are supposed to match based on the VLAN
+ID from the classified 802.1Q header (or the pvid if untagged).
+
+At the bridge layer, VLAN-unaware FDB entries have the special VID value of 0,
+whereas VLAN-aware FDB entries have non-zero VID values. Note that a
+VLAN-unaware bridge may have VLAN-aware (non-zero VID) FDB entries, and a
+VLAN-aware bridge may have VLAN-unaware FDB entries. As in hardware, the
+software bridge keeps separate address databases, and offloads to hardware the
+FDB entries belonging to these databases, through switchdev, asynchronously
+relative to the moment when the databases become active or inactive.
+
+When a user port operates in standalone mode, its driver should configure it to
+use a separate database called a port private database. This is different from
+the databases described above, and should impede operation as standalone port
+(packet in, packet out to the CPU port) as little as possible. For example,
+on ingress, it should not attempt to learn the MAC SA of ingress traffic, since
+learning is a bridging layer service and this is a standalone port, therefore
+it would consume useless space. With no address learning, the port private
+database should be empty in a naive implementation, and in this case, all
+received packets should be trivially flooded to the CPU port.
+
+DSA (cascade) and CPU ports are also called "shared" ports because they service
+multiple address databases, and the database that a packet should be associated
+to is usually embedded in the DSA tag. This means that the CPU port may
+simultaneously transport packets coming from a standalone port (which were
+classified by hardware in one address database), and from a bridge port (which
+were classified to a different address database).
+
+Switch drivers which satisfy certain criteria are able to optimize the naive
+configuration by removing the CPU port from the flooding domain of the switch,
+and just program the hardware with FDB entries pointing towards the CPU port
+for which it is known that software is interested in those MAC addresses.
+Packets which do not match a known FDB entry will not be delivered to the CPU,
+which will save CPU cycles required for creating an skb just to drop it.
+
+DSA is able to perform host address filtering for the following kinds of
+addresses:
+
+- Primary unicast MAC addresses of ports (``dev->dev_addr``). These are
+  associated with the port private database of the respective user port,
+  and the driver is notified to install them through ``port_fdb_add`` towards
+  the CPU port.
+
+- Secondary unicast and multicast MAC addresses of ports (addresses added
+  through ``dev_uc_add()`` and ``dev_mc_add()``). These are also associated
+  with the port private database of the respective user port.
+
+- Local/permanent bridge FDB entries (``BR_FDB_LOCAL``). These are the MAC
+  addresses of the bridge ports, for which packets must be terminated locally
+  and not forwarded. They are associated with the address database for that
+  bridge.
+
+- Static bridge FDB entries installed towards foreign (non-DSA) interfaces
+  present in the same bridge as some DSA switch ports. These are also
+  associated with the address database for that bridge.
+
+- Dynamically learned FDB entries on foreign interfaces present in the same
+  bridge as some DSA switch ports, only if ``ds->assisted_learning_on_cpu_port``
+  is set to true by the driver. These are associated with the address database
+  for that bridge.
+
+For various operations detailed below, DSA provides a ``dsa_db`` structure
+which can be of the following types:
+
+- ``DSA_DB_PORT``: the FDB (or MDB) entry to be installed or deleted belongs to
+  the port private database of user port ``db->dp``.
+- ``DSA_DB_BRIDGE``: the entry belongs to one of the address databases of bridge
+  ``db->bridge``. Separation between the VLAN-unaware database and the per-VID
+  databases of this bridge is expected to be done by the driver.
+- ``DSA_DB_LAG``: the entry belongs to the address database of LAG ``db->lag``.
+  Note: ``DSA_DB_LAG`` is currently unused and may be removed in the future.
+
+The drivers which act upon the ``dsa_db`` argument in ``port_fdb_add``,
+``port_mdb_add`` etc should declare ``ds->fdb_isolation`` as true.
+
+DSA associates each offloaded bridge and each offloaded LAG with a one-based ID
+(``struct dsa_bridge :: num``, ``struct dsa_lag :: id``) for the purposes of
+refcounting addresses on shared ports. Drivers may piggyback on DSA's numbering
+scheme (the ID is readable through ``db->bridge.num`` and ``db->lag.id`` or may
+implement their own.
+
+Only the drivers which declare support for FDB isolation are notified of FDB
+entries on the CPU port belonging to ``DSA_DB_PORT`` databases.
+For compatibility/legacy reasons, ``DSA_DB_BRIDGE`` addresses are notified to
+drivers even if they do not support FDB isolation. However, ``db->bridge.num``
+and ``db->lag.id`` are always set to 0 in that case (to denote the lack of
+isolation, for refcounting purposes).
+
+Note that it is not mandatory for a switch driver to implement physically
+separate address databases for each standalone user port. Since FDB entries in
+the port private databases will always point to the CPU port, there is no risk
+for incorrect forwarding decisions. In this case, all standalone ports may
+share the same database, but the reference counting of host-filtered addresses
+(not deleting the FDB entry for a port's MAC address if it's still in use by
+another port) becomes the responsibility of the driver, because DSA is unaware
+that the port databases are in fact shared. This can be achieved by calling
+``dsa_fdb_present_in_other_db()`` and ``dsa_mdb_present_in_other_db()``.
+The down side is that the RX filtering lists of each user port are in fact
+shared, which means that user port A may accept a packet with a MAC DA it
+shouldn't have, only because that MAC address was in the RX filtering list of
+user port B. These packets will still be dropped in software, however.
+
 Bridge layer
 ------------
 
+Offloading the bridge forwarding plane is optional and handled by the methods
+below. They may be absent, return -EOPNOTSUPP, or ``ds->max_num_bridges`` may
+be non-zero and exceeded, and in this case, joining a bridge port is still
+possible, but the packet forwarding will take place in software, and the ports
+under a software bridge must remain configured in the same way as for
+standalone operation, i.e. have all bridging service functions (address
+learning etc) disabled, and send all received packets to the CPU port only.
+
+Concretely, a port starts offloading the forwarding plane of a bridge once it
+returns success to the ``port_bridge_join`` method, and stops doing so after
+``port_bridge_leave`` has been called. Offloading the bridge means autonomously
+learning FDB entries in accordance with the software bridge port's state, and
+autonomously forwarding (or flooding) received packets without CPU intervention.
+This is optional even when offloading a bridge port. Tagging protocol drivers
+are expected to call ``dsa_default_offload_fwd_mark(skb)`` for packets which
+have already been autonomously forwarded in the forwarding domain of the
+ingress switch port. DSA, through ``dsa_port_devlink_setup()``, considers all
+switch ports part of the same tree ID to be part of the same bridge forwarding
+domain (capable of autonomous forwarding to each other).
+
+Offloading the TX forwarding process of a bridge is a distinct concept from
+simply offloading its forwarding plane, and refers to the ability of certain
+driver and tag protocol combinations to transmit a single skb coming from the
+bridge device's transmit function to potentially multiple egress ports (and
+thereby avoid its cloning in software).
+
+Packets for which the bridge requests this behavior are called data plane
+packets and have ``skb->offload_fwd_mark`` set to true in the tag protocol
+driver's ``xmit`` function. Data plane packets are subject to FDB lookup,
+hardware learning on the CPU port, and do not override the port STP state.
+Additionally, replication of data plane packets (multicast, flooding) is
+handled in hardware and the bridge driver will transmit a single skb for each
+packet that may or may not need replication.
+
+When the TX forwarding offload is enabled, the tag protocol driver is
+responsible to inject packets into the data plane of the hardware towards the
+correct bridging domain (FID) that the port is a part of. The port may be
+VLAN-unaware, and in this case the FID must be equal to the FID used by the
+driver for its VLAN-unaware address database associated with that bridge.
+Alternatively, the bridge may be VLAN-aware, and in that case, it is guaranteed
+that the packet is also VLAN-tagged with the VLAN ID that the bridge processed
+this packet in. It is the responsibility of the hardware to untag the VID on
+the egress-untagged ports, or keep the tag on the egress-tagged ones.
+
 - ``port_bridge_join``: bridge layer function invoked when a given switch port is
   added to a bridge, this function should do what's necessary at the switch
   level to permit the joining port to be added to the relevant logical
   domain for it to ingress/egress traffic with other members of the bridge.
+  By setting the ``tx_fwd_offload`` argument to true, the TX forwarding process
+  of this bridge is also offloaded.
 
 - ``port_bridge_leave``: bridge layer function invoked when a given switch port is
   removed from a bridge, this function should do what's necessary at the
   switch level to deny the leaving port from ingress/egress traffic from the
-  remaining bridge members. When the port leaves the bridge, it should be aged
-  out at the switch hardware for the switch to (re) learn MAC addresses behind
-  this port.
+  remaining bridge members.
 
 - ``port_stp_state_set``: bridge layer function invoked when a given switch port STP
   state is computed by the bridge layer and should be propagated to switch
-  hardware to forward/block/learn traffic. The switch driver is responsible for
-  computing a STP state change based on current and asked parameters and perform
-  the relevant ageing based on the intersection results
+  hardware to forward/block/learn traffic.
 
 - ``port_bridge_flags``: bridge layer function invoked when a port must
   configure its settings for e.g. flooding of unknown traffic or source address
@@ -667,21 +931,11 @@ Bridge layer
   CPU port, and flooding towards the CPU port should also be enabled, due to a
   lack of an explicit address filtering mechanism in the DSA core.
 
-- ``port_bridge_tx_fwd_offload``: bridge layer function invoked after
-  ``port_bridge_join`` when a driver sets ``ds->num_fwd_offloading_bridges`` to
-  a non-zero value. Returning success in this function activates the TX
-  forwarding offload bridge feature for this port, which enables the tagging
-  protocol driver to inject data plane packets towards the bridging domain that
-  the port is a part of. Data plane packets are subject to FDB lookup, hardware
-  learning on the CPU port, and do not override the port STP state.
-  Additionally, replication of data plane packets (multicast, flooding) is
-  handled in hardware and the bridge driver will transmit a single skb for each
-  packet that needs replication. The method is provided as a configuration
-  point for drivers that need to configure the hardware for enabling this
-  feature.
-
-- ``port_bridge_tx_fwd_unoffload``: bridge layer function invoked when a driver
-  leaves a bridge port which had the TX forwarding offload feature enabled.
+- ``port_fast_age``: bridge layer function invoked when flushing the
+  dynamically learned FDB entries on the port is necessary. This is called when
+  transitioning from an STP state where learning should take place to an STP
+  state where it shouldn't, or when leaving a bridge, or when address learning
+  is turned off via ``port_bridge_flags``.
 
 Bridge VLAN filtering
 ---------------------
@@ -697,55 +951,44 @@ Bridge VLAN filtering
   allowed.
 
 - ``port_vlan_add``: bridge layer function invoked when a VLAN is configured
-  (tagged or untagged) for the given switch port. If the operation is not
-  supported by the hardware, this function should return ``-EOPNOTSUPP`` to
-  inform the bridge code to fallback to a software implementation.
+  (tagged or untagged) for the given switch port. The CPU port becomes a member
+  of a VLAN only if a foreign bridge port is also a member of it (and
+  forwarding needs to take place in software), or the VLAN is installed to the
+  VLAN group of the bridge device itself, for termination purposes
+  (``bridge vlan add dev br0 vid 100 self``). VLANs on shared ports are
+  reference counted and removed when there is no user left. Drivers do not need
+  to manually install a VLAN on the CPU port.
 
 - ``port_vlan_del``: bridge layer function invoked when a VLAN is removed from the
   given switch port
 
-- ``port_vlan_dump``: bridge layer function invoked with a switchdev callback
-  function that the driver has to call for each VLAN the given port is a member
-  of. A switchdev object is used to carry the VID and bridge flags.
-
 - ``port_fdb_add``: bridge layer function invoked when the bridge wants to install a
   Forwarding Database entry, the switch hardware should be programmed with the
   specified address in the specified VLAN Id in the forwarding database
-  associated with this VLAN ID. If the operation is not supported, this
-  function should return ``-EOPNOTSUPP`` to inform the bridge code to fallback to
-  a software implementation.
-
-.. note:: VLAN ID 0 corresponds to the port private database, which, in the context
-        of DSA, would be its port-based VLAN, used by the associated bridge device.
+  associated with this VLAN ID.
 
 - ``port_fdb_del``: bridge layer function invoked when the bridge wants to remove a
   Forwarding Database entry, the switch hardware should be programmed to delete
   the specified MAC address from the specified VLAN ID if it was mapped into
   this port forwarding database
 
-- ``port_fdb_dump``: bridge layer function invoked with a switchdev callback
-  function that the driver has to call for each MAC address known to be behind
-  the given port. A switchdev object is used to carry the VID and FDB info.
+- ``port_fdb_dump``: bridge bypass function invoked by ``ndo_fdb_dump`` on the
+  physical DSA port interfaces. Since DSA does not attempt to keep in sync its
+  hardware FDB entries with the software bridge, this method is implemented as
+  a means to view the entries visible on user ports in the hardware database.
+  The entries reported by this function have the ``self`` flag in the output of
+  the ``bridge fdb show`` command.
 
 - ``port_mdb_add``: bridge layer function invoked when the bridge wants to install
-  a multicast database entry. If the operation is not supported, this function
-  should return ``-EOPNOTSUPP`` to inform the bridge code to fallback to a
-  software implementation. The switch hardware should be programmed with the
+  a multicast database entry. The switch hardware should be programmed with the
   specified address in the specified VLAN ID in the forwarding database
   associated with this VLAN ID.
 
-.. note:: VLAN ID 0 corresponds to the port private database, which, in the context
-        of DSA, would be its port-based VLAN, used by the associated bridge device.
-
 - ``port_mdb_del``: bridge layer function invoked when the bridge wants to remove a
   multicast database entry, the switch hardware should be programmed to delete
   the specified MAC address from the specified VLAN ID if it was mapped into
   this port forwarding database.
 
-- ``port_mdb_dump``: bridge layer function invoked with a switchdev callback
-  function that the driver has to call for each MAC address known to be behind
-  the given port. A switchdev object is used to carry the VID and MDB info.
-
 Link aggregation
 ----------------
 
index 9f41961d11d526e2006fe2e823cfdabd06e88b72..66c72230eaade96599bbfff2914b98e9011a3df8 100644 (file)
@@ -1052,11 +1052,7 @@ udp_rmem_min - INTEGER
        Default: 4K
 
 udp_wmem_min - INTEGER
-       Minimal size of send buffer used by UDP sockets in moderation.
-       Each UDP socket is able to use the size for sending data, even if
-       total pages of UDP sockets exceed udp_mem pressure. The unit is byte.
-
-       Default: 4K
+       UDP does not have tx memory accounting and this tunable has no effect.
 
 RAW variables
 =============
@@ -1085,7 +1081,7 @@ cipso_cache_enable - BOOLEAN
 cipso_cache_bucket_size - INTEGER
        The CIPSO label cache consists of a fixed size hash table with each
        hash bucket containing a number of cache entries.  This variable limits
-       the number of entries in each hash bucket; the larger the value the
+       the number of entries in each hash bucket; the larger the value is, the
        more CIPSO label mappings that can be cached.  When the number of
        entries in a given hash bucket reaches this limit adding new entries
        causes the oldest entry in the bucket to be removed to make room.
@@ -1179,7 +1175,7 @@ ip_autobind_reuse - BOOLEAN
        option should only be set by experts.
        Default: 0
 
-ip_dynaddr - BOOLEAN
+ip_dynaddr - INTEGER
        If set non-zero, enables support for dynamic addresses.
        If set to a non-zero value larger than 1, a kernel log
        message will be printed when dynamic address rewriting
index feb257b7f3501e5f70da3d4ce62c8fafb5f9ca20..ef341be2882b1a03ccd28f727a35f491a5534d44 100644 (file)
@@ -20,20 +20,20 @@ possible source of information on its own, the EM framework intervenes as an
 abstraction layer which standardizes the format of power cost tables in the
 kernel, hence enabling to avoid redundant work.
 
-The power values might be expressed in milli-Watts or in an 'abstract scale'.
+The power values might be expressed in micro-Watts or in an 'abstract scale'.
 Multiple subsystems might use the EM and it is up to the system integrator to
 check that the requirements for the power value scale types are met. An example
 can be found in the Energy-Aware Scheduler documentation
 Documentation/scheduler/sched-energy.rst. For some subsystems like thermal or
 powercap power values expressed in an 'abstract scale' might cause issues.
 These subsystems are more interested in estimation of power used in the past,
-thus the real milli-Watts might be needed. An example of these requirements can
+thus the real micro-Watts might be needed. An example of these requirements can
 be found in the Intelligent Power Allocation in
 Documentation/driver-api/thermal/power_allocator.rst.
 Kernel subsystems might implement automatic detection to check whether EM
 registered devices have inconsistent scale (based on EM internal flag).
 Important thing to keep in mind is that when the power values are expressed in
-an 'abstract scale' deriving real energy in milli-Joules would not be possible.
+an 'abstract scale' deriving real energy in micro-Joules would not be possible.
 
 The figure below depicts an example of drivers (Arm-specific here, but the
 approach is applicable to any architecture) providing power costs to the EM
@@ -98,7 +98,7 @@ Drivers are expected to register performance domains into the EM framework by
 calling the following API::
 
   int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
-               struct em_data_callback *cb, cpumask_t *cpus, bool milliwatts);
+               struct em_data_callback *cb, cpumask_t *cpus, bool microwatts);
 
 Drivers must provide a callback function returning <frequency, power> tuples
 for each performance state. The callback function provided by the driver is free
@@ -106,10 +106,10 @@ to fetch data from any relevant location (DT, firmware, ...), and by any mean
 deemed necessary. Only for CPU devices, drivers must specify the CPUs of the
 performance domains using cpumask. For other devices than CPUs the last
 argument must be set to NULL.
-The last argument 'milliwatts' is important to set with correct value. Kernel
+The last argument 'microwatts' is important to set with correct value. Kernel
 subsystems which use EM might rely on this flag to check if all EM devices use
 the same scale. If there are different scales, these subsystems might decide
-to: return warning/error, stop working or panic.
+to return warning/error, stop working or panic.
 See Section 3. for an example of driver implementing this
 callback, or Section 2.4 for further documentation on this API
 
@@ -137,7 +137,7 @@ The .get_cost() allows to provide the 'cost' values which reflect the
 efficiency of the CPUs. This would allow to provide EAS information which
 has different relation than what would be forced by the EM internal
 formulas calculating 'cost' values. To register an EM for such platform, the
-driver must set the flag 'milliwatts' to 0, provide .get_power() callback
+driver must set the flag 'microwatts' to 0, provide .get_power() callback
 and provide .get_cost() callback. The EM framework would handle such platform
 properly during registration. A flag EM_PERF_DOMAIN_ARTIFICIAL is set for such
 platform. Special care should be taken by other frameworks which are using EM
index c456b5225d6645754355e85b967ee0ce9db1c1e7..d140070815955fc710fd2dcac854438b24c910ba 100644 (file)
@@ -6,6 +6,15 @@
 netdev FAQ
 ==========
 
+tl;dr
+-----
+
+ - designate your patch to a tree - ``[PATCH net]`` or ``[PATCH net-next]``
+ - for fixes the ``Fixes:`` tag is required, regardless of the tree
+ - don't post large series (> 15 patches), break them up
+ - don't repost your patches within one 24h period
+ - reverse xmas tree
+
 What is netdev?
 ---------------
 It is a mailing list for all network-related Linux stuff.  This
@@ -136,6 +145,20 @@ it to the maintainer to figure out what is the most recent and current
 version that should be applied. If there is any doubt, the maintainer
 will reply and ask what should be done.
 
+How do I divide my work into patches?
+-------------------------------------
+
+Put yourself in the shoes of the reviewer. Each patch is read separately
+and therefore should constitute a comprehensible step towards your stated
+goal.
+
+Avoid sending series longer than 15 patches. Larger series takes longer
+to review as reviewers will defer looking at it until they find a large
+chunk of time. A small series can be reviewed in a short time, so Maintainers
+just do it. As a result, a sequence of smaller series gets merged quicker and
+with better review coverage. Re-posting large series also increases the mailing
+list traffic.
+
 I made changes to only a few patches in a patch series should I resend only those changed?
 ------------------------------------------------------------------------------------------
 No, please resend the entire patch series and make sure you do number your
@@ -183,6 +206,19 @@ it is requested that you make it look like this::
    * another line of text
    */
 
+What is "reverse xmas tree"?
+----------------------------
+
+Netdev has a convention for ordering local variables in functions.
+Order the variable declaration lines longest to shortest, e.g.::
+
+  struct scatterlist *sg;
+  struct sk_buff *skb;
+  int err, i;
+
+If there are dependencies between the variables preventing the ordering
+move the initialization out of line.
+
 I am working in existing code which uses non-standard formatting. Which formatting should I use?
 ------------------------------------------------------------------------------------------------
 Make your code follow the most recent guidelines, so that eventually all code
index 009b07e5a0f38284ff1c57fe62febf6cd99f0ffe..bf8431386d26983f20c2d8c4047eca6561258fbf 100644 (file)
@@ -10,7 +10,7 @@ AC97
 ====
 
 AC97 is a five wire interface commonly found on many PC sound cards. It is
-now also popular in many portable devices. This DAI has a reset line and time
+now also popular in many portable devices. This DAI has a RESET line and time
 multiplexes its data on its SDATA_OUT (playback) and SDATA_IN (capture) lines.
 The bit clock (BCLK) is always driven by the CODEC (usually 12.288MHz) and the
 frame (FRAME) (usually 48kHz) is always driven by the controller. Each AC97
index 42f5d04e38ec03e59aed8472f2e6419fba904c67..0f6898860d6d1ece70c9efb9e76011007c693668 100644 (file)
@@ -50,9 +50,9 @@ Di conseguenza, nella tabella dei simboli del kernel ci sarà una voce
 rappresentata dalla struttura ``kernel_symbol`` che avrà il campo
 ``namespace`` (spazio dei nomi) impostato. Un simbolo esportato senza uno spazio
 dei nomi avrà questo campo impostato a ``NULL``. Non esiste uno spazio dei nomi
-di base. Il programma ``modpost`` e il codice in kernel/module.c usano lo spazio
-dei nomi, rispettivamente, durante la compilazione e durante il caricamento
-di un modulo.
+di base. Il programma ``modpost`` e il codice in kernel/module/main.c usano lo
+spazio dei nomi, rispettivamente, durante la compilazione e durante il
+caricamento di un modulo.
 
 2.2 Usare il simbolo di preprocessore DEFAULT_SYMBOL_NAMESPACE
 ==============================================================
index e45fe80d1cd88439b7f5f3a1780881ea2dd5199a..962d31d019d74331cda09e55e557306f0a52b0dc 100644 (file)
@@ -224,7 +224,7 @@ kernel/kmod.c
 模块接口支持
 ------------
 
-更多信息请参考文件kernel/module.c
+更多信息请参阅kernel/module/目录下的文件
 
 硬件接口
 ========
index 6abf7ed534ca0c4ddac05d199be922f1ed109483..bb16f0611046d3435b095ef8325bb2298291f05b 100644 (file)
@@ -52,7 +52,7 @@
 
 相应的 ksymtab 条目结构体 ``kernel_symbol`` 将有相应的成员 ``命名空间`` 集。
 导出时未指明命名空间的符号将指向 ``NULL`` 。如果没有定义命名空间,则默认没有。
-``modpost`` 和kernel/module.c分别在构建时或模块加载时使用名称空间。
+``modpost`` 和kernel/module/main.c分别在构建时或模块加载时使用名称空间。
 
 2.2 使用DEFAULT_SYMBOL_NAMESPACE定义
 ====================================
index 11e00a46c610f913455ae86df942d1e98709a0a4..98a2839303071188de011d79a05d3d226a0125f9 100644 (file)
@@ -5657,7 +5657,8 @@ by a string of size ``name_size``.
        #define KVM_STATS_UNIT_BYTES            (0x1 << KVM_STATS_UNIT_SHIFT)
        #define KVM_STATS_UNIT_SECONDS          (0x2 << KVM_STATS_UNIT_SHIFT)
        #define KVM_STATS_UNIT_CYCLES           (0x3 << KVM_STATS_UNIT_SHIFT)
-       #define KVM_STATS_UNIT_MAX              KVM_STATS_UNIT_CYCLES
+       #define KVM_STATS_UNIT_BOOLEAN          (0x4 << KVM_STATS_UNIT_SHIFT)
+       #define KVM_STATS_UNIT_MAX              KVM_STATS_UNIT_BOOLEAN
 
        #define KVM_STATS_BASE_SHIFT            8
        #define KVM_STATS_BASE_MASK             (0xF << KVM_STATS_BASE_SHIFT)
@@ -5702,14 +5703,13 @@ Bits 0-3 of ``flags`` encode the type:
     by the ``hist_param`` field. The range of the Nth bucket (1 <= N < ``size``)
     is [``hist_param``*(N-1), ``hist_param``*N), while the range of the last
     bucket is [``hist_param``*(``size``-1), +INF). (+INF means positive infinity
-    value.) The bucket value indicates how many samples fell in the bucket's range.
+    value.)
   * ``KVM_STATS_TYPE_LOG_HIST``
     The statistic is reported as a logarithmic histogram. The number of
     buckets is specified by the ``size`` field. The range of the first bucket is
     [0, 1), while the range of the last bucket is [pow(2, ``size``-2), +INF).
     Otherwise, The Nth bucket (1 < N < ``size``) covers
-    [pow(2, N-2), pow(2, N-1)). The bucket value indicates how many samples fell
-    in the bucket's range.
+    [pow(2, N-2), pow(2, N-1)).
 
 Bits 4-7 of ``flags`` encode the unit:
 
@@ -5724,6 +5724,15 @@ Bits 4-7 of ``flags`` encode the unit:
     It indicates that the statistics data is used to measure time or latency.
   * ``KVM_STATS_UNIT_CYCLES``
     It indicates that the statistics data is used to measure CPU clock cycles.
+  * ``KVM_STATS_UNIT_BOOLEAN``
+    It indicates that the statistic will always be either 0 or 1.  Boolean
+    statistics of "peak" type will never go back from 1 to 0.  Boolean
+    statistics can be linear histograms (with two buckets) but not logarithmic
+    histograms.
+
+Note that, in the case of histograms, the unit applies to the bucket
+ranges, while the bucket value indicates how many samples fell in the
+bucket's range.
 
 Bits 8-11 of ``flags``, together with ``exponent``, encode the scale of the
 unit:
@@ -5746,7 +5755,7 @@ the corresponding statistics data.
 
 The ``bucket_size`` field is used as a parameter for histogram statistics data.
 It is only used by linear histogram statistics data, specifying the size of a
-bucket.
+bucket in the unit expressed by bits 4-11 of ``flags`` together with ``exponent``.
 
 The ``name`` field is the name string of the statistics data. The name string
 starts at the end of ``struct kvm_stats_desc``.  The maximum length including
index 66bffb24a348abc2d9dda48e91ba290b91baab9c..be011aaa8f3493d9cc1a95a0a8de1229cc3ba937 100644 (file)
@@ -426,7 +426,6 @@ F:  drivers/acpi/*thermal*
 ACPI VIOT DRIVER
 M:     Jean-Philippe Brucker <jean-philippe@linaro.org>
 L:     linux-acpi@vger.kernel.org
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Maintained
 F:     drivers/acpi/viot.c
@@ -960,7 +959,6 @@ F:  drivers/video/fbdev/geode/
 AMD IOMMU (AMD-VI)
 M:     Joerg Roedel <joro@8bytes.org>
 R:     Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
@@ -1040,6 +1038,7 @@ F:        arch/arm64/boot/dts/amd/
 
 AMD XGBE DRIVER
 M:     Tom Lendacky <thomas.lendacky@amd.com>
+M:     "Shyam Sundar S K" <Shyam-sundar.S-k@amd.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi
@@ -2499,10 +2498,8 @@ F:       drivers/power/reset/oxnas-restart.c
 N:     oxnas
 
 ARM/PALM TREO SUPPORT
-M:     Tomas Cech <sleep_walker@suse.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-W:     http://hackndev.com
+S:     Orphan
 F:     arch/arm/mach-pxa/palmtreo.*
 
 ARM/PALMTX,PALMT5,PALMLD,PALMTE2,PALMTC SUPPORT
@@ -2540,6 +2537,7 @@ W:        http://www.armlinux.org.uk/
 ARM/QUALCOMM SUPPORT
 M:     Andy Gross <agross@kernel.org>
 M:     Bjorn Andersson <bjorn.andersson@linaro.org>
+R:     Konrad Dybcio <konrad.dybcio@somainline.org>
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git
@@ -3617,16 +3615,18 @@ S:      Maintained
 F:     Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml
 F:     drivers/iio/accel/bma400*
 
-BPF (Safe dynamic programs and tools)
+BPF [GENERAL] (Safe Dynamic Programs and Tools)
 M:     Alexei Starovoitov <ast@kernel.org>
 M:     Daniel Borkmann <daniel@iogearbox.net>
 M:     Andrii Nakryiko <andrii@kernel.org>
-R:     Martin KaFai Lau <kafai@fb.com>
-R:     Song Liu <songliubraving@fb.com>
+R:     Martin KaFai Lau <martin.lau@linux.dev>
+R:     Song Liu <song@kernel.org>
 R:     Yonghong Song <yhs@fb.com>
 R:     John Fastabend <john.fastabend@gmail.com>
 R:     KP Singh <kpsingh@kernel.org>
-L:     netdev@vger.kernel.org
+R:     Stanislav Fomichev <sdf@google.com>
+R:     Hao Luo <haoluo@google.com>
+R:     Jiri Olsa <jolsa@kernel.org>
 L:     bpf@vger.kernel.org
 S:     Supported
 W:     https://bpf.io/
@@ -3658,12 +3658,9 @@ F:       scripts/pahole-version.sh
 F:     tools/bpf/
 F:     tools/lib/bpf/
 F:     tools/testing/selftests/bpf/
-N:     bpf
-K:     bpf
 
 BPF JIT for ARM
 M:     Shubham Bansal <illusionist.neo@gmail.com>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Odd Fixes
 F:     arch/arm/net/
@@ -3672,7 +3669,6 @@ BPF JIT for ARM64
 M:     Daniel Borkmann <daniel@iogearbox.net>
 M:     Alexei Starovoitov <ast@kernel.org>
 M:     Zi Shen Lim <zlim.lnx@gmail.com>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Supported
 F:     arch/arm64/net/
@@ -3680,14 +3676,12 @@ F:      arch/arm64/net/
 BPF JIT for MIPS (32-BIT AND 64-BIT)
 M:     Johan Almbladh <johan.almbladh@anyfinetworks.com>
 M:     Paul Burton <paulburton@kernel.org>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Maintained
 F:     arch/mips/net/
 
 BPF JIT for NFP NICs
 M:     Jakub Kicinski <kuba@kernel.org>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Odd Fixes
 F:     drivers/net/ethernet/netronome/nfp/bpf/
@@ -3695,7 +3689,6 @@ F:        drivers/net/ethernet/netronome/nfp/bpf/
 BPF JIT for POWERPC (32-BIT AND 64-BIT)
 M:     Naveen N. Rao <naveen.n.rao@linux.ibm.com>
 M:     Michael Ellerman <mpe@ellerman.id.au>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Supported
 F:     arch/powerpc/net/
@@ -3703,7 +3696,6 @@ F:        arch/powerpc/net/
 BPF JIT for RISC-V (32-bit)
 M:     Luke Nelson <luke.r.nels@gmail.com>
 M:     Xi Wang <xi.wang@gmail.com>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Maintained
 F:     arch/riscv/net/
@@ -3711,7 +3703,6 @@ X:        arch/riscv/net/bpf_jit_comp64.c
 
 BPF JIT for RISC-V (64-bit)
 M:     Björn Töpel <bjorn@kernel.org>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Maintained
 F:     arch/riscv/net/
@@ -3721,7 +3712,6 @@ BPF JIT for S390
 M:     Ilya Leoshkevich <iii@linux.ibm.com>
 M:     Heiko Carstens <hca@linux.ibm.com>
 M:     Vasily Gorbik <gor@linux.ibm.com>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Supported
 F:     arch/s390/net/
@@ -3729,14 +3719,12 @@ X:      arch/s390/net/pnet.c
 
 BPF JIT for SPARC (32-BIT AND 64-BIT)
 M:     David S. Miller <davem@davemloft.net>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Odd Fixes
 F:     arch/sparc/net/
 
 BPF JIT for X86 32-BIT
 M:     Wang YanQing <udknight@gmail.com>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Odd Fixes
 F:     arch/x86/net/bpf_jit_comp32.c
@@ -3744,13 +3732,60 @@ F:      arch/x86/net/bpf_jit_comp32.c
 BPF JIT for X86 64-BIT
 M:     Alexei Starovoitov <ast@kernel.org>
 M:     Daniel Borkmann <daniel@iogearbox.net>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Supported
 F:     arch/x86/net/
 X:     arch/x86/net/bpf_jit_comp32.c
 
-BPF LSM (Security Audit and Enforcement using BPF)
+BPF [CORE]
+M:     Alexei Starovoitov <ast@kernel.org>
+M:     Daniel Borkmann <daniel@iogearbox.net>
+R:     John Fastabend <john.fastabend@gmail.com>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/verifier.c
+F:     kernel/bpf/tnum.c
+F:     kernel/bpf/core.c
+F:     kernel/bpf/syscall.c
+F:     kernel/bpf/dispatcher.c
+F:     kernel/bpf/trampoline.c
+F:     include/linux/bpf*
+F:     include/linux/filter.h
+
+BPF [BTF]
+M:     Martin KaFai Lau <martin.lau@linux.dev>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/btf.c
+F:     include/linux/btf*
+
+BPF [TRACING]
+M:     Song Liu <song@kernel.org>
+R:     Jiri Olsa <jolsa@kernel.org>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/trace/bpf_trace.c
+F:     kernel/bpf/stackmap.c
+
+BPF [NETWORKING] (tc BPF, sock_addr)
+M:     Martin KaFai Lau <martin.lau@linux.dev>
+M:     Daniel Borkmann <daniel@iogearbox.net>
+R:     John Fastabend <john.fastabend@gmail.com>
+L:     bpf@vger.kernel.org
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     net/core/filter.c
+F:     net/sched/act_bpf.c
+F:     net/sched/cls_bpf.c
+
+BPF [NETWORKING] (struct_ops, reuseport)
+M:     Martin KaFai Lau <martin.lau@linux.dev>
+L:     bpf@vger.kernel.org
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/bpf_struct*
+
+BPF [SECURITY & LSM] (Security Audit and Enforcement using BPF)
 M:     KP Singh <kpsingh@kernel.org>
 R:     Florent Revest <revest@chromium.org>
 R:     Brendan Jackman <jackmanb@chromium.org>
@@ -3761,7 +3796,27 @@ F:       include/linux/bpf_lsm.h
 F:     kernel/bpf/bpf_lsm.c
 F:     security/bpf/
 
-BPF L7 FRAMEWORK
+BPF [STORAGE & CGROUPS]
+M:     Martin KaFai Lau <martin.lau@linux.dev>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/cgroup.c
+F:     kernel/bpf/*storage.c
+F:     kernel/bpf/bpf_lru*
+
+BPF [RINGBUF]
+M:     Andrii Nakryiko <andrii@kernel.org>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/ringbuf.c
+
+BPF [ITERATOR]
+M:     Yonghong Song <yhs@fb.com>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/*iter.c
+
+BPF [L7 FRAMEWORK] (sockmap)
 M:     John Fastabend <john.fastabend@gmail.com>
 M:     Jakub Sitnicki <jakub@cloudflare.com>
 L:     netdev@vger.kernel.org
@@ -3774,13 +3829,31 @@ F:      net/ipv4/tcp_bpf.c
 F:     net/ipv4/udp_bpf.c
 F:     net/unix/unix_bpf.c
 
-BPFTOOL
+BPF [LIBRARY] (libbpf)
+M:     Andrii Nakryiko <andrii@kernel.org>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     tools/lib/bpf/
+
+BPF [TOOLING] (bpftool)
 M:     Quentin Monnet <quentin@isovalent.com>
 L:     bpf@vger.kernel.org
 S:     Maintained
 F:     kernel/bpf/disasm.*
 F:     tools/bpf/bpftool/
 
+BPF [SELFTESTS] (Test Runners & Infrastructure)
+M:     Andrii Nakryiko <andrii@kernel.org>
+R:     Mykola Lysenko <mykolal@fb.com>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     tools/testing/selftests/bpf/
+
+BPF [MISC]
+L:     bpf@vger.kernel.org
+S:     Odd Fixes
+K:     (?:\b|_)bpf(?:\b|_)
+
 BROADCOM B44 10/100 ETHERNET DRIVER
 M:     Michael Chan <michael.chan@broadcom.com>
 L:     netdev@vger.kernel.org
@@ -4300,7 +4373,7 @@ L:        linux-pm@vger.kernel.org
 L:     linux-samsung-soc@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
-F:     Documentation/devicetree/bindings/devfreq/exynos-bus.txt
+F:     Documentation/devicetree/bindings/interconnect/samsung,exynos-bus.yaml
 F:     drivers/devfreq/exynos-bus.c
 
 BUSLOGIC SCSI DRIVER
@@ -5027,7 +5100,7 @@ COMPUTE EXPRESS LINK (CXL)
 M:     Alison Schofield <alison.schofield@intel.com>
 M:     Vishal Verma <vishal.l.verma@intel.com>
 M:     Ira Weiny <ira.weiny@intel.com>
-M:     Ben Widawsky <ben.widawsky@intel.com>
+M:     Ben Widawsky <bwidawsk@kernel.org>
 M:     Dan Williams <dan.j.williams@intel.com>
 L:     linux-cxl@vger.kernel.org
 S:     Maintained
@@ -5782,6 +5855,7 @@ L:        linux-pm@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
 F:     Documentation/devicetree/bindings/devfreq/
+F:     Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
 F:     drivers/devfreq/
 F:     include/linux/devfreq.h
 F:     include/trace/events/devfreq.h
@@ -5979,7 +6053,6 @@ DMA MAPPING HELPERS
 M:     Christoph Hellwig <hch@lst.de>
 M:     Marek Szyprowski <m.szyprowski@samsung.com>
 R:     Robin Murphy <robin.murphy@arm.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Supported
 W:     http://git.infradead.org/users/hch/dma-mapping.git
@@ -5992,7 +6065,6 @@ F:        kernel/dma/
 
 DMA MAPPING BENCHMARK
 M:     Xiang Chen <chenxiang66@hisilicon.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 F:     kernel/dma/map_benchmark.c
 F:     tools/testing/selftests/dma/
@@ -7577,7 +7649,6 @@ F:        drivers/gpu/drm/exynos/exynos_dp*
 
 EXYNOS SYSMMU (IOMMU) driver
 M:     Marek Szyprowski <m.szyprowski@samsung.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Maintained
 F:     drivers/iommu/exynos-iommu.c
@@ -9836,7 +9907,10 @@ INTEL ASoC DRIVERS
 M:     Cezary Rojewski <cezary.rojewski@intel.com>
 M:     Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
 M:     Liam Girdwood <liam.r.girdwood@linux.intel.com>
-M:     Jie Yang <yang.jie@linux.intel.com>
+M:     Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
+M:     Bard Liao <yung-chuan.liao@linux.intel.com>
+M:     Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
+M:     Kai Vehmanen <kai.vehmanen@linux.intel.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Supported
 F:     sound/soc/intel/
@@ -9999,7 +10073,6 @@ F:       drivers/hid/intel-ish-hid/
 INTEL IOMMU (VT-d)
 M:     David Woodhouse <dwmw2@infradead.org>
 M:     Lu Baolu <baolu.lu@linux.intel.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
@@ -10379,7 +10452,6 @@ F:      include/linux/iomap.h
 IOMMU DRIVERS
 M:     Joerg Roedel <joro@8bytes.org>
 M:     Will Deacon <will@kernel.org>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
@@ -12539,7 +12611,6 @@ F:      drivers/i2c/busses/i2c-mt65xx.c
 
 MEDIATEK IOMMU DRIVER
 M:     Yong Wu <yong.wu@mediatek.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 L:     linux-mediatek@lists.infradead.org (moderated for non-subscribers)
 S:     Supported
@@ -14292,7 +14363,8 @@ S:      Maintained
 F:     drivers/net/phy/nxp-c45-tja11xx.c
 
 NXP FSPI DRIVER
-M:     Ashish Kumar <ashish.kumar@nxp.com>
+M:     Han Xu <han.xu@nxp.com>
+M:     Haibo Chen <haibo.chen@nxp.com>
 R:     Yogesh Gaur <yogeshgaur.83@gmail.com>
 L:     linux-spi@vger.kernel.org
 S:     Maintained
@@ -15778,7 +15850,7 @@ PIN CONTROLLER - FREESCALE
 M:     Dong Aisheng <aisheng.dong@nxp.com>
 M:     Fabio Estevam <festevam@gmail.com>
 M:     Shawn Guo <shawnguo@kernel.org>
-M:     Stefan Agner <stefan@agner.ch>
+M:     Jacky Bai <ping.bai@nxp.com>
 R:     Pengutronix Kernel Team <kernel@pengutronix.de>
 L:     linux-gpio@vger.kernel.org
 S:     Maintained
@@ -15788,7 +15860,7 @@ F:      drivers/pinctrl/freescale/
 PIN CONTROLLER - INTEL
 M:     Mika Westerberg <mika.westerberg@linux.intel.com>
 M:     Andy Shevchenko <andy@kernel.org>
-S:     Maintained
+S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/intel.git
 F:     drivers/pinctrl/intel/
 
@@ -16310,7 +16382,7 @@ F:      drivers/crypto/qat/
 
 QCOM AUDIO (ASoC) DRIVERS
 M:     Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
-M:     Banajit Goswami <bgoswami@codeaurora.org>
+M:     Banajit Goswami <bgoswami@quicinc.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Supported
 F:     sound/soc/codecs/lpass-va-macro.c
@@ -16591,7 +16663,6 @@ F:      drivers/i2c/busses/i2c-qcom-cci.c
 
 QUALCOMM IOMMU
 M:     Rob Clark <robdclark@gmail.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
@@ -17203,12 +17274,15 @@ N:    riscv
 K:     riscv
 
 RISC-V/MICROCHIP POLARFIRE SOC SUPPORT
-M:     Lewis Hanly <lewis.hanly@microchip.com>
 M:     Conor Dooley <conor.dooley@microchip.com>
+M:     Daire McNamara <daire.mcnamara@microchip.com>
 L:     linux-riscv@lists.infradead.org
 S:     Supported
 F:     arch/riscv/boot/dts/microchip/
+F:     drivers/char/hw_random/mpfs-rng.c
+F:     drivers/clk/microchip/clk-mpfs.c
 F:     drivers/mailbox/mailbox-mpfs.c
+F:     drivers/pci/controller/pcie-microchip-host.c
 F:     drivers/soc/microchip/
 F:     include/soc/microchip/mpfs.h
 
@@ -18105,6 +18179,7 @@ F:      drivers/misc/sgi-xp/
 
 SHARED MEMORY COMMUNICATIONS (SMC) SOCKETS
 M:     Karsten Graul <kgraul@linux.ibm.com>
+M:     Wenjia Zhang <wenjia@linux.ibm.com>
 L:     linux-s390@vger.kernel.org
 S:     Supported
 W:     http://www.ibm.com/developerworks/linux/linux390/
@@ -18737,8 +18812,10 @@ F:     sound/soc/
 SOUND - SOUND OPEN FIRMWARE (SOF) DRIVERS
 M:     Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
 M:     Liam Girdwood <lgirdwood@gmail.com>
+M:     Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
+M:     Bard Liao <yung-chuan.liao@linux.intel.com>
 M:     Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
-M:     Kai Vehmanen <kai.vehmanen@linux.intel.com>
+R:     Kai Vehmanen <kai.vehmanen@linux.intel.com>
 M:     Daniel Baluta <daniel.baluta@nxp.com>
 L:     sound-open-firmware@alsa-project.org (moderated for non-subscribers)
 S:     Supported
@@ -19217,7 +19294,6 @@ F:      arch/x86/boot/video*
 
 SWIOTLB SUBSYSTEM
 M:     Christoph Hellwig <hch@infradead.org>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Supported
 W:     http://git.infradead.org/users/hch/dma-mapping.git
@@ -21893,7 +21969,6 @@ XEN SWIOTLB SUBSYSTEM
 M:     Juergen Gross <jgross@suse.com>
 M:     Stefano Stabellini <sstabellini@kernel.org>
 L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Supported
 F:     arch/x86/xen/*swiotlb*
index 990d2ee79186cae8ccb3ff15c93f636ba3c37fdc..b79c1c18149d38ff8798df248d73ec819c8a8dfe 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 5
 PATCHLEVEL = 19
 SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION = -rc8
 NAME = Superb Owl
 
 # *DOCUMENTATION*
index fcf9a41a4ef5b15efaac04bc85c420a435603fb8..71b9272acb28bf0e4f23226954c1d2a3be1fd256 100644 (file)
@@ -438,6 +438,13 @@ config MMU_GATHER_PAGE_SIZE
 
 config MMU_GATHER_NO_RANGE
        bool
+       select MMU_GATHER_MERGE_VMAS
+
+config MMU_GATHER_NO_FLUSH_CACHE
+       bool
+
+config MMU_GATHER_MERGE_VMAS
+       bool
 
 config MMU_GATHER_NO_GATHER
        bool
index 7719ea3d4933c76cd121087fbd22a972c483a7c5..81ccb0636a009c5c340e597cb925f6d0a137fdf3 100644 (file)
                status = "okay";
 
                eeprom@53 {
-                       compatible = "atmel,24c32";
+                       compatible = "atmel,24c02";
                        reg = <0x53>;
                        pagesize = <16>;
-                       size = <128>;
                        status = "okay";
                };
        };
index 806eb1d911d7ce29579048ba1e65dd2ffaa984c1..164201a8fbf2d876e11758d07eaed3829cd9d25d 100644 (file)
        status = "okay";
 
        eeprom@50 {
-               compatible = "atmel,24c32";
+               compatible = "atmel,24c02";
                reg = <0x50>;
                pagesize = <16>;
                status = "okay";
        };
 
        eeprom@52 {
-               compatible = "atmel,24c32";
+               compatible = "atmel,24c02";
                reg = <0x52>;
                pagesize = <16>;
                status = "disabled";
        };
 
        eeprom@53 {
-               compatible = "atmel,24c32";
+               compatible = "atmel,24c02";
                reg = <0x53>;
                pagesize = <16>;
                status = "disabled";
index fded07f370b390b292466ec67477819ccaaba7cb..d6ba4b2a60f6f53f1e4f6a64eb783de13eae7a4f 100644 (file)
                reg = <0x28>;
                #gpio-cells = <2>;
                gpio-controller;
-               ngpio = <32>;
+               ngpios = <62>;
        };
 
        sgtl5000: codec@a {
index 15621e03fa4d46f6f269744d78cb691ffcc216e3..2c3ae715c683d68c7920e78d65f96ac4b8f660d9 100644 (file)
        atmel_mxt_ts: touchscreen@4a {
                compatible = "atmel,maxtouch";
                pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_atmel_conn>;
+               pinctrl-0 = <&pinctrl_atmel_conn &pinctrl_atmel_snvs_conn>;
                reg = <0x4a>;
                interrupt-parent = <&gpio5>;
                interrupts = <4 IRQ_TYPE_EDGE_FALLING>;       /* SODIMM 107 / INT */
        pinctrl_atmel_conn: atmelconngrp {
                fsl,pins = <
                        MX6UL_PAD_JTAG_MOD__GPIO1_IO10          0xb0a0  /* SODIMM 106 */
-                       MX6ULL_PAD_SNVS_TAMPER4__GPIO5_IO04     0xb0a0  /* SODIMM 107 */
                >;
        };
 
 };
 
 &iomuxc_snvs {
+       pinctrl_atmel_snvs_conn: atmelsnvsconngrp {
+               fsl,pins = <
+                       MX6ULL_PAD_SNVS_TAMPER4__GPIO5_IO04     0xb0a0  /* SODIMM 107 */
+               >;
+       };
+
        pinctrl_snvs_gpio1: snvsgpio1grp {
                fsl,pins = <
                        MX6ULL_PAD_SNVS_TAMPER6__GPIO5_IO06     0x110a0 /* SODIMM 93 */
index c6b32064a0096a3b95c353e67fd7cf750a5f79c2..21b509c43393e7e0e766b2b652314bedf0a7e5a3 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
        bus-width = <4>;
+       no-1-8-v;
        non-removable;
-       cap-sd-highspeed;
-       sd-uhs-ddr50;
-       mmc-ddr-1_8v;
        vmmc-supply = <&reg_wifi>;
        enable-sdio-wakeup;
        status = "okay";
index 4cab1b3b3b29a5dd0e1ead930e9d2a1507e4a4e1..725dcf707b315c04208c21ea1639dbe6aeec56b8 100644 (file)
 
        phy4: ethernet-phy@5 {
                reg = <5>;
-               coma-mode-gpios = <&gpio 37 GPIO_ACTIVE_HIGH>;
+               coma-mode-gpios = <&gpio 37 GPIO_OPEN_DRAIN>;
        };
 
        phy5: ethernet-phy@6 {
                reg = <6>;
-               coma-mode-gpios = <&gpio 37 GPIO_ACTIVE_HIGH>;
+               coma-mode-gpios = <&gpio 37 GPIO_OPEN_DRAIN>;
        };
 
        phy6: ethernet-phy@7 {
                reg = <7>;
-               coma-mode-gpios = <&gpio 37 GPIO_ACTIVE_HIGH>;
+               coma-mode-gpios = <&gpio 37 GPIO_OPEN_DRAIN>;
        };
 
        phy7: ethernet-phy@8 {
                reg = <8>;
-               coma-mode-gpios = <&gpio 37 GPIO_ACTIVE_HIGH>;
+               coma-mode-gpios = <&gpio 37 GPIO_OPEN_DRAIN>;
        };
 };
 
index 814ad0b46232654da103923b0eaf43bae0d694be..c3b8a6d6302753d4b233cb9495bddd54208e9c74 100644 (file)
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
                        clock-names = "core", "iface";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&blsp1_uart2_default>;
                        status = "disabled";
                };
 
                        interrupts = <GIC_SPI 113 IRQ_TYPE_NONE>;
                        clocks = <&gcc GCC_BLSP2_UART1_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
                        clock-names = "core", "iface";
+                       pinctrl-names = "default", "sleep";
+                       pinctrl-0 = <&blsp2_uart1_default>;
+                       pinctrl-1 = <&blsp2_uart1_sleep>;
                        status = "disabled";
                };
 
                        interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&gcc GCC_BLSP2_UART4_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
                        clock-names = "core", "iface";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&blsp2_uart4_default>;
                        status = "disabled";
                };
 
                        interrupts = <0 106 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&gcc GCC_BLSP2_QUP6_I2C_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
                        clock-names = "core", "iface";
+                       pinctrl-names = "default", "sleep";
+                       pinctrl-0 = <&blsp2_i2c6_default>;
+                       pinctrl-1 = <&blsp2_i2c6_sleep>;
                        #address-cells = <1>;
                        #size-cells = <0>;
                };
                                };
                        };
 
-                       blsp1_uart2_active: blsp1-uart2-active {
+                       blsp1_uart2_default: blsp1-uart2-default {
                                rx {
                                        pins = "gpio5";
                                        function = "blsp_uart2";
                                };
                        };
 
-                       blsp2_uart1_active: blsp2-uart1-active {
+                       blsp2_uart1_default: blsp2-uart1-default {
                                tx-rts {
                                        pins = "gpio41", "gpio44";
                                        function = "blsp_uart7";
                                bias-pull-down;
                        };
 
-                       blsp2_uart4_active: blsp2-uart4-active {
+                       blsp2_uart4_default: blsp2-uart4-default {
                                tx-rts {
                                        pins = "gpio53", "gpio56";
                                        function = "blsp_uart10";
                                bias-pull-up;
                        };
 
-                       /* BLSP2_I2C6 info is missing - nobody uses it though? */
+                       blsp2_i2c6_default: blsp2-i2c6-default {
+                               pins = "gpio87", "gpio88";
+                               function = "blsp_i2c12";
+                               drive-strength = <2>;
+                               bias-disable;
+                       };
+
+                       blsp2_i2c6_sleep: blsp2-i2c6-sleep {
+                               pins = "gpio87", "gpio88";
+                               function = "blsp_i2c12";
+                               drive-strength = <2>;
+                               bias-pull-up;
+                       };
 
                        spi8_default: spi8_default {
                                mosi {
index 89c71d419f82ab78d532577352a2345277f4e0f5..659a17fc755cf234206670512de09c3cd876732d 100644 (file)
                                clocks = <&pmc PMC_TYPE_PERIPHERAL 55>, <&pmc PMC_TYPE_GCK 55>;
                                clock-names = "pclk", "gclk";
                                assigned-clocks = <&pmc PMC_TYPE_CORE PMC_I2S1_MUX>;
-                               assigned-parrents = <&pmc PMC_TYPE_GCK 55>;
+                               assigned-clock-parents = <&pmc PMC_TYPE_GCK 55>;
                                status = "disabled";
                        };
 
index e90cf3acd0b314f62fa70ffa89fab16ea5aa3764..543f24c2f4f6bccceed836886eca70863e9eddd6 100644 (file)
                                reg = <0x16>;
                                #reset-cells = <1>;
                        };
+
+                       scmi_voltd: protocol@17 {
+                               reg = <0x17>;
+
+                               scmi_reguls: regulators {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       scmi_reg11: reg11@0 {
+                                               reg = <0>;
+                                               regulator-name = "reg11";
+                                               regulator-min-microvolt = <1100000>;
+                                               regulator-max-microvolt = <1100000>;
+                                       };
+
+                                       scmi_reg18: reg18@1 {
+                                               voltd-name = "reg18";
+                                               reg = <1>;
+                                               regulator-name = "reg18";
+                                               regulator-min-microvolt = <1800000>;
+                                               regulator-max-microvolt = <1800000>;
+                                       };
+
+                                       scmi_usb33: usb33@2 {
+                                               reg = <2>;
+                                               regulator-name = "usb33";
+                                               regulator-min-microvolt = <3300000>;
+                                               regulator-max-microvolt = <3300000>;
+                                       };
+                               };
+                       };
                };
        };
 
                };
        };
 };
+
+&reg11 {
+       status = "disabled";
+};
+
+&reg18 {
+       status = "disabled";
+};
+
+&usb33 {
+       status = "disabled";
+};
+
+&usbotg_hs {
+       usb33d-supply = <&scmi_usb33>;
+};
+
+&usbphyc {
+       vdda1v1-supply = <&scmi_reg11>;
+       vdda1v8-supply = <&scmi_reg18>;
+};
+
+/delete-node/ &clk_hse;
+/delete-node/ &clk_hsi;
+/delete-node/ &clk_lse;
+/delete-node/ &clk_lsi;
+/delete-node/ &clk_csi;
index 7fdc324b3cf95ef4e4d70662ccb83a32f0d1d655..e04dda5ddd954e4246cae0b5a78b3d82bc98daa9 100644 (file)
                        compatible = "st,stm32-cec";
                        reg = <0x40016000 0x400>;
                        interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&rcc CEC_K>, <&clk_lse>;
+                       clocks = <&rcc CEC_K>, <&rcc CEC>;
                        clock-names = "cec", "hdmi-cec";
                        status = "disabled";
                };
                usbh_ohci: usb@5800c000 {
                        compatible = "generic-ohci";
                        reg = <0x5800c000 0x1000>;
-                       clocks = <&rcc USBH>, <&usbphyc>;
+                       clocks = <&usbphyc>, <&rcc USBH>;
                        resets = <&rcc USBH_R>;
                        interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
                        status = "disabled";
                usbh_ehci: usb@5800d000 {
                        compatible = "generic-ehci";
                        reg = <0x5800d000 0x1000>;
-                       clocks = <&rcc USBH>;
+                       clocks = <&usbphyc>, <&rcc USBH>;
                        resets = <&rcc USBH_R>;
                        interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
                        companion = <&usbh_ohci>;
index 36371d6ed6604a4d82312a9153a655843dffcb14..e539cc80bef8108cb4d55c3b4130958860c4e072 100644 (file)
        clocks = <&scmi_clk CK_SCMI_MPU>;
 };
 
+&dsi {
+       clocks = <&rcc DSI_K>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
+};
+
 &gpioz {
        clocks = <&scmi_clk CK_SCMI_GPIOZ>;
 };
index 03226a5969046f6fdfb1623619ab01ce6781b21f..97e4f94b0a24eeaedc34af98cccfbb76f7877152 100644 (file)
@@ -35,6 +35,7 @@
 };
 
 &dsi {
+       phy-dsi-supply = <&scmi_reg18>;
        clocks = <&rcc DSI_K>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
 };
 
index c1a79272c06889621ade8adaf02464023e006c38..9cf0a44d2f47e9e0d0329d896709b07b3d91465e 100644 (file)
        resets = <&scmi_reset RST_SCMI_CRYP1>;
 };
 
+&dsi {
+       clocks = <&rcc DSI_K>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
+};
+
 &gpioz {
        clocks = <&scmi_clk CK_SCMI_GPIOZ>;
 };
index 7842384ddbe457bf1e81bcad3a119d202103cc17..3b9dd6f4ccc96aabb22ddc6ad7a0b9913a394d35 100644 (file)
@@ -36,6 +36,7 @@
 };
 
 &dsi {
+       phy-dsi-supply = <&scmi_reg18>;
        clocks = <&rcc DSI_K>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
 };
 
index f19ed981da9d92d4b842fcb799bb1681d173e266..3706216ffb40bac94501f3f4f529e2d5f7a87cfc 100644 (file)
        flash@0 {
                #address-cells = <1>;
                #size-cells = <1>;
-               compatible = "mxicy,mx25l1606e", "winbond,w25q128";
+               compatible = "mxicy,mx25l1606e", "jedec,spi-nor";
                reg = <0>;
                spi-max-frequency = <40000000>;
        };
index ca32446b187f5d61da868e8a6a0d9deecc611757..f53086ddc48b032bbc58a06ffd9cc97abaed3731 100644 (file)
@@ -93,6 +93,7 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_DRM=y
 CONFIG_DRM_PANEL_SEIKO_43WVF1G=y
 CONFIG_DRM_MXSFB=y
+CONFIG_FB=y
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
index f1d0a7807cd0e13beca85a00ea9a34ef504b104a..41536feb4392140798e33f1c736f70c9dd798563 100644 (file)
@@ -112,19 +112,6 @@ static __always_inline void set_domain(unsigned int val)
 }
 #endif
 
-#ifdef CONFIG_CPU_USE_DOMAINS
-#define modify_domain(dom,type)                                        \
-       do {                                                    \
-               unsigned int domain = get_domain();             \
-               domain &= ~domain_mask(dom);                    \
-               domain = domain | domain_val(dom, type);        \
-               set_domain(domain);                             \
-       } while (0)
-
-#else
-static inline void modify_domain(unsigned dom, unsigned type)  { }
-#endif
-
 /*
  * Generate the T (user) versions of the LDR/STR and related
  * instructions (inline assembly)
index 92282558caf7cdbb36b27037e0de39bbb6a5744c..2b8970d8e5a2ff84bffb8fc2302b53d5d08882b9 100644 (file)
@@ -27,6 +27,7 @@ enum {
        MT_HIGH_VECTORS,
        MT_MEMORY_RWX,
        MT_MEMORY_RW,
+       MT_MEMORY_RO,
        MT_ROM,
        MT_MEMORY_RWX_NONCACHED,
        MT_MEMORY_RW_DTCM,
index 93051e2f402c8452a743e83ace1413258a0b6034..1408a6a15d0e03c81225c0f143f85011e8b0162f 100644 (file)
@@ -163,5 +163,31 @@ static inline unsigned long user_stack_pointer(struct pt_regs *regs)
                ((current_stack_pointer | (THREAD_SIZE - 1)) - 7) - 1;  \
 })
 
+
+/*
+ * Update ITSTATE after normal execution of an IT block instruction.
+ *
+ * The 8 IT state bits are split into two parts in CPSR:
+ *     ITSTATE<1:0> are in CPSR<26:25>
+ *     ITSTATE<7:2> are in CPSR<15:10>
+ */
+static inline unsigned long it_advance(unsigned long cpsr)
+{
+       if ((cpsr & 0x06000400) == 0) {
+               /* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */
+               cpsr &= ~PSR_IT_MASK;
+       } else {
+               /* We need to shift left ITSTATE<4:0> */
+               const unsigned long mask = 0x06001c00;  /* Mask ITSTATE<4:0> */
+               unsigned long it = cpsr & mask;
+               it <<= 1;
+               it |= it >> (27 - 10);  /* Carry ITSTATE<2> to correct place */
+               it &= mask;
+               cpsr &= ~mask;
+               cpsr |= it;
+       }
+       return cpsr;
+}
+
 #endif /* __ASSEMBLY__ */
 #endif
index 7aa3ded4af9292d006e2346efa554187467aa393..6a447ac67d80df7d8e79b60ad7e0d13d6076785d 100644 (file)
@@ -302,6 +302,7 @@ local_restart:
        b       ret_fast_syscall
 #endif
 ENDPROC(vector_swi)
+       .ltorg
 
        /*
         * This is the really slow path.  We're going to be doing
index b1a43d7bc56ce1c403eadfa1fdbd3f54a246b16d..df6d673e83d563ec3423aef9e8d84fb78067a6f9 100644 (file)
@@ -202,7 +202,7 @@ static const struct wakeup_source_info ws_info[] = {
 
 static const struct of_device_id sama5d2_ws_ids[] = {
        { .compatible = "atmel,sama5d2-gem",            .data = &ws_info[0] },
-       { .compatible = "atmel,at91rm9200-rtc",         .data = &ws_info[1] },
+       { .compatible = "atmel,sama5d2-rtc",            .data = &ws_info[1] },
        { .compatible = "atmel,sama5d3-udc",            .data = &ws_info[2] },
        { .compatible = "atmel,at91rm9200-ohci",        .data = &ws_info[2] },
        { .compatible = "usb-ohci",                     .data = &ws_info[2] },
@@ -213,24 +213,24 @@ static const struct of_device_id sama5d2_ws_ids[] = {
 };
 
 static const struct of_device_id sam9x60_ws_ids[] = {
-       { .compatible = "atmel,at91sam9x5-rtc",         .data = &ws_info[1] },
+       { .compatible = "microchip,sam9x60-rtc",        .data = &ws_info[1] },
        { .compatible = "atmel,at91rm9200-ohci",        .data = &ws_info[2] },
        { .compatible = "usb-ohci",                     .data = &ws_info[2] },
        { .compatible = "atmel,at91sam9g45-ehci",       .data = &ws_info[2] },
        { .compatible = "usb-ehci",                     .data = &ws_info[2] },
-       { .compatible = "atmel,at91sam9260-rtt",        .data = &ws_info[4] },
+       { .compatible = "microchip,sam9x60-rtt",        .data = &ws_info[4] },
        { .compatible = "cdns,sam9x60-macb",            .data = &ws_info[5] },
        { /* sentinel */ }
 };
 
 static const struct of_device_id sama7g5_ws_ids[] = {
-       { .compatible = "atmel,at91sam9x5-rtc",         .data = &ws_info[1] },
+       { .compatible = "microchip,sama7g5-rtc",        .data = &ws_info[1] },
        { .compatible = "microchip,sama7g5-ohci",       .data = &ws_info[2] },
        { .compatible = "usb-ohci",                     .data = &ws_info[2] },
        { .compatible = "atmel,at91sam9g45-ehci",       .data = &ws_info[2] },
        { .compatible = "usb-ehci",                     .data = &ws_info[2] },
        { .compatible = "microchip,sama7g5-sdhci",      .data = &ws_info[3] },
-       { .compatible = "atmel,at91sam9260-rtt",        .data = &ws_info[4] },
+       { .compatible = "microchip,sama7g5-rtt",        .data = &ws_info[4] },
        { /* sentinel */ }
 };
 
@@ -1079,7 +1079,7 @@ securam_fail:
        return ret;
 }
 
-static void at91_pm_secure_init(void)
+static void __init at91_pm_secure_init(void)
 {
        int suspend_mode;
        struct arm_smccc_res res;
index 4b8ad728bb42aa68b852e3dfee0b1c656e388426..32ac60b89fdcc5e48716f67c48d91498abff5ab7 100644 (file)
@@ -71,6 +71,7 @@ static void __init meson_smp_prepare_cpus(const char *scu_compatible,
        }
 
        sram_base = of_iomap(node, 0);
+       of_node_put(node);
        if (!sram_base) {
                pr_err("Couldn't map SRAM registers\n");
                return;
@@ -91,6 +92,7 @@ static void __init meson_smp_prepare_cpus(const char *scu_compatible,
        }
 
        scu_base = of_iomap(node, 0);
+       of_node_put(node);
        if (!scu_base) {
                pr_err("Couldn't map SCU registers\n");
                return;
index 87389d9456b95c30fc0730df589310d0c2523005..30d781d80fe0cba106d369df15d0968b8cd8c50a 100644 (file)
@@ -311,7 +311,7 @@ void __init rockchip_suspend_init(void)
                                             &match);
        if (!match) {
                pr_err("Failed to find PMU node\n");
-               return;
+               goto out_put;
        }
        pm_data = (struct rockchip_pm_data *) match->data;
 
@@ -320,9 +320,12 @@ void __init rockchip_suspend_init(void)
 
                if (ret) {
                        pr_err("%s: matches init error %d\n", __func__, ret);
-                       return;
+                       goto out_put;
                }
        }
 
        suspend_set_ops(pm_data->ops);
+
+out_put:
+       of_node_put(np);
 }
index a3a4589ec73b04ad14aa481195f2a0bc1377b5b8..fc439c2c16f83a2cd7fc556476637528605a218b 100644 (file)
@@ -631,7 +631,11 @@ config CPU_USE_DOMAINS
        bool
        help
          This option enables or disables the use of domain switching
-         via the set_fs() function.
+         using the DACR (domain access control register) to protect memory
+         domains from each other. In Linux we use three domains: kernel, user
+         and IO. The domains are used to protect userspace from kernelspace
+         and to handle IO-space as a special type of memory by assigning
+         manager or client roles to running code (such as a process).
 
 config CPU_V7M_NUM_IRQ
        int "Number of external interrupts connected to the NVIC"
index 6f499559d19362885c289d38c3a854a33f10c2bb..f8dd0b3cc8e040cb7cb737e10ae465c11882c913 100644 (file)
@@ -935,6 +935,9 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        if (type == TYPE_LDST)
                do_alignment_finish_ldst(addr, instr, regs, offset);
 
+       if (thumb_mode(regs))
+               regs->ARM_cpsr = it_advance(regs->ARM_cpsr);
+
        return 0;
 
  bad_or_fault:
index 5e2be37a198e29eefa1b0a3ce6b64296c4d0e2f6..cd17e324aa51ea6596cc83b76049b06ca8c329fb 100644 (file)
@@ -296,6 +296,13 @@ static struct mem_type mem_types[] __ro_after_init = {
                .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
                .domain    = DOMAIN_KERNEL,
        },
+       [MT_MEMORY_RO] = {
+               .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+                            L_PTE_XN | L_PTE_RDONLY,
+               .prot_l1   = PMD_TYPE_TABLE,
+               .prot_sect = PMD_TYPE_SECT,
+               .domain    = DOMAIN_KERNEL,
+       },
        [MT_ROM] = {
                .prot_sect = PMD_TYPE_SECT,
                .domain    = DOMAIN_KERNEL,
@@ -489,6 +496,7 @@ static void __init build_mem_type_table(void)
 
                        /* Also setup NX memory mapping */
                        mem_types[MT_MEMORY_RW].prot_sect |= PMD_SECT_XN;
+                       mem_types[MT_MEMORY_RO].prot_sect |= PMD_SECT_XN;
                }
                if (cpu_arch >= CPU_ARCH_ARMv7 && (cr & CR_TRE)) {
                        /*
@@ -568,6 +576,7 @@ static void __init build_mem_type_table(void)
                mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
                mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
                mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
+               mem_types[MT_MEMORY_RO].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
 #endif
 
                /*
@@ -587,6 +596,8 @@ static void __init build_mem_type_table(void)
                        mem_types[MT_MEMORY_RWX].prot_pte |= L_PTE_SHARED;
                        mem_types[MT_MEMORY_RW].prot_sect |= PMD_SECT_S;
                        mem_types[MT_MEMORY_RW].prot_pte |= L_PTE_SHARED;
+                       mem_types[MT_MEMORY_RO].prot_sect |= PMD_SECT_S;
+                       mem_types[MT_MEMORY_RO].prot_pte |= L_PTE_SHARED;
                        mem_types[MT_MEMORY_DMA_READY].prot_pte |= L_PTE_SHARED;
                        mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= PMD_SECT_S;
                        mem_types[MT_MEMORY_RWX_NONCACHED].prot_pte |= L_PTE_SHARED;
@@ -647,6 +658,8 @@ static void __init build_mem_type_table(void)
        mem_types[MT_MEMORY_RWX].prot_pte |= kern_pgprot;
        mem_types[MT_MEMORY_RW].prot_sect |= ecc_mask | cp->pmd;
        mem_types[MT_MEMORY_RW].prot_pte |= kern_pgprot;
+       mem_types[MT_MEMORY_RO].prot_sect |= ecc_mask | cp->pmd;
+       mem_types[MT_MEMORY_RO].prot_pte |= kern_pgprot;
        mem_types[MT_MEMORY_DMA_READY].prot_pte |= kern_pgprot;
        mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= ecc_mask;
        mem_types[MT_ROM].prot_sect |= cp->pmd;
@@ -1360,7 +1373,7 @@ static void __init devicemaps_init(const struct machine_desc *mdesc)
                map.pfn = __phys_to_pfn(__atags_pointer & SECTION_MASK);
                map.virtual = FDT_FIXED_BASE;
                map.length = FDT_FIXED_SIZE;
-               map.type = MT_ROM;
+               map.type = MT_MEMORY_RO;
                create_mapping(&map);
        }
 
index fb9f3eb6bf483d22041a06fc9eb17bdf87866558..8bc7a2d6d6c7f96cda00741fe76faa148cee7b51 100644 (file)
@@ -108,8 +108,7 @@ static unsigned int spectre_v2_install_workaround(unsigned int method)
 #else
 static unsigned int spectre_v2_install_workaround(unsigned int method)
 {
-       pr_info("CPU%u: Spectre V2: workarounds disabled by configuration\n",
-               smp_processor_id());
+       pr_info_once("Spectre V2: workarounds disabled by configuration\n");
 
        return SPECTRE_VULNERABLE;
 }
@@ -209,10 +208,10 @@ static int spectre_bhb_install_workaround(int method)
                        return SPECTRE_VULNERABLE;
 
                spectre_bhb_method = method;
-       }
 
-       pr_info("CPU%u: Spectre BHB: using %s workaround\n",
-               smp_processor_id(), spectre_bhb_method_name(method));
+               pr_info("CPU%u: Spectre BHB: enabling %s workaround for all CPUs\n",
+                       smp_processor_id(), spectre_bhb_method_name(method));
+       }
 
        return SPECTRE_MITIGATED;
 }
index 97317359899218873e1cfa0560c66645a78e16c5..facc889d05eeeaf3ec9a2332bee31865d963adf4 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/types.h>
 #include <linux/stddef.h>
 #include <asm/probes.h>
+#include <asm/ptrace.h>
 #include <asm/kprobes.h>
 
 void __init arm_probes_decode_init(void);
@@ -35,31 +36,6 @@ void __init find_str_pc_offset(void);
 #endif
 
 
-/*
- * Update ITSTATE after normal execution of an IT block instruction.
- *
- * The 8 IT state bits are split into two parts in CPSR:
- *     ITSTATE<1:0> are in CPSR<26:25>
- *     ITSTATE<7:2> are in CPSR<15:10>
- */
-static inline unsigned long it_advance(unsigned long cpsr)
-       {
-       if ((cpsr & 0x06000400) == 0) {
-               /* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */
-               cpsr &= ~PSR_IT_MASK;
-       } else {
-               /* We need to shift left ITSTATE<4:0> */
-               const unsigned long mask = 0x06001c00;  /* Mask ITSTATE<4:0> */
-               unsigned long it = cpsr & mask;
-               it <<= 1;
-               it |= it >> (27 - 10);  /* Carry ITSTATE<2> to correct place */
-               it &= mask;
-               cpsr &= ~mask;
-               cpsr |= it;
-       }
-       return cpsr;
-}
-
 static inline void __kprobes bx_write_pc(long pcv, struct pt_regs *regs)
 {
        long cpsr = regs->ARM_cpsr;
index 84a1cea1f43b9a3331b35093e4c57cb78d670815..309648c17f48685c8a115bcb1e03dd0212a35f49 100644 (file)
@@ -63,11 +63,12 @@ out:
 
 unsigned long __pfn_to_mfn(unsigned long pfn)
 {
-       struct rb_node *n = phys_to_mach.rb_node;
+       struct rb_node *n;
        struct xen_p2m_entry *entry;
        unsigned long irqflags;
 
        read_lock_irqsave(&p2m_lock, irqflags);
+       n = phys_to_mach.rb_node;
        while (n) {
                entry = rb_entry(n, struct xen_p2m_entry, rbnode_phys);
                if (entry->pfn <= pfn &&
@@ -152,10 +153,11 @@ bool __set_phys_to_machine_multi(unsigned long pfn,
        int rc;
        unsigned long irqflags;
        struct xen_p2m_entry *p2m_entry;
-       struct rb_node *n = phys_to_mach.rb_node;
+       struct rb_node *n;
 
        if (mfn == INVALID_P2M_ENTRY) {
                write_lock_irqsave(&p2m_lock, irqflags);
+               n = phys_to_mach.rb_node;
                while (n) {
                        p2m_entry = rb_entry(n, struct xen_p2m_entry, rbnode_phys);
                        if (p2m_entry->pfn <= pfn &&
index 66023d5535247df0dff768c09cbbfe1b48ab42cd..d084c33d5ca82317c5d861ab997b4c90aa10b3d5 100644 (file)
@@ -9,6 +9,14 @@
                /delete-node/ cpu@3;
        };
 
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+
        pmu {
                compatible = "arm,cortex-a53-pmu";
                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
index a4be040a00c0733186967379c2a1decd233765ad..967d2cd3c3cee4610de6d92416b84881d2e218b0 100644 (file)
@@ -29,6 +29,8 @@
                        device_type = "cpu";
                        compatible = "brcm,brahma-b53";
                        reg = <0x0>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x0 0xfff8>;
                        next-level-cache = <&l2>;
                };
 
index 92465f7776035a1464c0543906d118098f7c38d7..d5cdd77e5a95906e157b478a91c591dea4d8f364 100644 (file)
                        little-endian;
                };
 
-               efuse@1e80000 {
+               sfp: efuse@1e80000 {
                        compatible = "fsl,ls1028a-sfp";
                        reg = <0x0 0x1e80000 0x0 0x10000>;
+                       clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+                                           QORIQ_CLK_PLL_DIV(4)>;
+                       clock-names = "sfp";
                        #address-cells = <1>;
                        #size-cells = <1>;
 
index 4c3ac4214a2cdfe35184954717d3f62f34b4ad9c..9a4de739e6a2a1356e61c53412961d3be02c4da9 100644 (file)
 &iomuxc {
        pinctrl_eqos: eqosgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x3
-                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x3
-                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0                       0x91
-                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1                       0x91
-                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2                       0x91
-                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3                       0x91
-                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x91
-                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL                 0x91
-                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0                       0x1f
-                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1                       0x1f
-                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2                       0x1f
-                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3                       0x1f
-                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL                 0x1f
-                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x1f
-                       MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22                               0x19
+                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x2
+                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x2
+                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0                       0x90
+                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1                       0x90
+                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2                       0x90
+                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3                       0x90
+                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x90
+                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL                 0x90
+                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0                       0x16
+                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1                       0x16
+                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2                       0x16
+                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3                       0x16
+                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL                 0x16
+                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x16
+                       MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22                               0x10
                >;
        };
 
        pinctrl_fec: fecgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC               0x3
-                       MX8MP_IOMUXC_SAI1_RXD3__ENET1_MDIO              0x3
-                       MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0         0x91
-                       MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1         0x91
-                       MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2         0x91
-                       MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3         0x91
-                       MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC          0x91
-                       MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL      0x91
-                       MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL      0x1f
-                       MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC         0x1f
-                       MX8MP_IOMUXC_SAI1_RXD0__GPIO4_IO02              0x19
+                       MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC               0x2
+                       MX8MP_IOMUXC_SAI1_RXD3__ENET1_MDIO              0x2
+                       MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0         0x90
+                       MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1         0x90
+                       MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2         0x90
+                       MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3         0x90
+                       MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC          0x90
+                       MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL      0x90
+                       MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0         0x16
+                       MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1         0x16
+                       MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2         0x16
+                       MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3         0x16
+                       MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL      0x16
+                       MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC         0x16
+                       MX8MP_IOMUXC_SAI1_RXD0__GPIO4_IO02              0x10
                >;
        };
 
 
        pinctrl_gpio_led: gpioledgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16   0x19
+                       MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16   0x140
                >;
        };
 
        pinctrl_i2c1: i2c1grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c3: i2c3grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c5: i2c5grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SPDIF_RX__I2C5_SDA         0x400001c3
-                       MX8MP_IOMUXC_SPDIF_TX__I2C5_SCL         0x400001c3
+                       MX8MP_IOMUXC_SPDIF_RX__I2C5_SDA         0x400001c2
+                       MX8MP_IOMUXC_SPDIF_TX__I2C5_SCL         0x400001c2
                >;
        };
 
 
        pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x41
+                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x40
                >;
        };
 
        pinctrl_uart2: uart2grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX    0x49
-                       MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX    0x49
+                       MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX    0x140
+                       MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX    0x140
                >;
        };
 
        pinctrl_usb1_vbus: usb1grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO14__USB2_OTG_PWR   0x19
+                       MX8MP_IOMUXC_GPIO1_IO14__USB2_OTG_PWR   0x10
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d0
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d0
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d0
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d4
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d4
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d4
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d6
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d6
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d6
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
index 70a701a624a678785855bc1d6a35c20d3ea86355..dd703b6a5e17c91dac8860687a408ca4765310dc 100644 (file)
 &iomuxc {
        pinctrl_eqos: eqosgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x3
-                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x3
-                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0                       0x91
-                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1                       0x91
-                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2                       0x91
-                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3                       0x91
-                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x91
-                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL                 0x91
-                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0                       0x1f
-                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1                       0x1f
-                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2                       0x1f
-                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3                       0x1f
-                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL                 0x1f
-                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x1f
-                       MX8MP_IOMUXC_NAND_DATA01__GPIO3_IO07                            0x19
+                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x2
+                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x2
+                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0                       0x90
+                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1                       0x90
+                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2                       0x90
+                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3                       0x90
+                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x90
+                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL                 0x90
+                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0                       0x16
+                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1                       0x16
+                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2                       0x16
+                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3                       0x16
+                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL                 0x16
+                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x16
+                       MX8MP_IOMUXC_NAND_DATA01__GPIO3_IO07                            0x10
                >;
        };
 
        pinctrl_uart2: uart2grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX    0x49
-                       MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX    0x49
+                       MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX    0x40
+                       MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX    0x40
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d0
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d0
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d0
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
 
        pinctrl_reg_usb1: regusb1grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14     0x19
+                       MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14     0x10
                >;
        };
 
        pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x41
+                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x40
                >;
        };
 };
index 984a6b9ded8d7a8c4936f220d099ab2cc755c7c3..6aa720bafe2898593b80f292e768d83a0a29a105 100644 (file)
 &iomuxc {
        pinctrl_eqos: eqosgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                     0x3
-                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                   0x3
-                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0               0x91
-                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1               0x91
-                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2               0x91
-                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3               0x91
-                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x91
-                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL         0x91
-                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0               0x1f
-                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1               0x1f
-                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2               0x1f
-                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3               0x1f
-                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL         0x1f
-                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x1f
+                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                     0x2
+                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                   0x2
+                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0               0x90
+                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1               0x90
+                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2               0x90
+                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3               0x90
+                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x90
+                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL         0x90
+                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0               0x16
+                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1               0x16
+                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2               0x16
+                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3               0x16
+                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL         0x16
+                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x16
                        MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20                      0x10
                >;
        };
 
        pinctrl_i2c2: i2c2grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c2_gpio: i2c2gpiogrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C2_SCL__GPIO5_IO16       0x1e3
-                       MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17       0x1e3
+                       MX8MP_IOMUXC_I2C2_SCL__GPIO5_IO16       0x1e2
+                       MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17       0x1e2
                >;
        };
 
        pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x41
+                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x40
                >;
        };
 
        pinctrl_uart1: uart1grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX    0x49
-                       MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX    0x49
+                       MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX    0x40
+                       MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX    0x40
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d0
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d0
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d0
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d4
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d4
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d4
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d6
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d6
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d6
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 };
index 101d311476034bd2d82ce1ee61210a01d28d0c35..521215520a0f40acb3a9310f82eef1354328ee7c 100644 (file)
 
        pinctrl_hog: hoggrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO09__GPIO1_IO09     0x40000041 /* DIO0 */
-                       MX8MP_IOMUXC_GPIO1_IO11__GPIO1_IO11     0x40000041 /* DIO1 */
-                       MX8MP_IOMUXC_NAND_DQS__GPIO3_IO14       0x40000041 /* M2SKT_OFF# */
-                       MX8MP_IOMUXC_SD2_DATA2__GPIO2_IO17      0x40000159 /* PCIE1_WDIS# */
-                       MX8MP_IOMUXC_SD2_DATA3__GPIO2_IO18      0x40000159 /* PCIE2_WDIS# */
-                       MX8MP_IOMUXC_SD2_CMD__GPIO2_IO14        0x40000159 /* PCIE3_WDIS# */
-                       MX8MP_IOMUXC_NAND_DATA00__GPIO3_IO06    0x40000041 /* M2SKT_RST# */
-                       MX8MP_IOMUXC_SAI1_TXD6__GPIO4_IO18      0x40000159 /* M2SKT_WDIS# */
-                       MX8MP_IOMUXC_NAND_ALE__GPIO3_IO00       0x40000159 /* M2SKT_GDIS# */
+                       MX8MP_IOMUXC_GPIO1_IO09__GPIO1_IO09     0x40000040 /* DIO0 */
+                       MX8MP_IOMUXC_GPIO1_IO11__GPIO1_IO11     0x40000040 /* DIO1 */
+                       MX8MP_IOMUXC_NAND_DQS__GPIO3_IO14       0x40000040 /* M2SKT_OFF# */
+                       MX8MP_IOMUXC_SD2_DATA2__GPIO2_IO17      0x40000150 /* PCIE1_WDIS# */
+                       MX8MP_IOMUXC_SD2_DATA3__GPIO2_IO18      0x40000150 /* PCIE2_WDIS# */
+                       MX8MP_IOMUXC_SD2_CMD__GPIO2_IO14        0x40000150 /* PCIE3_WDIS# */
+                       MX8MP_IOMUXC_NAND_DATA00__GPIO3_IO06    0x40000040 /* M2SKT_RST# */
+                       MX8MP_IOMUXC_SAI1_TXD6__GPIO4_IO18      0x40000150 /* M2SKT_WDIS# */
+                       MX8MP_IOMUXC_NAND_ALE__GPIO3_IO00       0x40000150 /* M2SKT_GDIS# */
                        MX8MP_IOMUXC_SAI3_TXD__GPIO5_IO01       0x40000104 /* UART_TERM */
                        MX8MP_IOMUXC_SAI3_TXFS__GPIO4_IO31      0x40000104 /* UART_RS485 */
                        MX8MP_IOMUXC_SAI3_TXC__GPIO5_IO00       0x40000104 /* UART_HALF */
 
        pinctrl_accel: accelgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07     0x159
+                       MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07     0x150
                >;
        };
 
        pinctrl_eqos: eqosgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x3
-                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x3
-                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0               0x91
-                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1               0x91
-                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2               0x91
-                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3               0x91
-                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x91
-                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL         0x91
-                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0               0x1f
-                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1               0x1f
-                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2               0x1f
-                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3               0x1f
-                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL         0x1f
-                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x1f
-                       MX8MP_IOMUXC_SAI3_RXD__GPIO4_IO30               0x141 /* RST# */
-                       MX8MP_IOMUXC_SAI3_RXFS__GPIO4_IO28              0x159 /* IRQ# */
+                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x2
+                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x2
+                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0               0x90
+                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1               0x90
+                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2               0x90
+                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3               0x90
+                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x90
+                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL         0x90
+                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0               0x16
+                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1               0x16
+                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2               0x16
+                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3               0x16
+                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL         0x16
+                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x16
+                       MX8MP_IOMUXC_SAI3_RXD__GPIO4_IO30               0x140 /* RST# */
+                       MX8MP_IOMUXC_SAI3_RXFS__GPIO4_IO28              0x150 /* IRQ# */
                >;
        };
 
        pinctrl_fec: fecgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0         0x91
-                       MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1         0x91
-                       MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2         0x91
-                       MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3         0x91
-                       MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC          0x91
-                       MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL      0x91
-                       MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL      0x1f
-                       MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC         0x1f
-                       MX8MP_IOMUXC_SAI1_RXFS__ENET1_1588_EVENT0_IN    0x141
-                       MX8MP_IOMUXC_SAI1_RXC__ENET1_1588_EVENT0_OUT    0x141
+                       MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0         0x90
+                       MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1         0x90
+                       MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2         0x90
+                       MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3         0x90
+                       MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC          0x90
+                       MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL      0x90
+                       MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0         0x16
+                       MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1         0x16
+                       MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2         0x16
+                       MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3         0x16
+                       MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL      0x16
+                       MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC         0x16
+                       MX8MP_IOMUXC_SAI1_RXFS__ENET1_1588_EVENT0_IN    0x140
+                       MX8MP_IOMUXC_SAI1_RXC__ENET1_1588_EVENT0_OUT    0x140
                >;
        };
 
 
        pinctrl_gsc: gscgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20      0x159
+                       MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20      0x150
                >;
        };
 
        pinctrl_i2c1: i2c1grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c2: i2c2grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c3: i2c3grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c4: i2c4grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C4_SCL__I2C4_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C4_SCL__I2C4_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA         0x400001c2
                >;
        };
 
        pinctrl_ksz: kszgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SAI3_RXC__GPIO4_IO29       0x159 /* IRQ# */
-                       MX8MP_IOMUXC_SAI3_MCLK__GPIO5_IO02      0x141 /* RST# */
+                       MX8MP_IOMUXC_SAI3_RXC__GPIO4_IO29       0x150 /* IRQ# */
+                       MX8MP_IOMUXC_SAI3_MCLK__GPIO5_IO02      0x140 /* RST# */
                >;
        };
 
        pinctrl_gpio_leds: ledgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SD2_DATA0__GPIO2_IO15      0x19
-                       MX8MP_IOMUXC_SD2_DATA1__GPIO2_IO16      0x19
+                       MX8MP_IOMUXC_SD2_DATA0__GPIO2_IO15      0x10
+                       MX8MP_IOMUXC_SD2_DATA1__GPIO2_IO16      0x10
                >;
        };
 
        pinctrl_pmic: pmicgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_NAND_DATA01__GPIO3_IO07    0x141
+                       MX8MP_IOMUXC_NAND_DATA01__GPIO3_IO07    0x140
                >;
        };
 
        pinctrl_pps: ppsgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12     0x141
+                       MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12     0x140
                >;
        };
 
 
        pinctrl_reg_usb2: regusb2grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06     0x141
+                       MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06     0x140
                >;
        };
 
        pinctrl_reg_wifi: regwifigrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_NAND_DATA03__GPIO3_IO09    0x119
+                       MX8MP_IOMUXC_NAND_DATA03__GPIO3_IO09    0x110
                >;
        };
 
 
        pinctrl_uart3_gpio: uart3gpiogrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_NAND_DATA02__GPIO3_IO08    0x119
+                       MX8MP_IOMUXC_NAND_DATA02__GPIO3_IO08    0x110
                >;
        };
 
index d9542dfff83fba7888c8477d270114b8542df639..410d0d5e6f1e524a5d0d5ffd974db6f953e2f9ac 100644 (file)
                                        pgc_ispdwp: power-domain@18 {
                                                #power-domain-cells = <0>;
                                                reg = <IMX8MP_POWER_DOMAIN_MEDIAMIX_ISPDWP>;
-                                               clocks = <&clk IMX8MP_CLK_MEDIA_ISP_DIV>;
+                                               clocks = <&clk IMX8MP_CLK_MEDIA_ISP_ROOT>;
                                        };
                                };
                        };
index 3b0cc85d66742a4510ab18b2e7c05bff89f737f5..71e373b11de9d8bb990c852aa28469653100f43e 100644 (file)
@@ -74,7 +74,7 @@
                vdd_l17_29-supply = <&vph_pwr>;
                vdd_l20_21-supply = <&vph_pwr>;
                vdd_l25-supply = <&pm8994_s5>;
-               vdd_lvs1_2 = <&pm8994_s4>;
+               vdd_lvs1_2-supply = <&pm8994_s4>;
 
                /* S1, S2, S6 and S12 are managed by RPMPD */
 
index 7748b745a5df527e613bb3ca76c56552648acfc6..afa91ca9a3dcd423b6e8b6cba5bb3745735536c5 100644 (file)
                vdd_l17_29-supply = <&vph_pwr>;
                vdd_l20_21-supply = <&vph_pwr>;
                vdd_l25-supply = <&pm8994_s5>;
-               vdd_lvs1_2 = <&pm8994_s4>;
+               vdd_lvs1_2-supply = <&pm8994_s4>;
 
                /* S1, S2, S6 and S12 are managed by RPMPD */
 
index 0318d42c573649d2c8e56a3bd0d1c906697165c8..1ac2913b182ccdfb45cef036314ec87c8c400914 100644 (file)
                CPU6: cpu@102 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a57";
-                       reg = <0x0 0x101>;
+                       reg = <0x0 0x102>;
                        enable-method = "psci";
                        next-level-cache = <&L2_1>;
                };
                CPU7: cpu@103 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a57";
-                       reg = <0x0 0x101>;
+                       reg = <0x0 0x103>;
                        enable-method = "psci";
                        next-level-cache = <&L2_1>;
                };
index 9b3e3d13c1658d80a517df6773cd7b223496a2a7..d1e2df5164eaab4befb4e741d21b02908f1e9df7 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2021 Google LLC.
  */
 
-#include "sc7180-trogdor.dtsi"
+/* This file must be included after sc7180-trogdor.dtsi */
 
 / {
        /* BOARD-SPECIFIC TOP LEVEL NODES */
index fe2369c29aad2eed665843875575e58c416ae608..88f6a7d4d0203a708fe9a8d0f49eb85139b135cb 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2020 Google LLC.
  */
 
-#include "sc7180-trogdor.dtsi"
+/* This file must be included after sc7180-trogdor.dtsi */
 
 &ap_sar_sensor {
        semtech,cs0-ground;
index 0692ae0e60a42dfce746510e412a1e92afea0269..038538c8c6141686dcb0d6d8dda20afa7ffe052b 100644 (file)
 
                        power-domains = <&dispcc MDSS_GDSC>;
 
-                       clocks = <&gcc GCC_DISP_AHB_CLK>,
+                       clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
                                 <&dispcc DISP_CC_MDSS_MDP_CLK>;
                        clock-names = "iface", "core";
 
index 7d08fad76371734510ac07a32febb0e724fc6ef0..b87756bf1ce4481a6440182df05d362892bc7988 100644 (file)
                        reg = <0x0 0x17100000 0x0 0x10000>,     /* GICD */
                              <0x0 0x17180000 0x0 0x200000>;    /* GICR * 8 */
                        interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       gic_its: msi-controller@17140000 {
+                               compatible = "arm,gic-v3-its";
+                               reg = <0x0 0x17140000 0x0 0x20000>;
+                               msi-controller;
+                               #msi-cells = <1>;
+                       };
                };
 
                timer@17420000 {
 
                        iommus = <&apps_smmu 0xe0 0x0>;
 
-                       interconnects = <&aggre1_noc MASTER_UFS_MEM &mc_virt SLAVE_EBI1>,
-                                       <&gem_noc MASTER_APPSS_PROC &config_noc SLAVE_UFS_MEM_CFG>;
+                       interconnects = <&aggre1_noc MASTER_UFS_MEM 0 &mc_virt SLAVE_EBI1 0>,
+                                       <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_UFS_MEM_CFG 0>;
                        interconnect-names = "ufs-ddr", "cpu-ufs";
                        clock-names =
                                "core_clk",
index 913d845eb51a87a367e97c9e5d7e57c2cbe60940..1977103a5ef44c20074466a589ac037b4b691853 100644 (file)
@@ -376,7 +376,8 @@ camera: &i2c7 {
                <&cru ACLK_VIO>,
                <&cru ACLK_GIC_PRE>,
                <&cru PCLK_DDR>,
-               <&cru ACLK_HDCP>;
+               <&cru ACLK_HDCP>,
+               <&cru ACLK_VDU>;
        assigned-clock-rates =
                <600000000>, <1600000000>,
                <1000000000>,
@@ -388,6 +389,7 @@ camera: &i2c7 {
                <400000000>,
                <200000000>,
                <200000000>,
+               <400000000>,
                <400000000>;
 };
 
index fbd0346624e69cadad2ef15854e55fc2b65289fd..9d5b0e8c9cca72af9630f4e26496b294458bc071 100644 (file)
                        <&cru HCLK_PERILP1>, <&cru PCLK_PERILP1>,
                        <&cru ACLK_VIO>, <&cru ACLK_HDCP>,
                        <&cru ACLK_GIC_PRE>,
-                       <&cru PCLK_DDR>;
+                       <&cru PCLK_DDR>,
+                       <&cru ACLK_VDU>;
                assigned-clock-rates =
                         <594000000>,  <800000000>,
                        <1000000000>,
                         <100000000>,   <50000000>,
                         <400000000>, <400000000>,
                         <200000000>,
-                        <200000000>;
+                        <200000000>,
+                        <400000000>;
        };
 
        grf: syscon@ff770000 {
index 1534e11a9ad17373bb77de632bccc5aaae80f346..fa953b73664218328882b8dd7c559a9afea2f935 100644 (file)
 };
 
 &usb_host0_xhci {
+       dr_mode = "host";
        status = "okay";
 };
 
index 7bdcecc0dfe4b078ba5877df74aabcf3a5782d36..02d5f5a8ca036171f715114212eb9df5b7042d0c 100644 (file)
        assigned-clocks = <&cru SCLK_GMAC1_RX_TX>, <&cru SCLK_GMAC1_RGMII_SPEED>, <&cru SCLK_GMAC1>;
        assigned-clock-parents = <&cru SCLK_GMAC1_RGMII_SPEED>, <&cru SCLK_GMAC1>, <&gmac1_clkin>;
        clock_in_out = "input";
-       phy-mode = "rgmii-id";
+       phy-mode = "rgmii";
        phy-supply = <&vcc_3v3>;
        pinctrl-names = "default";
        pinctrl-0 = <&gmac1m1_miim
index 3498e65f59f8eb15e45b24d8dfa9844d4b4cf940..702861c6887486adf5166646541a7e626dd2cbe6 100644 (file)
@@ -4,21 +4,6 @@
 #define __ASM_CSKY_TLB_H
 
 #include <asm/cacheflush.h>
-
-#define tlb_start_vma(tlb, vma) \
-       do { \
-               if (!(tlb)->fullmm) \
-                       flush_cache_range(vma, (vma)->vm_start, (vma)->vm_end); \
-       }  while (0)
-
-#define tlb_end_vma(tlb, vma) \
-       do { \
-               if (!(tlb)->fullmm) \
-                       flush_tlb_range(vma, (vma)->vm_start, (vma)->vm_end); \
-       }  while (0)
-
-#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
-
 #include <asm-generic/tlb.h>
 
 #endif /* __ASM_CSKY_TLB_H */
index 1920d52653b4150571d8551b713ae1ed4a9b4b69..b57daee98b89c0988f200b7d0217350d939fb1f2 100644 (file)
@@ -54,7 +54,6 @@ config LOONGARCH
        select GENERIC_CMOS_UPDATE
        select GENERIC_CPU_AUTOPROBE
        select GENERIC_ENTRY
-       select GENERIC_FIND_FIRST_BIT
        select GENERIC_GETTIMEOFDAY
        select GENERIC_IRQ_MULTI_HANDLER
        select GENERIC_IRQ_PROBE
@@ -77,7 +76,6 @@ config LOONGARCH
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE
        select HAVE_ASM_MODVERSIONS
        select HAVE_CONTEXT_TRACKING
-       select HAVE_COPY_THREAD_TLS
        select HAVE_DEBUG_STACKOVERFLOW
        select HAVE_DMA_CONTIGUOUS
        select HAVE_EXIT_THREAD
@@ -86,8 +84,6 @@ config LOONGARCH
        select HAVE_IOREMAP_PROT
        select HAVE_IRQ_EXIT_ON_IRQ_STACK
        select HAVE_IRQ_TIME_ACCOUNTING
-       select HAVE_MEMBLOCK
-       select HAVE_MEMBLOCK_NODE_MAP
        select HAVE_MOD_ARCH_SPECIFIC
        select HAVE_NMI
        select HAVE_PERF_EVENTS
@@ -112,6 +108,7 @@ config LOONGARCH
        select TRACE_IRQFLAGS_SUPPORT
        select USE_PERCPU_NUMA_NODE_ID
        select ZONE_DMA32
+       select MMU_GATHER_MERGE_VMAS if MMU
 
 config 32BIT
        bool
index adb16e4b43b01911a04fc248b20689c3073994ff..b6be527831dd9cc057215b39847470242a23019c 100644 (file)
@@ -48,6 +48,5 @@
 #define fcsr1  $r1
 #define fcsr2  $r2
 #define fcsr3  $r3
-#define vcsr16 $r16
 
 #endif /* _ASM_FPREGDEF_H */
index 3dba4986f6c92eed4deba1da2ac286c993990527..dc47fc724fa17efd661b122f557d10951ddebc83 100644 (file)
@@ -6,6 +6,7 @@
 #define _ASM_PAGE_H
 
 #include <linux/const.h>
+#include <asm/addrspace.h>
 
 /*
  * PAGE_SHIFT determines the page size
index 1d63c934b289c14cc6d7c0932ba799ee5a0321ed..57ec45aa078ec06f0e04a97a80cbe850a1e18c26 100644 (file)
@@ -80,7 +80,6 @@ BUILD_FPR_ACCESS(64)
 
 struct loongarch_fpu {
        unsigned int    fcsr;
-       unsigned int    vcsr;
        uint64_t        fcc;    /* 8x8 */
        union fpureg    fpr[NUM_FPU_REGS];
 };
@@ -161,7 +160,6 @@ struct thread_struct {
         */                                                     \
        .fpu                    = {                             \
                .fcsr           = 0,                            \
-               .vcsr           = 0,                            \
                .fcc            = 0,                            \
                .fpr            = {{{0,},},},                   \
        },                                                      \
index 4f629ae9d5a9d0609d63e9140bdef3acb75862d6..dd24f5898f651cf9e264c9d6bf23fc8e3190e3ac 100644 (file)
@@ -137,16 +137,6 @@ static inline void invtlb_all(u32 op, u32 info, u64 addr)
                );
 }
 
-/*
- * LoongArch doesn't need any special per-pte or per-vma handling, except
- * we need to flush cache for area to be unmapped.
- */
-#define tlb_start_vma(tlb, vma)                                        \
-       do {                                                    \
-               if (!(tlb)->fullmm)                             \
-                       flush_cache_range(vma, vma->vm_start, vma->vm_end); \
-       }  while (0)
-#define tlb_end_vma(tlb, vma) do { } while (0)
 #define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0)
 
 static void tlb_flush(struct mmu_gather *tlb);
index bfb65eb2844f501b9ceb297fe9c0d4377e65079b..20cd9e16a95abb7b7677e2cfd8dc3f34212ae58d 100644 (file)
@@ -166,7 +166,6 @@ void output_thread_fpu_defines(void)
 
        OFFSET(THREAD_FCSR, loongarch_fpu, fcsr);
        OFFSET(THREAD_FCC,  loongarch_fpu, fcc);
-       OFFSET(THREAD_VCSR, loongarch_fpu, vcsr);
        BLANK();
 }
 
index 75c6ce0682a2411b345c467280f9fdc0f30d19f9..a631a7137667bfce45c6adfdc2666c180abb0b0b 100644 (file)
        movgr2fcsr      fcsr0, \tmp0
        .endm
 
-       .macro sc_save_vcsr base, tmp0
-       movfcsr2gr      \tmp0, vcsr16
-       EX      st.w \tmp0, \base, 0
-       .endm
-
-       .macro sc_restore_vcsr base, tmp0
-       EX      ld.w \tmp0, \base, 0
-       movgr2fcsr      vcsr16, \tmp0
-       .endm
-
 /*
  * Save a thread's fp context.
  */
index a76f547a5aa3a84911c50a38bdc0c2bf3b162f50..a13f92593cfdad89294abe8d37582b40c2c12954 100644 (file)
@@ -429,7 +429,6 @@ int __init init_numa_memory(void)
        return 0;
 }
 
-EXPORT_SYMBOL(init_numa_memory);
 #endif
 
 void __init paging_init(void)
index 6b6e16732c603fc09a4e61232b4bc14f207275ab..92e40403225783256ae816584c5abba19c32bcb3 100644 (file)
@@ -21,6 +21,7 @@ ccflags-vdso += $(filter --target=%,$(KBUILD_CFLAGS))
 endif
 
 cflags-vdso := $(ccflags-vdso) \
+       -isystem $(shell $(CC) -print-file-name=include) \
        $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
        -O2 -g -fno-strict-aliasing -fno-common -fno-builtin -G0 \
        -fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \
index 8ae15c2c18459eb08541998a07eaaabf4df7ea81..c6ad6f867a6a8f3e7b792180e67a8a030bebd758 100644 (file)
@@ -25,7 +25,7 @@ struct or1k_frameinfo {
 /*
  * Verify a frameinfo structure.  The return address should be a valid text
  * address.  The frame pointer may be null if its the last frame, otherwise
- * the frame pointer should point to a location in the stack after the the
+ * the frame pointer should point to a location in the stack after the
  * top of the next frame up.
  */
 static inline int or1k_frameinfo_valid(struct or1k_frameinfo *frameinfo)
index 7aa12e88c5800df99123852f15c09e3054951e2e..c235648fae23afd14393a24859927b52012a7ee9 100644 (file)
@@ -256,6 +256,7 @@ config PPC
        select IRQ_FORCED_THREADING
        select MMU_GATHER_PAGE_SIZE
        select MMU_GATHER_RCU_TABLE_FREE
+       select MMU_GATHER_MERGE_VMAS
        select MODULES_USE_ELF_RELA
        select NEED_DMA_MAP_STATE               if PPC64 || NOT_COHERENT_CACHE
        select NEED_PER_CPU_EMBED_FIRST_CHUNK   if PPC64
index 09a9ae5f3656173698fe941a0523cf7e195b392e..b3de6102a90779739a598d9784ab9b55ab6e1ee0 100644 (file)
@@ -19,8 +19,6 @@
 
 #include <linux/pagemap.h>
 
-#define tlb_start_vma(tlb, vma)        do { } while (0)
-#define tlb_end_vma(tlb, vma)  do { } while (0)
 #define __tlb_remove_tlb_entry __tlb_remove_tlb_entry
 
 #define tlb_flush tlb_flush
index 463c78c52cc5deb08c365bd62ff0d974375c8b2a..3805ad13b8f3d52a5899e1bf49d1433c2ecd5839 100644 (file)
@@ -176,12 +176,8 @@ static int __init pnv_get_random_long_early(unsigned long *v)
                    NULL) != pnv_get_random_long_early)
                return 0;
 
-       for_each_compatible_node(dn, NULL, "ibm,power-rng") {
-               if (rng_create(dn))
-                       continue;
-               /* Create devices for hwrng driver */
-               of_platform_device_create(dn, NULL, NULL);
-       }
+       for_each_compatible_node(dn, NULL, "ibm,power-rng")
+               rng_create(dn);
 
        if (!ppc_md.get_random_seed)
                return 0;
@@ -205,10 +201,18 @@ void __init pnv_rng_init(void)
 
 static int __init pnv_rng_late_init(void)
 {
+       struct device_node *dn;
        unsigned long v;
+
        /* In case it wasn't called during init for some other reason. */
        if (ppc_md.get_random_seed == pnv_get_random_long_early)
                pnv_get_random_long_early(&v);
+
+       if (ppc_md.get_random_seed == powernv_get_random_long) {
+               for_each_compatible_node(dn, NULL, "ibm,power-rng")
+                       of_platform_device_create(dn, NULL, NULL);
+       }
+
        return 0;
 }
 machine_subsys_initcall(powernv, pnv_rng_late_init);
index 32ffef9f6e5b4f116034fb1c65388e80d082c361..fcbb81feb7ad82588d6c57d811bfd5cfc2d6831d 100644 (file)
@@ -38,7 +38,7 @@ config RISCV
        select ARCH_SUPPORTS_ATOMIC_RMW
        select ARCH_SUPPORTS_DEBUG_PAGEALLOC if MMU
        select ARCH_SUPPORTS_HUGETLBFS if MMU
-       select ARCH_SUPPORTS_PAGE_TABLE_CHECK
+       select ARCH_SUPPORTS_PAGE_TABLE_CHECK if MMU
        select ARCH_USE_MEMTEST
        select ARCH_USE_QUEUED_RWLOCKS
        select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU
index 34cf8a598617b8cd0585d31a2068c1a97b8b8069..a4c46a03d2e26109eb4d74ab6c08d0f3d7bb9e16 100644 (file)
@@ -73,6 +73,7 @@ ifeq ($(CONFIG_PERF_EVENTS),y)
 endif
 
 KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-relax)
+KBUILD_AFLAGS_MODULE += $(call as-option,-Wa$(comma)-mno-relax)
 
 # GCC versions that support the "-mstrict-align" option default to allowing
 # unaligned accesses.  While unaligned accesses are explicitly allowed in the
index 039b92abf046c29c70eec876494ae0f8ffdfaebb..f72540bd14a3be3f05222d5f0bacc31b5f3f6f44 100644 (file)
@@ -35,7 +35,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               key0 {
+               key {
                        label = "KEY0";
                        linux,code = <BTN_0>;
                        gpios = <&gpio0 10 GPIO_ACTIVE_LOW>;
index b9e30df127fefedf8cf9203733fa09d83babbebb..8abdbe26a1d098583f99b4e87116b5dbc6acf45b 100644 (file)
@@ -47,7 +47,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               boot {
+               key-boot {
                        label = "BOOT";
                        linux,code = <BTN_0>;
                        gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
index 8d23401b0bbb6bcadbc293f45fc9247cbac5586b..3c6df1ecf76fd7f3534fdc557837ffad5e2ad1f1 100644 (file)
@@ -52,7 +52,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               boot {
+               key-boot {
                        label = "BOOT";
                        linux,code = <BTN_0>;
                        gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
index 24fd83b43d9d546e7f673333b61892f68d78457b..03c9843d503e6fc23cd3196c82aae6a96164a543 100644 (file)
        gpio-keys {
                compatible = "gpio-keys";
 
-               up {
+               key-up {
                        label = "UP";
                        linux,code = <BTN_1>;
                        gpios = <&gpio1_0 7 GPIO_ACTIVE_LOW>;
                };
 
-               press {
+               key-press {
                        label = "PRESS";
                        linux,code = <BTN_0>;
                        gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
                };
 
-               down {
+               key-down {
                        label = "DOWN";
                        linux,code = <BTN_2>;
                        gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
index 25341f38292aabf66a2a0b2b1ec70dffc5e004f8..7164ad06317812d7ee53fc81871345b98e69a77b 100644 (file)
@@ -23,7 +23,7 @@
        gpio-keys {
                compatible = "gpio-keys";
 
-               boot {
+               key-boot {
                        label = "BOOT";
                        linux,code = <BTN_0>;
                        gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
index 3095d08453a1150c259e6d98998e9a4cac4d0926..496d3b7642bd13abe4b5b4591fb92aea3bc50999 100644 (file)
@@ -50,6 +50,7 @@
                        riscv,isa = "rv64imafdc";
                        clocks = <&clkcfg CLK_CPU>;
                        tlb-split;
+                       next-level-cache = <&cctrllr>;
                        status = "okay";
 
                        cpu1_intc: interrupt-controller {
@@ -77,6 +78,7 @@
                        riscv,isa = "rv64imafdc";
                        clocks = <&clkcfg CLK_CPU>;
                        tlb-split;
+                       next-level-cache = <&cctrllr>;
                        status = "okay";
 
                        cpu2_intc: interrupt-controller {
                        riscv,isa = "rv64imafdc";
                        clocks = <&clkcfg CLK_CPU>;
                        tlb-split;
+                       next-level-cache = <&cctrllr>;
                        status = "okay";
 
                        cpu3_intc: interrupt-controller {
                        riscv,isa = "rv64imafdc";
                        clocks = <&clkcfg CLK_CPU>;
                        tlb-split;
+                       next-level-cache = <&cctrllr>;
                        status = "okay";
                        cpu4_intc: interrupt-controller {
                                #interrupt-cells = <1>;
index 672f02b21ce02de7a758a11b68955ed1c036f067..1031038423e748a79ee4919bfad45cb3592172aa 100644 (file)
@@ -111,6 +111,7 @@ void __init_or_module sifive_errata_patch_func(struct alt_entry *begin,
                        cpu_apply_errata |= tmp;
                }
        }
-       if (cpu_apply_errata != cpu_req_errata)
+       if (stage != RISCV_ALTERNATIVES_MODULE &&
+           cpu_apply_errata != cpu_req_errata)
                warn_miss_errata(cpu_req_errata - cpu_apply_errata);
 }
index 5c2aba5efbd0ecf4ff302af06f016e3fa55b36bf..dc42375c2357136356df1ca7f42480eeea98a3dc 100644 (file)
@@ -175,7 +175,7 @@ static inline pud_t pfn_pud(unsigned long pfn, pgprot_t prot)
 
 static inline unsigned long _pud_pfn(pud_t pud)
 {
-       return pud_val(pud) >> _PAGE_PFN_SHIFT;
+       return __page_val_to_pfn(pud_val(pud));
 }
 
 static inline pmd_t *pud_pgtable(pud_t pud)
@@ -278,13 +278,13 @@ static inline p4d_t pfn_p4d(unsigned long pfn, pgprot_t prot)
 
 static inline unsigned long _p4d_pfn(p4d_t p4d)
 {
-       return p4d_val(p4d) >> _PAGE_PFN_SHIFT;
+       return __page_val_to_pfn(p4d_val(p4d));
 }
 
 static inline pud_t *p4d_pgtable(p4d_t p4d)
 {
        if (pgtable_l4_enabled)
-               return (pud_t *)pfn_to_virt(p4d_val(p4d) >> _PAGE_PFN_SHIFT);
+               return (pud_t *)pfn_to_virt(__page_val_to_pfn(p4d_val(p4d)));
 
        return (pud_t *)pud_pgtable((pud_t) { p4d_val(p4d) });
 }
@@ -292,7 +292,7 @@ static inline pud_t *p4d_pgtable(p4d_t p4d)
 
 static inline struct page *p4d_page(p4d_t p4d)
 {
-       return pfn_to_page(p4d_val(p4d) >> _PAGE_PFN_SHIFT);
+       return pfn_to_page(__page_val_to_pfn(p4d_val(p4d)));
 }
 
 #define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
@@ -347,7 +347,7 @@ static inline void pgd_clear(pgd_t *pgd)
 static inline p4d_t *pgd_pgtable(pgd_t pgd)
 {
        if (pgtable_l5_enabled)
-               return (p4d_t *)pfn_to_virt(pgd_val(pgd) >> _PAGE_PFN_SHIFT);
+               return (p4d_t *)pfn_to_virt(__page_val_to_pfn(pgd_val(pgd)));
 
        return (p4d_t *)p4d_pgtable((p4d_t) { pgd_val(pgd) });
 }
@@ -355,7 +355,7 @@ static inline p4d_t *pgd_pgtable(pgd_t pgd)
 
 static inline struct page *pgd_page(pgd_t pgd)
 {
-       return pfn_to_page(pgd_val(pgd) >> _PAGE_PFN_SHIFT);
+       return pfn_to_page(__page_val_to_pfn(pgd_val(pgd)));
 }
 #define pgd_page(pgd)  pgd_page(pgd)
 
index 1d1be9d9419c1287a7b4ede8670e488408dae2b1..5dbd6610729bbf00ecbceee32d0dc9b55e7f107c 100644 (file)
@@ -261,7 +261,7 @@ static inline pgd_t pfn_pgd(unsigned long pfn, pgprot_t prot)
 
 static inline unsigned long _pgd_pfn(pgd_t pgd)
 {
-       return pgd_val(pgd) >> _PAGE_PFN_SHIFT;
+       return __page_val_to_pfn(pgd_val(pgd));
 }
 
 static inline struct page *pmd_page(pmd_t pmd)
@@ -590,14 +590,14 @@ static inline pmd_t pmd_mkinvalid(pmd_t pmd)
        return __pmd(pmd_val(pmd) & ~(_PAGE_PRESENT|_PAGE_PROT_NONE));
 }
 
-#define __pmd_to_phys(pmd)  (pmd_val(pmd) >> _PAGE_PFN_SHIFT << PAGE_SHIFT)
+#define __pmd_to_phys(pmd)  (__page_val_to_pfn(pmd_val(pmd)) << PAGE_SHIFT)
 
 static inline unsigned long pmd_pfn(pmd_t pmd)
 {
        return ((__pmd_to_phys(pmd) & PMD_MASK) >> PAGE_SHIFT);
 }
 
-#define __pud_to_phys(pud)  (pud_val(pud) >> _PAGE_PFN_SHIFT << PAGE_SHIFT)
+#define __pud_to_phys(pud)  (__page_val_to_pfn(pud_val(pud)) << PAGE_SHIFT)
 
 static inline unsigned long pud_pfn(pud_t pud)
 {
index c71d6591d53988d1565b2688dd7311fbab5c3b99..33bb60a354cd20633fd40cd8b5faa01c407d3814 100644 (file)
@@ -78,7 +78,7 @@ obj-$(CONFIG_SMP) += cpu_ops_sbi.o
 endif
 obj-$(CONFIG_HOTPLUG_CPU)      += cpu-hotplug.o
 obj-$(CONFIG_KGDB)             += kgdb.o
-obj-$(CONFIG_KEXEC)            += kexec_relocate.o crash_save_regs.o machine_kexec.o
+obj-$(CONFIG_KEXEC_CORE)       += kexec_relocate.o crash_save_regs.o machine_kexec.o
 obj-$(CONFIG_KEXEC_FILE)       += elf_kexec.o machine_kexec_file.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
 
index 9cb85095fd459fb5e9cea5d1d6e62e8c4b076128..0cb94992c15b32a852716ca877d95b5f14f63c6f 100644 (file)
@@ -349,7 +349,7 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
 {
        const char *strtab, *name, *shstrtab;
        const Elf_Shdr *sechdrs;
-       Elf_Rela *relas;
+       Elf64_Rela *relas;
        int i, r_type;
 
        /* String & section header string table */
index 1c00695ebee7ee1d41d36e6cff40322efa3a3f99..9826073fbc67d3c4a03390db49f7edf3eb25a542 100644 (file)
@@ -54,7 +54,7 @@ static inline unsigned long gstage_pte_index(gpa_t addr, u32 level)
 
 static inline unsigned long gstage_pte_page_vaddr(pte_t pte)
 {
-       return (unsigned long)pfn_to_virt(pte_val(pte) >> _PAGE_PFN_SHIFT);
+       return (unsigned long)pfn_to_virt(__page_val_to_pfn(pte_val(pte)));
 }
 
 static int gstage_page_size_to_level(unsigned long page_size, u32 *out_level)
index 7f4ad5e4373a9d72a9f1cd6acb962a4a929c9f9c..f3455dc013fa0cd8dfefd7a7116477c510985cf7 100644 (file)
@@ -781,9 +781,11 @@ static void kvm_riscv_check_vcpu_requests(struct kvm_vcpu *vcpu)
 
        if (kvm_request_pending(vcpu)) {
                if (kvm_check_request(KVM_REQ_SLEEP, vcpu)) {
+                       kvm_vcpu_srcu_read_unlock(vcpu);
                        rcuwait_wait_event(wait,
                                (!vcpu->arch.power_off) && (!vcpu->arch.pause),
                                TASK_INTERRUPTIBLE);
+                       kvm_vcpu_srcu_read_lock(vcpu);
 
                        if (vcpu->arch.power_off || vcpu->arch.pause) {
                                /*
index 8cd9e56c629ba8c374ab9cd0c0117663809cbd27..5a1a8dfda6f8e5d0ee45acd83574187c2661cf8d 100644 (file)
@@ -204,6 +204,7 @@ config S390
        select IOMMU_SUPPORT            if PCI
        select MMU_GATHER_NO_GATHER
        select MMU_GATHER_RCU_TABLE_FREE
+       select MMU_GATHER_MERGE_VMAS
        select MODULES_USE_ELF_RELA
        select NEED_DMA_MAP_STATE       if PCI
        select NEED_SG_DMA_LENGTH       if PCI
index 495c68a4df1e9d25b98ae194d3c1095d3d29c65e..4cb5d17e7ead620ee1a84db0347cf68f18a009c9 100644 (file)
@@ -82,7 +82,7 @@ endif
 
 ifdef CONFIG_EXPOLINE
   ifdef CONFIG_EXPOLINE_EXTERN
-    KBUILD_LDFLAGS_MODULE += arch/s390/lib/expoline.o
+    KBUILD_LDFLAGS_MODULE += arch/s390/lib/expoline/expoline.o
     CC_FLAGS_EXPOLINE := -mindirect-branch=thunk-extern
     CC_FLAGS_EXPOLINE += -mfunction-return=thunk-extern
   else
@@ -163,6 +163,12 @@ vdso_prepare: prepare0
        $(Q)$(MAKE) $(build)=arch/s390/kernel/vdso64 include/generated/vdso64-offsets.h
        $(if $(CONFIG_COMPAT),$(Q)$(MAKE) \
                $(build)=arch/s390/kernel/vdso32 include/generated/vdso32-offsets.h)
+
+ifdef CONFIG_EXPOLINE_EXTERN
+modules_prepare: expoline_prepare
+expoline_prepare:
+       $(Q)$(MAKE) $(build)=arch/s390/lib/expoline arch/s390/lib/expoline/expoline.o
+endif
 endif
 
 # Don't use tabs in echo arguments
index d910d71b5bb50e72df5def006d748ee2b23614cb..7e9e99523e952517a55859651fd36ea3ccb12f5d 100644 (file)
@@ -2,8 +2,6 @@
 #ifndef _ASM_S390_NOSPEC_ASM_H
 #define _ASM_S390_NOSPEC_ASM_H
 
-#include <asm/alternative-asm.h>
-#include <asm/asm-offsets.h>
 #include <asm/dwarf.h>
 
 #ifdef __ASSEMBLY__
index fe6407f0eb1b7e4ef4a51e67c446ce20de96985e..3a5c8fb590e55ddfda72e6908ced1f4626e2c7c0 100644 (file)
@@ -27,9 +27,6 @@ static inline void tlb_flush(struct mmu_gather *tlb);
 static inline bool __tlb_remove_page_size(struct mmu_gather *tlb,
                                          struct page *page, int page_size);
 
-#define tlb_start_vma(tlb, vma)                        do { } while (0)
-#define tlb_end_vma(tlb, vma)                  do { } while (0)
-
 #define tlb_flush tlb_flush
 #define pte_free_tlb pte_free_tlb
 #define pmd_free_tlb pmd_free_tlb
index 5d415b3db6d14c626988667d1894d68805213cd1..580d2e3265cb2ce04523064b2c14c76b78ae42db 100644 (file)
@@ -7,7 +7,6 @@ lib-y += delay.o string.o uaccess.o find.o spinlock.o
 obj-y += mem.o xor.o
 lib-$(CONFIG_KPROBES) += probes.o
 lib-$(CONFIG_UPROBES) += probes.o
-obj-$(CONFIG_EXPOLINE_EXTERN) += expoline.o
 obj-$(CONFIG_S390_KPROBES_SANITY_TEST) += test_kprobes_s390.o
 test_kprobes_s390-objs += test_kprobes_asm.o test_kprobes.o
 
@@ -22,3 +21,5 @@ 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
+
+obj-$(CONFIG_EXPOLINE_EXTERN) += expoline/
diff --git a/arch/s390/lib/expoline.S b/arch/s390/lib/expoline.S
deleted file mode 100644 (file)
index 92ed840..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-#include <asm/nospec-insn.h>
-#include <linux/linkage.h>
-
-.macro GEN_ALL_BR_THUNK_EXTERN
-       .irp r1,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
-       GEN_BR_THUNK_EXTERN %r\r1
-       .endr
-.endm
-
-GEN_ALL_BR_THUNK_EXTERN
diff --git a/arch/s390/lib/expoline/Makefile b/arch/s390/lib/expoline/Makefile
new file mode 100644 (file)
index 0000000..854631d
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y += expoline.o
diff --git a/arch/s390/lib/expoline/expoline.S b/arch/s390/lib/expoline/expoline.S
new file mode 100644 (file)
index 0000000..92ed840
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <asm/nospec-insn.h>
+#include <linux/linkage.h>
+
+.macro GEN_ALL_BR_THUNK_EXTERN
+       .irp r1,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+       GEN_BR_THUNK_EXTERN %r\r1
+       .endr
+.endm
+
+GEN_ALL_BR_THUNK_EXTERN
index cf9a3ec32406f856181af0eff2908fa4e00a0b96..fba90e670ed41d4821a45edeac6649936d85419e 100644 (file)
@@ -271,8 +271,12 @@ static inline void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size,
 #endif /* CONFIG_HAVE_IOREMAP_PROT */
 
 #else /* CONFIG_MMU */
-#define iounmap(addr)          do { } while (0)
-#define ioremap(offset, size)  ((void __iomem *)(unsigned long)(offset))
+static inline void __iomem *ioremap(phys_addr_t offset, size_t size)
+{
+       return (void __iomem *)(unsigned long)offset;
+}
+
+static inline void iounmap(volatile void __iomem *addr) { }
 #endif /* CONFIG_MMU */
 
 #define ioremap_uc     ioremap
index ba449c47effd8d975abf2f1130acef46e46662f9..4f7d1dfbc6086fbd01620e14ae76340c70984c92 100644 (file)
@@ -67,6 +67,8 @@ config SPARC64
        select HAVE_KRETPROBES
        select HAVE_KPROBES
        select MMU_GATHER_RCU_TABLE_FREE if SMP
+       select MMU_GATHER_MERGE_VMAS
+       select MMU_GATHER_NO_FLUSH_CACHE
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE
        select HAVE_DYNAMIC_FTRACE
        select HAVE_FTRACE_MCOUNT_RECORD
index 779a5a0f06080216cc0ce5ce30ca638b365b3b3d..3037187482db7ebe3334f99cb3e4e7af095933b7 100644 (file)
@@ -22,8 +22,6 @@ void smp_flush_tlb_mm(struct mm_struct *mm);
 void __flush_tlb_pending(unsigned long, unsigned long, unsigned long *);
 void flush_tlb_pending(void);
 
-#define tlb_start_vma(tlb, vma) do { } while (0)
-#define tlb_end_vma(tlb, vma)  do { } while (0)
 #define tlb_flush(tlb) flush_tlb_pending()
 
 /*
index 95af12e82a328448ce122a4eb81996d26bd1cb02..cdbd9653aa14e5b29ffba30d98a2741de6bc31aa 100644 (file)
@@ -102,8 +102,8 @@ extern unsigned long uml_physmem;
  * casting is the right thing, but 32-bit UML can't have 64-bit virtual
  * addresses
  */
-#define __pa(virt) to_phys((void *) (unsigned long) (virt))
-#define __va(phys) to_virt((unsigned long) (phys))
+#define __pa(virt) uml_to_phys((void *) (unsigned long) (virt))
+#define __va(phys) uml_to_virt((unsigned long) (phys))
 
 #define phys_to_pfn(p) ((p) >> PAGE_SHIFT)
 #define pfn_to_phys(pfn) PFN_PHYS(pfn)
index 4862c91d4213c4f6d1c1e9430ca902e080aae0a2..98aacd54410801551d3b887e1181a9e7b0f7429f 100644 (file)
@@ -9,12 +9,12 @@
 extern int phys_mapping(unsigned long phys, unsigned long long *offset_out);
 
 extern unsigned long uml_physmem;
-static inline unsigned long to_phys(void *virt)
+static inline unsigned long uml_to_phys(void *virt)
 {
        return(((unsigned long) virt) - uml_physmem);
 }
 
-static inline void *to_virt(unsigned long phys)
+static inline void *uml_to_virt(unsigned long phys)
 {
        return((void *) uml_physmem + phys);
 }
index 0760e24f2ebabf38465c70275d6f2cda1cd35332..9838967d0b2f1032d8dd00f69394b21b141eef8c 100644 (file)
@@ -432,6 +432,10 @@ void apply_retpolines(s32 *start, s32 *end)
 {
 }
 
+void apply_returns(s32 *start, s32 *end)
+{
+}
+
 void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
 {
 }
index 87d3129e7362ef25659c3a3245dfcbc8e998fc85..c316c993a94918d1b5d2b73a49be2501cc8a609f 100644 (file)
@@ -251,7 +251,7 @@ static int userspace_tramp(void *stack)
        signal(SIGTERM, SIG_DFL);
        signal(SIGWINCH, SIG_IGN);
 
-       fd = phys_mapping(to_phys(__syscall_stub_start), &offset);
+       fd = phys_mapping(uml_to_phys(__syscall_stub_start), &offset);
        addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE,
                      PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
        if (addr == MAP_FAILED) {
@@ -261,7 +261,7 @@ static int userspace_tramp(void *stack)
        }
 
        if (stack != NULL) {
-               fd = phys_mapping(to_phys(stack), &offset);
+               fd = phys_mapping(uml_to_phys(stack), &offset);
                addr = mmap((void *) STUB_DATA,
                            UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
                            MAP_FIXED | MAP_SHARED, fd, offset);
@@ -534,7 +534,7 @@ int copy_context_skas0(unsigned long new_stack, int pid)
        struct stub_data *data = (struct stub_data *) current_stack;
        struct stub_data *child_data = (struct stub_data *) new_stack;
        unsigned long long new_offset;
-       int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset);
+       int new_fd = phys_mapping(uml_to_phys((void *)new_stack), &new_offset);
 
        /*
         * prepare offset and fd of child's stack as argument for parent's
index be0b95e51df663f94a5c7e4c3fc3965179d26bdc..52a7f91527fe03fb1930d6a7cb7ae76269cacc06 100644 (file)
@@ -245,6 +245,7 @@ config X86
        select HAVE_PERF_REGS
        select HAVE_PERF_USER_STACK_DUMP
        select MMU_GATHER_RCU_TABLE_FREE        if PARAVIRT
+       select MMU_GATHER_MERGE_VMAS
        select HAVE_POSIX_CPU_TIMERS_TASK_WORK
        select HAVE_REGS_AND_STACK_ACCESS_API
        select HAVE_RELIABLE_STACKTRACE         if UNWINDER_ORC || STACK_VALIDATION
@@ -462,29 +463,6 @@ config GOLDFISH
        def_bool y
        depends on X86_GOLDFISH
 
-config RETPOLINE
-       bool "Avoid speculative indirect branches in kernel"
-       select OBJTOOL if HAVE_OBJTOOL
-       default y
-       help
-         Compile kernel with the retpoline compiler options to guard against
-         kernel-to-user data leaks by avoiding speculative indirect
-         branches. Requires a compiler with -mindirect-branch=thunk-extern
-         support for full protection. The kernel may run slower.
-
-config CC_HAS_SLS
-       def_bool $(cc-option,-mharden-sls=all)
-
-config SLS
-       bool "Mitigate Straight-Line-Speculation"
-       depends on CC_HAS_SLS && X86_64
-       select OBJTOOL if HAVE_OBJTOOL
-       default n
-       help
-         Compile the kernel with straight-line-speculation options to guard
-         against straight line speculation. The kernel image might be slightly
-         larger.
-
 config X86_CPU_RESCTRL
        bool "x86 CPU resource control support"
        depends on X86 && (CPU_SUP_INTEL || CPU_SUP_AMD)
@@ -2453,6 +2431,91 @@ source "kernel/livepatch/Kconfig"
 
 endmenu
 
+config CC_HAS_SLS
+       def_bool $(cc-option,-mharden-sls=all)
+
+config CC_HAS_RETURN_THUNK
+       def_bool $(cc-option,-mfunction-return=thunk-extern)
+
+menuconfig SPECULATION_MITIGATIONS
+       bool "Mitigations for speculative execution vulnerabilities"
+       default y
+       help
+         Say Y here to enable options which enable mitigations for
+         speculative execution hardware vulnerabilities.
+
+         If you say N, all mitigations will be disabled. You really
+         should know what you are doing to say so.
+
+if SPECULATION_MITIGATIONS
+
+config PAGE_TABLE_ISOLATION
+       bool "Remove the kernel mapping in user mode"
+       default y
+       depends on (X86_64 || X86_PAE)
+       help
+         This feature reduces the number of hardware side channels by
+         ensuring that the majority of kernel addresses are not mapped
+         into userspace.
+
+         See Documentation/x86/pti.rst for more details.
+
+config RETPOLINE
+       bool "Avoid speculative indirect branches in kernel"
+       select OBJTOOL if HAVE_OBJTOOL
+       default y
+       help
+         Compile kernel with the retpoline compiler options to guard against
+         kernel-to-user data leaks by avoiding speculative indirect
+         branches. Requires a compiler with -mindirect-branch=thunk-extern
+         support for full protection. The kernel may run slower.
+
+config RETHUNK
+       bool "Enable return-thunks"
+       depends on RETPOLINE && CC_HAS_RETURN_THUNK
+       select OBJTOOL if HAVE_OBJTOOL
+       default y if X86_64
+       help
+         Compile the kernel with the return-thunks compiler option to guard
+         against kernel-to-user data leaks by avoiding return speculation.
+         Requires a compiler with -mfunction-return=thunk-extern
+         support for full protection. The kernel may run slower.
+
+config CPU_UNRET_ENTRY
+       bool "Enable UNRET on kernel entry"
+       depends on CPU_SUP_AMD && RETHUNK && X86_64
+       default y
+       help
+         Compile the kernel with support for the retbleed=unret mitigation.
+
+config CPU_IBPB_ENTRY
+       bool "Enable IBPB on kernel entry"
+       depends on CPU_SUP_AMD && X86_64
+       default y
+       help
+         Compile the kernel with support for the retbleed=ibpb mitigation.
+
+config CPU_IBRS_ENTRY
+       bool "Enable IBRS on kernel entry"
+       depends on CPU_SUP_INTEL && X86_64
+       default y
+       help
+         Compile the kernel with support for the spectre_v2=ibrs mitigation.
+         This mitigates both spectre_v2 and retbleed at great cost to
+         performance.
+
+config SLS
+       bool "Mitigate Straight-Line-Speculation"
+       depends on CC_HAS_SLS && X86_64
+       select OBJTOOL if HAVE_OBJTOOL
+       default n
+       help
+         Compile the kernel with straight-line-speculation options to guard
+         against straight line speculation. The kernel image might be slightly
+         larger.
+
+endif
+
 config ARCH_HAS_ADD_PAGES
        def_bool y
        depends on ARCH_ENABLE_MEMORY_HOTPLUG
index a74886aed3495f29b356c3a0c63b3f6c1f8fa8f1..7854685c5f25b7926a6a722af83c134bd6ec6cd5 100644 (file)
@@ -21,6 +21,13 @@ ifdef CONFIG_CC_IS_CLANG
 RETPOLINE_CFLAGS       := -mretpoline-external-thunk
 RETPOLINE_VDSO_CFLAGS  := -mretpoline
 endif
+
+ifdef CONFIG_RETHUNK
+RETHUNK_CFLAGS         := -mfunction-return=thunk-extern
+RETPOLINE_CFLAGS       += $(RETHUNK_CFLAGS)
+endif
+
+export RETHUNK_CFLAGS
 export RETPOLINE_CFLAGS
 export RETPOLINE_VDSO_CFLAGS
 
index 44c350d627c79b4b13e29bfe74cbec1e5c69879f..d4a314cc50d6ee6ecaa7268f59bbb946c71fb916 100644 (file)
@@ -110,6 +110,7 @@ void kernel_add_identity_map(unsigned long start, unsigned long end)
 void initialize_identity_maps(void *rmode)
 {
        unsigned long cmdline;
+       struct setup_data *sd;
 
        /* Exclude the encryption mask from __PHYSICAL_MASK */
        physical_mask &= ~sme_me_mask;
@@ -163,6 +164,18 @@ void initialize_identity_maps(void *rmode)
        cmdline = get_cmd_line_ptr();
        kernel_add_identity_map(cmdline, cmdline + COMMAND_LINE_SIZE);
 
+       /*
+        * Also map the setup_data entries passed via boot_params in case they
+        * need to be accessed by uncompressed kernel via the identity mapping.
+        */
+       sd = (struct setup_data *)boot_params->hdr.setup_data;
+       while (sd) {
+               unsigned long sd_addr = (unsigned long)sd;
+
+               kernel_add_identity_map(sd_addr, sd_addr + sizeof(*sd) + sd->len);
+               sd = (struct setup_data *)sd->next;
+       }
+
        sev_prep_identity_maps(top_level_pgt);
 
        /* Load the new page-table. */
index 7fec5dcf643868aff199f72a839c7f8510309ddb..eeadbd7d92cc55e0b44163278525826a083940e5 100644 (file)
@@ -11,7 +11,7 @@ CFLAGS_REMOVE_common.o                = $(CC_FLAGS_FTRACE)
 
 CFLAGS_common.o                        += -fno-stack-protector
 
-obj-y                          := entry_$(BITS).o thunk_$(BITS).o syscall_$(BITS).o
+obj-y                          := entry.o entry_$(BITS).o thunk_$(BITS).o syscall_$(BITS).o
 obj-y                          += common.o
 
 obj-y                          += vdso/
index 29b36e9e4e741e2e36c69219a25934d0bfa2f4b4..f6907627172ba96d1be4976e65b843f294886327 100644 (file)
@@ -7,6 +7,8 @@
 #include <asm/asm-offsets.h>
 #include <asm/processor-flags.h>
 #include <asm/ptrace-abi.h>
+#include <asm/msr.h>
+#include <asm/nospec-branch.h>
 
 /*
 
@@ -282,6 +284,66 @@ For 32-bit we have the following conventions - kernel is built with
 
 #endif
 
+/*
+ * IBRS kernel mitigation for Spectre_v2.
+ *
+ * Assumes full context is established (PUSH_REGS, CR3 and GS) and it clobbers
+ * the regs it uses (AX, CX, DX). Must be called before the first RET
+ * instruction (NOTE! UNTRAIN_RET includes a RET instruction)
+ *
+ * The optional argument is used to save/restore the current value,
+ * which is used on the paranoid paths.
+ *
+ * Assumes x86_spec_ctrl_{base,current} to have SPEC_CTRL_IBRS set.
+ */
+.macro IBRS_ENTER save_reg
+#ifdef CONFIG_CPU_IBRS_ENTRY
+       ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_KERNEL_IBRS
+       movl    $MSR_IA32_SPEC_CTRL, %ecx
+
+.ifnb \save_reg
+       rdmsr
+       shl     $32, %rdx
+       or      %rdx, %rax
+       mov     %rax, \save_reg
+       test    $SPEC_CTRL_IBRS, %eax
+       jz      .Ldo_wrmsr_\@
+       lfence
+       jmp     .Lend_\@
+.Ldo_wrmsr_\@:
+.endif
+
+       movq    PER_CPU_VAR(x86_spec_ctrl_current), %rdx
+       movl    %edx, %eax
+       shr     $32, %rdx
+       wrmsr
+.Lend_\@:
+#endif
+.endm
+
+/*
+ * Similar to IBRS_ENTER, requires KERNEL GS,CR3 and clobbers (AX, CX, DX)
+ * regs. Must be called after the last RET.
+ */
+.macro IBRS_EXIT save_reg
+#ifdef CONFIG_CPU_IBRS_ENTRY
+       ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_KERNEL_IBRS
+       movl    $MSR_IA32_SPEC_CTRL, %ecx
+
+.ifnb \save_reg
+       mov     \save_reg, %rdx
+.else
+       movq    PER_CPU_VAR(x86_spec_ctrl_current), %rdx
+       andl    $(~SPEC_CTRL_IBRS), %edx
+.endif
+
+       movl    %edx, %eax
+       shr     $32, %rdx
+       wrmsr
+.Lend_\@:
+#endif
+.endm
+
 /*
  * Mitigate Spectre v1 for conditional swapgs code paths.
  *
diff --git a/arch/x86/entry/entry.S b/arch/x86/entry/entry.S
new file mode 100644 (file)
index 0000000..bfb7bcb
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Common place for both 32- and 64-bit entry routines.
+ */
+
+#include <linux/linkage.h>
+#include <asm/export.h>
+#include <asm/msr-index.h>
+
+.pushsection .noinstr.text, "ax"
+
+SYM_FUNC_START(entry_ibpb)
+       movl    $MSR_IA32_PRED_CMD, %ecx
+       movl    $PRED_CMD_IBPB, %eax
+       xorl    %edx, %edx
+       wrmsr
+       RET
+SYM_FUNC_END(entry_ibpb)
+/* For KVM */
+EXPORT_SYMBOL_GPL(entry_ibpb);
+
+.popsection
index 887420844066454f696f60dd78aa69a520580699..e309e7156038935ab92cd025616c5c765e3a5214 100644 (file)
@@ -698,7 +698,6 @@ SYM_CODE_START(__switch_to_asm)
        movl    %ebx, PER_CPU_VAR(__stack_chk_guard)
 #endif
 
-#ifdef CONFIG_RETPOLINE
        /*
         * When switching from a shallower to a deeper call stack
         * the RSB may either underflow or use entries populated
@@ -707,7 +706,6 @@ SYM_CODE_START(__switch_to_asm)
         * speculative execution to prevent attack.
         */
        FILL_RETURN_BUFFER %ebx, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
-#endif
 
        /* Restore flags or the incoming task to restore AC state. */
        popfl
index 4300ba49b5eeace08b31c83247e0e5a6a37f8d35..9953d966d12443115bc7ecb3d5c083c9b5c8847f 100644 (file)
@@ -85,7 +85,7 @@
  */
 
 SYM_CODE_START(entry_SYSCALL_64)
-       UNWIND_HINT_EMPTY
+       UNWIND_HINT_ENTRY
        ENDBR
 
        swapgs
@@ -112,6 +112,11 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL)
        movq    %rsp, %rdi
        /* Sign extend the lower 32bit as syscall numbers are treated as int */
        movslq  %eax, %rsi
+
+       /* clobbers %rax, make sure it is after saving the syscall nr */
+       IBRS_ENTER
+       UNTRAIN_RET
+
        call    do_syscall_64           /* returns with IRQs disabled */
 
        /*
@@ -191,6 +196,7 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL)
         * perf profiles. Nothing jumps here.
         */
 syscall_return_via_sysret:
+       IBRS_EXIT
        POP_REGS pop_rdi=0
 
        /*
@@ -249,7 +255,6 @@ SYM_FUNC_START(__switch_to_asm)
        movq    %rbx, PER_CPU_VAR(fixed_percpu_data) + stack_canary_offset
 #endif
 
-#ifdef CONFIG_RETPOLINE
        /*
         * When switching from a shallower to a deeper call stack
         * the RSB may either underflow or use entries populated
@@ -258,7 +263,6 @@ SYM_FUNC_START(__switch_to_asm)
         * speculative execution to prevent attack.
         */
        FILL_RETURN_BUFFER %r12, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
-#endif
 
        /* restore callee-saved registers */
        popq    %r15
@@ -322,13 +326,13 @@ SYM_CODE_END(ret_from_fork)
 #endif
 .endm
 
-/* Save all registers in pt_regs */
-SYM_CODE_START_LOCAL(push_and_clear_regs)
+SYM_CODE_START_LOCAL(xen_error_entry)
        UNWIND_HINT_FUNC
        PUSH_AND_CLEAR_REGS save_ret=1
        ENCODE_FRAME_POINTER 8
+       UNTRAIN_RET
        RET
-SYM_CODE_END(push_and_clear_regs)
+SYM_CODE_END(xen_error_entry)
 
 /**
  * idtentry_body - Macro to emit code calling the C function
@@ -337,9 +341,6 @@ SYM_CODE_END(push_and_clear_regs)
  */
 .macro idtentry_body cfunc has_error_code:req
 
-       call push_and_clear_regs
-       UNWIND_HINT_REGS
-
        /*
         * Call error_entry() and switch to the task stack if from userspace.
         *
@@ -349,7 +350,7 @@ SYM_CODE_END(push_and_clear_regs)
         * switch the CR3.  So it can skip invoking error_entry().
         */
        ALTERNATIVE "call error_entry; movq %rax, %rsp", \
-               "", X86_FEATURE_XENPV
+                   "call xen_error_entry", X86_FEATURE_XENPV
 
        ENCODE_FRAME_POINTER
        UNWIND_HINT_REGS
@@ -612,6 +613,7 @@ __irqentry_text_end:
 
 SYM_CODE_START_LOCAL(common_interrupt_return)
 SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL)
+       IBRS_EXIT
 #ifdef CONFIG_DEBUG_ENTRY
        /* Assert that pt_regs indicates user mode. */
        testb   $3, CS(%rsp)
@@ -897,6 +899,9 @@ SYM_CODE_END(xen_failsafe_callback)
  *              1 -> no SWAPGS on exit
  *
  *     Y        GSBASE value at entry, must be restored in paranoid_exit
+ *
+ * R14 - old CR3
+ * R15 - old SPEC_CTRL
  */
 SYM_CODE_START_LOCAL(paranoid_entry)
        UNWIND_HINT_FUNC
@@ -940,7 +945,7 @@ SYM_CODE_START_LOCAL(paranoid_entry)
         * is needed here.
         */
        SAVE_AND_SET_GSBASE scratch_reg=%rax save_reg=%rbx
-       RET
+       jmp .Lparanoid_gsbase_done
 
 .Lparanoid_entry_checkgs:
        /* EBX = 1 -> kernel GSBASE active, no restore required */
@@ -959,8 +964,16 @@ SYM_CODE_START_LOCAL(paranoid_entry)
        xorl    %ebx, %ebx
        swapgs
 .Lparanoid_kernel_gsbase:
-
        FENCE_SWAPGS_KERNEL_ENTRY
+.Lparanoid_gsbase_done:
+
+       /*
+        * Once we have CR3 and %GS setup save and set SPEC_CTRL. Just like
+        * CR3 above, keep the old value in a callee saved register.
+        */
+       IBRS_ENTER save_reg=%r15
+       UNTRAIN_RET
+
        RET
 SYM_CODE_END(paranoid_entry)
 
@@ -982,9 +995,19 @@ SYM_CODE_END(paranoid_entry)
  *              1 -> no SWAPGS on exit
  *
  *     Y        User space GSBASE, must be restored unconditionally
+ *
+ * R14 - old CR3
+ * R15 - old SPEC_CTRL
  */
 SYM_CODE_START_LOCAL(paranoid_exit)
        UNWIND_HINT_REGS
+
+       /*
+        * Must restore IBRS state before both CR3 and %GS since we need access
+        * to the per-CPU x86_spec_ctrl_shadow variable.
+        */
+       IBRS_EXIT save_reg=%r15
+
        /*
         * The order of operations is important. RESTORE_CR3 requires
         * kernel GSBASE.
@@ -1017,6 +1040,10 @@ SYM_CODE_END(paranoid_exit)
  */
 SYM_CODE_START_LOCAL(error_entry)
        UNWIND_HINT_FUNC
+
+       PUSH_AND_CLEAR_REGS save_ret=1
+       ENCODE_FRAME_POINTER 8
+
        testb   $3, CS+8(%rsp)
        jz      .Lerror_kernelspace
 
@@ -1028,9 +1055,12 @@ SYM_CODE_START_LOCAL(error_entry)
        FENCE_SWAPGS_USER_ENTRY
        /* We have user CR3.  Change to kernel CR3. */
        SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
+       IBRS_ENTER
+       UNTRAIN_RET
 
        leaq    8(%rsp), %rdi                   /* arg0 = pt_regs pointer */
 .Lerror_entry_from_usermode_after_swapgs:
+
        /* Put us onto the real thread stack. */
        call    sync_regs
        RET
@@ -1065,6 +1095,7 @@ SYM_CODE_START_LOCAL(error_entry)
 .Lerror_entry_done_lfence:
        FENCE_SWAPGS_KERNEL_ENTRY
        leaq    8(%rsp), %rax                   /* return pt_regs pointer */
+       ANNOTATE_UNRET_END
        RET
 
 .Lbstep_iret:
@@ -1080,6 +1111,8 @@ SYM_CODE_START_LOCAL(error_entry)
        swapgs
        FENCE_SWAPGS_USER_ENTRY
        SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
+       IBRS_ENTER
+       UNTRAIN_RET
 
        /*
         * Pretend that the exception came from user mode: set up pt_regs
@@ -1185,6 +1218,9 @@ SYM_CODE_START(asm_exc_nmi)
        PUSH_AND_CLEAR_REGS rdx=(%rdx)
        ENCODE_FRAME_POINTER
 
+       IBRS_ENTER
+       UNTRAIN_RET
+
        /*
         * At this point we no longer need to worry about stack damage
         * due to nesting -- we're on the normal thread stack and we're
@@ -1409,6 +1445,9 @@ end_repeat_nmi:
        movq    $-1, %rsi
        call    exc_nmi
 
+       /* Always restore stashed SPEC_CTRL value (see paranoid_entry) */
+       IBRS_EXIT save_reg=%r15
+
        /* Always restore stashed CR3 value (see paranoid_entry) */
        RESTORE_CR3 scratch_reg=%r15 save_reg=%r14
 
index d1052742ad0cd51c3628978ec53d1a50b12445be..682338e7e2a38dbedcdef57ac6cbb6078e8abe75 100644 (file)
@@ -4,7 +4,6 @@
  *
  * Copyright 2000-2002 Andi Kleen, SuSE Labs.
  */
-#include "calling.h"
 #include <asm/asm-offsets.h>
 #include <asm/current.h>
 #include <asm/errno.h>
 #include <asm/irqflags.h>
 #include <asm/asm.h>
 #include <asm/smap.h>
+#include <asm/nospec-branch.h>
 #include <linux/linkage.h>
 #include <linux/err.h>
 
+#include "calling.h"
+
        .section .entry.text, "ax"
 
 /*
@@ -47,7 +49,7 @@
  * 0(%ebp) arg6
  */
 SYM_CODE_START(entry_SYSENTER_compat)
-       UNWIND_HINT_EMPTY
+       UNWIND_HINT_ENTRY
        ENDBR
        /* Interrupts are off on entry. */
        swapgs
@@ -88,6 +90,9 @@ SYM_INNER_LABEL(entry_SYSENTER_compat_after_hwframe, SYM_L_GLOBAL)
 
        cld
 
+       IBRS_ENTER
+       UNTRAIN_RET
+
        /*
         * SYSENTER doesn't filter flags, so we need to clear NT and AC
         * ourselves.  To save a few cycles, we can check whether
@@ -174,7 +179,7 @@ SYM_CODE_END(entry_SYSENTER_compat)
  * 0(%esp) arg6
  */
 SYM_CODE_START(entry_SYSCALL_compat)
-       UNWIND_HINT_EMPTY
+       UNWIND_HINT_ENTRY
        ENDBR
        /* Interrupts are off on entry. */
        swapgs
@@ -203,6 +208,9 @@ SYM_INNER_LABEL(entry_SYSCALL_compat_after_hwframe, SYM_L_GLOBAL)
        PUSH_AND_CLEAR_REGS rcx=%rbp rax=$-ENOSYS
        UNWIND_HINT_REGS
 
+       IBRS_ENTER
+       UNTRAIN_RET
+
        movq    %rsp, %rdi
        call    do_fast_syscall_32
        /* XEN PV guests always use IRET path */
@@ -217,6 +225,8 @@ sysret32_from_system_call:
         */
        STACKLEAK_ERASE
 
+       IBRS_EXIT
+
        movq    RBX(%rsp), %rbx         /* pt_regs->rbx */
        movq    RBP(%rsp), %rbp         /* pt_regs->rbp */
        movq    EFLAGS(%rsp), %r11      /* pt_regs->flags (in r11) */
@@ -295,7 +305,7 @@ SYM_CODE_END(entry_SYSCALL_compat)
  * ebp  arg6
  */
 SYM_CODE_START(entry_INT80_compat)
-       UNWIND_HINT_EMPTY
+       UNWIND_HINT_ENTRY
        ENDBR
        /*
         * Interrupts are off on entry.
@@ -337,6 +347,9 @@ SYM_CODE_START(entry_INT80_compat)
 
        cld
 
+       IBRS_ENTER
+       UNTRAIN_RET
+
        movq    %rsp, %rdi
        call    do_int80_syscall_32
        jmp     swapgs_restore_regs_and_return_to_usermode
index c2a8b76ae0bce2d1b77d420fa588b65d6bbdf0a4..76cd790ed0bd565e5ccb16a64d574115f8c97014 100644 (file)
@@ -92,6 +92,7 @@ endif
 endif
 
 $(vobjs): KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_LTO) $(RANDSTRUCT_CFLAGS) $(GCC_PLUGINS_CFLAGS) $(RETPOLINE_CFLAGS),$(KBUILD_CFLAGS)) $(CFL)
+$(vobjs): KBUILD_AFLAGS += -DBUILD_VDSO
 
 #
 # vDSO code runs in userspace and -pg doesn't help with profiling anyway.
index 15e35159ebb68d950fb605de0d3868c5c77b46fa..ef2dd182724314f24db5ba592699c304ff231523 100644 (file)
@@ -19,17 +19,20 @@ __vsyscall_page:
 
        mov $__NR_gettimeofday, %rax
        syscall
-       RET
+       ret
+       int3
 
        .balign 1024, 0xcc
        mov $__NR_time, %rax
        syscall
-       RET
+       ret
+       int3
 
        .balign 1024, 0xcc
        mov $__NR_getcpu, %rax
        syscall
-       RET
+       ret
+       int3
 
        .balign 4096, 0xcc
 
index 13179f31fe10facf139f4c7c00fd8627363a5594..4f70fb6c2c1eb78e35f717ffb3085ee9f459e145 100644 (file)
@@ -278,9 +278,9 @@ enum {
 };
 
 /*
- * For formats with LBR_TSX flags (e.g. LBR_FORMAT_EIP_FLAGS2), bits 61:62 in
- * MSR_LAST_BRANCH_FROM_x are the TSX flags when TSX is supported, but when
- * TSX is not supported they have no consistent behavior:
+ * For format LBR_FORMAT_EIP_FLAGS2, bits 61:62 in MSR_LAST_BRANCH_FROM_x
+ * are the TSX flags when TSX is supported, but when TSX is not supported
+ * they have no consistent behavior:
  *
  *   - For wrmsr(), bits 61:62 are considered part of the sign extension.
  *   - For HW updates (branch captures) bits 61:62 are always OFF and are not
@@ -288,7 +288,7 @@ enum {
  *
  * Therefore, if:
  *
- *   1) LBR has TSX format
+ *   1) LBR format LBR_FORMAT_EIP_FLAGS2
  *   2) CPU has no TSX support enabled
  *
  * ... then any value passed to wrmsr() must be sign extended to 63 bits and any
@@ -300,7 +300,7 @@ static inline bool lbr_from_signext_quirk_needed(void)
        bool tsx_support = boot_cpu_has(X86_FEATURE_HLE) ||
                           boot_cpu_has(X86_FEATURE_RTM);
 
-       return !tsx_support && x86_pmu.lbr_has_tsx;
+       return !tsx_support;
 }
 
 static DEFINE_STATIC_KEY_FALSE(lbr_from_quirk_key);
@@ -1609,9 +1609,6 @@ void intel_pmu_lbr_init_hsw(void)
        x86_pmu.lbr_sel_map  = hsw_lbr_sel_map;
 
        x86_get_pmu(smp_processor_id())->task_ctx_cache = create_lbr_kmem_cache(size, 0);
-
-       if (lbr_from_signext_quirk_needed())
-               static_branch_enable(&lbr_from_quirk_key);
 }
 
 /* skylake */
@@ -1702,7 +1699,11 @@ 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;
+               x86_pmu.lbr_from_flags = 1;
+               if (lbr_from_signext_quirk_needed())
+                       static_branch_enable(&lbr_from_quirk_key);
+               break;
+
        case LBR_FORMAT_EIP_FLAGS:
                x86_pmu.lbr_from_flags = 1;
                break;
index 9b10c8c76087aabe701c7908d760710b53e181ed..9542c582d546b2ae270f3568794c57de4478d0b4 100644 (file)
@@ -76,6 +76,7 @@ extern int alternatives_patched;
 extern void alternative_instructions(void);
 extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
 extern void apply_retpolines(s32 *start, s32 *end);
+extern void apply_returns(s32 *start, s32 *end);
 extern void apply_ibt_endbr(s32 *start, s32 *end);
 
 struct module;
index 03acc823838a7e46f739ce301af252543168dcd7..a77b915d36a8ed8885f4c33e11597a3950102747 100644 (file)
 #define X86_FEATURE_PROC_FEEDBACK      ( 7*32+ 9) /* AMD ProcFeedbackInterface */
 #define X86_FEATURE_XCOMPACTED         ( 7*32+10) /* "" Use compacted XSTATE (XSAVES or XSAVEC) */
 #define X86_FEATURE_PTI                        ( 7*32+11) /* Kernel Page Table Isolation enabled */
-#define X86_FEATURE_RETPOLINE          ( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
-#define X86_FEATURE_RETPOLINE_LFENCE   ( 7*32+13) /* "" Use LFENCE for Spectre variant 2 */
+#define X86_FEATURE_KERNEL_IBRS                ( 7*32+12) /* "" Set/clear IBRS on kernel entry/exit */
+#define X86_FEATURE_RSB_VMEXIT         ( 7*32+13) /* "" Fill RSB on VM-Exit */
 #define X86_FEATURE_INTEL_PPIN         ( 7*32+14) /* Intel Processor Inventory Number */
 #define X86_FEATURE_CDP_L2             ( 7*32+15) /* Code and Data Prioritization L2 */
 #define X86_FEATURE_MSR_SPEC_CTRL      ( 7*32+16) /* "" MSR SPEC_CTRL is implemented */
 #define X86_FEATURE_PER_THREAD_MBA     (11*32+ 7) /* "" Per-thread Memory Bandwidth Allocation */
 #define X86_FEATURE_SGX1               (11*32+ 8) /* "" Basic SGX */
 #define X86_FEATURE_SGX2               (11*32+ 9) /* "" SGX Enclave Dynamic Memory Management (EDMM) */
+#define X86_FEATURE_ENTRY_IBPB         (11*32+10) /* "" Issue an IBPB on kernel entry */
+#define X86_FEATURE_RRSBA_CTRL         (11*32+11) /* "" RET prediction control */
+#define X86_FEATURE_RETPOLINE          (11*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
+#define X86_FEATURE_RETPOLINE_LFENCE   (11*32+13) /* "" Use LFENCE for Spectre variant 2 */
+#define X86_FEATURE_RETHUNK            (11*32+14) /* "" Use REturn THUNK */
+#define X86_FEATURE_UNRET              (11*32+15) /* "" AMD BTB untrain return */
+#define X86_FEATURE_USE_IBPB_FW                (11*32+16) /* "" Use IBPB during runtime firmware calls */
 
 /* 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_VIRT_SSBD          (13*32+25) /* Virtualized Speculative Store Bypass Disable */
 #define X86_FEATURE_AMD_SSB_NO         (13*32+26) /* "" Speculative Store Bypass is fixed in hardware. */
 #define X86_FEATURE_CPPC               (13*32+27) /* Collaborative Processor Performance Control */
+#define X86_FEATURE_BTC_NO             (13*32+29) /* "" Not vulnerable to Branch Type Confusion */
 #define X86_FEATURE_BRS                        (13*32+31) /* Branch Sampling available */
 
 /* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */
 #define X86_BUG_ITLB_MULTIHIT          X86_BUG(23) /* CPU may incur MCE during certain page attribute changes */
 #define X86_BUG_SRBDS                  X86_BUG(24) /* CPU may leak RNG bits if not mitigated */
 #define X86_BUG_MMIO_STALE_DATA                X86_BUG(25) /* CPU is affected by Processor MMIO Stale Data vulnerabilities */
+#define X86_BUG_RETBLEED               X86_BUG(26) /* CPU is affected by RETBleed */
 
 #endif /* _ASM_X86_CPUFEATURES_H */
index 36369e76cc631ecbb488c175d3c330cebee88737..33d2cd04d2544791b1363f8d7578a7d45b7fc749 100644 (file)
 # define DISABLE_PTI           (1 << (X86_FEATURE_PTI & 31))
 #endif
 
+#ifdef CONFIG_RETPOLINE
+# define DISABLE_RETPOLINE     0
+#else
+# define DISABLE_RETPOLINE     ((1 << (X86_FEATURE_RETPOLINE & 31)) | \
+                                (1 << (X86_FEATURE_RETPOLINE_LFENCE & 31)))
+#endif
+
+#ifdef CONFIG_RETHUNK
+# define DISABLE_RETHUNK       0
+#else
+# define DISABLE_RETHUNK       (1 << (X86_FEATURE_RETHUNK & 31))
+#endif
+
+#ifdef CONFIG_CPU_UNRET_ENTRY
+# define DISABLE_UNRET         0
+#else
+# define DISABLE_UNRET         (1 << (X86_FEATURE_UNRET & 31))
+#endif
+
 #ifdef CONFIG_INTEL_IOMMU_SVM
 # define DISABLE_ENQCMD                0
 #else
 #define DISABLED_MASK8 (DISABLE_TDX_GUEST)
 #define DISABLED_MASK9 (DISABLE_SGX)
 #define DISABLED_MASK10        0
-#define DISABLED_MASK11        0
+#define DISABLED_MASK11        (DISABLE_RETPOLINE|DISABLE_RETHUNK|DISABLE_UNRET)
 #define DISABLED_MASK12        0
 #define DISABLED_MASK13        0
 #define DISABLED_MASK14        0
index 85865f1645bd3cced0d77b202a3edc77b616990e..73ca2004983562ca3774d5a6796cf80e231c312f 100644 (file)
 #define __ALIGN_STR    __stringify(__ALIGN)
 #endif
 
+#if defined(CONFIG_RETHUNK) && !defined(__DISABLE_EXPORTS) && !defined(BUILD_VDSO)
+#define RET    jmp __x86_return_thunk
+#else /* CONFIG_RETPOLINE */
 #ifdef CONFIG_SLS
 #define RET    ret; int3
 #else
 #define RET    ret
 #endif
+#endif /* CONFIG_RETPOLINE */
 
 #else /* __ASSEMBLY__ */
 
+#if defined(CONFIG_RETHUNK) && !defined(__DISABLE_EXPORTS) && !defined(BUILD_VDSO)
+#define ASM_RET        "jmp __x86_return_thunk\n\t"
+#else /* CONFIG_RETPOLINE */
 #ifdef CONFIG_SLS
 #define ASM_RET        "ret; int3\n\t"
 #else
 #define ASM_RET        "ret\n\t"
 #endif
+#endif /* CONFIG_RETPOLINE */
 
 #endif /* __ASSEMBLY__ */
 
index d27e0581b7777ba086a772453cc52f6afacdcdeb..cc615be27a54b2daf55352ab1d34c244ee0790c6 100644 (file)
@@ -51,6 +51,8 @@
 #define SPEC_CTRL_STIBP                        BIT(SPEC_CTRL_STIBP_SHIFT)      /* STIBP mask */
 #define SPEC_CTRL_SSBD_SHIFT           2          /* Speculative Store Bypass Disable bit */
 #define SPEC_CTRL_SSBD                 BIT(SPEC_CTRL_SSBD_SHIFT)       /* Speculative Store Bypass Disable */
+#define SPEC_CTRL_RRSBA_DIS_S_SHIFT    6          /* Disable RRSBA behavior */
+#define SPEC_CTRL_RRSBA_DIS_S          BIT(SPEC_CTRL_RRSBA_DIS_S_SHIFT)
 
 #define MSR_IA32_PRED_CMD              0x00000049 /* Prediction Command */
 #define PRED_CMD_IBPB                  BIT(0)     /* Indirect Branch Prediction Barrier */
@@ -93,6 +95,7 @@
 #define MSR_IA32_ARCH_CAPABILITIES     0x0000010a
 #define ARCH_CAP_RDCL_NO               BIT(0)  /* Not susceptible to Meltdown */
 #define ARCH_CAP_IBRS_ALL              BIT(1)  /* Enhanced IBRS support */
+#define ARCH_CAP_RSBA                  BIT(2)  /* RET may use alternative branch predictors */
 #define ARCH_CAP_SKIP_VMENTRY_L1DFLUSH BIT(3)  /* Skip L1D flush on vmentry */
 #define ARCH_CAP_SSB_NO                        BIT(4)  /*
                                                 * Not susceptible to Speculative Store Bypass
                                                 * bit available to control VERW
                                                 * behavior.
                                                 */
+#define ARCH_CAP_RRSBA                 BIT(19) /*
+                                                * Indicates RET may use predictors
+                                                * other than the RSB. With eIBRS
+                                                * enabled predictions in kernel mode
+                                                * are restricted to targets in
+                                                * kernel.
+                                                */
 
 #define MSR_IA32_FLUSH_CMD             0x0000010b
 #define L1D_FLUSH                      BIT(0)  /*
 /* Fam 17h MSRs */
 #define MSR_F17H_IRPERF                        0xc00000e9
 
+#define MSR_ZEN2_SPECTRAL_CHICKEN      0xc00110e3
+#define MSR_ZEN2_SPECTRAL_CHICKEN_BIT  BIT_ULL(1)
+
 /* Fam 16h MSRs */
 #define MSR_F16H_L2I_PERF_CTL          0xc0010230
 #define MSR_F16H_L2I_PERF_CTR          0xc0010231
index da251a5645b0ec25ae5eec7279684d20b26ed528..38a3e86e665ef25310ac60bca516f58d84201680 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/cpufeatures.h>
 #include <asm/msr-index.h>
 #include <asm/unwind_hints.h>
+#include <asm/percpu.h>
 
 #define RETPOLINE_THUNK_SIZE   32
 
        .popsection
 .endm
 
+/*
+ * (ab)use RETPOLINE_SAFE on RET to annotate away 'bare' RET instructions
+ * vs RETBleed validation.
+ */
+#define ANNOTATE_UNRET_SAFE ANNOTATE_RETPOLINE_SAFE
+
+/*
+ * Abuse ANNOTATE_RETPOLINE_SAFE on a NOP to indicate UNRET_END, should
+ * eventually turn into it's own annotation.
+ */
+.macro ANNOTATE_UNRET_END
+#ifdef CONFIG_DEBUG_ENTRY
+       ANNOTATE_RETPOLINE_SAFE
+       nop
+#endif
+.endm
+
 /*
  * JMP_NOSPEC and CALL_NOSPEC macros can be used instead of a simple
  * indirect jmp/call which may be susceptible to the Spectre variant 2
   * monstrosity above, manually.
   */
 .macro FILL_RETURN_BUFFER reg:req nr:req ftr:req
-#ifdef CONFIG_RETPOLINE
        ALTERNATIVE "jmp .Lskip_rsb_\@", "", \ftr
        __FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)
 .Lskip_rsb_\@:
+.endm
+
+#ifdef CONFIG_CPU_UNRET_ENTRY
+#define CALL_ZEN_UNTRAIN_RET   "call zen_untrain_ret"
+#else
+#define CALL_ZEN_UNTRAIN_RET   ""
+#endif
+
+/*
+ * Mitigate RETBleed for AMD/Hygon Zen uarch. Requires KERNEL CR3 because the
+ * return thunk isn't mapped into the userspace tables (then again, AMD
+ * typically has NO_MELTDOWN).
+ *
+ * While zen_untrain_ret() doesn't clobber anything but requires stack,
+ * entry_ibpb() will clobber AX, CX, DX.
+ *
+ * As such, this must be placed after every *SWITCH_TO_KERNEL_CR3 at a point
+ * where we have a stack but before any RET instruction.
+ */
+.macro UNTRAIN_RET
+#if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_IBPB_ENTRY)
+       ANNOTATE_UNRET_END
+       ALTERNATIVE_2 "",                                               \
+                     CALL_ZEN_UNTRAIN_RET, X86_FEATURE_UNRET,          \
+                     "call entry_ibpb", X86_FEATURE_ENTRY_IBPB
 #endif
 .endm
 
        _ASM_PTR " 999b\n\t"                                    \
        ".popsection\n\t"
 
-#ifdef CONFIG_RETPOLINE
-
 typedef u8 retpoline_thunk_t[RETPOLINE_THUNK_SIZE];
+extern retpoline_thunk_t __x86_indirect_thunk_array[];
+
+extern void __x86_return_thunk(void);
+extern void zen_untrain_ret(void);
+extern void entry_ibpb(void);
+
+#ifdef CONFIG_RETPOLINE
 
 #define GEN(reg) \
        extern retpoline_thunk_t __x86_indirect_thunk_ ## reg;
 #include <asm/GEN-for-each-reg.h>
 #undef GEN
 
-extern retpoline_thunk_t __x86_indirect_thunk_array[];
-
 #ifdef CONFIG_X86_64
 
 /*
@@ -193,6 +238,7 @@ enum spectre_v2_mitigation {
        SPECTRE_V2_EIBRS,
        SPECTRE_V2_EIBRS_RETPOLINE,
        SPECTRE_V2_EIBRS_LFENCE,
+       SPECTRE_V2_IBRS,
 };
 
 /* The indirect branch speculation control variants */
@@ -235,6 +281,9 @@ static inline void indirect_branch_prediction_barrier(void)
 
 /* The Intel SPEC CTRL MSR base value cache */
 extern u64 x86_spec_ctrl_base;
+DECLARE_PER_CPU(u64, x86_spec_ctrl_current);
+extern void write_spec_ctrl_current(u64 val, bool force);
+extern u64 spec_ctrl_current(void);
 
 /*
  * With retpoline, we must use IBRS to restrict branch prediction
@@ -244,18 +293,18 @@ extern u64 x86_spec_ctrl_base;
  */
 #define firmware_restrict_branch_speculation_start()                   \
 do {                                                                   \
-       u64 val = x86_spec_ctrl_base | SPEC_CTRL_IBRS;                  \
-                                                                       \
        preempt_disable();                                              \
-       alternative_msr_write(MSR_IA32_SPEC_CTRL, val,                  \
+       alternative_msr_write(MSR_IA32_SPEC_CTRL,                       \
+                             spec_ctrl_current() | SPEC_CTRL_IBRS,     \
                              X86_FEATURE_USE_IBRS_FW);                 \
+       alternative_msr_write(MSR_IA32_PRED_CMD, PRED_CMD_IBPB,         \
+                             X86_FEATURE_USE_IBPB_FW);                 \
 } while (0)
 
 #define firmware_restrict_branch_speculation_end()                     \
 do {                                                                   \
-       u64 val = x86_spec_ctrl_base;                                   \
-                                                                       \
-       alternative_msr_write(MSR_IA32_SPEC_CTRL, val,                  \
+       alternative_msr_write(MSR_IA32_SPEC_CTRL,                       \
+                             spec_ctrl_current(),                      \
                              X86_FEATURE_USE_IBRS_FW);                 \
        preempt_enable();                                               \
 } while (0)
index f8b9ee97a89133bd3a921dde8e79552a0198cffb..f37cbff7354c49e211e51743f1b229286dae656d 100644 (file)
@@ -120,6 +120,9 @@ void *extend_brk(size_t size, size_t align);
        static char __brk_##name[size]
 
 extern void probe_roms(void);
+
+void clear_bss(void);
+
 #ifdef __i386__
 
 asmlinkage void __init i386_start_kernel(void);
index 2d8dacd026437a2968c29226f7f9aeaefa96f45e..343b722ccaf21d0654b5d7dc19596a4ef548a8e5 100644 (file)
  * relative displacement across sections.
  */
 
+/*
+ * The trampoline is 8 bytes and of the general form:
+ *
+ *   jmp.d32 \func
+ *   ud1 %esp, %ecx
+ *
+ * That trailing #UD provides both a speculation stop and serves as a unique
+ * 3 byte signature identifying static call trampolines. Also see tramp_ud[]
+ * and __static_call_fixup().
+ */
 #define __ARCH_DEFINE_STATIC_CALL_TRAMP(name, insns)                   \
        asm(".pushsection .static_call.text, \"ax\"             \n"     \
            ".align 4                                           \n"     \
@@ -28,7 +38,7 @@
            STATIC_CALL_TRAMP_STR(name) ":                      \n"     \
            ANNOTATE_NOENDBR                                            \
            insns "                                             \n"     \
-           ".byte 0x53, 0x43, 0x54                             \n"     \
+           ".byte 0x0f, 0xb9, 0xcc                             \n"     \
            ".type " STATIC_CALL_TRAMP_STR(name) ", @function   \n"     \
            ".size " STATIC_CALL_TRAMP_STR(name) ", . - " STATIC_CALL_TRAMP_STR(name) " \n" \
            ".popsection                                        \n")
 #define ARCH_DEFINE_STATIC_CALL_TRAMP(name, func)                      \
        __ARCH_DEFINE_STATIC_CALL_TRAMP(name, ".byte 0xe9; .long " #func " - (. + 4)")
 
+#ifdef CONFIG_RETHUNK
+#define ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name)                       \
+       __ARCH_DEFINE_STATIC_CALL_TRAMP(name, "jmp __x86_return_thunk")
+#else
 #define ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name)                       \
        __ARCH_DEFINE_STATIC_CALL_TRAMP(name, "ret; int3; nop; nop; nop")
+#endif
 
 #define ARCH_DEFINE_STATIC_CALL_RET0_TRAMP(name)                       \
        ARCH_DEFINE_STATIC_CALL_TRAMP(name, __static_call_return0)
@@ -48,4 +63,6 @@
            ".long " STATIC_CALL_KEY_STR(name) " - .            \n"     \
            ".popsection                                        \n")
 
+extern bool __static_call_fixup(void *tramp, u8 op, void *dest);
+
 #endif /* _ASM_STATIC_CALL_H */
index 1bfe979bb9bcd25c1bc8d5c9ec82e581bb21bafc..580636cdc257b78930db0d9b9236cfa9fd62ed21 100644 (file)
@@ -2,9 +2,6 @@
 #ifndef _ASM_X86_TLB_H
 #define _ASM_X86_TLB_H
 
-#define tlb_start_vma(tlb, vma) do { } while (0)
-#define tlb_end_vma(tlb, vma) do { } while (0)
-
 #define tlb_flush tlb_flush
 static inline void tlb_flush(struct mmu_gather *tlb);
 
index 8b33674288ea7b2bbe23f4ddbca32555fc6d7daf..f66fbe6537dd7abac82b6bca5e6258f88a81d4b7 100644 (file)
@@ -8,7 +8,11 @@
 #ifdef __ASSEMBLY__
 
 .macro UNWIND_HINT_EMPTY
-       UNWIND_HINT sp_reg=ORC_REG_UNDEFINED type=UNWIND_HINT_TYPE_CALL end=1
+       UNWIND_HINT type=UNWIND_HINT_TYPE_CALL end=1
+.endm
+
+.macro UNWIND_HINT_ENTRY
+       UNWIND_HINT type=UNWIND_HINT_TYPE_ENTRY end=1
 .endm
 
 .macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 partial=0
        UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=8 type=UNWIND_HINT_TYPE_FUNC
 .endm
 
+.macro UNWIND_HINT_SAVE
+       UNWIND_HINT type=UNWIND_HINT_TYPE_SAVE
+.endm
+
+.macro UNWIND_HINT_RESTORE
+       UNWIND_HINT type=UNWIND_HINT_TYPE_RESTORE
+.endm
+
 #else
 
 #define UNWIND_HINT_FUNC \
index bea5cdcdf53252bf4fed4199ee2c7b11a48416ac..e02a8a8ef23cec816ab256135623baa11b0de2f3 100644 (file)
@@ -15,7 +15,7 @@
 #define SETUP_INDIRECT                 (1<<31)
 
 /* SETUP_INDIRECT | max(SETUP_*) */
-#define SETUP_TYPE_MAX                 (SETUP_INDIRECT | SETUP_JAILHOUSE)
+#define SETUP_TYPE_MAX                 (SETUP_INDIRECT | SETUP_CC_BLOB)
 
 /* ram_size flags */
 #define RAMDISK_IMAGE_START_MASK       0x07FF
index 8b8cbf22461a4feff2249a2d731b538a31c30501..8d8752b44f11395298a40acce79de2027614248b 100644 (file)
 
 /* Refer to drivers/acpi/cppc_acpi.c for the description of functions */
 
+bool cpc_supported_by_cpu(void)
+{
+       switch (boot_cpu_data.x86_vendor) {
+       case X86_VENDOR_AMD:
+       case X86_VENDOR_HYGON:
+               if (boot_cpu_data.x86 == 0x19 && ((boot_cpu_data.x86_model <= 0x0f) ||
+                   (boot_cpu_data.x86_model >= 0x20 && boot_cpu_data.x86_model <= 0x2f)))
+                       return true;
+               else if (boot_cpu_data.x86 == 0x17 &&
+                        boot_cpu_data.x86_model >= 0x70 && boot_cpu_data.x86_model <= 0x7f)
+                       return true;
+               return boot_cpu_has(X86_FEATURE_CPPC);
+       }
+       return false;
+}
+
 bool cpc_ffh_supported(void)
 {
        return true;
index e257f6c80372139d83401fcda0b64828fabd0408..62f6b8b7c4a5285933b80013ff6fe2aa7bf6e183 100644 (file)
@@ -115,6 +115,7 @@ static void __init_or_module add_nops(void *insns, unsigned int len)
 }
 
 extern s32 __retpoline_sites[], __retpoline_sites_end[];
+extern s32 __return_sites[], __return_sites_end[];
 extern s32 __ibt_endbr_seal[], __ibt_endbr_seal_end[];
 extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
 extern s32 __smp_locks[], __smp_locks_end[];
@@ -507,9 +508,78 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end)
        }
 }
 
+#ifdef CONFIG_RETHUNK
+/*
+ * Rewrite the compiler generated return thunk tail-calls.
+ *
+ * For example, convert:
+ *
+ *   JMP __x86_return_thunk
+ *
+ * into:
+ *
+ *   RET
+ */
+static int patch_return(void *addr, struct insn *insn, u8 *bytes)
+{
+       int i = 0;
+
+       if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
+               return -1;
+
+       bytes[i++] = RET_INSN_OPCODE;
+
+       for (; i < insn->length;)
+               bytes[i++] = INT3_INSN_OPCODE;
+
+       return i;
+}
+
+void __init_or_module noinline apply_returns(s32 *start, s32 *end)
+{
+       s32 *s;
+
+       for (s = start; s < end; s++) {
+               void *dest = NULL, *addr = (void *)s + *s;
+               struct insn insn;
+               int len, ret;
+               u8 bytes[16];
+               u8 op;
+
+               ret = insn_decode_kernel(&insn, addr);
+               if (WARN_ON_ONCE(ret < 0))
+                       continue;
+
+               op = insn.opcode.bytes[0];
+               if (op == JMP32_INSN_OPCODE)
+                       dest = addr + insn.length + insn.immediate.value;
+
+               if (__static_call_fixup(addr, op, dest) ||
+                   WARN_ONCE(dest != &__x86_return_thunk,
+                             "missing return thunk: %pS-%pS: %*ph",
+                             addr, dest, 5, addr))
+                       continue;
+
+               DPRINTK("return thunk at: %pS (%px) len: %d to: %pS",
+                       addr, addr, insn.length,
+                       addr + insn.length + insn.immediate.value);
+
+               len = patch_return(addr, &insn, bytes);
+               if (len == insn.length) {
+                       DUMP_BYTES(((u8*)addr),  len, "%px: orig: ", addr);
+                       DUMP_BYTES(((u8*)bytes), len, "%px: repl: ", addr);
+                       text_poke_early(addr, bytes, len);
+               }
+       }
+}
+#else
+void __init_or_module noinline apply_returns(s32 *start, s32 *end) { }
+#endif /* CONFIG_RETHUNK */
+
 #else /* !CONFIG_RETPOLINE || !CONFIG_OBJTOOL */
 
 void __init_or_module noinline apply_retpolines(s32 *start, s32 *end) { }
+void __init_or_module noinline apply_returns(s32 *start, s32 *end) { }
 
 #endif /* CONFIG_RETPOLINE && CONFIG_OBJTOOL */
 
@@ -860,6 +930,7 @@ void __init alternative_instructions(void)
         * those can rewrite the retpoline thunks.
         */
        apply_retpolines(__retpoline_sites, __retpoline_sites_end);
+       apply_returns(__return_sites, __return_sites_end);
 
        /*
         * Then patch alternatives, such that those paravirt calls that are in
index 437308004ef2e4f1345947ce318c62bc56a6036f..cb50589a7102fa3825703d6a7a87c1d00b906149 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/suspend.h>
 #include <asm/tlbflush.h>
 #include <asm/tdx.h>
+#include "../kvm/vmx/vmx.h"
 
 #ifdef CONFIG_XEN
 #include <xen/interface/xen.h>
@@ -107,4 +108,9 @@ static void __used common(void)
        OFFSET(TSS_sp0, tss_struct, x86_tss.sp0);
        OFFSET(TSS_sp1, tss_struct, x86_tss.sp1);
        OFFSET(TSS_sp2, tss_struct, x86_tss.sp2);
+
+       if (IS_ENABLED(CONFIG_KVM_INTEL)) {
+               BLANK();
+               OFFSET(VMX_spec_ctrl, vcpu_vmx, spec_ctrl);
+       }
 }
index 0c0b09796ced30153adbaf5cee1c686ba6063201..35d5288394cb82f187b4314e0795f6cef5343dd8 100644 (file)
@@ -862,6 +862,28 @@ static void init_amd_bd(struct cpuinfo_x86 *c)
        clear_rdrand_cpuid_bit(c);
 }
 
+void init_spectral_chicken(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_CPU_UNRET_ENTRY
+       u64 value;
+
+       /*
+        * On Zen2 we offer this chicken (bit) on the altar of Speculation.
+        *
+        * This suppresses speculation from the middle of a basic block, i.e. it
+        * suppresses non-branch predictions.
+        *
+        * We use STIBP as a heuristic to filter out Zen2 from the rest of F17H
+        */
+       if (!cpu_has(c, X86_FEATURE_HYPERVISOR) && cpu_has(c, X86_FEATURE_AMD_STIBP)) {
+               if (!rdmsrl_safe(MSR_ZEN2_SPECTRAL_CHICKEN, &value)) {
+                       value |= MSR_ZEN2_SPECTRAL_CHICKEN_BIT;
+                       wrmsrl_safe(MSR_ZEN2_SPECTRAL_CHICKEN, value);
+               }
+       }
+#endif
+}
+
 static void init_amd_zn(struct cpuinfo_x86 *c)
 {
        set_cpu_cap(c, X86_FEATURE_ZEN);
@@ -870,12 +892,21 @@ static void init_amd_zn(struct cpuinfo_x86 *c)
        node_reclaim_distance = 32;
 #endif
 
-       /*
-        * Fix erratum 1076: CPB feature bit not being set in CPUID.
-        * Always set it, except when running under a hypervisor.
-        */
-       if (!cpu_has(c, X86_FEATURE_HYPERVISOR) && !cpu_has(c, X86_FEATURE_CPB))
-               set_cpu_cap(c, X86_FEATURE_CPB);
+       /* Fix up CPUID bits, but only if not virtualised. */
+       if (!cpu_has(c, X86_FEATURE_HYPERVISOR)) {
+
+               /* Erratum 1076: CPB feature bit not being set in CPUID. */
+               if (!cpu_has(c, X86_FEATURE_CPB))
+                       set_cpu_cap(c, X86_FEATURE_CPB);
+
+               /*
+                * Zen3 (Fam19 model < 0x10) parts are not susceptible to
+                * Branch Type Confusion, but predate the allocation of the
+                * BTC_NO bit.
+                */
+               if (c->x86 == 0x19 && !cpu_has(c, X86_FEATURE_BTC_NO))
+                       set_cpu_cap(c, X86_FEATURE_BTC_NO);
+       }
 }
 
 static void init_amd(struct cpuinfo_x86 *c)
@@ -907,7 +938,8 @@ static void init_amd(struct cpuinfo_x86 *c)
        case 0x12: init_amd_ln(c); break;
        case 0x15: init_amd_bd(c); break;
        case 0x16: init_amd_jg(c); break;
-       case 0x17: fallthrough;
+       case 0x17: init_spectral_chicken(c);
+                  fallthrough;
        case 0x19: init_amd_zn(c); break;
        }
 
index 74c62cc47a5ff35a90adc06f2653985d68700799..6454bc767f0fdfa3d69497b1fc54c624098ef091 100644 (file)
@@ -38,6 +38,8 @@
 
 static void __init spectre_v1_select_mitigation(void);
 static void __init spectre_v2_select_mitigation(void);
+static void __init retbleed_select_mitigation(void);
+static void __init spectre_v2_user_select_mitigation(void);
 static void __init ssb_select_mitigation(void);
 static void __init l1tf_select_mitigation(void);
 static void __init mds_select_mitigation(void);
@@ -48,16 +50,40 @@ static void __init mmio_select_mitigation(void);
 static void __init srbds_select_mitigation(void);
 static void __init l1d_flush_select_mitigation(void);
 
-/* The base value of the SPEC_CTRL MSR that always has to be preserved. */
+/* The base value of the SPEC_CTRL MSR without task-specific bits set */
 u64 x86_spec_ctrl_base;
 EXPORT_SYMBOL_GPL(x86_spec_ctrl_base);
+
+/* The current value of the SPEC_CTRL MSR with task-specific bits set */
+DEFINE_PER_CPU(u64, x86_spec_ctrl_current);
+EXPORT_SYMBOL_GPL(x86_spec_ctrl_current);
+
 static DEFINE_MUTEX(spec_ctrl_mutex);
 
 /*
- * The vendor and possibly platform specific bits which can be modified in
- * x86_spec_ctrl_base.
+ * Keep track of the SPEC_CTRL MSR value for the current task, which may differ
+ * from x86_spec_ctrl_base due to STIBP/SSB in __speculation_ctrl_update().
  */
-static u64 __ro_after_init x86_spec_ctrl_mask = SPEC_CTRL_IBRS;
+void write_spec_ctrl_current(u64 val, bool force)
+{
+       if (this_cpu_read(x86_spec_ctrl_current) == val)
+               return;
+
+       this_cpu_write(x86_spec_ctrl_current, val);
+
+       /*
+        * When KERNEL_IBRS this MSR is written on return-to-user, unless
+        * forced the update can be delayed until that time.
+        */
+       if (force || !cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS))
+               wrmsrl(MSR_IA32_SPEC_CTRL, val);
+}
+
+u64 spec_ctrl_current(void)
+{
+       return this_cpu_read(x86_spec_ctrl_current);
+}
+EXPORT_SYMBOL_GPL(spec_ctrl_current);
 
 /*
  * AMD specific MSR info for Speculative Store Bypass control.
@@ -114,13 +140,21 @@ void __init check_bugs(void)
        if (boot_cpu_has(X86_FEATURE_MSR_SPEC_CTRL))
                rdmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
 
-       /* Allow STIBP in MSR_SPEC_CTRL if supported */
-       if (boot_cpu_has(X86_FEATURE_STIBP))
-               x86_spec_ctrl_mask |= SPEC_CTRL_STIBP;
-
        /* Select the proper CPU mitigations before patching alternatives: */
        spectre_v1_select_mitigation();
        spectre_v2_select_mitigation();
+       /*
+        * retbleed_select_mitigation() relies on the state set by
+        * spectre_v2_select_mitigation(); specifically it wants to know about
+        * spectre_v2=ibrs.
+        */
+       retbleed_select_mitigation();
+       /*
+        * spectre_v2_user_select_mitigation() relies on the state set by
+        * retbleed_select_mitigation(); specifically the STIBP selection is
+        * forced for UNRET.
+        */
+       spectre_v2_user_select_mitigation();
        ssb_select_mitigation();
        l1tf_select_mitigation();
        md_clear_select_mitigation();
@@ -161,31 +195,17 @@ void __init check_bugs(void)
 #endif
 }
 
+/*
+ * NOTE: This function is *only* called for SVM.  VMX spec_ctrl handling is
+ * done in vmenter.S.
+ */
 void
 x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool setguest)
 {
-       u64 msrval, guestval, hostval = x86_spec_ctrl_base;
+       u64 msrval, guestval = guest_spec_ctrl, hostval = spec_ctrl_current();
        struct thread_info *ti = current_thread_info();
 
-       /* Is MSR_SPEC_CTRL implemented ? */
        if (static_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) {
-               /*
-                * Restrict guest_spec_ctrl to supported values. Clear the
-                * modifiable bits in the host base value and or the
-                * modifiable bits from the guest value.
-                */
-               guestval = hostval & ~x86_spec_ctrl_mask;
-               guestval |= guest_spec_ctrl & x86_spec_ctrl_mask;
-
-               /* SSBD controlled in MSR_SPEC_CTRL */
-               if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
-                   static_cpu_has(X86_FEATURE_AMD_SSBD))
-                       hostval |= ssbd_tif_to_spec_ctrl(ti->flags);
-
-               /* Conditional STIBP enabled? */
-               if (static_branch_unlikely(&switch_to_cond_stibp))
-                       hostval |= stibp_tif_to_spec_ctrl(ti->flags);
-
                if (hostval != guestval) {
                        msrval = setguest ? guestval : hostval;
                        wrmsrl(MSR_IA32_SPEC_CTRL, msrval);
@@ -752,12 +772,180 @@ static int __init nospectre_v1_cmdline(char *str)
 }
 early_param("nospectre_v1", nospectre_v1_cmdline);
 
-#undef pr_fmt
-#define pr_fmt(fmt)     "Spectre V2 : " fmt
-
 static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init =
        SPECTRE_V2_NONE;
 
+#undef pr_fmt
+#define pr_fmt(fmt)     "RETBleed: " fmt
+
+enum retbleed_mitigation {
+       RETBLEED_MITIGATION_NONE,
+       RETBLEED_MITIGATION_UNRET,
+       RETBLEED_MITIGATION_IBPB,
+       RETBLEED_MITIGATION_IBRS,
+       RETBLEED_MITIGATION_EIBRS,
+};
+
+enum retbleed_mitigation_cmd {
+       RETBLEED_CMD_OFF,
+       RETBLEED_CMD_AUTO,
+       RETBLEED_CMD_UNRET,
+       RETBLEED_CMD_IBPB,
+};
+
+static const char * const retbleed_strings[] = {
+       [RETBLEED_MITIGATION_NONE]      = "Vulnerable",
+       [RETBLEED_MITIGATION_UNRET]     = "Mitigation: untrained return thunk",
+       [RETBLEED_MITIGATION_IBPB]      = "Mitigation: IBPB",
+       [RETBLEED_MITIGATION_IBRS]      = "Mitigation: IBRS",
+       [RETBLEED_MITIGATION_EIBRS]     = "Mitigation: Enhanced IBRS",
+};
+
+static enum retbleed_mitigation retbleed_mitigation __ro_after_init =
+       RETBLEED_MITIGATION_NONE;
+static enum retbleed_mitigation_cmd retbleed_cmd __ro_after_init =
+       RETBLEED_CMD_AUTO;
+
+static int __ro_after_init retbleed_nosmt = false;
+
+static int __init retbleed_parse_cmdline(char *str)
+{
+       if (!str)
+               return -EINVAL;
+
+       while (str) {
+               char *next = strchr(str, ',');
+               if (next) {
+                       *next = 0;
+                       next++;
+               }
+
+               if (!strcmp(str, "off")) {
+                       retbleed_cmd = RETBLEED_CMD_OFF;
+               } else if (!strcmp(str, "auto")) {
+                       retbleed_cmd = RETBLEED_CMD_AUTO;
+               } else if (!strcmp(str, "unret")) {
+                       retbleed_cmd = RETBLEED_CMD_UNRET;
+               } else if (!strcmp(str, "ibpb")) {
+                       retbleed_cmd = RETBLEED_CMD_IBPB;
+               } else if (!strcmp(str, "nosmt")) {
+                       retbleed_nosmt = true;
+               } else {
+                       pr_err("Ignoring unknown retbleed option (%s).", str);
+               }
+
+               str = next;
+       }
+
+       return 0;
+}
+early_param("retbleed", retbleed_parse_cmdline);
+
+#define RETBLEED_UNTRAIN_MSG "WARNING: BTB untrained return thunk mitigation is only effective on AMD/Hygon!\n"
+#define RETBLEED_INTEL_MSG "WARNING: Spectre v2 mitigation leaves CPU vulnerable to RETBleed attacks, data leaks possible!\n"
+
+static void __init retbleed_select_mitigation(void)
+{
+       bool mitigate_smt = false;
+
+       if (!boot_cpu_has_bug(X86_BUG_RETBLEED) || cpu_mitigations_off())
+               return;
+
+       switch (retbleed_cmd) {
+       case RETBLEED_CMD_OFF:
+               return;
+
+       case RETBLEED_CMD_UNRET:
+               if (IS_ENABLED(CONFIG_CPU_UNRET_ENTRY)) {
+                       retbleed_mitigation = RETBLEED_MITIGATION_UNRET;
+               } else {
+                       pr_err("WARNING: kernel not compiled with CPU_UNRET_ENTRY.\n");
+                       goto do_cmd_auto;
+               }
+               break;
+
+       case RETBLEED_CMD_IBPB:
+               if (!boot_cpu_has(X86_FEATURE_IBPB)) {
+                       pr_err("WARNING: CPU does not support IBPB.\n");
+                       goto do_cmd_auto;
+               } else if (IS_ENABLED(CONFIG_CPU_IBPB_ENTRY)) {
+                       retbleed_mitigation = RETBLEED_MITIGATION_IBPB;
+               } else {
+                       pr_err("WARNING: kernel not compiled with CPU_IBPB_ENTRY.\n");
+                       goto do_cmd_auto;
+               }
+               break;
+
+do_cmd_auto:
+       case RETBLEED_CMD_AUTO:
+       default:
+               if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
+                   boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
+                       if (IS_ENABLED(CONFIG_CPU_UNRET_ENTRY))
+                               retbleed_mitigation = RETBLEED_MITIGATION_UNRET;
+                       else if (IS_ENABLED(CONFIG_CPU_IBPB_ENTRY) && boot_cpu_has(X86_FEATURE_IBPB))
+                               retbleed_mitigation = RETBLEED_MITIGATION_IBPB;
+               }
+
+               /*
+                * The Intel mitigation (IBRS or eIBRS) was already selected in
+                * spectre_v2_select_mitigation().  'retbleed_mitigation' will
+                * be set accordingly below.
+                */
+
+               break;
+       }
+
+       switch (retbleed_mitigation) {
+       case RETBLEED_MITIGATION_UNRET:
+               setup_force_cpu_cap(X86_FEATURE_RETHUNK);
+               setup_force_cpu_cap(X86_FEATURE_UNRET);
+
+               if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
+                   boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
+                       pr_err(RETBLEED_UNTRAIN_MSG);
+
+               mitigate_smt = true;
+               break;
+
+       case RETBLEED_MITIGATION_IBPB:
+               setup_force_cpu_cap(X86_FEATURE_ENTRY_IBPB);
+               mitigate_smt = true;
+               break;
+
+       default:
+               break;
+       }
+
+       if (mitigate_smt && !boot_cpu_has(X86_FEATURE_STIBP) &&
+           (retbleed_nosmt || cpu_mitigations_auto_nosmt()))
+               cpu_smt_disable(false);
+
+       /*
+        * Let IBRS trump all on Intel without affecting the effects of the
+        * retbleed= cmdline option.
+        */
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+               switch (spectre_v2_enabled) {
+               case SPECTRE_V2_IBRS:
+                       retbleed_mitigation = RETBLEED_MITIGATION_IBRS;
+                       break;
+               case SPECTRE_V2_EIBRS:
+               case SPECTRE_V2_EIBRS_RETPOLINE:
+               case SPECTRE_V2_EIBRS_LFENCE:
+                       retbleed_mitigation = RETBLEED_MITIGATION_EIBRS;
+                       break;
+               default:
+                       pr_err(RETBLEED_INTEL_MSG);
+               }
+       }
+
+       pr_info("%s\n", retbleed_strings[retbleed_mitigation]);
+}
+
+#undef pr_fmt
+#define pr_fmt(fmt)     "Spectre V2 : " fmt
+
 static enum spectre_v2_user_mitigation spectre_v2_user_stibp __ro_after_init =
        SPECTRE_V2_USER_NONE;
 static enum spectre_v2_user_mitigation spectre_v2_user_ibpb __ro_after_init =
@@ -787,6 +975,7 @@ static inline const char *spectre_v2_module_string(void) { return ""; }
 #define SPECTRE_V2_LFENCE_MSG "WARNING: LFENCE mitigation is not recommended for this CPU, data leaks possible!\n"
 #define SPECTRE_V2_EIBRS_EBPF_MSG "WARNING: Unprivileged eBPF is enabled with eIBRS on, data leaks possible via Spectre v2 BHB attacks!\n"
 #define SPECTRE_V2_EIBRS_LFENCE_EBPF_SMT_MSG "WARNING: Unprivileged eBPF is enabled with eIBRS+LFENCE mitigation and SMT, data leaks possible via Spectre v2 BHB attacks!\n"
+#define SPECTRE_V2_IBRS_PERF_MSG "WARNING: IBRS mitigation selected on Enhanced IBRS CPU, this may cause unnecessary performance loss\n"
 
 #ifdef CONFIG_BPF_SYSCALL
 void unpriv_ebpf_notify(int new_state)
@@ -828,6 +1017,7 @@ enum spectre_v2_mitigation_cmd {
        SPECTRE_V2_CMD_EIBRS,
        SPECTRE_V2_CMD_EIBRS_RETPOLINE,
        SPECTRE_V2_CMD_EIBRS_LFENCE,
+       SPECTRE_V2_CMD_IBRS,
 };
 
 enum spectre_v2_user_cmd {
@@ -868,13 +1058,15 @@ static void __init spec_v2_user_print_cond(const char *reason, bool secure)
                pr_info("spectre_v2_user=%s forced on command line.\n", reason);
 }
 
+static __ro_after_init enum spectre_v2_mitigation_cmd spectre_v2_cmd;
+
 static enum spectre_v2_user_cmd __init
-spectre_v2_parse_user_cmdline(enum spectre_v2_mitigation_cmd v2_cmd)
+spectre_v2_parse_user_cmdline(void)
 {
        char arg[20];
        int ret, i;
 
-       switch (v2_cmd) {
+       switch (spectre_v2_cmd) {
        case SPECTRE_V2_CMD_NONE:
                return SPECTRE_V2_USER_CMD_NONE;
        case SPECTRE_V2_CMD_FORCE:
@@ -900,15 +1092,16 @@ spectre_v2_parse_user_cmdline(enum spectre_v2_mitigation_cmd v2_cmd)
        return SPECTRE_V2_USER_CMD_AUTO;
 }
 
-static inline bool spectre_v2_in_eibrs_mode(enum spectre_v2_mitigation mode)
+static inline bool spectre_v2_in_ibrs_mode(enum spectre_v2_mitigation mode)
 {
-       return (mode == SPECTRE_V2_EIBRS ||
-               mode == SPECTRE_V2_EIBRS_RETPOLINE ||
-               mode == SPECTRE_V2_EIBRS_LFENCE);
+       return mode == SPECTRE_V2_IBRS ||
+              mode == SPECTRE_V2_EIBRS ||
+              mode == SPECTRE_V2_EIBRS_RETPOLINE ||
+              mode == SPECTRE_V2_EIBRS_LFENCE;
 }
 
 static void __init
-spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
+spectre_v2_user_select_mitigation(void)
 {
        enum spectre_v2_user_mitigation mode = SPECTRE_V2_USER_NONE;
        bool smt_possible = IS_ENABLED(CONFIG_SMP);
@@ -921,7 +1114,7 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
            cpu_smt_control == CPU_SMT_NOT_SUPPORTED)
                smt_possible = false;
 
-       cmd = spectre_v2_parse_user_cmdline(v2_cmd);
+       cmd = spectre_v2_parse_user_cmdline();
        switch (cmd) {
        case SPECTRE_V2_USER_CMD_NONE:
                goto set_mode;
@@ -969,12 +1162,12 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
        }
 
        /*
-        * If no STIBP, enhanced IBRS is enabled or SMT impossible, STIBP is not
-        * required.
+        * If no STIBP, IBRS or enhanced IBRS is enabled, or SMT impossible,
+        * STIBP is not required.
         */
        if (!boot_cpu_has(X86_FEATURE_STIBP) ||
            !smt_possible ||
-           spectre_v2_in_eibrs_mode(spectre_v2_enabled))
+           spectre_v2_in_ibrs_mode(spectre_v2_enabled))
                return;
 
        /*
@@ -986,6 +1179,13 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
            boot_cpu_has(X86_FEATURE_AMD_STIBP_ALWAYS_ON))
                mode = SPECTRE_V2_USER_STRICT_PREFERRED;
 
+       if (retbleed_mitigation == RETBLEED_MITIGATION_UNRET) {
+               if (mode != SPECTRE_V2_USER_STRICT &&
+                   mode != SPECTRE_V2_USER_STRICT_PREFERRED)
+                       pr_info("Selecting STIBP always-on mode to complement retbleed mitigation\n");
+               mode = SPECTRE_V2_USER_STRICT_PREFERRED;
+       }
+
        spectre_v2_user_stibp = mode;
 
 set_mode:
@@ -999,6 +1199,7 @@ static const char * const spectre_v2_strings[] = {
        [SPECTRE_V2_EIBRS]                      = "Mitigation: Enhanced IBRS",
        [SPECTRE_V2_EIBRS_LFENCE]               = "Mitigation: Enhanced IBRS + LFENCE",
        [SPECTRE_V2_EIBRS_RETPOLINE]            = "Mitigation: Enhanced IBRS + Retpolines",
+       [SPECTRE_V2_IBRS]                       = "Mitigation: IBRS",
 };
 
 static const struct {
@@ -1016,6 +1217,7 @@ static const struct {
        { "eibrs,lfence",       SPECTRE_V2_CMD_EIBRS_LFENCE,      false },
        { "eibrs,retpoline",    SPECTRE_V2_CMD_EIBRS_RETPOLINE,   false },
        { "auto",               SPECTRE_V2_CMD_AUTO,              false },
+       { "ibrs",               SPECTRE_V2_CMD_IBRS,              false },
 };
 
 static void __init spec_v2_print_cond(const char *reason, bool secure)
@@ -1078,6 +1280,30 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
                return SPECTRE_V2_CMD_AUTO;
        }
 
+       if (cmd == SPECTRE_V2_CMD_IBRS && !IS_ENABLED(CONFIG_CPU_IBRS_ENTRY)) {
+               pr_err("%s selected but not compiled in. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if (cmd == SPECTRE_V2_CMD_IBRS && boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) {
+               pr_err("%s selected but not Intel CPU. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if (cmd == SPECTRE_V2_CMD_IBRS && !boot_cpu_has(X86_FEATURE_IBRS)) {
+               pr_err("%s selected but CPU doesn't have IBRS. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if (cmd == SPECTRE_V2_CMD_IBRS && boot_cpu_has(X86_FEATURE_XENPV)) {
+               pr_err("%s selected but running as XenPV guest. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
        spec_v2_print_cond(mitigation_options[i].option,
                           mitigation_options[i].secure);
        return cmd;
@@ -1093,6 +1319,22 @@ static enum spectre_v2_mitigation __init spectre_v2_select_retpoline(void)
        return SPECTRE_V2_RETPOLINE;
 }
 
+/* Disable in-kernel use of non-RSB RET predictors */
+static void __init spec_ctrl_disable_kernel_rrsba(void)
+{
+       u64 ia32_cap;
+
+       if (!boot_cpu_has(X86_FEATURE_RRSBA_CTRL))
+               return;
+
+       ia32_cap = x86_read_arch_cap_msr();
+
+       if (ia32_cap & ARCH_CAP_RRSBA) {
+               x86_spec_ctrl_base |= SPEC_CTRL_RRSBA_DIS_S;
+               write_spec_ctrl_current(x86_spec_ctrl_base, true);
+       }
+}
+
 static void __init spectre_v2_select_mitigation(void)
 {
        enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline();
@@ -1117,6 +1359,15 @@ static void __init spectre_v2_select_mitigation(void)
                        break;
                }
 
+               if (IS_ENABLED(CONFIG_CPU_IBRS_ENTRY) &&
+                   boot_cpu_has_bug(X86_BUG_RETBLEED) &&
+                   retbleed_cmd != RETBLEED_CMD_OFF &&
+                   boot_cpu_has(X86_FEATURE_IBRS) &&
+                   boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+                       mode = SPECTRE_V2_IBRS;
+                       break;
+               }
+
                mode = spectre_v2_select_retpoline();
                break;
 
@@ -1133,6 +1384,10 @@ static void __init spectre_v2_select_mitigation(void)
                mode = spectre_v2_select_retpoline();
                break;
 
+       case SPECTRE_V2_CMD_IBRS:
+               mode = SPECTRE_V2_IBRS;
+               break;
+
        case SPECTRE_V2_CMD_EIBRS:
                mode = SPECTRE_V2_EIBRS;
                break;
@@ -1149,10 +1404,9 @@ static void __init spectre_v2_select_mitigation(void)
        if (mode == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled())
                pr_err(SPECTRE_V2_EIBRS_EBPF_MSG);
 
-       if (spectre_v2_in_eibrs_mode(mode)) {
-               /* Force it so VMEXIT will restore correctly */
+       if (spectre_v2_in_ibrs_mode(mode)) {
                x86_spec_ctrl_base |= SPEC_CTRL_IBRS;
-               wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+               write_spec_ctrl_current(x86_spec_ctrl_base, true);
        }
 
        switch (mode) {
@@ -1160,6 +1414,12 @@ static void __init spectre_v2_select_mitigation(void)
        case SPECTRE_V2_EIBRS:
                break;
 
+       case SPECTRE_V2_IBRS:
+               setup_force_cpu_cap(X86_FEATURE_KERNEL_IBRS);
+               if (boot_cpu_has(X86_FEATURE_IBRS_ENHANCED))
+                       pr_warn(SPECTRE_V2_IBRS_PERF_MSG);
+               break;
+
        case SPECTRE_V2_LFENCE:
        case SPECTRE_V2_EIBRS_LFENCE:
                setup_force_cpu_cap(X86_FEATURE_RETPOLINE_LFENCE);
@@ -1171,43 +1431,116 @@ static void __init spectre_v2_select_mitigation(void)
                break;
        }
 
+       /*
+        * Disable alternate RSB predictions in kernel when indirect CALLs and
+        * JMPs gets protection against BHI and Intramode-BTI, but RET
+        * prediction from a non-RSB predictor is still a risk.
+        */
+       if (mode == SPECTRE_V2_EIBRS_LFENCE ||
+           mode == SPECTRE_V2_EIBRS_RETPOLINE ||
+           mode == SPECTRE_V2_RETPOLINE)
+               spec_ctrl_disable_kernel_rrsba();
+
        spectre_v2_enabled = mode;
        pr_info("%s\n", spectre_v2_strings[mode]);
 
        /*
-        * If spectre v2 protection has been enabled, unconditionally fill
-        * RSB during a context switch; this protects against two independent
-        * issues:
+        * If Spectre v2 protection has been enabled, fill the RSB during a
+        * context switch.  In general there are two types of RSB attacks
+        * across context switches, for which the CALLs/RETs may be unbalanced.
+        *
+        * 1) RSB underflow
+        *
+        *    Some Intel parts have "bottomless RSB".  When the RSB is empty,
+        *    speculated return targets may come from the branch predictor,
+        *    which could have a user-poisoned BTB or BHB entry.
+        *
+        *    AMD has it even worse: *all* returns are speculated from the BTB,
+        *    regardless of the state of the RSB.
         *
-        *      - RSB underflow (and switch to BTB) on Skylake+
-        *      - SpectreRSB variant of spectre v2 on X86_BUG_SPECTRE_V2 CPUs
+        *    When IBRS or eIBRS is enabled, the "user -> kernel" attack
+        *    scenario is mitigated by the IBRS branch prediction isolation
+        *    properties, so the RSB buffer filling wouldn't be necessary to
+        *    protect against this type of attack.
+        *
+        *    The "user -> user" attack scenario is mitigated by RSB filling.
+        *
+        * 2) Poisoned RSB entry
+        *
+        *    If the 'next' in-kernel return stack is shorter than 'prev',
+        *    'next' could be tricked into speculating with a user-poisoned RSB
+        *    entry.
+        *
+        *    The "user -> kernel" attack scenario is mitigated by SMEP and
+        *    eIBRS.
+        *
+        *    The "user -> user" scenario, also known as SpectreBHB, requires
+        *    RSB clearing.
+        *
+        * So to mitigate all cases, unconditionally fill RSB on context
+        * switches.
+        *
+        * FIXME: Is this pointless for retbleed-affected AMD?
         */
        setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW);
        pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch\n");
 
        /*
-        * Retpoline means the kernel is safe because it has no indirect
-        * branches. Enhanced IBRS protects firmware too, so, enable restricted
-        * speculation around firmware calls only when Enhanced IBRS isn't
-        * supported.
+        * Similar to context switches, there are two types of RSB attacks
+        * after vmexit:
+        *
+        * 1) RSB underflow
+        *
+        * 2) Poisoned RSB entry
+        *
+        * When retpoline is enabled, both are mitigated by filling/clearing
+        * the RSB.
+        *
+        * When IBRS is enabled, while #1 would be mitigated by the IBRS branch
+        * prediction isolation protections, RSB still needs to be cleared
+        * because of #2.  Note that SMEP provides no protection here, unlike
+        * user-space-poisoned RSB entries.
+        *
+        * eIBRS, on the other hand, has RSB-poisoning protections, so it
+        * doesn't need RSB clearing after vmexit.
+        */
+       if (boot_cpu_has(X86_FEATURE_RETPOLINE) ||
+           boot_cpu_has(X86_FEATURE_KERNEL_IBRS))
+               setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT);
+
+       /*
+        * Retpoline protects the kernel, but doesn't protect firmware.  IBRS
+        * and Enhanced IBRS protect firmware too, so enable IBRS around
+        * firmware calls only when IBRS / Enhanced IBRS aren't otherwise
+        * enabled.
         *
         * Use "mode" to check Enhanced IBRS instead of boot_cpu_has(), because
         * the user might select retpoline on the kernel command line and if
         * the CPU supports Enhanced IBRS, kernel might un-intentionally not
         * enable IBRS around firmware calls.
         */
-       if (boot_cpu_has(X86_FEATURE_IBRS) && !spectre_v2_in_eibrs_mode(mode)) {
+       if (boot_cpu_has_bug(X86_BUG_RETBLEED) &&
+           (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
+            boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)) {
+
+               if (retbleed_cmd != RETBLEED_CMD_IBPB) {
+                       setup_force_cpu_cap(X86_FEATURE_USE_IBPB_FW);
+                       pr_info("Enabling Speculation Barrier for firmware calls\n");
+               }
+
+       } else if (boot_cpu_has(X86_FEATURE_IBRS) && !spectre_v2_in_ibrs_mode(mode)) {
                setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW);
                pr_info("Enabling Restricted Speculation for firmware calls\n");
        }
 
        /* Set up IBPB and STIBP depending on the general spectre V2 command */
-       spectre_v2_user_select_mitigation(cmd);
+       spectre_v2_cmd = cmd;
 }
 
 static void update_stibp_msr(void * __unused)
 {
-       wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+       u64 val = spec_ctrl_current() | (x86_spec_ctrl_base & SPEC_CTRL_STIBP);
+       write_spec_ctrl_current(val, true);
 }
 
 /* Update x86_spec_ctrl_base in case SMT state changed. */
@@ -1423,16 +1756,6 @@ static enum ssb_mitigation __init __ssb_select_mitigation(void)
                break;
        }
 
-       /*
-        * If SSBD is controlled by the SPEC_CTRL MSR, then set the proper
-        * bit in the mask to allow guests to use the mitigation even in the
-        * case where the host does not enable it.
-        */
-       if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
-           static_cpu_has(X86_FEATURE_AMD_SSBD)) {
-               x86_spec_ctrl_mask |= SPEC_CTRL_SSBD;
-       }
-
        /*
         * We have three CPU feature flags that are in play here:
         *  - X86_BUG_SPEC_STORE_BYPASS - CPU is susceptible.
@@ -1450,7 +1773,7 @@ static enum ssb_mitigation __init __ssb_select_mitigation(void)
                        x86_amd_ssb_disable();
                } else {
                        x86_spec_ctrl_base |= SPEC_CTRL_SSBD;
-                       wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+                       write_spec_ctrl_current(x86_spec_ctrl_base, true);
                }
        }
 
@@ -1701,7 +2024,7 @@ int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
 void x86_spec_ctrl_setup_ap(void)
 {
        if (boot_cpu_has(X86_FEATURE_MSR_SPEC_CTRL))
-               wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+               write_spec_ctrl_current(x86_spec_ctrl_base, true);
 
        if (ssb_mode == SPEC_STORE_BYPASS_DISABLE)
                x86_amd_ssb_disable();
@@ -1938,7 +2261,7 @@ static ssize_t mmio_stale_data_show_state(char *buf)
 
 static char *stibp_state(void)
 {
-       if (spectre_v2_in_eibrs_mode(spectre_v2_enabled))
+       if (spectre_v2_in_ibrs_mode(spectre_v2_enabled))
                return "";
 
        switch (spectre_v2_user_stibp) {
@@ -1994,6 +2317,24 @@ static ssize_t srbds_show_state(char *buf)
        return sprintf(buf, "%s\n", srbds_strings[srbds_mitigation]);
 }
 
+static ssize_t retbleed_show_state(char *buf)
+{
+       if (retbleed_mitigation == RETBLEED_MITIGATION_UNRET) {
+           if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
+               boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
+                   return sprintf(buf, "Vulnerable: untrained return thunk on non-Zen uarch\n");
+
+           return sprintf(buf, "%s; SMT %s\n",
+                          retbleed_strings[retbleed_mitigation],
+                          !sched_smt_active() ? "disabled" :
+                          spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
+                          spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED ?
+                          "enabled with STIBP protection" : "vulnerable");
+       }
+
+       return sprintf(buf, "%s\n", retbleed_strings[retbleed_mitigation]);
+}
+
 static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr,
                               char *buf, unsigned int bug)
 {
@@ -2039,6 +2380,9 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
        case X86_BUG_MMIO_STALE_DATA:
                return mmio_stale_data_show_state(buf);
 
+       case X86_BUG_RETBLEED:
+               return retbleed_show_state(buf);
+
        default:
                break;
        }
@@ -2095,4 +2439,9 @@ ssize_t cpu_show_mmio_stale_data(struct device *dev, struct device_attribute *at
 {
        return cpu_show_common(dev, attr, buf, X86_BUG_MMIO_STALE_DATA);
 }
+
+ssize_t cpu_show_retbleed(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return cpu_show_common(dev, attr, buf, X86_BUG_RETBLEED);
+}
 #endif
index 4730b0a58f24a559f3f4c5decca80589e3c64b4e..736262a76a12b74541c855dd231a47befa81ebbc 100644 (file)
@@ -1205,48 +1205,60 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
        {}
 };
 
+#define VULNBL(vendor, family, model, blacklist)       \
+       X86_MATCH_VENDOR_FAM_MODEL(vendor, family, model, blacklist)
+
 #define VULNBL_INTEL_STEPPINGS(model, steppings, issues)                  \
        X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE(INTEL, 6,             \
                                            INTEL_FAM6_##model, steppings, \
                                            X86_FEATURE_ANY, issues)
 
+#define VULNBL_AMD(family, blacklist)          \
+       VULNBL(AMD, family, X86_MODEL_ANY, blacklist)
+
+#define VULNBL_HYGON(family, blacklist)                \
+       VULNBL(HYGON, family, X86_MODEL_ANY, blacklist)
+
 #define SRBDS          BIT(0)
 /* CPU is affected by X86_BUG_MMIO_STALE_DATA */
 #define MMIO           BIT(1)
 /* CPU is affected by Shared Buffers Data Sampling (SBDS), a variant of X86_BUG_MMIO_STALE_DATA */
 #define MMIO_SBDS      BIT(2)
+/* CPU is affected by RETbleed, speculating where you would not expect it */
+#define RETBLEED       BIT(3)
 
 static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = {
        VULNBL_INTEL_STEPPINGS(IVYBRIDGE,       X86_STEPPING_ANY,               SRBDS),
        VULNBL_INTEL_STEPPINGS(HASWELL,         X86_STEPPING_ANY,               SRBDS),
        VULNBL_INTEL_STEPPINGS(HASWELL_L,       X86_STEPPING_ANY,               SRBDS),
        VULNBL_INTEL_STEPPINGS(HASWELL_G,       X86_STEPPING_ANY,               SRBDS),
-       VULNBL_INTEL_STEPPINGS(HASWELL_X,       BIT(2) | BIT(4),                MMIO),
-       VULNBL_INTEL_STEPPINGS(BROADWELL_D,     X86_STEPPINGS(0x3, 0x5),        MMIO),
+       VULNBL_INTEL_STEPPINGS(HASWELL_X,       X86_STEPPING_ANY,               MMIO),
+       VULNBL_INTEL_STEPPINGS(BROADWELL_D,     X86_STEPPING_ANY,               MMIO),
        VULNBL_INTEL_STEPPINGS(BROADWELL_G,     X86_STEPPING_ANY,               SRBDS),
        VULNBL_INTEL_STEPPINGS(BROADWELL_X,     X86_STEPPING_ANY,               MMIO),
        VULNBL_INTEL_STEPPINGS(BROADWELL,       X86_STEPPING_ANY,               SRBDS),
-       VULNBL_INTEL_STEPPINGS(SKYLAKE_L,       X86_STEPPINGS(0x3, 0x3),        SRBDS | MMIO),
-       VULNBL_INTEL_STEPPINGS(SKYLAKE_L,       X86_STEPPING_ANY,               SRBDS),
-       VULNBL_INTEL_STEPPINGS(SKYLAKE_X,       BIT(3) | BIT(4) | BIT(6) |
-                                               BIT(7) | BIT(0xB),              MMIO),
-       VULNBL_INTEL_STEPPINGS(SKYLAKE,         X86_STEPPINGS(0x3, 0x3),        SRBDS | MMIO),
-       VULNBL_INTEL_STEPPINGS(SKYLAKE,         X86_STEPPING_ANY,               SRBDS),
-       VULNBL_INTEL_STEPPINGS(KABYLAKE_L,      X86_STEPPINGS(0x9, 0xC),        SRBDS | MMIO),
-       VULNBL_INTEL_STEPPINGS(KABYLAKE_L,      X86_STEPPINGS(0x0, 0x8),        SRBDS),
-       VULNBL_INTEL_STEPPINGS(KABYLAKE,        X86_STEPPINGS(0x9, 0xD),        SRBDS | MMIO),
-       VULNBL_INTEL_STEPPINGS(KABYLAKE,        X86_STEPPINGS(0x0, 0x8),        SRBDS),
-       VULNBL_INTEL_STEPPINGS(ICELAKE_L,       X86_STEPPINGS(0x5, 0x5),        MMIO | MMIO_SBDS),
-       VULNBL_INTEL_STEPPINGS(ICELAKE_D,       X86_STEPPINGS(0x1, 0x1),        MMIO),
-       VULNBL_INTEL_STEPPINGS(ICELAKE_X,       X86_STEPPINGS(0x4, 0x6),        MMIO),
-       VULNBL_INTEL_STEPPINGS(COMETLAKE,       BIT(2) | BIT(3) | BIT(5),       MMIO | MMIO_SBDS),
-       VULNBL_INTEL_STEPPINGS(COMETLAKE_L,     X86_STEPPINGS(0x1, 0x1),        MMIO | MMIO_SBDS),
-       VULNBL_INTEL_STEPPINGS(COMETLAKE_L,     X86_STEPPINGS(0x0, 0x0),        MMIO),
-       VULNBL_INTEL_STEPPINGS(LAKEFIELD,       X86_STEPPINGS(0x1, 0x1),        MMIO | MMIO_SBDS),
-       VULNBL_INTEL_STEPPINGS(ROCKETLAKE,      X86_STEPPINGS(0x1, 0x1),        MMIO),
-       VULNBL_INTEL_STEPPINGS(ATOM_TREMONT,    X86_STEPPINGS(0x1, 0x1),        MMIO | MMIO_SBDS),
+       VULNBL_INTEL_STEPPINGS(SKYLAKE_L,       X86_STEPPING_ANY,               SRBDS | MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(SKYLAKE_X,       X86_STEPPING_ANY,               MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(SKYLAKE,         X86_STEPPING_ANY,               SRBDS | MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(KABYLAKE_L,      X86_STEPPING_ANY,               SRBDS | MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(KABYLAKE,        X86_STEPPING_ANY,               SRBDS | MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(CANNONLAKE_L,    X86_STEPPING_ANY,               RETBLEED),
+       VULNBL_INTEL_STEPPINGS(ICELAKE_L,       X86_STEPPING_ANY,               MMIO | MMIO_SBDS | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(ICELAKE_D,       X86_STEPPING_ANY,               MMIO),
+       VULNBL_INTEL_STEPPINGS(ICELAKE_X,       X86_STEPPING_ANY,               MMIO),
+       VULNBL_INTEL_STEPPINGS(COMETLAKE,       X86_STEPPING_ANY,               MMIO | MMIO_SBDS | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(COMETLAKE_L,     X86_STEPPINGS(0x0, 0x0),        MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(COMETLAKE_L,     X86_STEPPING_ANY,               MMIO | MMIO_SBDS | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(LAKEFIELD,       X86_STEPPING_ANY,               MMIO | MMIO_SBDS | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(ROCKETLAKE,      X86_STEPPING_ANY,               MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(ATOM_TREMONT,    X86_STEPPING_ANY,               MMIO | MMIO_SBDS),
        VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_D,  X86_STEPPING_ANY,               MMIO),
-       VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_L,  X86_STEPPINGS(0x0, 0x0),        MMIO | MMIO_SBDS),
+       VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_L,  X86_STEPPING_ANY,               MMIO | MMIO_SBDS),
+
+       VULNBL_AMD(0x15, RETBLEED),
+       VULNBL_AMD(0x16, RETBLEED),
+       VULNBL_AMD(0x17, RETBLEED),
+       VULNBL_HYGON(0x18, RETBLEED),
        {}
 };
 
@@ -1348,6 +1360,11 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
            !arch_cap_mmio_immune(ia32_cap))
                setup_force_cpu_bug(X86_BUG_MMIO_STALE_DATA);
 
+       if (!cpu_has(c, X86_FEATURE_BTC_NO)) {
+               if (cpu_matches(cpu_vuln_blacklist, RETBLEED) || (ia32_cap & ARCH_CAP_RSBA))
+                       setup_force_cpu_bug(X86_BUG_RETBLEED);
+       }
+
        if (cpu_matches(cpu_vuln_whitelist, NO_MELTDOWN))
                return;
 
index 2a8e584fc991384813cab20de6b1746fbe8f1e38..7c9b5893c30aba0d3eb21c758264292d26a2e767 100644 (file)
@@ -61,6 +61,8 @@ static inline void tsx_init(void) { }
 static inline void tsx_ap_init(void) { }
 #endif /* CONFIG_CPU_SUP_INTEL */
 
+extern void init_spectral_chicken(struct cpuinfo_x86 *c);
+
 extern void get_cpu_cap(struct cpuinfo_x86 *c);
 extern void get_cpu_address_sizes(struct cpuinfo_x86 *c);
 extern void cpu_detect_cache_sizes(struct cpuinfo_x86 *c);
index 3fcdda4c1e114f6a83a589f92508df1061cad467..21fd425088fe5801ff5b62ca212a44477f62c5fb 100644 (file)
@@ -302,6 +302,12 @@ static void init_hygon(struct cpuinfo_x86 *c)
        /* get apicid instead of initial apic id from cpuid */
        c->apicid = hard_smp_processor_id();
 
+       /*
+        * XXX someone from Hygon needs to confirm this DTRT
+        *
+       init_spectral_chicken(c);
+        */
+
        set_cpu_cap(c, X86_FEATURE_ZEN);
        set_cpu_cap(c, X86_FEATURE_CPB);
 
index dbaa8326d6f289d16a3dc431261c80fa063cebb7..fd44b54c90d50483646909e581e8cc7eaad67188 100644 (file)
@@ -27,6 +27,7 @@ static const struct cpuid_bit cpuid_bits[] = {
        { X86_FEATURE_APERFMPERF,       CPUID_ECX,  0, 0x00000006, 0 },
        { X86_FEATURE_EPB,              CPUID_ECX,  3, 0x00000006, 0 },
        { X86_FEATURE_INTEL_PPIN,       CPUID_EBX,  0, 0x00000007, 1 },
+       { X86_FEATURE_RRSBA_CTRL,       CPUID_EDX,  2, 0x00000007, 2 },
        { X86_FEATURE_CQM_LLC,          CPUID_EDX,  1, 0x0000000f, 0 },
        { X86_FEATURE_CQM_OCCUP_LLC,    CPUID_EDX,  0, 0x0000000f, 1 },
        { X86_FEATURE_CQM_MBM_TOTAL,    CPUID_EDX,  1, 0x0000000f, 1 },
index 5b4efc927d808b68d5d5a18adaf1991dcd6fef52..24b9fa89aa276cb4a589ab315499230fce7b1b4d 100644 (file)
@@ -301,7 +301,7 @@ union ftrace_op_code_union {
        } __attribute__((packed));
 };
 
-#define RET_SIZE               1 + IS_ENABLED(CONFIG_SLS)
+#define RET_SIZE               (IS_ENABLED(CONFIG_RETPOLINE) ? 5 : 1 + IS_ENABLED(CONFIG_SLS))
 
 static unsigned long
 create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
@@ -357,7 +357,10 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
                goto fail;
 
        ip = trampoline + size;
-       memcpy(ip, retq, RET_SIZE);
+       if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
+               __text_gen_insn(ip, JMP32_INSN_OPCODE, ip, &__x86_return_thunk, JMP32_INSN_SIZE);
+       else
+               memcpy(ip, retq, sizeof(retq));
 
        /* No need to test direct calls on created trampolines */
        if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) {
index bd4a34100ed0cd53acf56114dcb976ec6186a669..6a3cfaf6b72ad6351dadcb837459eedefe3834ba 100644 (file)
@@ -426,10 +426,12 @@ void __init do_early_exception(struct pt_regs *regs, int trapnr)
 
 /* Don't add a printk in there. printk relies on the PDA which is not initialized 
    yet. */
-static void __init clear_bss(void)
+void __init clear_bss(void)
 {
        memset(__bss_start, 0,
               (unsigned long) __bss_stop - (unsigned long) __bss_start);
+       memset(__brk_base, 0,
+              (unsigned long) __brk_limit - (unsigned long) __brk_base);
 }
 
 static unsigned long get_cmd_line_ptr(void)
index eb8656bac99b6be6ccc4ebb6b182278ec41ce4ab..9b7acc9c7874c135fc83d4e62806977e01837212 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/cpufeatures.h>
 #include <asm/percpu.h>
 #include <asm/nops.h>
+#include <asm/nospec-branch.h>
 #include <asm/bootparam.h>
 #include <asm/export.h>
 #include <asm/pgtable_32.h>
index 92c4afa2b7298d2a45f6fc3e67843fdb73354bfe..d860d437631b649dd37476ff96195fadfbf0b2e5 100644 (file)
@@ -389,6 +389,8 @@ SYM_CODE_START_NOALIGN(vc_boot_ghcb)
        UNWIND_HINT_IRET_REGS offset=8
        ENDBR
 
+       ANNOTATE_UNRET_END
+
        /* Build pt_regs */
        PUSH_AND_CLEAR_REGS
 
@@ -448,6 +450,7 @@ SYM_CODE_END(early_idt_handler_array)
 
 SYM_CODE_START_LOCAL(early_idt_handler_common)
        UNWIND_HINT_IRET_REGS offset=16
+       ANNOTATE_UNRET_END
        /*
         * The stack is the hardware frame, an error code or zero, and the
         * vector number.
@@ -497,6 +500,8 @@ SYM_CODE_START_NOALIGN(vc_no_ghcb)
        UNWIND_HINT_IRET_REGS offset=8
        ENDBR
 
+       ANNOTATE_UNRET_END
+
        /* Build pt_regs */
        PUSH_AND_CLEAR_REGS
 
index b98ffcf4d250f1e62a145d4c79483fe2440a5828..67828d97338902b7fe3aca46bf297b369c00ee01 100644 (file)
@@ -253,7 +253,7 @@ int module_finalize(const Elf_Ehdr *hdr,
 {
        const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
                *para = NULL, *orc = NULL, *orc_ip = NULL,
-               *retpolines = NULL, *ibt_endbr = NULL;
+               *retpolines = NULL, *returns = NULL, *ibt_endbr = NULL;
        char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
 
        for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
@@ -271,6 +271,8 @@ int module_finalize(const Elf_Ehdr *hdr,
                        orc_ip = s;
                if (!strcmp(".retpoline_sites", secstrings + s->sh_name))
                        retpolines = s;
+               if (!strcmp(".return_sites", secstrings + s->sh_name))
+                       returns = s;
                if (!strcmp(".ibt_endbr_seal", secstrings + s->sh_name))
                        ibt_endbr = s;
        }
@@ -287,6 +289,10 @@ int module_finalize(const Elf_Ehdr *hdr,
                void *rseg = (void *)retpolines->sh_addr;
                apply_retpolines(rseg, rseg + retpolines->sh_size);
        }
+       if (returns) {
+               void *rseg = (void *)returns->sh_addr;
+               apply_returns(rseg, rseg + returns->sh_size);
+       }
        if (alt) {
                /* patch .altinstructions */
                void *aseg = (void *)alt->sh_addr;
index 9b2772b7e1f3990eee3760100880054cf7942a31..d456ce21c255269a49b70f387d8e0580f85dea11 100644 (file)
@@ -600,7 +600,7 @@ static __always_inline void __speculation_ctrl_update(unsigned long tifp,
        }
 
        if (updmsr)
-               wrmsrl(MSR_IA32_SPEC_CTRL, msr);
+               write_spec_ctrl_current(msr, false);
 }
 
 static unsigned long speculation_ctrl_update_tif(struct task_struct *tsk)
index fcc8a7699103a4ad416c1bf5cdf08e07c4b6063c..c7c4b1917336d1d95b5b998b0b065a89513287cd 100644 (file)
@@ -7,10 +7,12 @@
 #include <linux/linkage.h>
 #include <asm/page_types.h>
 #include <asm/kexec.h>
+#include <asm/nospec-branch.h>
 #include <asm/processor-flags.h>
 
 /*
- * Must be relocatable PIC code callable as a C function
+ * Must be relocatable PIC code callable as a C function, in particular
+ * there must be a plain RET and not jump to return thunk.
  */
 
 #define PTR(x) (x << 2)
@@ -91,7 +93,9 @@ SYM_CODE_START_NOALIGN(relocate_kernel)
        movl    %edi, %eax
        addl    $(identity_mapped - relocate_kernel), %eax
        pushl   %eax
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(relocate_kernel)
 
 SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
@@ -159,12 +163,15 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
        xorl    %edx, %edx
        xorl    %esi, %esi
        xorl    %ebp, %ebp
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 1:
        popl    %edx
        movl    CP_PA_SWAP_PAGE(%edi), %esp
        addl    $PAGE_SIZE, %esp
 2:
+       ANNOTATE_RETPOLINE_SAFE
        call    *%edx
 
        /* get the re-entry point of the peer system */
@@ -190,7 +197,9 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
        movl    %edi, %eax
        addl    $(virtual_mapped - relocate_kernel), %eax
        pushl   %eax
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(identity_mapped)
 
 SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped)
@@ -208,7 +217,9 @@ SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped)
        popl    %edi
        popl    %esi
        popl    %ebx
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(virtual_mapped)
 
        /* Do the copies */
@@ -271,7 +282,9 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages)
        popl    %edi
        popl    %ebx
        popl    %ebp
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(swap_pages)
 
        .globl kexec_control_code_size
index c1d8626c53b663e952c06f69468596f51eabbc6b..4809c0dc4eb0ceb64b8dbab19cf5cc9525352609 100644 (file)
@@ -13,7 +13,8 @@
 #include <asm/unwind_hints.h>
 
 /*
- * Must be relocatable PIC code callable as a C function
+ * Must be relocatable PIC code callable as a C function, in particular
+ * there must be a plain RET and not jump to return thunk.
  */
 
 #define PTR(x) (x << 3)
@@ -105,7 +106,9 @@ SYM_CODE_START_NOALIGN(relocate_kernel)
        /* jump to identity mapped page */
        addq    $(identity_mapped - relocate_kernel), %r8
        pushq   %r8
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(relocate_kernel)
 
 SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
@@ -200,7 +203,9 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
        xorl    %r14d, %r14d
        xorl    %r15d, %r15d
 
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 
 1:
        popq    %rdx
@@ -219,7 +224,9 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
        call    swap_pages
        movq    $virtual_mapped, %rax
        pushq   %rax
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(identity_mapped)
 
 SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped)
@@ -241,7 +248,9 @@ SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped)
        popq    %r12
        popq    %rbp
        popq    %rbx
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(virtual_mapped)
 
        /* Do the copies */
@@ -298,7 +307,9 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages)
        lea     PAGE_SIZE(%rax), %rsi
        jmp     0b
 3:
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(swap_pages)
 
        .globl kexec_control_code_size
index aa72cefdd5be61552e820f6ff65a949bf424fd97..aaaba85d6d7ff01e596f8b77c42ac72c707b0f0d 100644 (file)
@@ -11,6 +11,13 @@ enum insn_type {
        RET = 3,  /* tramp / site cond-tail-call */
 };
 
+/*
+ * ud1 %esp, %ecx - a 3 byte #UD that is unique to trampolines, chosen such
+ * that there is no false-positive trampoline identification while also being a
+ * speculation stop.
+ */
+static const u8 tramp_ud[] = { 0x0f, 0xb9, 0xcc };
+
 /*
  * cs cs cs xorl %eax, %eax - a single 5 byte instruction that clears %[er]ax
  */
@@ -18,7 +25,8 @@ static const u8 xor5rax[] = { 0x2e, 0x2e, 0x2e, 0x31, 0xc0 };
 
 static const u8 retinsn[] = { RET_INSN_OPCODE, 0xcc, 0xcc, 0xcc, 0xcc };
 
-static void __ref __static_call_transform(void *insn, enum insn_type type, void *func)
+static void __ref __static_call_transform(void *insn, enum insn_type type,
+                                         void *func, bool modinit)
 {
        const void *emulate = NULL;
        int size = CALL_INSN_SIZE;
@@ -43,14 +51,17 @@ static void __ref __static_call_transform(void *insn, enum insn_type type, void
                break;
 
        case RET:
-               code = &retinsn;
+               if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
+                       code = text_gen_insn(JMP32_INSN_OPCODE, insn, &__x86_return_thunk);
+               else
+                       code = &retinsn;
                break;
        }
 
        if (memcmp(insn, code, size) == 0)
                return;
 
-       if (unlikely(system_state == SYSTEM_BOOTING))
+       if (system_state == SYSTEM_BOOTING || modinit)
                return text_poke_early(insn, code, size);
 
        text_poke_bp(insn, code, size, emulate);
@@ -60,7 +71,7 @@ static void __static_call_validate(void *insn, bool tail, bool tramp)
 {
        u8 opcode = *(u8 *)insn;
 
-       if (tramp && memcmp(insn+5, "SCT", 3)) {
+       if (tramp && memcmp(insn+5, tramp_ud, 3)) {
                pr_err("trampoline signature fail");
                BUG();
        }
@@ -104,14 +115,42 @@ void arch_static_call_transform(void *site, void *tramp, void *func, bool tail)
 
        if (tramp) {
                __static_call_validate(tramp, true, true);
-               __static_call_transform(tramp, __sc_insn(!func, true), func);
+               __static_call_transform(tramp, __sc_insn(!func, true), func, false);
        }
 
        if (IS_ENABLED(CONFIG_HAVE_STATIC_CALL_INLINE) && site) {
                __static_call_validate(site, tail, false);
-               __static_call_transform(site, __sc_insn(!func, tail), func);
+               __static_call_transform(site, __sc_insn(!func, tail), func, false);
        }
 
        mutex_unlock(&text_mutex);
 }
 EXPORT_SYMBOL_GPL(arch_static_call_transform);
+
+#ifdef CONFIG_RETHUNK
+/*
+ * This is called by apply_returns() to fix up static call trampolines,
+ * specifically ARCH_DEFINE_STATIC_CALL_NULL_TRAMP which is recorded as
+ * having a return trampoline.
+ *
+ * The problem is that static_call() is available before determining
+ * X86_FEATURE_RETHUNK and, by implication, running alternatives.
+ *
+ * This means that __static_call_transform() above can have overwritten the
+ * return trampoline and we now need to fix things up to be consistent.
+ */
+bool __static_call_fixup(void *tramp, u8 op, void *dest)
+{
+       if (memcmp(tramp+5, tramp_ud, 3)) {
+               /* Not a trampoline site, not our problem. */
+               return false;
+       }
+
+       mutex_lock(&text_mutex);
+       if (op == RET_INSN_OPCODE || dest == &__x86_return_thunk)
+               __static_call_transform(tramp, RET, NULL, true);
+       mutex_unlock(&text_mutex);
+
+       return true;
+}
+#endif
index 81aba718ecd5616ff67d7eaaa207e0fa1e193cc0..15f29053cec46e462aa01c84c2b1f33e7c89ceaf 100644 (file)
@@ -141,7 +141,7 @@ SECTIONS
 
 #ifdef CONFIG_RETPOLINE
                __indirect_thunk_start = .;
-               *(.text.__x86.indirect_thunk)
+               *(.text.__x86.*)
                __indirect_thunk_end = .;
 #endif
        } :text =0xcccc
@@ -283,6 +283,13 @@ SECTIONS
                *(.retpoline_sites)
                __retpoline_sites_end = .;
        }
+
+       . = ALIGN(8);
+       .return_sites : AT(ADDR(.return_sites) - LOAD_OFFSET) {
+               __return_sites = .;
+               *(.return_sites)
+               __return_sites_end = .;
+       }
 #endif
 
 #ifdef CONFIG_X86_KERNEL_IBT
@@ -385,7 +392,7 @@ SECTIONS
        __end_of_kernel_reserve = .;
 
        . = ALIGN(PAGE_SIZE);
-       .brk (NOLOAD) : AT(ADDR(.brk) - LOAD_OFFSET) {
+       .brk : AT(ADDR(.brk) - LOAD_OFFSET) {
                __brk_base = .;
                . += 64 * 1024;         /* 64k alignment slop space */
                *(.bss..brk)            /* areas brk users have reserved */
index 89b11e7dca8aa5d994122fdf7d1831bda5952df7..f8382abe22ff811f9faddf6995f4f8cf5899416c 100644 (file)
 #define X8(x...) X4(x), X4(x)
 #define X16(x...) X8(x), X8(x)
 
-#define NR_FASTOP (ilog2(sizeof(ulong)) + 1)
-#define FASTOP_SIZE (8 * (1 + HAS_KERNEL_IBT))
-
 struct opcode {
        u64 flags;
        u8 intercept;
@@ -306,9 +303,15 @@ static void invalidate_registers(struct x86_emulate_ctxt *ctxt)
  * Moreover, they are all exactly FASTOP_SIZE bytes long, so functions for
  * different operand sizes can be reached by calculation, rather than a jump
  * table (which would be bigger than the code).
+ *
+ * The 16 byte alignment, considering 5 bytes for the RET thunk, 3 for ENDBR
+ * and 1 for the straight line speculation INT3, leaves 7 bytes for the
+ * body of the function.  Currently none is larger than 4.
  */
 static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop);
 
+#define FASTOP_SIZE    16
+
 #define __FOP_FUNC(name) \
        ".align " __stringify(FASTOP_SIZE) " \n\t" \
        ".type " name ", @function \n\t" \
@@ -325,13 +328,15 @@ static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop);
 #define FOP_RET(name) \
        __FOP_RET(#name)
 
-#define FOP_START(op) \
+#define __FOP_START(op, align) \
        extern void em_##op(struct fastop *fake); \
        asm(".pushsection .text, \"ax\" \n\t" \
            ".global em_" #op " \n\t" \
-           ".align " __stringify(FASTOP_SIZE) " \n\t" \
+           ".align " __stringify(align) " \n\t" \
            "em_" #op ":\n\t"
 
+#define FOP_START(op) __FOP_START(op, FASTOP_SIZE)
+
 #define FOP_END \
            ".popsection")
 
@@ -435,17 +440,12 @@ static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop);
 /*
  * Depending on .config the SETcc functions look like:
  *
- * ENDBR       [4 bytes; CONFIG_X86_KERNEL_IBT]
- * SETcc %al   [3 bytes]
- * RET         [1 byte]
- * INT3        [1 byte; CONFIG_SLS]
- *
- * Which gives possible sizes 4, 5, 8 or 9.  When rounded up to the
- * next power-of-two alignment they become 4, 8 or 16 resp.
+ * ENDBR                       [4 bytes; CONFIG_X86_KERNEL_IBT]
+ * SETcc %al                   [3 bytes]
+ * RET | JMP __x86_return_thunk        [1,5 bytes; CONFIG_RETHUNK]
+ * INT3                                [1 byte; CONFIG_SLS]
  */
-#define SETCC_LENGTH   (ENDBR_INSN_SIZE + 4 + IS_ENABLED(CONFIG_SLS))
-#define SETCC_ALIGN    (4 << IS_ENABLED(CONFIG_SLS) << HAS_KERNEL_IBT)
-static_assert(SETCC_LENGTH <= SETCC_ALIGN);
+#define SETCC_ALIGN    16
 
 #define FOP_SETCC(op) \
        ".align " __stringify(SETCC_ALIGN) " \n\t" \
@@ -453,9 +453,10 @@ static_assert(SETCC_LENGTH <= SETCC_ALIGN);
        #op ": \n\t" \
        ASM_ENDBR \
        #op " %al \n\t" \
-       __FOP_RET(#op)
+       __FOP_RET(#op) \
+       ".skip " __stringify(SETCC_ALIGN) " - (.-" #op "), 0xcc \n\t"
 
-FOP_START(setcc)
+__FOP_START(setcc, SETCC_ALIGN)
 FOP_SETCC(seto)
 FOP_SETCC(setno)
 FOP_SETCC(setc)
index dfaeb47fcf2a75cbd2756931efe22a9d2a70ec43..723f8534986c31b505a2e5d314c347f720fbecd9 100644 (file)
@@ -110,6 +110,15 @@ SYM_FUNC_START(__svm_vcpu_run)
        mov %r15, VCPU_R15(%_ASM_AX)
 #endif
 
+       /*
+        * Mitigate RETBleed for AMD/Hygon Zen uarch. RET should be
+        * untrained as soon as we exit the VM and are back to the
+        * kernel. This should be done before re-enabling interrupts
+        * because interrupt handlers won't sanitize 'ret' if the return is
+        * from the kernel.
+        */
+       UNTRAIN_RET
+
        /*
         * Clear all general purpose registers except RSP and RAX to prevent
         * speculative use of the guest's values, even those that are reloaded
@@ -190,6 +199,15 @@ SYM_FUNC_START(__svm_sev_es_vcpu_run)
        FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RETPOLINE
 #endif
 
+       /*
+        * Mitigate RETBleed for AMD/Hygon Zen uarch. RET should be
+        * untrained as soon as we exit the VM and are back to the
+        * kernel. This should be done before re-enabling interrupts
+        * because interrupt handlers won't sanitize RET if the return is
+        * from the kernel.
+        */
+       UNTRAIN_RET
+
        pop %_ASM_BX
 
 #ifdef CONFIG_X86_64
index 3f430e2183753a5d594d8308a3d73477d921ebdc..c0e24826a86f718bcb7b2859dc8739c04d75d8a3 100644 (file)
@@ -4,8 +4,8 @@
 
 #include <asm/vmx.h>
 
-#include "lapic.h"
-#include "x86.h"
+#include "../lapic.h"
+#include "../x86.h"
 
 extern bool __read_mostly enable_vpid;
 extern bool __read_mostly flexpriority_enabled;
index f5cb18e00e789259b591c677ad5ddac18a3ce621..ab135f9ef52f28673e3f3b9e906166944d669488 100644 (file)
@@ -2278,7 +2278,6 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0
                                  SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY |
                                  SECONDARY_EXEC_APIC_REGISTER_VIRT |
                                  SECONDARY_EXEC_ENABLE_VMFUNC |
-                                 SECONDARY_EXEC_TSC_SCALING |
                                  SECONDARY_EXEC_DESC);
 
                if (nested_cpu_has(vmcs12,
@@ -3087,7 +3086,7 @@ static int nested_vmx_check_vmentry_hw(struct kvm_vcpu *vcpu)
        }
 
        vm_fail = __vmx_vcpu_run(vmx, (unsigned long *)&vcpu->arch.regs,
-                                vmx->loaded_vmcs->launched);
+                                __vmx_vcpu_run_flags(vmx));
 
        if (vmx->msr_autoload.host.nr)
                vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr);
diff --git a/arch/x86/kvm/vmx/run_flags.h b/arch/x86/kvm/vmx/run_flags.h
new file mode 100644 (file)
index 0000000..edc3f16
--- /dev/null
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __KVM_X86_VMX_RUN_FLAGS_H
+#define __KVM_X86_VMX_RUN_FLAGS_H
+
+#define VMX_RUN_VMRESUME       (1 << 0)
+#define VMX_RUN_SAVE_SPEC_CTRL (1 << 1)
+
+#endif /* __KVM_X86_VMX_RUN_FLAGS_H */
index 435c187927c4853deec9f5d14032e8964c4ed75e..4182c7ffc90910a30a8e7f465cc44bfdc8b35d7a 100644 (file)
@@ -1,10 +1,13 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #include <linux/linkage.h>
 #include <asm/asm.h>
+#include <asm/asm-offsets.h>
 #include <asm/bitsperlong.h>
 #include <asm/kvm_vcpu_regs.h>
 #include <asm/nospec-branch.h>
+#include <asm/percpu.h>
 #include <asm/segment.h>
+#include "run_flags.h"
 
 #define WORD_SIZE (BITS_PER_LONG / 8)
 
 
 .section .noinstr.text, "ax"
 
-/**
- * vmx_vmenter - VM-Enter the current loaded VMCS
- *
- * %RFLAGS.ZF: !VMCS.LAUNCHED, i.e. controls VMLAUNCH vs. VMRESUME
- *
- * Returns:
- *     %RFLAGS.CF is set on VM-Fail Invalid
- *     %RFLAGS.ZF is set on VM-Fail Valid
- *     %RFLAGS.{CF,ZF} are cleared on VM-Success, i.e. VM-Exit
- *
- * Note that VMRESUME/VMLAUNCH fall-through and return directly if
- * they VM-Fail, whereas a successful VM-Enter + VM-Exit will jump
- * to vmx_vmexit.
- */
-SYM_FUNC_START_LOCAL(vmx_vmenter)
-       /* EFLAGS.ZF is set if VMCS.LAUNCHED == 0 */
-       je 2f
-
-1:     vmresume
-       RET
-
-2:     vmlaunch
-       RET
-
-3:     cmpb $0, kvm_rebooting
-       je 4f
-       RET
-4:     ud2
-
-       _ASM_EXTABLE(1b, 3b)
-       _ASM_EXTABLE(2b, 3b)
-
-SYM_FUNC_END(vmx_vmenter)
-
-/**
- * vmx_vmexit - Handle a VMX VM-Exit
- *
- * Returns:
- *     %RFLAGS.{CF,ZF} are cleared on VM-Success, i.e. VM-Exit
- *
- * This is vmx_vmenter's partner in crime.  On a VM-Exit, control will jump
- * here after hardware loads the host's state, i.e. this is the destination
- * referred to by VMCS.HOST_RIP.
- */
-SYM_FUNC_START(vmx_vmexit)
-#ifdef CONFIG_RETPOLINE
-       ALTERNATIVE "jmp .Lvmexit_skip_rsb", "", X86_FEATURE_RETPOLINE
-       /* Preserve guest's RAX, it's used to stuff the RSB. */
-       push %_ASM_AX
-
-       /* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */
-       FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RETPOLINE
-
-       /* Clear RFLAGS.CF and RFLAGS.ZF to preserve VM-Exit, i.e. !VM-Fail. */
-       or $1, %_ASM_AX
-
-       pop %_ASM_AX
-.Lvmexit_skip_rsb:
-#endif
-       RET
-SYM_FUNC_END(vmx_vmexit)
-
 /**
  * __vmx_vcpu_run - Run a vCPU via a transition to VMX guest mode
- * @vmx:       struct vcpu_vmx * (forwarded to vmx_update_host_rsp)
+ * @vmx:       struct vcpu_vmx *
  * @regs:      unsigned long * (to guest registers)
- * @launched:  %true if the VMCS has been launched
+ * @flags:     VMX_RUN_VMRESUME:       use VMRESUME instead of VMLAUNCH
+ *             VMX_RUN_SAVE_SPEC_CTRL: save guest SPEC_CTRL into vmx->spec_ctrl
  *
  * Returns:
  *     0 on VM-Exit, 1 on VM-Fail
@@ -115,24 +57,56 @@ SYM_FUNC_START(__vmx_vcpu_run)
 #endif
        push %_ASM_BX
 
+       /* Save @vmx for SPEC_CTRL handling */
+       push %_ASM_ARG1
+
+       /* Save @flags for SPEC_CTRL handling */
+       push %_ASM_ARG3
+
        /*
         * Save @regs, _ASM_ARG2 may be modified by vmx_update_host_rsp() and
         * @regs is needed after VM-Exit to save the guest's register values.
         */
        push %_ASM_ARG2
 
-       /* Copy @launched to BL, _ASM_ARG3 is volatile. */
+       /* Copy @flags to BL, _ASM_ARG3 is volatile. */
        mov %_ASM_ARG3B, %bl
 
-       /* Adjust RSP to account for the CALL to vmx_vmenter(). */
-       lea -WORD_SIZE(%_ASM_SP), %_ASM_ARG2
+       lea (%_ASM_SP), %_ASM_ARG2
        call vmx_update_host_rsp
 
+       ALTERNATIVE "jmp .Lspec_ctrl_done", "", X86_FEATURE_MSR_SPEC_CTRL
+
+       /*
+        * SPEC_CTRL handling: if the guest's SPEC_CTRL value differs from the
+        * host's, write the MSR.
+        *
+        * IMPORTANT: To avoid RSB underflow attacks and any other nastiness,
+        * there must not be any returns or indirect branches between this code
+        * and vmentry.
+        */
+       mov 2*WORD_SIZE(%_ASM_SP), %_ASM_DI
+       movl VMX_spec_ctrl(%_ASM_DI), %edi
+       movl PER_CPU_VAR(x86_spec_ctrl_current), %esi
+       cmp %edi, %esi
+       je .Lspec_ctrl_done
+       mov $MSR_IA32_SPEC_CTRL, %ecx
+       xor %edx, %edx
+       mov %edi, %eax
+       wrmsr
+
+.Lspec_ctrl_done:
+
+       /*
+        * Since vmentry is serializing on affected CPUs, there's no need for
+        * an LFENCE to stop speculation from skipping the wrmsr.
+        */
+
        /* Load @regs to RAX. */
        mov (%_ASM_SP), %_ASM_AX
 
        /* Check if vmlaunch or vmresume is needed */
-       testb %bl, %bl
+       testb $VMX_RUN_VMRESUME, %bl
 
        /* Load guest registers.  Don't clobber flags. */
        mov VCPU_RCX(%_ASM_AX), %_ASM_CX
@@ -154,11 +128,37 @@ SYM_FUNC_START(__vmx_vcpu_run)
        /* Load guest RAX.  This kills the @regs pointer! */
        mov VCPU_RAX(%_ASM_AX), %_ASM_AX
 
-       /* Enter guest mode */
-       call vmx_vmenter
+       /* Check EFLAGS.ZF from 'testb' above */
+       jz .Lvmlaunch
+
+       /*
+        * After a successful VMRESUME/VMLAUNCH, control flow "magically"
+        * resumes below at 'vmx_vmexit' due to the VMCS HOST_RIP setting.
+        * So this isn't a typical function and objtool needs to be told to
+        * save the unwind state here and restore it below.
+        */
+       UNWIND_HINT_SAVE
+
+/*
+ * If VMRESUME/VMLAUNCH and corresponding vmexit succeed, execution resumes at
+ * the 'vmx_vmexit' label below.
+ */
+.Lvmresume:
+       vmresume
+       jmp .Lvmfail
+
+.Lvmlaunch:
+       vmlaunch
+       jmp .Lvmfail
 
-       /* Jump on VM-Fail. */
-       jbe 2f
+       _ASM_EXTABLE(.Lvmresume, .Lfixup)
+       _ASM_EXTABLE(.Lvmlaunch, .Lfixup)
+
+SYM_INNER_LABEL(vmx_vmexit, SYM_L_GLOBAL)
+
+       /* Restore unwind state from before the VMRESUME/VMLAUNCH. */
+       UNWIND_HINT_RESTORE
+       ENDBR
 
        /* Temporarily save guest's RAX. */
        push %_ASM_AX
@@ -185,21 +185,23 @@ SYM_FUNC_START(__vmx_vcpu_run)
        mov %r15, VCPU_R15(%_ASM_AX)
 #endif
 
-       /* Clear RAX to indicate VM-Exit (as opposed to VM-Fail). */
-       xor %eax, %eax
+       /* Clear return value to indicate VM-Exit (as opposed to VM-Fail). */
+       xor %ebx, %ebx
 
+.Lclear_regs:
        /*
-        * Clear all general purpose registers except RSP and RAX to prevent
+        * Clear all general purpose registers except RSP and RBX to prevent
         * speculative use of the guest's values, even those that are reloaded
         * via the stack.  In theory, an L1 cache miss when restoring registers
         * could lead to speculative execution with the guest's values.
         * Zeroing XORs are dirt cheap, i.e. the extra paranoia is essentially
         * free.  RSP and RAX are exempt as RSP is restored by hardware during
-        * VM-Exit and RAX is explicitly loaded with 0 or 1 to return VM-Fail.
+        * VM-Exit and RBX is explicitly loaded with 0 or 1 to hold the return
+        * value.
         */
-1:     xor %ecx, %ecx
+       xor %eax, %eax
+       xor %ecx, %ecx
        xor %edx, %edx
-       xor %ebx, %ebx
        xor %ebp, %ebp
        xor %esi, %esi
        xor %edi, %edi
@@ -216,8 +218,30 @@ SYM_FUNC_START(__vmx_vcpu_run)
 
        /* "POP" @regs. */
        add $WORD_SIZE, %_ASM_SP
-       pop %_ASM_BX
 
+       /*
+        * IMPORTANT: RSB filling and SPEC_CTRL handling must be done before
+        * the first unbalanced RET after vmexit!
+        *
+        * For retpoline or IBRS, RSB filling is needed to prevent poisoned RSB
+        * entries and (in some cases) RSB underflow.
+        *
+        * eIBRS has its own protection against poisoned RSB, so it doesn't
+        * need the RSB filling sequence.  But it does need to be enabled
+        * before the first unbalanced RET.
+         */
+
+       FILL_RETURN_BUFFER %_ASM_CX, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_VMEXIT
+
+       pop %_ASM_ARG2  /* @flags */
+       pop %_ASM_ARG1  /* @vmx */
+
+       call vmx_spec_ctrl_restore_host
+
+       /* Put return value in AX */
+       mov %_ASM_BX, %_ASM_AX
+
+       pop %_ASM_BX
 #ifdef CONFIG_X86_64
        pop %r12
        pop %r13
@@ -230,9 +254,15 @@ SYM_FUNC_START(__vmx_vcpu_run)
        pop %_ASM_BP
        RET
 
-       /* VM-Fail.  Out-of-line to avoid a taken Jcc after VM-Exit. */
-2:     mov $1, %eax
-       jmp 1b
+.Lfixup:
+       cmpb $0, kvm_rebooting
+       jne .Lvmfail
+       ud2
+.Lvmfail:
+       /* VM-Fail: set return value to 1 */
+       mov $1, %_ASM_BX
+       jmp .Lclear_regs
+
 SYM_FUNC_END(__vmx_vcpu_run)
 
 
index 3a919e49129bf5458692ea1c058f2bc28971bdf0..be7c19374fdd94d7347ea4c83588e9454e164530 100644 (file)
@@ -383,9 +383,9 @@ static __always_inline void vmx_disable_fb_clear(struct vcpu_vmx *vmx)
        if (!vmx->disable_fb_clear)
                return;
 
-       rdmsrl(MSR_IA32_MCU_OPT_CTRL, msr);
+       msr = __rdmsr(MSR_IA32_MCU_OPT_CTRL);
        msr |= FB_CLEAR_DIS;
-       wrmsrl(MSR_IA32_MCU_OPT_CTRL, msr);
+       native_wrmsrl(MSR_IA32_MCU_OPT_CTRL, msr);
        /* Cache the MSR value to avoid reading it later */
        vmx->msr_ia32_mcu_opt_ctrl = msr;
 }
@@ -396,7 +396,7 @@ static __always_inline void vmx_enable_fb_clear(struct vcpu_vmx *vmx)
                return;
 
        vmx->msr_ia32_mcu_opt_ctrl &= ~FB_CLEAR_DIS;
-       wrmsrl(MSR_IA32_MCU_OPT_CTRL, vmx->msr_ia32_mcu_opt_ctrl);
+       native_wrmsrl(MSR_IA32_MCU_OPT_CTRL, vmx->msr_ia32_mcu_opt_ctrl);
 }
 
 static void vmx_update_fb_clear_dis(struct kvm_vcpu *vcpu, struct vcpu_vmx *vmx)
@@ -839,6 +839,24 @@ static bool msr_write_intercepted(struct vcpu_vmx *vmx, u32 msr)
                                         MSR_IA32_SPEC_CTRL);
 }
 
+unsigned int __vmx_vcpu_run_flags(struct vcpu_vmx *vmx)
+{
+       unsigned int flags = 0;
+
+       if (vmx->loaded_vmcs->launched)
+               flags |= VMX_RUN_VMRESUME;
+
+       /*
+        * If writes to the SPEC_CTRL MSR aren't intercepted, the guest is free
+        * to change it directly without causing a vmexit.  In that case read
+        * it after vmexit and store it in vmx->spec_ctrl.
+        */
+       if (unlikely(!msr_write_intercepted(vmx, MSR_IA32_SPEC_CTRL)))
+               flags |= VMX_RUN_SAVE_SPEC_CTRL;
+
+       return flags;
+}
+
 static void clear_atomic_switch_msr_special(struct vcpu_vmx *vmx,
                unsigned long entry, unsigned long exit)
 {
@@ -6813,6 +6831,31 @@ void noinstr vmx_update_host_rsp(struct vcpu_vmx *vmx, unsigned long host_rsp)
        }
 }
 
+void noinstr vmx_spec_ctrl_restore_host(struct vcpu_vmx *vmx,
+                                       unsigned int flags)
+{
+       u64 hostval = this_cpu_read(x86_spec_ctrl_current);
+
+       if (!cpu_feature_enabled(X86_FEATURE_MSR_SPEC_CTRL))
+               return;
+
+       if (flags & VMX_RUN_SAVE_SPEC_CTRL)
+               vmx->spec_ctrl = __rdmsr(MSR_IA32_SPEC_CTRL);
+
+       /*
+        * If the guest/host SPEC_CTRL values differ, restore the host value.
+        *
+        * For legacy IBRS, the IBRS bit always needs to be written after
+        * transitioning from a less privileged predictor mode, regardless of
+        * whether the guest/host values differ.
+        */
+       if (cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS) ||
+           vmx->spec_ctrl != hostval)
+               native_wrmsrl(MSR_IA32_SPEC_CTRL, hostval);
+
+       barrier_nospec();
+}
+
 static fastpath_t vmx_exit_handlers_fastpath(struct kvm_vcpu *vcpu)
 {
        switch (to_vmx(vcpu)->exit_reason.basic) {
@@ -6826,7 +6869,8 @@ 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)
+                                       struct vcpu_vmx *vmx,
+                                       unsigned long flags)
 {
        guest_state_enter_irqoff();
 
@@ -6845,7 +6889,7 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
                native_write_cr2(vcpu->arch.cr2);
 
        vmx->fail = __vmx_vcpu_run(vmx, (unsigned long *)&vcpu->arch.regs,
-                                  vmx->loaded_vmcs->launched);
+                                  flags);
 
        vcpu->arch.cr2 = native_read_cr2();
 
@@ -6944,36 +6988,8 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu)
 
        kvm_wait_lapic_expire(vcpu);
 
-       /*
-        * If this vCPU has touched SPEC_CTRL, restore the guest's value if
-        * it's non-zero. Since vmentry is serialising on affected CPUs, there
-        * is no need to worry about the conditional branch over the wrmsr
-        * being speculatively taken.
-        */
-       x86_spec_ctrl_set_guest(vmx->spec_ctrl, 0);
-
        /* The actual VMENTER/EXIT is in the .noinstr.text section. */
-       vmx_vcpu_enter_exit(vcpu, vmx);
-
-       /*
-        * We do not use IBRS in the kernel. If this vCPU has used the
-        * SPEC_CTRL MSR it may have left it on; save the value and
-        * turn it off. This is much more efficient than blindly adding
-        * it to the atomic save/restore list. Especially as the former
-        * (Saving guest MSRs on vmexit) doesn't even exist in KVM.
-        *
-        * For non-nested case:
-        * If the L01 MSR bitmap does not intercept the MSR, then we need to
-        * save it.
-        *
-        * For nested case:
-        * If the L02 MSR bitmap does not intercept the MSR, then we need to
-        * save it.
-        */
-       if (unlikely(!msr_write_intercepted(vmx, MSR_IA32_SPEC_CTRL)))
-               vmx->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL);
-
-       x86_spec_ctrl_restore_host(vmx->spec_ctrl, 0);
+       vmx_vcpu_enter_exit(vcpu, vmx, __vmx_vcpu_run_flags(vmx));
 
        /* All fields are clean at this point */
        if (static_branch_unlikely(&enable_evmcs)) {
index 8d2342ede0c59d3c9a9a407743acfb713572de54..1e7f9453894b1456984d51d4485307c2f3ffb876 100644 (file)
@@ -8,11 +8,12 @@
 #include <asm/intel_pt.h>
 
 #include "capabilities.h"
-#include "kvm_cache_regs.h"
+#include "../kvm_cache_regs.h"
 #include "posted_intr.h"
 #include "vmcs.h"
 #include "vmx_ops.h"
-#include "cpuid.h"
+#include "../cpuid.h"
+#include "run_flags.h"
 
 #define MSR_TYPE_R     1
 #define MSR_TYPE_W     2
@@ -404,7 +405,10 @@ void vmx_set_virtual_apic_mode(struct kvm_vcpu *vcpu);
 struct vmx_uret_msr *vmx_find_uret_msr(struct vcpu_vmx *vmx, u32 msr);
 void pt_update_intercept_for_msr(struct kvm_vcpu *vcpu);
 void vmx_update_host_rsp(struct vcpu_vmx *vmx, unsigned long host_rsp);
-bool __vmx_vcpu_run(struct vcpu_vmx *vmx, unsigned long *regs, bool launched);
+void vmx_spec_ctrl_restore_host(struct vcpu_vmx *vmx, unsigned int flags);
+unsigned int __vmx_vcpu_run_flags(struct vcpu_vmx *vmx);
+bool __vmx_vcpu_run(struct vcpu_vmx *vmx, unsigned long *regs,
+                   unsigned int flags);
 int vmx_find_loadstore_msr_slot(struct vmx_msrs *m, u32 msr);
 void vmx_ept_load_pdptrs(struct kvm_vcpu *vcpu);
 
index 5e7f4122578014a630b3ba99d82e464b6dd7bf7a..5cfc49ddb1b442801bf058779e86f0102a7536ec 100644 (file)
@@ -8,7 +8,7 @@
 
 #include "evmcs.h"
 #include "vmcs.h"
-#include "x86.h"
+#include "../x86.h"
 
 asmlinkage void vmread_error(unsigned long field, bool fault);
 __attribute__((regparm(0))) void vmread_error_trampoline(unsigned long field,
index 1910e1e78b1534346cbf0fd85a35ad05c4c31003..e5fa335a4ea794959f4a5aec13c747bc9e66ce0f 100644 (file)
@@ -298,7 +298,7 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
        STATS_DESC_COUNTER(VCPU, directed_yield_successful),
        STATS_DESC_COUNTER(VCPU, preemption_reported),
        STATS_DESC_COUNTER(VCPU, preemption_other),
-       STATS_DESC_ICOUNTER(VCPU, guest_mode)
+       STATS_DESC_IBOOLEAN(VCPU, guest_mode)
 };
 
 const struct kvm_stats_header kvm_vcpu_stats_header = {
@@ -6029,6 +6029,11 @@ split_irqchip_unlock:
                r = 0;
                break;
        case KVM_CAP_X86_USER_SPACE_MSR:
+               r = -EINVAL;
+               if (cap->args[0] & ~(KVM_MSR_EXIT_REASON_INVAL |
+                                    KVM_MSR_EXIT_REASON_UNKNOWN |
+                                    KVM_MSR_EXIT_REASON_FILTER))
+                       break;
                kvm->arch.user_space_msr_mask = cap->args[0];
                r = 0;
                break;
@@ -6183,6 +6188,9 @@ static int kvm_vm_ioctl_set_msr_filter(struct kvm *kvm, void __user *argp)
        if (copy_from_user(&filter, user_msr_filter, sizeof(filter)))
                return -EFAULT;
 
+       if (filter.flags & ~KVM_MSR_FILTER_DEFAULT_DENY)
+               return -EINVAL;
+
        for (i = 0; i < ARRAY_SIZE(filter.ranges); i++)
                empty &= !filter.ranges[i].nmsrs;
 
@@ -9143,15 +9151,17 @@ static int kvm_pv_clock_pairing(struct kvm_vcpu *vcpu, gpa_t paddr,
  */
 static void kvm_pv_kick_cpu_op(struct kvm *kvm, int apicid)
 {
-       struct kvm_lapic_irq lapic_irq;
-
-       lapic_irq.shorthand = APIC_DEST_NOSHORT;
-       lapic_irq.dest_mode = APIC_DEST_PHYSICAL;
-       lapic_irq.level = 0;
-       lapic_irq.dest_id = apicid;
-       lapic_irq.msi_redir_hint = false;
+       /*
+        * All other fields are unused for APIC_DM_REMRD, but may be consumed by
+        * common code, e.g. for tracing. Defer initialization to the compiler.
+        */
+       struct kvm_lapic_irq lapic_irq = {
+               .delivery_mode = APIC_DM_REMRD,
+               .dest_mode = APIC_DEST_PHYSICAL,
+               .shorthand = APIC_DEST_NOSHORT,
+               .dest_id = apicid,
+       };
 
-       lapic_irq.delivery_mode = APIC_DM_REMRD;
        kvm_irq_delivery_to_apic(kvm, NULL, &lapic_irq, NULL);
 }
 
@@ -12631,9 +12641,9 @@ void kvm_arch_end_assignment(struct kvm *kvm)
 }
 EXPORT_SYMBOL_GPL(kvm_arch_end_assignment);
 
-bool kvm_arch_has_assigned_device(struct kvm *kvm)
+bool noinstr kvm_arch_has_assigned_device(struct kvm *kvm)
 {
-       return atomic_read(&kvm->arch.assigned_device_count);
+       return arch_atomic_read(&kvm->arch.assigned_device_count);
 }
 EXPORT_SYMBOL_GPL(kvm_arch_has_assigned_device);
 
index d83cba364e31d1e9b3c653971c79e5057a33a149..724bbf83eb5b0910819b83a8cb5b349d45a6fe8d 100644 (file)
@@ -39,7 +39,7 @@ SYM_FUNC_START(__memmove)
        /* FSRM implies ERMS => no length checks, do the copy directly */
 .Lmemmove_begin_forward:
        ALTERNATIVE "cmp $0x20, %rdx; jb 1f", "", X86_FEATURE_FSRM
-       ALTERNATIVE "", __stringify(movq %rdx, %rcx; rep movsb; RET), X86_FEATURE_ERMS
+       ALTERNATIVE "", "jmp .Lmemmove_erms", X86_FEATURE_ERMS
 
        /*
         * movsq instruction have many startup latency
@@ -205,6 +205,11 @@ SYM_FUNC_START(__memmove)
        movb %r11b, (%rdi)
 13:
        RET
+
+.Lmemmove_erms:
+       movq %rdx, %rcx
+       rep movsb
+       RET
 SYM_FUNC_END(__memmove)
 EXPORT_SYMBOL(__memmove)
 
index b2b2366885a2b672960805bbb17a7c33a50952cf..073289a55f8495cb3f175d97d847485b05eb7a8b 100644 (file)
@@ -33,9 +33,9 @@ SYM_INNER_LABEL(__x86_indirect_thunk_\reg, SYM_L_GLOBAL)
        UNWIND_HINT_EMPTY
        ANNOTATE_NOENDBR
 
-       ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), \
-                     __stringify(RETPOLINE \reg), X86_FEATURE_RETPOLINE, \
-                     __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *%\reg; int3), X86_FEATURE_RETPOLINE_LFENCE
+       ALTERNATIVE_2 __stringify(RETPOLINE \reg), \
+                     __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *%\reg; int3), X86_FEATURE_RETPOLINE_LFENCE, \
+                     __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), ALT_NOT(X86_FEATURE_RETPOLINE)
 
 .endm
 
@@ -67,3 +67,76 @@ SYM_CODE_END(__x86_indirect_thunk_array)
 #define GEN(reg) EXPORT_THUNK(reg)
 #include <asm/GEN-for-each-reg.h>
 #undef GEN
+
+/*
+ * This function name is magical and is used by -mfunction-return=thunk-extern
+ * for the compiler to generate JMPs to it.
+ */
+#ifdef CONFIG_RETHUNK
+
+       .section .text.__x86.return_thunk
+
+/*
+ * Safety details here pertain to the AMD Zen{1,2} microarchitecture:
+ * 1) The RET at __x86_return_thunk must be on a 64 byte boundary, for
+ *    alignment within the BTB.
+ * 2) The instruction at zen_untrain_ret must contain, and not
+ *    end with, the 0xc3 byte of the RET.
+ * 3) STIBP must be enabled, or SMT disabled, to prevent the sibling thread
+ *    from re-poisioning the BTB prediction.
+ */
+       .align 64
+       .skip 63, 0xcc
+SYM_FUNC_START_NOALIGN(zen_untrain_ret);
+
+       /*
+        * As executed from zen_untrain_ret, this is:
+        *
+        *   TEST $0xcc, %bl
+        *   LFENCE
+        *   JMP __x86_return_thunk
+        *
+        * Executing the TEST instruction has a side effect of evicting any BTB
+        * prediction (potentially attacker controlled) attached to the RET, as
+        * __x86_return_thunk + 1 isn't an instruction boundary at the moment.
+        */
+       .byte   0xf6
+
+       /*
+        * As executed from __x86_return_thunk, this is a plain RET.
+        *
+        * As part of the TEST above, RET is the ModRM byte, and INT3 the imm8.
+        *
+        * We subsequently jump backwards and architecturally execute the RET.
+        * This creates a correct BTB prediction (type=ret), but in the
+        * meantime we suffer Straight Line Speculation (because the type was
+        * no branch) which is halted by the INT3.
+        *
+        * With SMT enabled and STIBP active, a sibling thread cannot poison
+        * RET's prediction to a type of its choice, but can evict the
+        * prediction due to competitive sharing. If the prediction is
+        * evicted, __x86_return_thunk will suffer Straight Line Speculation
+        * which will be contained safely by the INT3.
+        */
+SYM_INNER_LABEL(__x86_return_thunk, SYM_L_GLOBAL)
+       ret
+       int3
+SYM_CODE_END(__x86_return_thunk)
+
+       /*
+        * Ensure the TEST decoding / BTB invalidation is complete.
+        */
+       lfence
+
+       /*
+        * Jump back and execute the RET in the middle of the TEST instruction.
+        * INT3 is for SLS protection.
+        */
+       jmp __x86_return_thunk
+       int3
+SYM_FUNC_END(zen_untrain_ret)
+__EXPORT_THUNK(zen_untrain_ret)
+
+EXPORT_SYMBOL(__x86_return_thunk)
+
+#endif /* CONFIG_RETHUNK */
index d8cfce221275e078e06a4371a31acad6467671b9..57ba5502aecf97196d9e40ac28dfbabb8b95b15b 100644 (file)
@@ -77,10 +77,20 @@ static uint8_t __pte2cachemode_tbl[8] = {
        [__pte2cm_idx(_PAGE_PWT | _PAGE_PCD | _PAGE_PAT)] = _PAGE_CACHE_MODE_UC,
 };
 
-/* Check that the write-protect PAT entry is set for write-protect */
+/*
+ * Check that the write-protect PAT entry is set for write-protect.
+ * To do this without making assumptions how PAT has been set up (Xen has
+ * another layout than the kernel), translate the _PAGE_CACHE_MODE_WP cache
+ * mode via the __cachemode2pte_tbl[] into protection bits (those protection
+ * bits will select a cache mode of WP or better), and then translate the
+ * protection bits back into the cache mode using __pte2cm_idx() and the
+ * __pte2cachemode_tbl[] array. This will return the really used cache mode.
+ */
 bool x86_has_pat_wp(void)
 {
-       return __pte2cachemode_tbl[_PAGE_CACHE_MODE_WP] == _PAGE_CACHE_MODE_WP;
+       uint16_t prot = __cachemode2pte_tbl[_PAGE_CACHE_MODE_WP];
+
+       return __pte2cachemode_tbl[__pte2cm_idx(prot)] == _PAGE_CACHE_MODE_WP;
 }
 
 enum page_cache_mode pgprot2cachemode(pgprot_t pgprot)
index 3d1dba05fce4aea38ffa67c25240eadbbe171b76..9de3d900bc927142b5ec1688551464c26aa60851 100644 (file)
@@ -65,7 +65,10 @@ SYM_FUNC_START(sme_encrypt_execute)
        movq    %rbp, %rsp              /* Restore original stack pointer */
        pop     %rbp
 
-       RET
+       /* Offset to __x86_return_thunk would be wrong here */
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_FUNC_END(sme_encrypt_execute)
 
 SYM_FUNC_START(__enc_copy)
@@ -151,6 +154,9 @@ SYM_FUNC_START(__enc_copy)
        pop     %r12
        pop     %r15
 
-       RET
+       /* Offset to __x86_return_thunk would be wrong here */
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 .L__enc_copy_end:
 SYM_FUNC_END(__enc_copy)
index c98b8c0ed3b83b77bc2ec5ec8e8894e2222bcefb..b808c9a80d1bebc627d34828d4782147fcbaa815 100644 (file)
@@ -412,16 +412,30 @@ static void emit_indirect_jump(u8 **pprog, int reg, u8 *ip)
 {
        u8 *prog = *pprog;
 
-#ifdef CONFIG_RETPOLINE
        if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE)) {
                EMIT_LFENCE();
                EMIT2(0xFF, 0xE0 + reg);
        } else if (cpu_feature_enabled(X86_FEATURE_RETPOLINE)) {
                OPTIMIZER_HIDE_VAR(reg);
                emit_jump(&prog, &__x86_indirect_thunk_array[reg], ip);
-       } else
-#endif
-       EMIT2(0xFF, 0xE0 + reg);
+       } else {
+               EMIT2(0xFF, 0xE0 + reg);
+       }
+
+       *pprog = prog;
+}
+
+static void emit_return(u8 **pprog, u8 *ip)
+{
+       u8 *prog = *pprog;
+
+       if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) {
+               emit_jump(&prog, &__x86_return_thunk, ip);
+       } else {
+               EMIT1(0xC3);            /* ret */
+               if (IS_ENABLED(CONFIG_SLS))
+                       EMIT1(0xCC);    /* int3 */
+       }
 
        *pprog = prog;
 }
@@ -1686,7 +1700,7 @@ emit_jmp:
                        ctx->cleanup_addr = proglen;
                        pop_callee_regs(&prog, callee_regs_used);
                        EMIT1(0xC9);         /* leave */
-                       EMIT1(0xC3);         /* ret */
+                       emit_return(&prog, image + addrs[i - 1] + (prog - temp));
                        break;
 
                default:
@@ -2189,7 +2203,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
        if (flags & BPF_TRAMP_F_SKIP_FRAME)
                /* skip our return address and return to parent */
                EMIT4(0x48, 0x83, 0xC4, 8); /* add rsp, 8 */
-       EMIT1(0xC3); /* ret */
+       emit_return(&prog, prog);
        /* Make sure the trampoline generation logic doesn't overflow */
        if (WARN_ON_ONCE(prog > (u8 *)image_end - BPF_INSN_SAFETY)) {
                ret = -EFAULT;
index 9ffe2bad27d50382cc47062d41a43e9d0825fba1..4e5257a4811b28e980b9bd48f813be1448154273 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/objtool.h>
 #include <asm/page_types.h>
 #include <asm/segment.h>
+#include <asm/nospec-branch.h>
 
        .text
        .code64
@@ -75,7 +76,9 @@ STACK_FRAME_NON_STANDARD __efi64_thunk
 1:     movq    0x20(%rsp), %rsp
        pop     %rbx
        pop     %rbp
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 
        .code32
 2:     pushl   $__KERNEL_CS
index e3297b15701c67fa648fb6085fafef5152ce879c..70fb2ea85e907468df9500091d9b8f27aa279e7d 100644 (file)
@@ -1183,15 +1183,19 @@ static void __init xen_domu_set_legacy_features(void)
 extern void early_xen_iret_patch(void);
 
 /* First C function to be called on Xen boot */
-asmlinkage __visible void __init xen_start_kernel(void)
+asmlinkage __visible void __init xen_start_kernel(struct start_info *si)
 {
        struct physdev_set_iopl set_iopl;
        unsigned long initrd_start = 0;
        int rc;
 
-       if (!xen_start_info)
+       if (!si)
                return;
 
+       clear_bss();
+
+       xen_start_info = si;
+
        __text_gen_insn(&early_xen_iret_patch,
                        JMP32_INSN_OPCODE, &early_xen_iret_patch, &xen_iret,
                        JMP32_INSN_SIZE);
index 81aa46f770c540f1ab0780cc9837c32bcdebeab8..cfa99e8f054be5dba1e339e268c20115acc79d9b 100644 (file)
@@ -918,7 +918,7 @@ void xen_enable_sysenter(void)
        if (!boot_cpu_has(sysenter_feature))
                return;
 
-       ret = register_callback(CALLBACKTYPE_sysenter, xen_sysenter_target);
+       ret = register_callback(CALLBACKTYPE_sysenter, xen_entry_SYSENTER_compat);
        if(ret != 0)
                setup_clear_cpu_cap(sysenter_feature);
 }
@@ -927,7 +927,7 @@ void xen_enable_syscall(void)
 {
        int ret;
 
-       ret = register_callback(CALLBACKTYPE_syscall, xen_syscall_target);
+       ret = register_callback(CALLBACKTYPE_syscall, xen_entry_SYSCALL_64);
        if (ret != 0) {
                printk(KERN_ERR "Failed to set syscall callback: %d\n", ret);
                /* Pretty fatal; 64-bit userspace has no other
@@ -936,7 +936,7 @@ void xen_enable_syscall(void)
 
        if (boot_cpu_has(X86_FEATURE_SYSCALL32)) {
                ret = register_callback(CALLBACKTYPE_syscall32,
-                                       xen_syscall32_target);
+                                       xen_entry_SYSCALL_compat);
                if (ret != 0)
                        setup_clear_cpu_cap(X86_FEATURE_SYSCALL32);
        }
index caa9bc2fa100897cff0d5fa79ec4fb27a249871d..6b4fdf6b95422b3787269f8950d6c10a3ed9b9da 100644 (file)
@@ -121,7 +121,7 @@ SYM_FUNC_END(xen_read_cr2_direct);
 
 .macro xen_pv_trap name
 SYM_CODE_START(xen_\name)
-       UNWIND_HINT_EMPTY
+       UNWIND_HINT_ENTRY
        ENDBR
        pop %rcx
        pop %r11
@@ -234,8 +234,8 @@ SYM_CODE_END(xenpv_restore_regs_and_return_to_usermode)
  */
 
 /* Normal 64-bit system call target */
-SYM_CODE_START(xen_syscall_target)
-       UNWIND_HINT_EMPTY
+SYM_CODE_START(xen_entry_SYSCALL_64)
+       UNWIND_HINT_ENTRY
        ENDBR
        popq %rcx
        popq %r11
@@ -249,13 +249,13 @@ SYM_CODE_START(xen_syscall_target)
        movq $__USER_CS, 1*8(%rsp)
 
        jmp entry_SYSCALL_64_after_hwframe
-SYM_CODE_END(xen_syscall_target)
+SYM_CODE_END(xen_entry_SYSCALL_64)
 
 #ifdef CONFIG_IA32_EMULATION
 
 /* 32-bit compat syscall target */
-SYM_CODE_START(xen_syscall32_target)
-       UNWIND_HINT_EMPTY
+SYM_CODE_START(xen_entry_SYSCALL_compat)
+       UNWIND_HINT_ENTRY
        ENDBR
        popq %rcx
        popq %r11
@@ -269,11 +269,11 @@ SYM_CODE_START(xen_syscall32_target)
        movq $__USER32_CS, 1*8(%rsp)
 
        jmp entry_SYSCALL_compat_after_hwframe
-SYM_CODE_END(xen_syscall32_target)
+SYM_CODE_END(xen_entry_SYSCALL_compat)
 
 /* 32-bit compat sysenter target */
-SYM_CODE_START(xen_sysenter_target)
-       UNWIND_HINT_EMPTY
+SYM_CODE_START(xen_entry_SYSENTER_compat)
+       UNWIND_HINT_ENTRY
        ENDBR
        /*
         * NB: Xen is polite and clears TF from EFLAGS for us.  This means
@@ -291,19 +291,19 @@ SYM_CODE_START(xen_sysenter_target)
        movq $__USER32_CS, 1*8(%rsp)
 
        jmp entry_SYSENTER_compat_after_hwframe
-SYM_CODE_END(xen_sysenter_target)
+SYM_CODE_END(xen_entry_SYSENTER_compat)
 
 #else /* !CONFIG_IA32_EMULATION */
 
-SYM_CODE_START(xen_syscall32_target)
-SYM_CODE_START(xen_sysenter_target)
-       UNWIND_HINT_EMPTY
+SYM_CODE_START(xen_entry_SYSCALL_compat)
+SYM_CODE_START(xen_entry_SYSENTER_compat)
+       UNWIND_HINT_ENTRY
        ENDBR
        lea 16(%rsp), %rsp      /* strip %rcx, %r11 */
        mov $-ENOSYS, %rax
        pushq $0
        jmp hypercall_iret
-SYM_CODE_END(xen_sysenter_target)
-SYM_CODE_END(xen_syscall32_target)
+SYM_CODE_END(xen_entry_SYSENTER_compat)
+SYM_CODE_END(xen_entry_SYSCALL_compat)
 
 #endif /* CONFIG_IA32_EMULATION */
index 3a2cd93bf0590e6acb5b2bad7d8a7e282050152f..ffaa62167f6e8ddf1da9fcc439503e5fa1215700 100644 (file)
@@ -26,6 +26,7 @@ SYM_CODE_START(hypercall_page)
        .rept (PAGE_SIZE / 32)
                UNWIND_HINT_FUNC
                ANNOTATE_NOENDBR
+               ANNOTATE_UNRET_SAFE
                ret
                /*
                 * Xen will write the hypercall page, and sort out ENDBR.
@@ -48,15 +49,6 @@ SYM_CODE_START(startup_xen)
        ANNOTATE_NOENDBR
        cld
 
-       /* Clear .bss */
-       xor %eax,%eax
-       mov $__bss_start, %rdi
-       mov $__bss_stop, %rcx
-       sub %rdi, %rcx
-       shr $3, %rcx
-       rep stosq
-
-       mov %rsi, xen_start_info
        mov initial_stack(%rip), %rsp
 
        /* Set up %gs.
@@ -71,6 +63,7 @@ SYM_CODE_START(startup_xen)
        cdq
        wrmsr
 
+       mov     %rsi, %rdi
        call xen_start_kernel
 SYM_CODE_END(startup_xen)
        __FINIT
index fd0fec6e92f4ca66a828acb32c592777a2f741e9..9a8bb972193d884e097adb1b58d71d7aa9d614e0 100644 (file)
 /* These are code, but not functions.  Defined in entry.S */
 extern const char xen_failsafe_callback[];
 
-void xen_sysenter_target(void);
+void xen_entry_SYSENTER_compat(void);
 #ifdef CONFIG_X86_64
-void xen_syscall_target(void);
-void xen_syscall32_target(void);
+void xen_entry_SYSCALL_64(void);
+void xen_entry_SYSCALL_compat(void);
 #endif
 
 extern void *xen_initial_gdt;
index 7771dacc99cb7d30328b277ac6866c8b2bf39f44..f5e6527ebc9c11d7a9d5b9641c17a4072ff7e2cb 100644 (file)
@@ -345,6 +345,7 @@ void __blk_queue_split(struct request_queue *q, struct bio **bio,
                /* there isn't chance to merge the splitted bio */
                split->bi_opf |= REQ_NOMERGE;
 
+               blkcg_bio_issue_init(split);
                bio_chain(split, *bio);
                trace_block_split(split, (*bio)->bi_iter.bi_sector);
                submit_bio_noacct(*bio);
index 476755703cf8b44c9c12425f7b347409baef7170..bf9b511573d75135182a3f15711d617c5e335e38 100644 (file)
@@ -43,6 +43,7 @@ config SYSTEM_TRUSTED_KEYRING
        bool "Provide system-wide ring of trusted keys"
        depends on KEYS
        depends on ASYMMETRIC_KEY_TYPE
+       depends on X509_CERTIFICATE_PARSER
        help
          Provide a system keyring to which trusted keys can be added.  Keys in
          the keyring are considered to be trusted.  Keys may be added at will
index 1d44893a997bafda0c2bee3c2beb2894841438f9..7b81685b56550f9f87623cfef298e8ae378d07e6 100644 (file)
@@ -666,6 +666,18 @@ config CRYPTO_CRC32_MIPS
          CRC32c and CRC32 CRC algorithms implemented using mips crypto
          instructions, when available.
 
+config CRYPTO_CRC32_S390
+       tristate "CRC-32 algorithms"
+       depends on S390
+       select CRYPTO_HASH
+       select CRC32
+       help
+         Select this option if you want to use hardware accelerated
+         implementations of CRC algorithms.  With this option, you
+         can optimize the computation of CRC-32 (IEEE 802.3 Ethernet)
+         and CRC-32C (Castagnoli).
+
+         It is available with IBM z13 or later.
 
 config CRYPTO_XXHASH
        tristate "xxHash hash algorithm"
@@ -898,6 +910,16 @@ config CRYPTO_SHA512_SSSE3
          Extensions version 1 (AVX1), or Advanced Vector Extensions
          version 2 (AVX2) instructions, when available.
 
+config CRYPTO_SHA512_S390
+       tristate "SHA384 and SHA512 digest algorithm"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA512 secure hash standard.
+
+         It is available as of z10.
+
 config CRYPTO_SHA1_OCTEON
        tristate "SHA1 digest algorithm (OCTEON)"
        depends on CPU_CAVIUM_OCTEON
@@ -930,6 +952,16 @@ config CRYPTO_SHA1_PPC_SPE
          SHA-1 secure hash standard (DFIPS 180-4) implemented
          using powerpc SPE SIMD instruction set.
 
+config CRYPTO_SHA1_S390
+       tristate "SHA1 digest algorithm"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+
+         It is available as of z990.
+
 config CRYPTO_SHA256
        tristate "SHA224 and SHA256 digest algorithm"
        select CRYPTO_HASH
@@ -970,6 +1002,16 @@ config CRYPTO_SHA256_SPARC64
          SHA-256 secure hash standard (DFIPS 180-2) implemented
          using sparc64 crypto instructions, when available.
 
+config CRYPTO_SHA256_S390
+       tristate "SHA256 digest algorithm"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA256 secure hash standard (DFIPS 180-2).
+
+         It is available as of z9.
+
 config CRYPTO_SHA512
        tristate "SHA384 and SHA512 digest algorithms"
        select CRYPTO_HASH
@@ -1010,6 +1052,26 @@ config CRYPTO_SHA3
          References:
          http://keccak.noekeon.org/
 
+config CRYPTO_SHA3_256_S390
+       tristate "SHA3_224 and SHA3_256 digest algorithm"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA3_256 secure hash standard.
+
+         It is available as of z14.
+
+config CRYPTO_SHA3_512_S390
+       tristate "SHA3_384 and SHA3_512 digest algorithm"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA3_512 secure hash standard.
+
+         It is available as of z14.
+
 config CRYPTO_SM3
        tristate
 
@@ -1070,6 +1132,16 @@ config CRYPTO_GHASH_CLMUL_NI_INTEL
          This is the x86_64 CLMUL-NI accelerated implementation of
          GHASH, the hash function used in GCM (Galois/Counter mode).
 
+config CRYPTO_GHASH_S390
+       tristate "GHASH hash function"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of GHASH,
+         the hash function used in GCM (Galois/Counter mode).
+
+         It is available as of z196.
+
 comment "Ciphers"
 
 config CRYPTO_AES
@@ -1185,6 +1257,23 @@ config CRYPTO_AES_PPC_SPE
          architecture specific assembler implementations that work on 1KB
          tables or 256 bytes S-boxes.
 
+config CRYPTO_AES_S390
+       tristate "AES cipher algorithms"
+       depends on S390
+       select CRYPTO_ALGAPI
+       select CRYPTO_SKCIPHER
+       help
+         This is the s390 hardware accelerated implementation of the
+         AES cipher algorithms (FIPS-197).
+
+         As of z9 the ECB and CBC modes are hardware accelerated
+         for 128 bit keys.
+         As of z10 the ECB and CBC modes are hardware accelerated
+         for all AES key sizes.
+         As of z196 the CTR mode is hardware accelerated for all AES
+         key sizes and XTS mode is hardware accelerated for 256 and
+         512 bit keys.
+
 config CRYPTO_ANUBIS
        tristate "Anubis cipher algorithm"
        depends on CRYPTO_USER_API_ENABLE_OBSOLETE
@@ -1415,6 +1504,19 @@ config CRYPTO_DES3_EDE_X86_64
          algorithm are provided; regular processing one input block and
          one that processes three blocks parallel.
 
+config CRYPTO_DES_S390
+       tristate "DES and Triple DES cipher algorithms"
+       depends on S390
+       select CRYPTO_ALGAPI
+       select CRYPTO_SKCIPHER
+       select CRYPTO_LIB_DES
+       help
+         This is the s390 hardware accelerated implementation of the
+         DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+
+         As of z990 the ECB and CBC mode are hardware accelerated.
+         As of z196 the CTR mode is hardware accelerated.
+
 config CRYPTO_FCRYPT
        tristate "FCrypt cipher algorithm"
        select CRYPTO_ALGAPI
@@ -1474,6 +1576,18 @@ config CRYPTO_CHACHA_MIPS
        select CRYPTO_SKCIPHER
        select CRYPTO_ARCH_HAVE_LIB_CHACHA
 
+config CRYPTO_CHACHA_S390
+       tristate "ChaCha20 stream cipher"
+       depends on S390
+       select CRYPTO_SKCIPHER
+       select CRYPTO_LIB_CHACHA_GENERIC
+       select CRYPTO_ARCH_HAVE_LIB_CHACHA
+       help
+         This is the s390 SIMD implementation of the ChaCha20 stream
+         cipher (RFC 7539).
+
+         It is available as of z13.
+
 config CRYPTO_SEED
        tristate "SEED cipher algorithm"
        depends on CRYPTO_USER_API_ENABLE_OBSOLETE
index 43177c20ce4f6d1e50b1acf06a934d39dc22e82f..eaea733b368aeb7cd6ee44a80fce5b1f64d1d841 100644 (file)
@@ -73,7 +73,7 @@ module_param(device_id_scheme, bool, 0444);
 static int only_lcd = -1;
 module_param(only_lcd, int, 0444);
 
-static bool has_backlight;
+static bool may_report_brightness_keys;
 static int register_count;
 static DEFINE_MUTEX(register_count_mutex);
 static DEFINE_MUTEX(video_list_lock);
@@ -1224,7 +1224,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
        acpi_video_device_find_cap(data);
 
        if (data->cap._BCM && data->cap._BCL)
-               has_backlight = true;
+               may_report_brightness_keys = true;
 
        mutex_lock(&video->device_list_lock);
        list_add_tail(&data->entry, &video->video_device_list);
@@ -1693,6 +1693,9 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
                break;
        }
 
+       if (keycode)
+               may_report_brightness_keys = true;
+
        acpi_notifier_call_chain(device, event, 0);
 
        if (keycode && (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS)) {
@@ -2253,7 +2256,7 @@ void acpi_video_unregister(void)
        if (register_count) {
                acpi_bus_unregister_driver(&acpi_video_bus);
                register_count = 0;
-               has_backlight = false;
+               may_report_brightness_keys = false;
        }
        mutex_unlock(&register_count_mutex);
 }
@@ -2275,7 +2278,7 @@ void acpi_video_unregister_backlight(void)
 
 bool acpi_video_handles_brightness_key_presses(void)
 {
-       return has_backlight &&
+       return may_report_brightness_keys &&
               (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS);
 }
 EXPORT_SYMBOL(acpi_video_handles_brightness_key_presses);
index 86fa61a21826c3f25d7eef67255aa065da402bb6..e2db1bdd9dd2580d73a86e0552daae5f8f4ed4fb 100644 (file)
@@ -298,7 +298,7 @@ EXPORT_SYMBOL_GPL(osc_cpc_flexible_adr_space_confirmed);
 bool osc_sb_native_usb4_support_confirmed;
 EXPORT_SYMBOL_GPL(osc_sb_native_usb4_support_confirmed);
 
-bool osc_sb_cppc_not_supported;
+bool osc_sb_cppc2_support_acked;
 
 static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48";
 static void acpi_bus_osc_negotiate_platform_control(void)
@@ -358,11 +358,6 @@ static void acpi_bus_osc_negotiate_platform_control(void)
                return;
        }
 
-#ifdef CONFIG_ACPI_CPPC_LIB
-       osc_sb_cppc_not_supported = !(capbuf_ret[OSC_SUPPORT_DWORD] &
-                       (OSC_SB_CPC_SUPPORT | OSC_SB_CPCV2_SUPPORT));
-#endif
-
        /*
         * Now run _OSC again with query flag clear and with the caps
         * supported by both the OS and the platform.
@@ -376,6 +371,10 @@ static void acpi_bus_osc_negotiate_platform_control(void)
 
        capbuf_ret = context.ret.pointer;
        if (context.ret.length > OSC_SUPPORT_DWORD) {
+#ifdef CONFIG_ACPI_CPPC_LIB
+               osc_sb_cppc2_support_acked = capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_CPCV2_SUPPORT;
+#endif
+
                osc_sb_apei_support_acked =
                        capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_APEI_SUPPORT;
                osc_pc_lpi_support_confirmed =
index 903528f7e187e4bc1698e4d24ed5d2693f080527..3c6d4ef87be0f178d0d9f0e99abaac7cb4ecd9ec 100644 (file)
@@ -577,6 +577,19 @@ bool __weak cpc_ffh_supported(void)
        return false;
 }
 
+/**
+ * cpc_supported_by_cpu() - check if CPPC is supported by CPU
+ *
+ * Check if the architectural support for CPPC is present even
+ * if the _OSC hasn't prescribed it
+ *
+ * Return: true for supported, false for not supported
+ */
+bool __weak cpc_supported_by_cpu(void)
+{
+       return false;
+}
+
 /**
  * pcc_data_alloc() - Allocate the pcc_data memory for pcc subspace
  *
@@ -684,8 +697,11 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
        acpi_status status;
        int ret = -ENODATA;
 
-       if (osc_sb_cppc_not_supported)
-               return -ENODEV;
+       if (!osc_sb_cppc2_support_acked) {
+               pr_debug("CPPC v2 _OSC not acked\n");
+               if (!cpc_supported_by_cpu())
+                       return -ENODEV;
+       }
 
        /* Parse the ACPI _CPC table for this CPU. */
        status = acpi_evaluate_object_typed(handle, "_CPC", NULL, &output,
@@ -766,7 +782,8 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
 
                                        if (!osc_cpc_flexible_adr_space_confirmed) {
                                                pr_debug("Flexible address space capability not supported\n");
-                                               goto out_free;
+                                               if (!cpc_supported_by_cpu())
+                                                       goto out_free;
                                        }
 
                                        addr = ioremap(gas_t->address, gas_t->bit_width/8);
@@ -793,7 +810,8 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
                                }
                                if (!osc_cpc_flexible_adr_space_confirmed) {
                                        pr_debug("Flexible address space capability not supported\n");
-                                       goto out_free;
+                                       if (!cpc_supported_by_cpu())
+                                               goto out_free;
                                }
                        } else {
                                if (gas_t->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE || !cpc_ffh_supported()) {
index 0e3ed5eb367b2846f1b36541fb8bf731d8de33ae..0cb20324da164a5bd1086148692c350d995c6c9e 100644 (file)
@@ -493,13 +493,8 @@ static int amba_device_try_add(struct amba_device *dev, struct resource *parent)
                goto skip_probe;
 
        ret = amba_read_periphid(dev);
-       if (ret) {
-               if (ret != -EPROBE_DEFER) {
-                       amba_device_put(dev);
-                       goto err_out;
-               }
+       if (ret)
                goto err_release;
-       }
 
 skip_probe:
        ret = device_add(&dev->dev);
@@ -546,6 +541,7 @@ static int amba_deferred_retry(void)
                        continue;
 
                list_del_init(&ddev->node);
+               amba_device_put(ddev->dev);
                kfree(ddev);
        }
 
index 7cd789c4985d40e956fe554929b66b7dc7dccf11..460d6f163e41bf1c849b3b54ef9ef551b75094f3 100644 (file)
@@ -486,7 +486,18 @@ static void device_link_release_fn(struct work_struct *work)
        /* Ensure that all references to the link object have been dropped. */
        device_link_synchronize_removal();
 
-       pm_runtime_release_supplier(link, true);
+       pm_runtime_release_supplier(link);
+       /*
+        * If supplier_preactivated is set, the link has been dropped between
+        * the pm_runtime_get_suppliers() and pm_runtime_put_suppliers() calls
+        * in __driver_probe_device().  In that case, drop the supplier's
+        * PM-runtime usage counter to remove the reference taken by
+        * pm_runtime_get_suppliers().
+        */
+       if (link->supplier_preactivated)
+               pm_runtime_put_noidle(link->supplier);
+
+       pm_request_idle(link->supplier);
 
        put_device(link->consumer);
        put_device(link->supplier);
index a97776ea9d99067bb53c21210a7818e7dae39897..4c98849577d4ed262292db4ae29d21465e2944fc 100644 (file)
@@ -570,6 +570,12 @@ ssize_t __weak cpu_show_mmio_stale_data(struct device *dev,
        return sysfs_emit(buf, "Not affected\n");
 }
 
+ssize_t __weak cpu_show_retbleed(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       return sysfs_emit(buf, "Not affected\n");
+}
+
 static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
 static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL);
 static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL);
@@ -580,6 +586,7 @@ static DEVICE_ATTR(tsx_async_abort, 0444, cpu_show_tsx_async_abort, NULL);
 static DEVICE_ATTR(itlb_multihit, 0444, cpu_show_itlb_multihit, NULL);
 static DEVICE_ATTR(srbds, 0444, cpu_show_srbds, NULL);
 static DEVICE_ATTR(mmio_stale_data, 0444, cpu_show_mmio_stale_data, NULL);
+static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL);
 
 static struct attribute *cpu_root_vulnerabilities_attrs[] = {
        &dev_attr_meltdown.attr,
@@ -592,6 +599,7 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = {
        &dev_attr_itlb_multihit.attr,
        &dev_attr_srbds.attr,
        &dev_attr_mmio_stale_data.attr,
+       &dev_attr_retbleed.attr,
        NULL
 };
 
index 739e52cd4aba5dd4b3c666ad9cbdf38120747cb5..55a10e6d4e2a755a20ae3f830103f6dec53697a1 100644 (file)
@@ -222,6 +222,9 @@ static void genpd_debug_remove(struct generic_pm_domain *genpd)
 {
        struct dentry *d;
 
+       if (!genpd_debugfs_dir)
+               return;
+
        d = debugfs_lookup(genpd->name, genpd_debugfs_dir);
        debugfs_remove(d);
 }
index 676dc72d912d1bd6f091584dd0aef331d2bbb1b6..997be3ac20a799908378518567aa432275f790d3 100644 (file)
@@ -308,13 +308,10 @@ static int rpm_get_suppliers(struct device *dev)
 /**
  * pm_runtime_release_supplier - Drop references to device link's supplier.
  * @link: Target device link.
- * @check_idle: Whether or not to check if the supplier device is idle.
  *
- * Drop all runtime PM references associated with @link to its supplier device
- * and if @check_idle is set, check if that device is idle (and so it can be
- * suspended).
+ * Drop all runtime PM references associated with @link to its supplier device.
  */
-void pm_runtime_release_supplier(struct device_link *link, bool check_idle)
+void pm_runtime_release_supplier(struct device_link *link)
 {
        struct device *supplier = link->supplier;
 
@@ -327,9 +324,6 @@ void pm_runtime_release_supplier(struct device_link *link, bool check_idle)
        while (refcount_dec_not_one(&link->rpm_active) &&
               atomic_read(&supplier->power.usage_count) > 0)
                pm_runtime_put_noidle(supplier);
-
-       if (check_idle)
-               pm_request_idle(supplier);
 }
 
 static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend)
@@ -337,8 +331,11 @@ static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend)
        struct device_link *link;
 
        list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
-                               device_links_read_lock_held())
-               pm_runtime_release_supplier(link, try_to_suspend);
+                               device_links_read_lock_held()) {
+               pm_runtime_release_supplier(link);
+               if (try_to_suspend)
+                       pm_request_idle(link->supplier);
+       }
 }
 
 static void rpm_put_suppliers(struct device *dev)
@@ -1771,7 +1768,6 @@ void pm_runtime_get_suppliers(struct device *dev)
                if (link->flags & DL_FLAG_PM_RUNTIME) {
                        link->supplier_preactivated = true;
                        pm_runtime_get_sync(link->supplier);
-                       refcount_inc(&link->rpm_active);
                }
 
        device_links_read_unlock(idx);
@@ -1791,19 +1787,8 @@ void pm_runtime_put_suppliers(struct device *dev)
        list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
                                device_links_read_lock_held())
                if (link->supplier_preactivated) {
-                       bool put;
-
                        link->supplier_preactivated = false;
-
-                       spin_lock_irq(&dev->power.lock);
-
-                       put = pm_runtime_status_suspended(dev) &&
-                             refcount_dec_not_one(&link->rpm_active);
-
-                       spin_unlock_irq(&dev->power.lock);
-
-                       if (put)
-                               pm_runtime_put(link->supplier);
+                       pm_runtime_put(link->supplier);
                }
 
        device_links_read_unlock(idx);
@@ -1838,7 +1823,8 @@ void pm_runtime_drop_link(struct device_link *link)
                return;
 
        pm_runtime_drop_link_count(link->consumer);
-       pm_runtime_release_supplier(link, true);
+       pm_runtime_release_supplier(link);
+       pm_request_idle(link->supplier);
 }
 
 static bool pm_runtime_need_not_resume(struct device *dev)
@@ -1876,10 +1862,13 @@ int pm_runtime_force_suspend(struct device *dev)
 
        callback = RPM_GET_CALLBACK(dev, runtime_suspend);
 
+       dev_pm_enable_wake_irq_check(dev, true);
        ret = callback ? callback(dev) : 0;
        if (ret)
                goto err;
 
+       dev_pm_enable_wake_irq_complete(dev);
+
        /*
         * If the device can stay in suspend after the system-wide transition
         * to the working state that will follow, drop the children counter of
@@ -1896,6 +1885,7 @@ int pm_runtime_force_suspend(struct device *dev)
        return 0;
 
 err:
+       dev_pm_disable_wake_irq_check(dev, true);
        pm_runtime_enable(dev);
        return ret;
 }
@@ -1929,9 +1919,11 @@ int pm_runtime_force_resume(struct device *dev)
 
        callback = RPM_GET_CALLBACK(dev, runtime_resume);
 
+       dev_pm_disable_wake_irq_check(dev, false);
        ret = callback ? callback(dev) : 0;
        if (ret) {
                pm_runtime_set_suspended(dev);
+               dev_pm_enable_wake_irq_check(dev, false);
                goto out;
        }
 
index 11a4ffe913672457aba29d3db77a53afcfa6cb98..e3befa2c1b661675b7b3cc80401cb5bc846379fe 100644 (file)
@@ -500,36 +500,6 @@ void device_set_wakeup_capable(struct device *dev, bool capable)
 }
 EXPORT_SYMBOL_GPL(device_set_wakeup_capable);
 
-/**
- * device_init_wakeup - Device wakeup initialization.
- * @dev: Device to handle.
- * @enable: Whether or not to enable @dev as a wakeup device.
- *
- * By default, most devices should leave wakeup disabled.  The exceptions are
- * devices that everyone expects to be wakeup sources: keyboards, power buttons,
- * possibly network interfaces, etc.  Also, devices that don't generate their
- * own wakeup requests but merely forward requests from one bus to another
- * (like PCI bridges) should have wakeup enabled by default.
- */
-int device_init_wakeup(struct device *dev, bool enable)
-{
-       int ret = 0;
-
-       if (!dev)
-               return -EINVAL;
-
-       if (enable) {
-               device_set_wakeup_capable(dev, true);
-               ret = device_wakeup_enable(dev);
-       } else {
-               device_wakeup_disable(dev);
-               device_set_wakeup_capable(dev, false);
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(device_init_wakeup);
-
 /**
  * device_set_wakeup_enable - Enable or disable a device to wake up the system.
  * @dev: Device to handle.
index 33f04ef78984c77ed32b576d38729b2d65aa7126..3646c0cae672a338bc92d64c649417b328ebe3b6 100644 (file)
@@ -152,6 +152,10 @@ static unsigned int xen_blkif_max_ring_order;
 module_param_named(max_ring_page_order, xen_blkif_max_ring_order, int, 0444);
 MODULE_PARM_DESC(max_ring_page_order, "Maximum order of pages to be used for the shared ring");
 
+static bool __read_mostly xen_blkif_trusted = true;
+module_param_named(trusted, xen_blkif_trusted, bool, 0644);
+MODULE_PARM_DESC(trusted, "Is the backend trusted");
+
 #define BLK_RING_SIZE(info)    \
        __CONST_RING_SIZE(blkif, XEN_PAGE_SIZE * (info)->nr_ring_pages)
 
@@ -210,6 +214,7 @@ struct blkfront_info
        unsigned int feature_discard:1;
        unsigned int feature_secdiscard:1;
        unsigned int feature_persistent:1;
+       unsigned int bounce:1;
        unsigned int discard_granularity;
        unsigned int discard_alignment;
        /* Number of 4KB segments handled */
@@ -310,8 +315,8 @@ static int fill_grant_buffer(struct blkfront_ring_info *rinfo, int num)
                if (!gnt_list_entry)
                        goto out_of_memory;
 
-               if (info->feature_persistent) {
-                       granted_page = alloc_page(GFP_NOIO);
+               if (info->bounce) {
+                       granted_page = alloc_page(GFP_NOIO | __GFP_ZERO);
                        if (!granted_page) {
                                kfree(gnt_list_entry);
                                goto out_of_memory;
@@ -330,7 +335,7 @@ out_of_memory:
        list_for_each_entry_safe(gnt_list_entry, n,
                                 &rinfo->grants, node) {
                list_del(&gnt_list_entry->node);
-               if (info->feature_persistent)
+               if (info->bounce)
                        __free_page(gnt_list_entry->page);
                kfree(gnt_list_entry);
                i--;
@@ -376,7 +381,7 @@ static struct grant *get_grant(grant_ref_t *gref_head,
        /* Assign a gref to this page */
        gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head);
        BUG_ON(gnt_list_entry->gref == -ENOSPC);
-       if (info->feature_persistent)
+       if (info->bounce)
                grant_foreign_access(gnt_list_entry, info);
        else {
                /* Grant access to the GFN passed by the caller */
@@ -400,7 +405,7 @@ static struct grant *get_indirect_grant(grant_ref_t *gref_head,
        /* Assign a gref to this page */
        gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head);
        BUG_ON(gnt_list_entry->gref == -ENOSPC);
-       if (!info->feature_persistent) {
+       if (!info->bounce) {
                struct page *indirect_page;
 
                /* Fetch a pre-allocated page to use for indirect grefs */
@@ -703,7 +708,7 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri
                .grant_idx = 0,
                .segments = NULL,
                .rinfo = rinfo,
-               .need_copy = rq_data_dir(req) && info->feature_persistent,
+               .need_copy = rq_data_dir(req) && info->bounce,
        };
 
        /*
@@ -981,11 +986,12 @@ static void xlvbd_flush(struct blkfront_info *info)
 {
        blk_queue_write_cache(info->rq, info->feature_flush ? true : false,
                              info->feature_fua ? true : false);
-       pr_info("blkfront: %s: %s %s %s %s %s\n",
+       pr_info("blkfront: %s: %s %s %s %s %s %s %s\n",
                info->gd->disk_name, flush_info(info),
                "persistent grants:", info->feature_persistent ?
                "enabled;" : "disabled;", "indirect descriptors:",
-               info->max_indirect_segments ? "enabled;" : "disabled;");
+               info->max_indirect_segments ? "enabled;" : "disabled;",
+               "bounce buffer:", info->bounce ? "enabled" : "disabled;");
 }
 
 static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset)
@@ -1207,7 +1213,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo)
        if (!list_empty(&rinfo->indirect_pages)) {
                struct page *indirect_page, *n;
 
-               BUG_ON(info->feature_persistent);
+               BUG_ON(info->bounce);
                list_for_each_entry_safe(indirect_page, n, &rinfo->indirect_pages, lru) {
                        list_del(&indirect_page->lru);
                        __free_page(indirect_page);
@@ -1224,7 +1230,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo)
                                                          NULL);
                                rinfo->persistent_gnts_c--;
                        }
-                       if (info->feature_persistent)
+                       if (info->bounce)
                                __free_page(persistent_gnt->page);
                        kfree(persistent_gnt);
                }
@@ -1245,7 +1251,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo)
                for (j = 0; j < segs; j++) {
                        persistent_gnt = rinfo->shadow[i].grants_used[j];
                        gnttab_end_foreign_access(persistent_gnt->gref, NULL);
-                       if (info->feature_persistent)
+                       if (info->bounce)
                                __free_page(persistent_gnt->page);
                        kfree(persistent_gnt);
                }
@@ -1428,7 +1434,7 @@ static int blkif_completion(unsigned long *id,
        data.s = s;
        num_sg = s->num_sg;
 
-       if (bret->operation == BLKIF_OP_READ && info->feature_persistent) {
+       if (bret->operation == BLKIF_OP_READ && info->bounce) {
                for_each_sg(s->sg, sg, num_sg, i) {
                        BUG_ON(sg->offset + sg->length > PAGE_SIZE);
 
@@ -1487,7 +1493,7 @@ static int blkif_completion(unsigned long *id,
                                 * Add the used indirect page back to the list of
                                 * available pages for indirect grefs.
                                 */
-                               if (!info->feature_persistent) {
+                               if (!info->bounce) {
                                        indirect_page = s->indirect_grants[i]->page;
                                        list_add(&indirect_page->lru, &rinfo->indirect_pages);
                                }
@@ -1764,6 +1770,10 @@ static int talk_to_blkback(struct xenbus_device *dev,
        if (!info)
                return -ENODEV;
 
+       /* Check if backend is trusted. */
+       info->bounce = !xen_blkif_trusted ||
+                      !xenbus_read_unsigned(dev->nodename, "trusted", 1);
+
        max_page_order = xenbus_read_unsigned(info->xbdev->otherend,
                                              "max-ring-page-order", 0);
        ring_page_order = min(xen_blkif_max_ring_order, max_page_order);
@@ -2173,17 +2183,18 @@ static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo)
        if (err)
                goto out_of_memory;
 
-       if (!info->feature_persistent && info->max_indirect_segments) {
+       if (!info->bounce && info->max_indirect_segments) {
                /*
-                * We are using indirect descriptors but not persistent
-                * grants, we need to allocate a set of pages that can be
+                * We are using indirect descriptors but don't have a bounce
+                * buffer, we need to allocate a set of pages that can be
                 * used for mapping indirect grefs
                 */
                int num = INDIRECT_GREFS(grants) * BLK_RING_SIZE(info);
 
                BUG_ON(!list_empty(&rinfo->indirect_pages));
                for (i = 0; i < num; i++) {
-                       struct page *indirect_page = alloc_page(GFP_KERNEL);
+                       struct page *indirect_page = alloc_page(GFP_KERNEL |
+                                                               __GFP_ZERO);
                        if (!indirect_page)
                                goto out_of_memory;
                        list_add(&indirect_page->lru, &rinfo->indirect_pages);
@@ -2276,6 +2287,8 @@ static void blkfront_gather_backend_features(struct blkfront_info *info)
                info->feature_persistent =
                        !!xenbus_read_unsigned(info->xbdev->otherend,
                                               "feature-persistent", 0);
+       if (info->feature_persistent)
+               info->bounce = true;
 
        indirect_segments = xenbus_read_unsigned(info->xbdev->otherend,
                                        "feature-max-indirect-segments", 0);
@@ -2547,6 +2560,13 @@ static void blkfront_delay_work(struct work_struct *work)
        struct blkfront_info *info;
        bool need_schedule_work = false;
 
+       /*
+        * Note that when using bounce buffers but not persistent grants
+        * there's no need to run blkfront_delay_work because grants are
+        * revoked in blkif_completion or else an error is reported and the
+        * connection is closed.
+        */
+
        mutex_lock(&blkfront_mutex);
 
        list_for_each_entry(info, &info_list, info_list) {
index e3dd1dd3dd226845bce6146f78b6b0d8979a7638..a1af90bacc9f8b99a7f3c307711620213be3132a 100644 (file)
@@ -1174,7 +1174,7 @@ static void __cold entropy_timer(struct timer_list *timer)
  */
 static void __cold try_to_generate_entropy(void)
 {
-       enum { NUM_TRIAL_SAMPLES = 8192, MAX_SAMPLES_PER_BIT = 32 };
+       enum { NUM_TRIAL_SAMPLES = 8192, MAX_SAMPLES_PER_BIT = HZ / 30 };
        struct entropy_timer_state stack;
        unsigned int i, num_different = 0;
        unsigned long last = random_get_entropy();
index d1535ac13e8942d10dd8897d4c2690d2fed2cb71..81cb90955d68b9d572b39b1fe89bd435c8517bb6 100644 (file)
@@ -213,7 +213,7 @@ static int lan966x_gate_clk_register(struct device *dev,
 
                hw_data->hws[i] =
                        devm_clk_hw_register_gate(dev, clk_gate_desc[idx].name,
-                                                 "lan966x", 0, base,
+                                                 "lan966x", 0, gate_base,
                                                  clk_gate_desc[idx].bit_idx,
                                                  0, &clk_gate_lock);
 
index c3038cdc6865002a8cddbac49e64cd1a586ef5a5..2a84fc63371e2ea2adcd0f3228889d2610b0a257 100644 (file)
@@ -268,7 +268,7 @@ config LOONGSON2_CPUFREQ
          This option adds a CPUFreq driver for loongson processors which
          support software configurable cpu frequency.
 
-         Loongson2F and it's successors support this feature.
+         Loongson2F and its successors support this feature.
 
          If in doubt, say N.
 
index 3d514b82d055469fbcc43a6b6694f0f30525794b..1bb2b90ebb21c2fc4acc19c2f71b79350e83ce7f 100644 (file)
@@ -78,6 +78,8 @@ static bool boost_state(unsigned int cpu)
 
        switch (boot_cpu_data.x86_vendor) {
        case X86_VENDOR_INTEL:
+       case X86_VENDOR_CENTAUR:
+       case X86_VENDOR_ZHAOXIN:
                rdmsr_on_cpu(cpu, MSR_IA32_MISC_ENABLE, &lo, &hi);
                msr = lo | ((u64)hi << 32);
                return !(msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE);
@@ -97,6 +99,8 @@ static int boost_set_msr(bool enable)
 
        switch (boot_cpu_data.x86_vendor) {
        case X86_VENDOR_INTEL:
+       case X86_VENDOR_CENTAUR:
+       case X86_VENDOR_ZHAOXIN:
                msr_addr = MSR_IA32_MISC_ENABLE;
                msr_mask = MSR_IA32_MISC_ENABLE_TURBO_DISABLE;
                break;
index 2cad42774164799dc1895116f5ca7783e46b281a..954eef26685f1e83addefdd66f6fb2bd6e4cae3f 100644 (file)
@@ -843,12 +843,14 @@ ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf)
        unsigned int cpu;
 
        for_each_cpu(cpu, mask) {
-               if (i)
-                       i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " ");
-               i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu);
+               i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u ", cpu);
                if (i >= (PAGE_SIZE - 5))
                        break;
        }
+
+       /* Remove the extra space at the end */
+       i--;
+
        i += sprintf(&buf[i], "\n");
        return i;
 }
@@ -971,21 +973,10 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
        if (!fattr->store)
                return -EIO;
 
-       /*
-        * cpus_read_trylock() is used here to work around a circular lock
-        * dependency problem with respect to the cpufreq_register_driver().
-        */
-       if (!cpus_read_trylock())
-               return -EBUSY;
-
-       if (cpu_online(policy->cpu)) {
-               down_write(&policy->rwsem);
-               if (likely(!policy_is_inactive(policy)))
-                       ret = fattr->store(policy, buf, count);
-               up_write(&policy->rwsem);
-       }
-
-       cpus_read_unlock();
+       down_write(&policy->rwsem);
+       if (likely(!policy_is_inactive(policy)))
+               ret = fattr->store(policy, buf, count);
+       up_write(&policy->rwsem);
 
        return ret;
 }
@@ -1282,6 +1273,13 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
        unsigned long flags;
        int cpu;
 
+       /*
+        * The callers must ensure the policy is inactive by now, to avoid any
+        * races with show()/store() callbacks.
+        */
+       if (unlikely(!policy_is_inactive(policy)))
+               pr_warn("%s: Freeing active policy\n", __func__);
+
        /* Remove policy from list */
        write_lock_irqsave(&cpufreq_driver_lock, flags);
        list_del(&policy->policy_list);
@@ -1536,8 +1534,6 @@ out_destroy_policy:
        for_each_cpu(j, policy->real_cpus)
                remove_cpu_dev_symlink(policy, j, get_cpu_device(j));
 
-       cpumask_clear(policy->cpus);
-
 out_offline_policy:
        if (cpufreq_driver->offline)
                cpufreq_driver->offline(policy);
@@ -1547,6 +1543,7 @@ out_exit_policy:
                cpufreq_driver->exit(policy);
 
 out_free_policy:
+       cpumask_clear(policy->cpus);
        up_write(&policy->rwsem);
 
        cpufreq_policy_free(policy);
index e8fbf970ff07888c7aa82eb67ee6c388d92c9fc7..c52d19d67557f59bd88aab1c63def629edded859 100644 (file)
@@ -416,10 +416,13 @@ static struct dbs_governor od_dbs_gov = {
 static void od_set_powersave_bias(unsigned int powersave_bias)
 {
        unsigned int cpu;
-       cpumask_t done;
+       cpumask_var_t done;
+
+       if (!alloc_cpumask_var(&done, GFP_KERNEL))
+               return;
 
        default_powersave_bias = powersave_bias;
-       cpumask_clear(&done);
+       cpumask_clear(done);
 
        cpus_read_lock();
        for_each_online_cpu(cpu) {
@@ -428,7 +431,7 @@ static void od_set_powersave_bias(unsigned int powersave_bias)
                struct dbs_data *dbs_data;
                struct od_dbs_tuners *od_tuners;
 
-               if (cpumask_test_cpu(cpu, &done))
+               if (cpumask_test_cpu(cpu, done))
                        continue;
 
                policy = cpufreq_cpu_get_raw(cpu);
@@ -439,13 +442,15 @@ static void od_set_powersave_bias(unsigned int powersave_bias)
                if (!policy_dbs)
                        continue;
 
-               cpumask_or(&done, &done, policy->cpus);
+               cpumask_or(done, done, policy->cpus);
 
                dbs_data = policy_dbs->dbs_data;
                od_tuners = dbs_data->tuners;
                od_tuners->powersave_bias = default_powersave_bias;
        }
        cpus_read_unlock();
+
+       free_cpumask_var(done);
 }
 
 void od_register_powersave_bias_handler(unsigned int (*f)
index 813cccbfe9348b58479d4906517a00639355fae0..f0e0a35c7f21744e4e5ac042c9bd3f8fc11387d1 100644 (file)
@@ -51,7 +51,7 @@ static const u16 cpufreq_mtk_offsets[REG_ARRAY_SIZE] = {
 };
 
 static int __maybe_unused
-mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *mW,
+mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *uW,
                          unsigned long *KHz)
 {
        struct mtk_cpufreq_data *data;
@@ -71,8 +71,9 @@ mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *mW,
        i--;
 
        *KHz = data->table[i].frequency;
-       *mW = readl_relaxed(data->reg_bases[REG_EM_POWER_TBL] +
-                           i * LUT_ROW_SIZE) / 1000;
+       /* Provide micro-Watts value to the Energy Model */
+       *uW = readl_relaxed(data->reg_bases[REG_EM_POWER_TBL] +
+                           i * LUT_ROW_SIZE);
 
        return 0;
 }
index 37a1eb20f5ba6dff4634bcf52172b74b2687d3b5..76f6b3884e6b2dc070e20f51f592d48ef04bf15d 100644 (file)
@@ -439,9 +439,13 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
 
        /* Both presence and absence of sram regulator are valid cases. */
        info->sram_reg = regulator_get_optional(cpu_dev, "sram");
-       if (IS_ERR(info->sram_reg))
+       if (IS_ERR(info->sram_reg)) {
+               ret = PTR_ERR(info->sram_reg);
+               if (ret == -EPROBE_DEFER)
+                       goto out_free_resources;
+
                info->sram_reg = NULL;
-       else {
+       else {
                ret = regulator_enable(info->sram_reg);
                if (ret) {
                        dev_warn(cpu_dev, "cpu%d: failed to enable vsram\n", cpu);
index 6d2a4cf46db708601b6428fd5a04134af6ff2566..513a071845c263a0df2ed4d24adf8de41a56e3b5 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/slab.h>
 #include <linux/scmi_protocol.h>
 #include <linux/types.h>
+#include <linux/units.h>
 
 struct scmi_data {
        int domain_id;
@@ -99,6 +100,7 @@ static int __maybe_unused
 scmi_get_cpu_power(struct device *cpu_dev, unsigned long *power,
                   unsigned long *KHz)
 {
+       enum scmi_power_scale power_scale = perf_ops->power_scale_get(ph);
        unsigned long Hz;
        int ret, domain;
 
@@ -112,6 +114,10 @@ scmi_get_cpu_power(struct device *cpu_dev, unsigned long *power,
        if (ret)
                return ret;
 
+       /* Convert the power to uW if it is mW (ignore bogoW) */
+       if (power_scale == SCMI_POWER_MILLIWATTS)
+               *power *= MICROWATT_PER_MILLIWATT;
+
        /* The EM framework specifies the frequency in KHz. */
        *KHz = Hz / 1000;
 
@@ -249,8 +255,9 @@ static int scmi_cpufreq_exit(struct cpufreq_policy *policy)
 static void scmi_cpufreq_register_em(struct cpufreq_policy *policy)
 {
        struct em_data_callback em_cb = EM_DATA_CB(scmi_get_cpu_power);
-       bool power_scale_mw = perf_ops->power_scale_mw_get(ph);
+       enum scmi_power_scale power_scale = perf_ops->power_scale_get(ph);
        struct scmi_data *priv = policy->driver_data;
+       bool em_power_scale = false;
 
        /*
         * This callback will be called for each policy, but we don't need to
@@ -262,9 +269,13 @@ static void scmi_cpufreq_register_em(struct cpufreq_policy *policy)
        if (!priv->nr_opp)
                return;
 
+       if (power_scale == SCMI_POWER_MILLIWATTS
+           || power_scale == SCMI_POWER_MICROWATTS)
+               em_power_scale = true;
+
        em_dev_register_perf_domain(get_cpu_device(policy->cpu), priv->nr_opp,
                                    &em_cb, priv->opp_shared_cpus,
-                                   power_scale_mw);
+                                   em_power_scale);
 }
 
 static struct cpufreq_driver scmi_cpufreq_driver = {
index cb2a96eafc02750acc5e7e66fa53cea18a50523a..1dff3a52917de9a6b79d1cd9e301a24659b412f6 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/sched.h>
 #include <linux/module.h>
 #include <linux/kvm_para.h>
+#include <trace/events/power.h>
 
 static unsigned int guest_halt_poll_ns __read_mostly = 200000;
 module_param(guest_halt_poll_ns, uint, 0644);
@@ -90,6 +91,7 @@ static void adjust_poll_limit(struct cpuidle_device *dev, u64 block_ns)
                if (val > guest_halt_poll_ns)
                        val = guest_halt_poll_ns;
 
+               trace_guest_halt_poll_ns_grow(val, dev->poll_limit_ns);
                dev->poll_limit_ns = val;
        } else if (block_ns > guest_halt_poll_ns &&
                   guest_halt_poll_allow_shrink) {
@@ -100,6 +102,7 @@ static void adjust_poll_limit(struct cpuidle_device *dev, u64 block_ns)
                        val = 0;
                else
                        val /= shrink;
+               trace_guest_halt_poll_ns_shrink(val, dev->poll_limit_ns);
                dev->poll_limit_ns = val;
        }
 }
index ee99c02c84e81e516b5e986519790ac044472650..3e6aa319920b708375b56eb4210ab4bc54b078cb 100644 (file)
@@ -133,98 +133,6 @@ config CRYPTO_PAES_S390
          Select this option if you want to use the paes cipher
          for example to use protected key encrypted devices.
 
-config CRYPTO_SHA1_S390
-       tristate "SHA1 digest algorithm"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
-
-         It is available as of z990.
-
-config CRYPTO_SHA256_S390
-       tristate "SHA256 digest algorithm"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA256 secure hash standard (DFIPS 180-2).
-
-         It is available as of z9.
-
-config CRYPTO_SHA512_S390
-       tristate "SHA384 and SHA512 digest algorithm"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA512 secure hash standard.
-
-         It is available as of z10.
-
-config CRYPTO_SHA3_256_S390
-       tristate "SHA3_224 and SHA3_256 digest algorithm"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA3_256 secure hash standard.
-
-         It is available as of z14.
-
-config CRYPTO_SHA3_512_S390
-       tristate "SHA3_384 and SHA3_512 digest algorithm"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA3_512 secure hash standard.
-
-         It is available as of z14.
-
-config CRYPTO_DES_S390
-       tristate "DES and Triple DES cipher algorithms"
-       depends on S390
-       select CRYPTO_ALGAPI
-       select CRYPTO_SKCIPHER
-       select CRYPTO_LIB_DES
-       help
-         This is the s390 hardware accelerated implementation of the
-         DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
-
-         As of z990 the ECB and CBC mode are hardware accelerated.
-         As of z196 the CTR mode is hardware accelerated.
-
-config CRYPTO_AES_S390
-       tristate "AES cipher algorithms"
-       depends on S390
-       select CRYPTO_ALGAPI
-       select CRYPTO_SKCIPHER
-       help
-         This is the s390 hardware accelerated implementation of the
-         AES cipher algorithms (FIPS-197).
-
-         As of z9 the ECB and CBC modes are hardware accelerated
-         for 128 bit keys.
-         As of z10 the ECB and CBC modes are hardware accelerated
-         for all AES key sizes.
-         As of z196 the CTR mode is hardware accelerated for all AES
-         key sizes and XTS mode is hardware accelerated for 256 and
-         512 bit keys.
-
-config CRYPTO_CHACHA_S390
-       tristate "ChaCha20 stream cipher"
-       depends on S390
-       select CRYPTO_SKCIPHER
-       select CRYPTO_LIB_CHACHA_GENERIC
-       select CRYPTO_ARCH_HAVE_LIB_CHACHA
-       help
-         This is the s390 SIMD implementation of the ChaCha20 stream
-         cipher (RFC 7539).
-
-         It is available as of z13.
-
 config S390_PRNG
        tristate "Pseudo random number generator device driver"
        depends on S390
@@ -238,29 +146,6 @@ config S390_PRNG
 
          It is available as of z9.
 
-config CRYPTO_GHASH_S390
-       tristate "GHASH hash function"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of GHASH,
-         the hash function used in GCM (Galois/Counter mode).
-
-         It is available as of z196.
-
-config CRYPTO_CRC32_S390
-       tristate "CRC-32 algorithms"
-       depends on S390
-       select CRYPTO_HASH
-       select CRC32
-       help
-         Select this option if you want to use hardware accelerated
-         implementations of CRC algorithms.  With this option, you
-         can optimize the computation of CRC-32 (IEEE 802.3 Ethernet)
-         and CRC-32C (Castagnoli).
-
-         It is available with IBM z13 or later.
-
 config CRYPTO_DEV_NIAGARA2
        tristate "Niagara2 Stream Processing Unit driver"
        select CRYPTO_LIB_DES
index 0e89a7a932d40e18f92be92d3fb0f7a983f9a5dc..bfc8ee876278c9c19765780ab90495332157382a 100644 (file)
@@ -197,7 +197,7 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
        else
                cxld->target_type = CXL_DECODER_ACCELERATOR;
 
-       if (is_cxl_endpoint(to_cxl_port(cxld->dev.parent)))
+       if (is_endpoint_decoder(&cxld->dev))
                return 0;
 
        target_list.value =
index 54f434733b5623cc35d18c161479e40d8fc372b4..cbf23beebebefaf89df8bf7055b4ac765d5731b0 100644 (file)
@@ -355,11 +355,13 @@ static int cxl_to_mem_cmd(struct cxl_mem_command *mem_cmd,
                return -EBUSY;
 
        /* Check the input buffer is the expected size */
-       if (info->size_in != send_cmd->in.size)
+       if ((info->size_in != CXL_VARIABLE_PAYLOAD) &&
+           (info->size_in != send_cmd->in.size))
                return -ENOMEM;
 
        /* Check the output buffer is at least large enough */
-       if (send_cmd->out.size < info->size_out)
+       if ((info->size_out != CXL_VARIABLE_PAYLOAD) &&
+           (send_cmd->out.size < info->size_out))
                return -ENOMEM;
 
        *mem_cmd = (struct cxl_mem_command) {
index ea60abda65006715cfdf04275dba6704b024c90b..dbce99bdffabc5e9615da5924290c5e195895229 100644 (file)
@@ -272,7 +272,7 @@ static const struct device_type cxl_decoder_root_type = {
        .groups = cxl_decoder_root_attribute_groups,
 };
 
-static bool is_endpoint_decoder(struct device *dev)
+bool is_endpoint_decoder(struct device *dev)
 {
        return dev->type == &cxl_decoder_endpoint_type;
 }
index 140dc3278cde142b2e5374a7d00c7a0ad51d4035..6799b27c7db20c02cf97eccb9eae4c3ddfe64f74 100644 (file)
@@ -340,6 +340,7 @@ struct cxl_dport *cxl_find_dport_by_dev(struct cxl_port *port,
 
 struct cxl_decoder *to_cxl_decoder(struct device *dev);
 bool is_root_decoder(struct device *dev);
+bool is_endpoint_decoder(struct device *dev);
 bool is_cxl_decoder(struct device *dev);
 struct cxl_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
                                           unsigned int nr_targets);
index 60d10ee1e7fcd7bc625400e49672b265633b093d..7df0b053373a39727fdca41d5af74940b193ca92 100644 (file)
@@ -300,13 +300,13 @@ struct cxl_mbox_identify {
 } __packed;
 
 struct cxl_mbox_get_lsa {
-       u32 offset;
-       u32 length;
+       __le32 offset;
+       __le32 length;
 } __packed;
 
 struct cxl_mbox_set_lsa {
-       u32 offset;
-       u32 reserved;
+       __le32 offset;
+       __le32 reserved;
        u8 data[];
 } __packed;
 
index c310f1fd3db02eea814c15fdb4c597a62fc1a85e..a979d0b484d56a7aa5f4a5f9230d8230ab13becc 100644 (file)
@@ -29,6 +29,7 @@ static int create_endpoint(struct cxl_memdev *cxlmd,
 {
        struct cxl_dev_state *cxlds = cxlmd->cxlds;
        struct cxl_port *endpoint;
+       int rc;
 
        endpoint = devm_cxl_add_port(&parent_port->dev, &cxlmd->dev,
                                     cxlds->component_reg_phys, parent_port);
@@ -37,13 +38,17 @@ static int create_endpoint(struct cxl_memdev *cxlmd,
 
        dev_dbg(&cxlmd->dev, "add: %s\n", dev_name(&endpoint->dev));
 
+       rc = cxl_endpoint_autoremove(cxlmd, endpoint);
+       if (rc)
+               return rc;
+
        if (!endpoint->dev.driver) {
                dev_err(&cxlmd->dev, "%s failed probe\n",
                        dev_name(&endpoint->dev));
                return -ENXIO;
        }
 
-       return cxl_endpoint_autoremove(cxlmd, endpoint);
+       return 0;
 }
 
 static void enable_suspend(void *data)
index bbeef91e637e9e7f5c3615234f50f0fc3d6b951d..0aaa70b4e0f7173489a7db52840931e68ff5b271 100644 (file)
@@ -108,8 +108,8 @@ static int cxl_pmem_get_config_data(struct cxl_dev_state *cxlds,
                return -EINVAL;
 
        get_lsa = (struct cxl_mbox_get_lsa) {
-               .offset = cmd->in_offset,
-               .length = cmd->in_length,
+               .offset = cpu_to_le32(cmd->in_offset),
+               .length = cpu_to_le32(cmd->in_length),
        };
 
        rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_LSA, &get_lsa,
@@ -139,7 +139,7 @@ static int cxl_pmem_set_config_data(struct cxl_dev_state *cxlds,
                return -ENOMEM;
 
        *set_lsa = (struct cxl_mbox_set_lsa) {
-               .offset = cmd->in_offset,
+               .offset = cpu_to_le32(cmd->in_offset),
        };
        memcpy(set_lsa->data, cmd->in_buf, cmd->in_length);
 
index 87eb2b837e68dfebb5f9d59cbf770de8ad2f7233..9754d8b31621168e249dbdab3e33714ba83fb7b9 100644 (file)
@@ -120,6 +120,16 @@ config ARM_TEGRA_DEVFREQ
          It reads ACTMON counters of memory controllers and adjusts the
          operating frequencies and voltages with OPP support.
 
+config ARM_MEDIATEK_CCI_DEVFREQ
+       tristate "MEDIATEK CCI DEVFREQ Driver"
+       depends on ARM_MEDIATEK_CPUFREQ || COMPILE_TEST
+       select DEVFREQ_GOV_PASSIVE
+       help
+         This adds a devfreq driver for MediaTek Cache Coherent Interconnect
+         which is shared the same regulators with the cpu cluster. It can track
+         buck voltages and update a proper CCI frequency. Use the notification
+         to get the regulator status.
+
 config ARM_RK3399_DMC_DEVFREQ
        tristate "ARM RK3399 DMC DEVFREQ Driver"
        depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \
index 0b6be92a25d9c0719d8536531e836b9cc138196e..bf40d04928d03d5dbd0c0267ef2269332c496535 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)     += governor_passive.o
 obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)   += exynos-bus.o
 obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ)      += imx-bus.o
 obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ)   += imx8m-ddrc.o
+obj-$(CONFIG_ARM_MEDIATEK_CCI_DEVFREQ) += mtk-cci-devfreq.o
 obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ)   += rk3399_dmc.o
 obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ)       += sun8i-a33-mbus.o
 obj-$(CONFIG_ARM_TEGRA_DEVFREQ)                += tegra30-devfreq.o
index 9602141bb8ec49d8fbf47a160616c4a107e51720..63347a5ae5999af2053b0802d71dcae1c551d0e2 100644 (file)
@@ -696,6 +696,8 @@ static int qos_notifier_call(struct devfreq *devfreq)
 /**
  * qos_min_notifier_call() - Callback for QoS min_freq changes.
  * @nb:                Should be devfreq->nb_min
+ * @val:       not used
+ * @ptr:       not used
  */
 static int qos_min_notifier_call(struct notifier_block *nb,
                                         unsigned long val, void *ptr)
@@ -706,6 +708,8 @@ static int qos_min_notifier_call(struct notifier_block *nb,
 /**
  * qos_max_notifier_call() - Callback for QoS max_freq changes.
  * @nb:                Should be devfreq->nb_max
+ * @val:       not used
+ * @ptr:       not used
  */
 static int qos_max_notifier_call(struct notifier_block *nb,
                                         unsigned long val, void *ptr)
index e689101abc93036c0b84a435e1489bdb1c41d1cf..f7dcc44f9414c09009399ccb74b2d794c6c628d6 100644 (file)
@@ -447,9 +447,9 @@ static int exynos_bus_probe(struct platform_device *pdev)
                }
        }
 
-       max_state = bus->devfreq->profile->max_state;
-       min_freq = (bus->devfreq->profile->freq_table[0] / 1000);
-       max_freq = (bus->devfreq->profile->freq_table[max_state - 1] / 1000);
+       max_state = bus->devfreq->max_state;
+       min_freq = (bus->devfreq->freq_table[0] / 1000);
+       max_freq = (bus->devfreq->freq_table[max_state - 1] / 1000);
        pr_info("exynos-bus: new bus device registered: %s (%6ld KHz ~ %6ld KHz)\n",
                        dev_name(dev), min_freq, max_freq);
 
index f3f6e25053ed2a7952080b3138be19caf54c77d2..f87067fc574d69735c2b7e60583175ec7b6e0d38 100644 (file)
@@ -59,7 +59,7 @@ static int imx_bus_init_icc(struct device *dev)
        struct imx_bus *priv = dev_get_drvdata(dev);
        const char *icc_driver_name;
 
-       if (!of_get_property(dev->of_node, "#interconnect-cells", 0))
+       if (!of_get_property(dev->of_node, "#interconnect-cells", NULL))
                return 0;
        if (!IS_ENABLED(CONFIG_INTERCONNECT_IMX)) {
                dev_warn(dev, "imx interconnect drivers disabled\n");
diff --git a/drivers/devfreq/mtk-cci-devfreq.c b/drivers/devfreq/mtk-cci-devfreq.c
new file mode 100644 (file)
index 0000000..71abb3f
--- /dev/null
@@ -0,0 +1,440 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 MediaTek Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/devfreq.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/regulator/consumer.h>
+
+struct mtk_ccifreq_platform_data {
+       int min_volt_shift;
+       int max_volt_shift;
+       int proc_max_volt;
+       int sram_min_volt;
+       int sram_max_volt;
+};
+
+struct mtk_ccifreq_drv {
+       struct device *dev;
+       struct devfreq *devfreq;
+       struct regulator *proc_reg;
+       struct regulator *sram_reg;
+       struct clk *cci_clk;
+       struct clk *inter_clk;
+       int inter_voltage;
+       unsigned long pre_freq;
+       /* Avoid race condition for regulators between notify and policy */
+       struct mutex reg_lock;
+       struct notifier_block opp_nb;
+       const struct mtk_ccifreq_platform_data *soc_data;
+       int vtrack_max;
+};
+
+static int mtk_ccifreq_set_voltage(struct mtk_ccifreq_drv *drv, int new_voltage)
+{
+       const struct mtk_ccifreq_platform_data *soc_data = drv->soc_data;
+       struct device *dev = drv->dev;
+       int pre_voltage, pre_vsram, new_vsram, vsram, voltage, ret;
+       int retry_max = drv->vtrack_max;
+
+       if (!drv->sram_reg) {
+               ret = regulator_set_voltage(drv->proc_reg, new_voltage,
+                                           drv->soc_data->proc_max_volt);
+               return ret;
+       }
+
+       pre_voltage = regulator_get_voltage(drv->proc_reg);
+       if (pre_voltage < 0) {
+               dev_err(dev, "invalid vproc value: %d\n", pre_voltage);
+               return pre_voltage;
+       }
+
+       pre_vsram = regulator_get_voltage(drv->sram_reg);
+       if (pre_vsram < 0) {
+               dev_err(dev, "invalid vsram value: %d\n", pre_vsram);
+               return pre_vsram;
+       }
+
+       new_vsram = clamp(new_voltage + soc_data->min_volt_shift,
+                         soc_data->sram_min_volt, soc_data->sram_max_volt);
+
+       do {
+               if (pre_voltage <= new_voltage) {
+                       vsram = clamp(pre_voltage + soc_data->max_volt_shift,
+                                     soc_data->sram_min_volt, new_vsram);
+                       ret = regulator_set_voltage(drv->sram_reg, vsram,
+                                                   soc_data->sram_max_volt);
+                       if (ret)
+                               return ret;
+
+                       if (vsram == soc_data->sram_max_volt ||
+                           new_vsram == soc_data->sram_min_volt)
+                               voltage = new_voltage;
+                       else
+                               voltage = vsram - soc_data->min_volt_shift;
+
+                       ret = regulator_set_voltage(drv->proc_reg, voltage,
+                                                   soc_data->proc_max_volt);
+                       if (ret) {
+                               regulator_set_voltage(drv->sram_reg, pre_vsram,
+                                                     soc_data->sram_max_volt);
+                               return ret;
+                       }
+               } else if (pre_voltage > new_voltage) {
+                       voltage = max(new_voltage,
+                                     pre_vsram - soc_data->max_volt_shift);
+                       ret = regulator_set_voltage(drv->proc_reg, voltage,
+                                                   soc_data->proc_max_volt);
+                       if (ret)
+                               return ret;
+
+                       if (voltage == new_voltage)
+                               vsram = new_vsram;
+                       else
+                               vsram = max(new_vsram,
+                                           voltage + soc_data->min_volt_shift);
+
+                       ret = regulator_set_voltage(drv->sram_reg, vsram,
+                                                   soc_data->sram_max_volt);
+                       if (ret) {
+                               regulator_set_voltage(drv->proc_reg, pre_voltage,
+                                                     soc_data->proc_max_volt);
+                               return ret;
+                       }
+               }
+
+               pre_voltage = voltage;
+               pre_vsram = vsram;
+
+               if (--retry_max < 0) {
+                       dev_err(dev,
+                               "over loop count, failed to set voltage\n");
+                       return -EINVAL;
+               }
+       } while (voltage != new_voltage || vsram != new_vsram);
+
+       return 0;
+}
+
+static int mtk_ccifreq_target(struct device *dev, unsigned long *freq,
+                             u32 flags)
+{
+       struct mtk_ccifreq_drv *drv = dev_get_drvdata(dev);
+       struct clk *cci_pll = clk_get_parent(drv->cci_clk);
+       struct dev_pm_opp *opp;
+       unsigned long opp_rate;
+       int voltage, pre_voltage, inter_voltage, target_voltage, ret;
+
+       if (!drv)
+               return -EINVAL;
+
+       if (drv->pre_freq == *freq)
+               return 0;
+
+       inter_voltage = drv->inter_voltage;
+
+       opp_rate = *freq;
+       opp = devfreq_recommended_opp(dev, &opp_rate, 1);
+       if (IS_ERR(opp)) {
+               dev_err(dev, "failed to find opp for freq: %ld\n", opp_rate);
+               return PTR_ERR(opp);
+       }
+
+       mutex_lock(&drv->reg_lock);
+
+       voltage = dev_pm_opp_get_voltage(opp);
+       dev_pm_opp_put(opp);
+
+       pre_voltage = regulator_get_voltage(drv->proc_reg);
+       if (pre_voltage < 0) {
+               dev_err(dev, "invalid vproc value: %d\n", pre_voltage);
+               ret = pre_voltage;
+               goto out_unlock;
+       }
+
+       /* scale up: set voltage first then freq. */
+       target_voltage = max(inter_voltage, voltage);
+       if (pre_voltage <= target_voltage) {
+               ret = mtk_ccifreq_set_voltage(drv, target_voltage);
+               if (ret) {
+                       dev_err(dev, "failed to scale up voltage\n");
+                       goto out_restore_voltage;
+               }
+       }
+
+       /* switch the cci clock to intermediate clock source. */
+       ret = clk_set_parent(drv->cci_clk, drv->inter_clk);
+       if (ret) {
+               dev_err(dev, "failed to re-parent cci clock\n");
+               goto out_restore_voltage;
+       }
+
+       /* set the original clock to target rate. */
+       ret = clk_set_rate(cci_pll, *freq);
+       if (ret) {
+               dev_err(dev, "failed to set cci pll rate: %d\n", ret);
+               clk_set_parent(drv->cci_clk, cci_pll);
+               goto out_restore_voltage;
+       }
+
+       /* switch the cci clock back to the original clock source. */
+       ret = clk_set_parent(drv->cci_clk, cci_pll);
+       if (ret) {
+               dev_err(dev, "failed to re-parent cci clock\n");
+               mtk_ccifreq_set_voltage(drv, inter_voltage);
+               goto out_unlock;
+       }
+
+       /*
+        * If the new voltage is lower than the intermediate voltage or the
+        * original voltage, scale down to the new voltage.
+        */
+       if (voltage < inter_voltage || voltage < pre_voltage) {
+               ret = mtk_ccifreq_set_voltage(drv, voltage);
+               if (ret) {
+                       dev_err(dev, "failed to scale down voltage\n");
+                       goto out_unlock;
+               }
+       }
+
+       drv->pre_freq = *freq;
+       mutex_unlock(&drv->reg_lock);
+
+       return 0;
+
+out_restore_voltage:
+       mtk_ccifreq_set_voltage(drv, pre_voltage);
+
+out_unlock:
+       mutex_unlock(&drv->reg_lock);
+       return ret;
+}
+
+static int mtk_ccifreq_opp_notifier(struct notifier_block *nb,
+                                   unsigned long event, void *data)
+{
+       struct dev_pm_opp *opp = data;
+       struct mtk_ccifreq_drv *drv;
+       unsigned long freq, volt;
+
+       drv = container_of(nb, struct mtk_ccifreq_drv, opp_nb);
+
+       if (event == OPP_EVENT_ADJUST_VOLTAGE) {
+               freq = dev_pm_opp_get_freq(opp);
+
+               mutex_lock(&drv->reg_lock);
+               /* current opp item is changed */
+               if (freq == drv->pre_freq) {
+                       volt = dev_pm_opp_get_voltage(opp);
+                       mtk_ccifreq_set_voltage(drv, volt);
+               }
+               mutex_unlock(&drv->reg_lock);
+       }
+
+       return 0;
+}
+
+static struct devfreq_dev_profile mtk_ccifreq_profile = {
+       .target = mtk_ccifreq_target,
+};
+
+static int mtk_ccifreq_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mtk_ccifreq_drv *drv;
+       struct devfreq_passive_data *passive_data;
+       struct dev_pm_opp *opp;
+       unsigned long rate, opp_volt;
+       int ret;
+
+       drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
+       if (!drv)
+               return -ENOMEM;
+
+       drv->dev = dev;
+       drv->soc_data = (const struct mtk_ccifreq_platform_data *)
+                               of_device_get_match_data(&pdev->dev);
+       mutex_init(&drv->reg_lock);
+       platform_set_drvdata(pdev, drv);
+
+       drv->cci_clk = devm_clk_get(dev, "cci");
+       if (IS_ERR(drv->cci_clk)) {
+               ret = PTR_ERR(drv->cci_clk);
+               return dev_err_probe(dev, ret, "failed to get cci clk\n");
+       }
+
+       drv->inter_clk = devm_clk_get(dev, "intermediate");
+       if (IS_ERR(drv->inter_clk)) {
+               ret = PTR_ERR(drv->inter_clk);
+               return dev_err_probe(dev, ret,
+                                    "failed to get intermediate clk\n");
+       }
+
+       drv->proc_reg = devm_regulator_get_optional(dev, "proc");
+       if (IS_ERR(drv->proc_reg)) {
+               ret = PTR_ERR(drv->proc_reg);
+               return dev_err_probe(dev, ret,
+                                    "failed to get proc regulator\n");
+       }
+
+       ret = regulator_enable(drv->proc_reg);
+       if (ret) {
+               dev_err(dev, "failed to enable proc regulator\n");
+               return ret;
+       }
+
+       drv->sram_reg = devm_regulator_get_optional(dev, "sram");
+       if (IS_ERR(drv->sram_reg))
+               drv->sram_reg = NULL;
+       else {
+               ret = regulator_enable(drv->sram_reg);
+               if (ret) {
+                       dev_err(dev, "failed to enable sram regulator\n");
+                       goto out_free_resources;
+               }
+       }
+
+       /*
+        * We assume min voltage is 0 and tracking target voltage using
+        * min_volt_shift for each iteration.
+        * The retry_max is 3 times of expected iteration count.
+        */
+       drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv->soc_data->sram_max_volt,
+                                              drv->soc_data->proc_max_volt),
+                                          drv->soc_data->min_volt_shift);
+
+       ret = clk_prepare_enable(drv->cci_clk);
+       if (ret)
+               goto out_free_resources;
+
+       ret = dev_pm_opp_of_add_table(dev);
+       if (ret) {
+               dev_err(dev, "failed to add opp table: %d\n", ret);
+               goto out_disable_cci_clk;
+       }
+
+       rate = clk_get_rate(drv->inter_clk);
+       opp = dev_pm_opp_find_freq_ceil(dev, &rate);
+       if (IS_ERR(opp)) {
+               ret = PTR_ERR(opp);
+               dev_err(dev, "failed to get intermediate opp: %d\n", ret);
+               goto out_remove_opp_table;
+       }
+       drv->inter_voltage = dev_pm_opp_get_voltage(opp);
+       dev_pm_opp_put(opp);
+
+       rate = U32_MAX;
+       opp = dev_pm_opp_find_freq_floor(drv->dev, &rate);
+       if (IS_ERR(opp)) {
+               dev_err(dev, "failed to get opp\n");
+               ret = PTR_ERR(opp);
+               goto out_remove_opp_table;
+       }
+
+       opp_volt = dev_pm_opp_get_voltage(opp);
+       dev_pm_opp_put(opp);
+       ret = mtk_ccifreq_set_voltage(drv, opp_volt);
+       if (ret) {
+               dev_err(dev, "failed to scale to highest voltage %lu in proc_reg\n",
+                       opp_volt);
+               goto out_remove_opp_table;
+       }
+
+       passive_data = devm_kzalloc(dev, sizeof(*passive_data), GFP_KERNEL);
+       if (!passive_data) {
+               ret = -ENOMEM;
+               goto out_remove_opp_table;
+       }
+
+       passive_data->parent_type = CPUFREQ_PARENT_DEV;
+       drv->devfreq = devm_devfreq_add_device(dev, &mtk_ccifreq_profile,
+                                              DEVFREQ_GOV_PASSIVE,
+                                              passive_data);
+       if (IS_ERR(drv->devfreq)) {
+               ret = -EPROBE_DEFER;
+               dev_err(dev, "failed to add devfreq device: %ld\n",
+                       PTR_ERR(drv->devfreq));
+               goto out_remove_opp_table;
+       }
+
+       drv->opp_nb.notifier_call = mtk_ccifreq_opp_notifier;
+       ret = dev_pm_opp_register_notifier(dev, &drv->opp_nb);
+       if (ret) {
+               dev_err(dev, "failed to register opp notifier: %d\n", ret);
+               goto out_remove_opp_table;
+       }
+       return 0;
+
+out_remove_opp_table:
+       dev_pm_opp_of_remove_table(dev);
+
+out_disable_cci_clk:
+       clk_disable_unprepare(drv->cci_clk);
+
+out_free_resources:
+       if (regulator_is_enabled(drv->proc_reg))
+               regulator_disable(drv->proc_reg);
+       if (drv->sram_reg && regulator_is_enabled(drv->sram_reg))
+               regulator_disable(drv->sram_reg);
+
+       return ret;
+}
+
+static int mtk_ccifreq_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mtk_ccifreq_drv *drv;
+
+       drv = platform_get_drvdata(pdev);
+
+       dev_pm_opp_unregister_notifier(dev, &drv->opp_nb);
+       dev_pm_opp_of_remove_table(dev);
+       clk_disable_unprepare(drv->cci_clk);
+       regulator_disable(drv->proc_reg);
+       if (drv->sram_reg)
+               regulator_disable(drv->sram_reg);
+
+       return 0;
+}
+
+static const struct mtk_ccifreq_platform_data mt8183_platform_data = {
+       .min_volt_shift = 100000,
+       .max_volt_shift = 200000,
+       .proc_max_volt = 1150000,
+};
+
+static const struct mtk_ccifreq_platform_data mt8186_platform_data = {
+       .min_volt_shift = 100000,
+       .max_volt_shift = 250000,
+       .proc_max_volt = 1118750,
+       .sram_min_volt = 850000,
+       .sram_max_volt = 1118750,
+};
+
+static const struct of_device_id mtk_ccifreq_machines[] = {
+       { .compatible = "mediatek,mt8183-cci", .data = &mt8183_platform_data },
+       { .compatible = "mediatek,mt8186-cci", .data = &mt8186_platform_data },
+       { },
+};
+MODULE_DEVICE_TABLE(of, mtk_ccifreq_machines);
+
+static struct platform_driver mtk_ccifreq_platdrv = {
+       .probe  = mtk_ccifreq_probe,
+       .remove = mtk_ccifreq_remove,
+       .driver = {
+               .name = "mtk-ccifreq",
+               .of_match_table = mtk_ccifreq_machines,
+       },
+};
+module_platform_driver(mtk_ccifreq_platdrv);
+
+MODULE_DESCRIPTION("MediaTek CCI devfreq driver");
+MODULE_AUTHOR("Jia-Wei Chang <jia-wei.chang@mediatek.com>");
+MODULE_LICENSE("GPL v2");
index 65ecf17a36f491a2b16317b0ec7952ab906d0a1c..585a95fe2bd6d358839d2e4b67fa6e57ccefe69b 100644 (file)
@@ -922,8 +922,10 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
 
        devfreq = devm_devfreq_add_device(&pdev->dev, &tegra_devfreq_profile,
                                          "tegra_actmon", NULL);
-       if (IS_ERR(devfreq))
+       if (IS_ERR(devfreq)) {
+               dev_err(&pdev->dev, "Failed to add device: %pe\n", devfreq);
                return PTR_ERR(devfreq);
+       }
 
        return 0;
 }
index 0cce6e4ec9462c3305d6b55476705658a0dcfe97..205acb2c744ded50d42d2138f288cdce9ef97967 100644 (file)
@@ -343,7 +343,7 @@ void dma_resv_replace_fences(struct dma_resv *obj, uint64_t context,
                if (old->context != context)
                        continue;
 
-               dma_resv_list_set(list, i, replacement, usage);
+               dma_resv_list_set(list, i, dma_fence_get(replacement), usage);
                dma_fence_put(old);
        }
 }
index 3e9d726504e2ed776ddc1155ef43130da5811533..7b3e6030f7b4b007e0ace835bbaeccbda21cb8d3 100644 (file)
@@ -1900,6 +1900,11 @@ static int at_xdmac_alloc_chan_resources(struct dma_chan *chan)
        for (i = 0; i < init_nr_desc_per_channel; i++) {
                desc = at_xdmac_alloc_desc(chan, GFP_KERNEL);
                if (!desc) {
+                       if (i == 0) {
+                               dev_warn(chan2dev(chan),
+                                        "can't allocate any descriptors\n");
+                               return -EIO;
+                       }
                        dev_warn(chan2dev(chan),
                                "only %d descriptors have been allocated\n", i);
                        break;
index 0a2168a4ccb0cf177ee99b4d7522b1b2c06ae0df..f696246f57fdb3734523930610bc650c52872fdb 100644 (file)
@@ -675,16 +675,10 @@ static int dmatest_func(void *data)
        /*
         * src and dst buffers are freed by ourselves below
         */
-       if (params->polled) {
+       if (params->polled)
                flags = DMA_CTRL_ACK;
-       } else {
-               if (dma_has_cap(DMA_INTERRUPT, dev->cap_mask)) {
-                       flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
-               } else {
-                       pr_err("Channel does not support interrupt!\n");
-                       goto err_pq_array;
-               }
-       }
+       else
+               flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
 
        ktime = ktime_get();
        while (!(kthread_should_stop() ||
@@ -912,7 +906,6 @@ error_unmap_continue:
        runtime = ktime_to_us(ktime);
 
        ret = 0;
-err_pq_array:
        kfree(dma_pq);
 err_srcs_array:
        kfree(srcs);
index e9c9bcb1f5c20ffc2f8eb93bd6c086069e385506..c741da02b67e9831554da2023cb9cc73c0662ad4 100644 (file)
@@ -1164,8 +1164,9 @@ static int dma_chan_pause(struct dma_chan *dchan)
                        BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT;
                axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
        } else {
-               val = BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT |
-                     BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT;
+               val = axi_dma_ioread32(chan->chip, DMAC_CHSUSPREG);
+               val |= BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT |
+                       BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT;
                axi_dma_iowrite32(chan->chip, DMAC_CHSUSPREG, val);
        }
 
@@ -1190,12 +1191,13 @@ static inline void axi_chan_resume(struct axi_dma_chan *chan)
 {
        u32 val;
 
-       val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
        if (chan->chip->dw->hdata->reg_map_8_channels) {
+               val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
                val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT);
                val |=  (BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT);
                axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
        } else {
+               val = axi_dma_ioread32(chan->chip, DMAC_CHSUSPREG);
                val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT);
                val |=  (BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT);
                axi_dma_iowrite32(chan->chip, DMAC_CHSUSPREG, val);
index ff0ea60051f0c90e50463de27df0abf5b53f9e27..5a8cc52c1abfd16938aa3d98ebfc28ebe323045a 100644 (file)
@@ -716,10 +716,7 @@ static void idxd_device_wqs_clear_state(struct idxd_device *idxd)
                struct idxd_wq *wq = idxd->wqs[i];
 
                mutex_lock(&wq->wq_lock);
-               if (wq->state == IDXD_WQ_ENABLED) {
-                       idxd_wq_disable_cleanup(wq);
-                       wq->state = IDXD_WQ_DISABLED;
-               }
+               idxd_wq_disable_cleanup(wq);
                idxd_wq_device_reset_cleanup(wq);
                mutex_unlock(&wq->wq_lock);
        }
index 355fb3ef4cbfaf1ce6d04892a9030aa21418813f..aa3478257ddb54f73204bc80694f56e8fe288d70 100644 (file)
@@ -512,15 +512,16 @@ static int idxd_probe(struct idxd_device *idxd)
        dev_dbg(dev, "IDXD reset complete\n");
 
        if (IS_ENABLED(CONFIG_INTEL_IDXD_SVM) && sva) {
-               if (iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA))
+               if (iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA)) {
                        dev_warn(dev, "Unable to turn on user SVA feature.\n");
-               else
+               } else {
                        set_bit(IDXD_FLAG_USER_PASID_ENABLED, &idxd->flags);
 
-               if (idxd_enable_system_pasid(idxd))
-                       dev_warn(dev, "No in-kernel DMA with PASID.\n");
-               else
-                       set_bit(IDXD_FLAG_PASID_ENABLED, &idxd->flags);
+                       if (idxd_enable_system_pasid(idxd))
+                               dev_warn(dev, "No in-kernel DMA with PASID.\n");
+                       else
+                               set_bit(IDXD_FLAG_PASID_ENABLED, &idxd->flags);
+               }
        } else if (!sva) {
                dev_warn(dev, "User forced SVA off via module param.\n");
        }
index 8535018ee7a2e14ecf4bbae9878949b0c8ea1335..f37a276f519e6ef91c64a1319d55ce3af9b392fc 100644 (file)
@@ -891,7 +891,7 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
         * SDMA stops cyclic channel when DMA request triggers a channel and no SDMA
         * owned buffer is available (i.e. BD_DONE was set too late).
         */
-       if (!is_sdma_channel_enabled(sdmac->sdma, sdmac->channel)) {
+       if (sdmac->desc && !is_sdma_channel_enabled(sdmac->sdma, sdmac->channel)) {
                dev_warn(sdmac->sdma->dev, "restart cyclic channel %d\n", sdmac->channel);
                sdma_enable_channel(sdmac->sdma, sdmac->channel);
        }
@@ -2346,7 +2346,7 @@ MODULE_DESCRIPTION("i.MX SDMA driver");
 #if IS_ENABLED(CONFIG_SOC_IMX6Q)
 MODULE_FIRMWARE("imx/sdma/sdma-imx6q.bin");
 #endif
-#if IS_ENABLED(CONFIG_SOC_IMX7D)
+#if IS_ENABLED(CONFIG_SOC_IMX7D) || IS_ENABLED(CONFIG_SOC_IMX8M)
 MODULE_FIRMWARE("imx/sdma/sdma-imx7d.bin");
 #endif
 MODULE_LICENSE("GPL");
index efe8bd3a0e2aa5c14a0f49fd9154d0930fd56196..9b9184f964be397a4f5f5b8a7a1c2410032d6456 100644 (file)
@@ -1593,11 +1593,12 @@ static int intel_ldma_probe(struct platform_device *pdev)
        d->core_clk = devm_clk_get_optional(dev, NULL);
        if (IS_ERR(d->core_clk))
                return PTR_ERR(d->core_clk);
-       clk_prepare_enable(d->core_clk);
 
        d->rst = devm_reset_control_get_optional(dev, NULL);
        if (IS_ERR(d->rst))
                return PTR_ERR(d->rst);
+
+       clk_prepare_enable(d->core_clk);
        reset_control_deassert(d->rst);
 
        ret = devm_add_action_or_reset(dev, ldma_clk_disable, d);
index 858400e42ec05c5541f703bdd7e901552cda77a8..09915a5cba3ea6bda18d6125eefb8a68284e4ac3 100644 (file)
@@ -2589,7 +2589,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
 
        /* If the DMAC pool is empty, alloc new */
        if (!desc) {
-               DEFINE_SPINLOCK(lock);
+               static DEFINE_SPINLOCK(lock);
                LIST_HEAD(pool);
 
                if (!add_desc(&pool, &lock, GFP_ATOMIC, 1))
index 87f6ca1541cffb0d31ebf0a17bc27c59b330c677..2ff787df513e60ec23f14bb0e888aedf46cc4bbe 100644 (file)
@@ -558,14 +558,6 @@ static int bam_alloc_chan(struct dma_chan *chan)
        return 0;
 }
 
-static int bam_pm_runtime_get_sync(struct device *dev)
-{
-       if (pm_runtime_enabled(dev))
-               return pm_runtime_get_sync(dev);
-
-       return 0;
-}
-
 /**
  * bam_free_chan - Frees dma resources associated with specific channel
  * @chan: specified channel
@@ -581,7 +573,7 @@ static void bam_free_chan(struct dma_chan *chan)
        unsigned long flags;
        int ret;
 
-       ret = bam_pm_runtime_get_sync(bdev->dev);
+       ret = pm_runtime_get_sync(bdev->dev);
        if (ret < 0)
                return;
 
@@ -784,7 +776,7 @@ static int bam_pause(struct dma_chan *chan)
        unsigned long flag;
        int ret;
 
-       ret = bam_pm_runtime_get_sync(bdev->dev);
+       ret = pm_runtime_get_sync(bdev->dev);
        if (ret < 0)
                return ret;
 
@@ -810,7 +802,7 @@ static int bam_resume(struct dma_chan *chan)
        unsigned long flag;
        int ret;
 
-       ret = bam_pm_runtime_get_sync(bdev->dev);
+       ret = pm_runtime_get_sync(bdev->dev);
        if (ret < 0)
                return ret;
 
@@ -919,7 +911,7 @@ static irqreturn_t bam_dma_irq(int irq, void *data)
        if (srcs & P_IRQ)
                tasklet_schedule(&bdev->task);
 
-       ret = bam_pm_runtime_get_sync(bdev->dev);
+       ret = pm_runtime_get_sync(bdev->dev);
        if (ret < 0)
                return IRQ_NONE;
 
@@ -1037,7 +1029,7 @@ static void bam_start_dma(struct bam_chan *bchan)
        if (!vd)
                return;
 
-       ret = bam_pm_runtime_get_sync(bdev->dev);
+       ret = pm_runtime_get_sync(bdev->dev);
        if (ret < 0)
                return;
 
@@ -1374,11 +1366,6 @@ static int bam_dma_probe(struct platform_device *pdev)
        if (ret)
                goto err_unregister_dma;
 
-       if (!bdev->bamclk) {
-               pm_runtime_disable(&pdev->dev);
-               return 0;
-       }
-
        pm_runtime_irq_safe(&pdev->dev);
        pm_runtime_set_autosuspend_delay(&pdev->dev, BAM_DMA_AUTOSUSPEND_DELAY);
        pm_runtime_use_autosuspend(&pdev->dev);
@@ -1462,10 +1449,8 @@ static int __maybe_unused bam_dma_suspend(struct device *dev)
 {
        struct bam_device *bdev = dev_get_drvdata(dev);
 
-       if (bdev->bamclk) {
-               pm_runtime_force_suspend(dev);
-               clk_unprepare(bdev->bamclk);
-       }
+       pm_runtime_force_suspend(dev);
+       clk_unprepare(bdev->bamclk);
 
        return 0;
 }
@@ -1475,13 +1460,11 @@ static int __maybe_unused bam_dma_resume(struct device *dev)
        struct bam_device *bdev = dev_get_drvdata(dev);
        int ret;
 
-       if (bdev->bamclk) {
-               ret = clk_prepare(bdev->bamclk);
-               if (ret)
-                       return ret;
+       ret = clk_prepare(bdev->bamclk);
+       if (ret)
+               return ret;
 
-               pm_runtime_force_resume(dev);
-       }
+       pm_runtime_force_resume(dev);
 
        return 0;
 }
index 71d24fc07c0038cdf23e350d913902c8e9d576b6..f744ddbbbad7fa35e41bfd39915feb2d9cfcae73 100644 (file)
@@ -245,6 +245,7 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
        if (dma_spec->args[0] >= xbar->xbar_requests) {
                dev_err(&pdev->dev, "Invalid XBAR request number: %d\n",
                        dma_spec->args[0]);
+               put_device(&pdev->dev);
                return ERR_PTR(-EINVAL);
        }
 
@@ -252,12 +253,14 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
        dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
        if (!dma_spec->np) {
                dev_err(&pdev->dev, "Can't get DMA master\n");
+               put_device(&pdev->dev);
                return ERR_PTR(-EINVAL);
        }
 
        map = kzalloc(sizeof(*map), GFP_KERNEL);
        if (!map) {
                of_node_put(dma_spec->np);
+               put_device(&pdev->dev);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -268,6 +271,8 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
                mutex_unlock(&xbar->mutex);
                dev_err(&pdev->dev, "Run out of free DMA requests\n");
                kfree(map);
+               of_node_put(dma_spec->np);
+               put_device(&pdev->dev);
                return ERR_PTR(-ENOMEM);
        }
        set_bit(map->xbar_out, xbar->dma_inuse);
index f6fe723ab869e4836ee341d046585dd95a908220..d4e23101448ae370750d4de36138de0680899a70 100644 (file)
@@ -181,7 +181,7 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol,
                return NULL;
        }
 
-       id = ida_simple_get(&scmi_bus_id, 1, 0, GFP_KERNEL);
+       id = ida_alloc_min(&scmi_bus_id, 1, GFP_KERNEL);
        if (id < 0) {
                kfree_const(scmi_dev->name);
                kfree(scmi_dev);
@@ -204,7 +204,7 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol,
 put_dev:
        kfree_const(scmi_dev->name);
        put_device(&scmi_dev->dev);
-       ida_simple_remove(&scmi_bus_id, id);
+       ida_free(&scmi_bus_id, id);
        return NULL;
 }
 
@@ -212,7 +212,7 @@ void scmi_device_destroy(struct scmi_device *scmi_dev)
 {
        kfree_const(scmi_dev->name);
        scmi_handle_put(scmi_dev->handle);
-       ida_simple_remove(&scmi_bus_id, scmi_dev->id);
+       ida_free(&scmi_bus_id, scmi_dev->id);
        device_unregister(&scmi_dev->dev);
 }
 
index c7a83f6e38e5a76bdb0fb1d20be585b9ffdd24a4..3ed7ae0d6781e560a69ed79935acabb1c8266235 100644 (file)
@@ -194,6 +194,7 @@ static int rate_cmp_func(const void *_r1, const void *_r2)
 }
 
 struct scmi_clk_ipriv {
+       struct device *dev;
        u32 clk_id;
        struct scmi_clock_info *clk;
 };
@@ -223,6 +224,29 @@ iter_clk_describe_update_state(struct scmi_iterator_state *st,
        st->num_returned = NUM_RETURNED(flags);
        p->clk->rate_discrete = RATE_DISCRETE(flags);
 
+       /* Warn about out of spec replies ... */
+       if (!p->clk->rate_discrete &&
+           (st->num_returned != 3 || st->num_remaining != 0)) {
+               dev_warn(p->dev,
+                        "Out-of-spec CLOCK_DESCRIBE_RATES reply for %s - returned:%d remaining:%d rx_len:%zd\n",
+                        p->clk->name, st->num_returned, st->num_remaining,
+                        st->rx_len);
+
+               /*
+                * A known quirk: a triplet is returned but num_returned != 3
+                * Check for a safe payload size and fix.
+                */
+               if (st->num_returned != 3 && st->num_remaining == 0 &&
+                   st->rx_len == sizeof(*r) + sizeof(__le32) * 2 * 3) {
+                       st->num_returned = 3;
+                       st->num_remaining = 0;
+               } else {
+                       dev_err(p->dev,
+                               "Cannot fix out-of-spec reply !\n");
+                       return -EPROTO;
+               }
+       }
+
        return 0;
 }
 
@@ -255,7 +279,6 @@ iter_clk_describe_process_response(const struct scmi_protocol_handle *ph,
 
                *rate = RATE_TO_U64(r->rate[st->loop_idx]);
                p->clk->list.num_rates++;
-               //XXX dev_dbg(ph->dev, "Rate %llu Hz\n", *rate);
        }
 
        return ret;
@@ -275,6 +298,7 @@ scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id,
        struct scmi_clk_ipriv cpriv = {
                .clk_id = clk_id,
                .clk = clk,
+               .dev = ph->dev,
        };
 
        iter = ph->hops->iter_response_init(ph, &ops, SCMI_MAX_NUM_RATES,
index c1922bd650ae2c65bb64351146c7fe0916341975..8b7ac6663d57de6e8824aac6d0aa4e8509670912 100644 (file)
@@ -1223,6 +1223,7 @@ static int scmi_iterator_run(void *iter)
                if (ret)
                        break;
 
+               st->rx_len = i->t->rx.len;
                ret = iops->update_state(st, i->resp, i->priv);
                if (ret)
                        break;
index b503c22cfd326831cb612ae2d1dde004e3b0b0a9..8abace56b95885da4ccb9d52488083996c234e9e 100644 (file)
@@ -117,6 +117,7 @@ struct scmi_optee_channel {
        u32 channel_id;
        u32 tee_session;
        u32 caps;
+       u32 rx_len;
        struct mutex mu;
        struct scmi_chan_info *cinfo;
        union {
@@ -302,6 +303,9 @@ static int invoke_process_msg_channel(struct scmi_optee_channel *channel, size_t
                return -EIO;
        }
 
+       /* Save response size */
+       channel->rx_len = param[2].u.memref.size;
+
        return 0;
 }
 
@@ -353,6 +357,7 @@ static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *ch
        shbuf = tee_shm_get_va(channel->tee_shm, 0);
        memset(shbuf, 0, msg_size);
        channel->req.msg = shbuf;
+       channel->rx_len = msg_size;
 
        return 0;
 }
@@ -508,7 +513,7 @@ static void scmi_optee_fetch_response(struct scmi_chan_info *cinfo,
        struct scmi_optee_channel *channel = cinfo->transport_info;
 
        if (channel->tee_shm)
-               msg_fetch_response(channel->req.msg, SCMI_OPTEE_MAX_MSG_SIZE, xfer);
+               msg_fetch_response(channel->req.msg, channel->rx_len, xfer);
        else
                shmem_fetch_response(channel->req.shmem, xfer);
 }
index bbb0331801ff49274d23f2ea61d582f4f0dbdf7b..92414e53f9084189575fdb65f233851772122c62 100644 (file)
@@ -170,8 +170,7 @@ struct perf_dom_info {
 struct scmi_perf_info {
        u32 version;
        int num_domains;
-       bool power_scale_mw;
-       bool power_scale_uw;
+       enum scmi_power_scale power_scale;
        u64 stats_addr;
        u32 stats_size;
        struct perf_dom_info *dom_info;
@@ -201,9 +200,13 @@ static int scmi_perf_attributes_get(const struct scmi_protocol_handle *ph,
                u16 flags = le16_to_cpu(attr->flags);
 
                pi->num_domains = le16_to_cpu(attr->num_domains);
-               pi->power_scale_mw = POWER_SCALE_IN_MILLIWATT(flags);
+
+               if (POWER_SCALE_IN_MILLIWATT(flags))
+                       pi->power_scale = SCMI_POWER_MILLIWATTS;
                if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3)
-                       pi->power_scale_uw = POWER_SCALE_IN_MICROWATT(flags);
+                       if (POWER_SCALE_IN_MICROWATT(flags))
+                               pi->power_scale = SCMI_POWER_MICROWATTS;
+
                pi->stats_addr = le32_to_cpu(attr->stats_addr_low) |
                                (u64)le32_to_cpu(attr->stats_addr_high) << 32;
                pi->stats_size = le32_to_cpu(attr->stats_size);
@@ -792,11 +795,12 @@ static bool scmi_fast_switch_possible(const struct scmi_protocol_handle *ph,
        return dom->fc_info && dom->fc_info->level_set_addr;
 }
 
-static bool scmi_power_scale_mw_get(const struct scmi_protocol_handle *ph)
+static enum scmi_power_scale
+scmi_power_scale_get(const struct scmi_protocol_handle *ph)
 {
        struct scmi_perf_info *pi = ph->get_priv(ph);
 
-       return pi->power_scale_mw;
+       return pi->power_scale;
 }
 
 static const struct scmi_perf_proto_ops perf_proto_ops = {
@@ -811,7 +815,7 @@ static const struct scmi_perf_proto_ops perf_proto_ops = {
        .freq_get = scmi_dvfs_freq_get,
        .est_power_get = scmi_dvfs_est_power_get,
        .fast_switch_possible = scmi_fast_switch_possible,
-       .power_scale_mw_get = scmi_power_scale_mw_get,
+       .power_scale_get = scmi_power_scale_get,
 };
 
 static int scmi_perf_set_notify_enabled(const struct scmi_protocol_handle *ph,
index c679f3fb8718bb845fbe43068a7398c740d7f5e9..51c31379f9b3e85bb4fae72e7dbf4c36767b9b58 100644 (file)
@@ -179,6 +179,8 @@ struct scmi_protocol_handle {
  * @max_resources: Maximum acceptable number of items, configured by the caller
  *                depending on the underlying resources that it is querying.
  * @loop_idx: The iterator loop index in the current multi-part reply.
+ * @rx_len: Size in bytes of the currenly processed message; it can be used by
+ *         the user of the iterator to verify a reply size.
  * @priv: Optional pointer to some additional state-related private data setup
  *       by the caller during the iterations.
  */
@@ -188,6 +190,7 @@ struct scmi_iterator_state {
        unsigned int num_remaining;
        unsigned int max_resources;
        unsigned int loop_idx;
+       size_t rx_len;
        void *priv;
 };
 
index 73089a24f04b637c886b5177cdd852791ae04d83..ceae84c19d226d911fbed1e891fdb87183a1bd4a 100644 (file)
@@ -6,7 +6,7 @@
 #include <linux/efi.h>
 #include <linux/reboot.h>
 
-static void (*orig_pm_power_off)(void);
+static struct sys_off_handler *efi_sys_off_handler;
 
 int efi_reboot_quirk_mode = -1;
 
@@ -51,15 +51,11 @@ bool __weak efi_poweroff_required(void)
        return false;
 }
 
-static void efi_power_off(void)
+static int efi_power_off(struct sys_off_data *data)
 {
        efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
-       /*
-        * The above call should not return, if it does fall back to
-        * the original power off method (typically ACPI poweroff).
-        */
-       if (orig_pm_power_off)
-               orig_pm_power_off();
+
+       return NOTIFY_DONE;
 }
 
 static int __init efi_shutdown_init(void)
@@ -68,8 +64,13 @@ static int __init efi_shutdown_init(void)
                return -ENODEV;
 
        if (efi_poweroff_required()) {
-               orig_pm_power_off = pm_power_off;
-               pm_power_off = efi_power_off;
+               /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */
+               efi_sys_off_handler =
+                       register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
+                                                SYS_OFF_PRIO_FIRMWARE + 1,
+                                                efi_power_off, NULL);
+               if (IS_ERR(efi_sys_off_handler))
+                       return PTR_ERR(efi_sys_off_handler);
        }
 
        return 0;
index 08bc52c3cdcbedb19c170488caa101daf9f9f932..ecd7d169470b068ddbbc9685ae33a1f0a860cd32 100644 (file)
@@ -351,6 +351,9 @@ static const struct regmap_config pca953x_i2c_regmap = {
        .reg_bits = 8,
        .val_bits = 8,
 
+       .use_single_read = true,
+       .use_single_write = true,
+
        .readable_reg = pca953x_readable_register,
        .writeable_reg = pca953x_writeable_register,
        .volatile_reg = pca953x_volatile_register,
@@ -906,15 +909,18 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert)
 {
        DECLARE_BITMAP(val, MAX_LINE);
+       u8 regaddr;
        int ret;
 
-       ret = regcache_sync_region(chip->regmap, chip->regs->output,
-                                  chip->regs->output + NBANK(chip));
+       regaddr = pca953x_recalc_addr(chip, chip->regs->output, 0);
+       ret = regcache_sync_region(chip->regmap, regaddr,
+                                  regaddr + NBANK(chip) - 1);
        if (ret)
                goto out;
 
-       ret = regcache_sync_region(chip->regmap, chip->regs->direction,
-                                  chip->regs->direction + NBANK(chip));
+       regaddr = pca953x_recalc_addr(chip, chip->regs->direction, 0);
+       ret = regcache_sync_region(chip->regmap, regaddr,
+                                  regaddr + NBANK(chip) - 1);
        if (ret)
                goto out;
 
@@ -1127,14 +1133,14 @@ static int pca953x_regcache_sync(struct device *dev)
         * sync these registers first and only then sync the rest.
         */
        regaddr = pca953x_recalc_addr(chip, chip->regs->direction, 0);
-       ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip));
+       ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip) - 1);
        if (ret) {
                dev_err(dev, "Failed to sync GPIO dir registers: %d\n", ret);
                return ret;
        }
 
        regaddr = pca953x_recalc_addr(chip, chip->regs->output, 0);
-       ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip));
+       ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip) - 1);
        if (ret) {
                dev_err(dev, "Failed to sync GPIO out registers: %d\n", ret);
                return ret;
@@ -1144,7 +1150,7 @@ static int pca953x_regcache_sync(struct device *dev)
        if (chip->driver_data & PCA_PCAL) {
                regaddr = pca953x_recalc_addr(chip, PCAL953X_IN_LATCH, 0);
                ret = regcache_sync_region(chip->regmap, regaddr,
-                                          regaddr + NBANK(chip));
+                                          regaddr + NBANK(chip) - 1);
                if (ret) {
                        dev_err(dev, "Failed to sync INT latch registers: %d\n",
                                ret);
@@ -1153,7 +1159,7 @@ static int pca953x_regcache_sync(struct device *dev)
 
                regaddr = pca953x_recalc_addr(chip, PCAL953X_INT_MASK, 0);
                ret = regcache_sync_region(chip->regmap, regaddr,
-                                          regaddr + NBANK(chip));
+                                          regaddr + NBANK(chip) - 1);
                if (ret) {
                        dev_err(dev, "Failed to sync INT mask registers: %d\n",
                                ret);
index 98109839102fba84dd8a809cebc0d36172c1a4fb..1020c2feb24964303c279fa352af7839991a8775 100644 (file)
@@ -991,28 +991,22 @@ static struct configfs_attribute *gpio_sim_device_config_attrs[] = {
 };
 
 struct gpio_sim_chip_name_ctx {
-       struct gpio_sim_device *dev;
+       struct fwnode_handle *swnode;
        char *page;
 };
 
 static int gpio_sim_emit_chip_name(struct device *dev, void *data)
 {
        struct gpio_sim_chip_name_ctx *ctx = data;
-       struct fwnode_handle *swnode;
-       struct gpio_sim_bank *bank;
 
        /* This would be the sysfs device exported in /sys/class/gpio. */
        if (dev->class)
                return 0;
 
-       swnode = dev_fwnode(dev);
+       if (device_match_fwnode(dev, ctx->swnode))
+               return sprintf(ctx->page, "%s\n", dev_name(dev));
 
-       list_for_each_entry(bank, &ctx->dev->bank_list, siblings) {
-               if (bank->swnode == swnode)
-                       return sprintf(ctx->page, "%s\n", dev_name(dev));
-       }
-
-       return -ENODATA;
+       return 0;
 }
 
 static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item,
@@ -1020,7 +1014,7 @@ static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item,
 {
        struct gpio_sim_bank *bank = to_gpio_sim_bank(item);
        struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank);
-       struct gpio_sim_chip_name_ctx ctx = { dev, page };
+       struct gpio_sim_chip_name_ctx ctx = { bank->swnode, page };
        int ret;
 
        mutex_lock(&dev->lock);
index 23cddb265a0dc3b6d5b6ed9108496ab6449dc209..9db42f6a20439c01b228488e6015a69e330249ca 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
 
 #define VF610_GPIO_PER_PORT            32
 
index b6d3a57e27edc06b3ded115df1e676b7b5566975..7f8e2fed29884dca7330b9bc3961bbf8f0b40340 100644 (file)
@@ -99,7 +99,7 @@ static inline void xgpio_set_value32(unsigned long *map, int bit, u32 v)
        const unsigned long offset = (bit % BITS_PER_LONG) & BIT(5);
 
        map[index] &= ~(0xFFFFFFFFul << offset);
-       map[index] |= v << offset;
+       map[index] |= (unsigned long)v << offset;
 }
 
 static inline int xgpio_regoffset(struct xgpio_instance *chip, int ch)
index f5aa5f93342a4dc44f791267d8ad7f0619f53ff3..b26e643383762b189d3a7733be5ac4f319bec4c6 100644 (file)
@@ -421,6 +421,10 @@ out_free_lh:
  * @work: the worker that implements software debouncing
  * @sw_debounced: flag indicating if the software debouncer is active
  * @level: the current debounced physical level of the line
+ * @hdesc: the Hardware Timestamp Engine (HTE) descriptor
+ * @raw_level: the line level at the time of event
+ * @total_discard_seq: the running counter of the discarded events
+ * @last_seqno: the last sequence number before debounce period expires
  */
 struct line {
        struct gpio_desc *desc;
@@ -1460,11 +1464,12 @@ static ssize_t linereq_read(struct file *file,
 static void linereq_free(struct linereq *lr)
 {
        unsigned int i;
-       bool hte;
+       bool hte = false;
 
        for (i = 0; i < lr->num_lines; i++) {
-               hte = !!test_bit(FLAG_EVENT_CLOCK_HTE,
-                                &lr->lines[i].desc->flags);
+               if (lr->lines[i].desc)
+                       hte = !!test_bit(FLAG_EVENT_CLOCK_HTE,
+                                        &lr->lines[i].desc->flags);
                edge_detector_stop(&lr->lines[i], hte);
                if (lr->lines[i].desc)
                        gpiod_free(lr->lines[i].desc);
index e88c497fa0106104673bd556a68b29baa6039ef3..f65656df361994f1a6245bdc7509f3894fe59d1f 100644 (file)
@@ -256,7 +256,6 @@ config DRM_AMDGPU
        select HWMON
        select BACKLIGHT_CLASS_DEVICE
        select INTERVAL_TREE
-       select DRM_BUDDY
        help
          Choose this option if you have a recent AMD Radeon graphics card.
 
index 6b6d46e29e6e8bd21dd5a3ee3789a7858c4757ce..4608599ba6bb54d6a3d64c93007ee6b9f53f1e1f 100644 (file)
@@ -1364,16 +1364,10 @@ void amdgpu_amdkfd_gpuvm_destroy_cb(struct amdgpu_device *adev,
                                    struct amdgpu_vm *vm)
 {
        struct amdkfd_process_info *process_info = vm->process_info;
-       struct amdgpu_bo *pd = vm->root.bo;
 
        if (!process_info)
                return;
 
-       /* Release eviction fence from PD */
-       amdgpu_bo_reserve(pd, false);
-       amdgpu_bo_fence(pd, NULL, false);
-       amdgpu_bo_unreserve(pd);
-
        /* Update process info */
        mutex_lock(&process_info->lock);
        process_info->n_vms--;
index 714178f1b6c6edb83464fbd2fcfbfc5d16ec3eab..2168163aad2d386014040bc666e528aaeee89ab1 100644 (file)
@@ -40,7 +40,7 @@ static void amdgpu_bo_list_free_rcu(struct rcu_head *rcu)
 {
        struct amdgpu_bo_list *list = container_of(rcu, struct amdgpu_bo_list,
                                                   rhead);
-
+       mutex_destroy(&list->bo_list_mutex);
        kvfree(list);
 }
 
@@ -136,6 +136,7 @@ int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp,
 
        trace_amdgpu_cs_bo_status(list->num_entries, total_size);
 
+       mutex_init(&list->bo_list_mutex);
        *result = list;
        return 0;
 
index 529d52a204cf4a5bc8a92d261b02d92ae2982630..9caea1688fc322db41d4a05538f043265cac9cf6 100644 (file)
@@ -47,6 +47,10 @@ struct amdgpu_bo_list {
        struct amdgpu_bo *oa_obj;
        unsigned first_userptr;
        unsigned num_entries;
+
+       /* Protect access during command submission.
+        */
+       struct mutex bo_list_mutex;
 };
 
 int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id,
index b28af04b0c3e93be60aacd802d6b24843c29fa4a..d8f1335bc68f416154b6ee3aae6f5a4028f08cbf 100644 (file)
@@ -519,6 +519,8 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
                        return r;
        }
 
+       mutex_lock(&p->bo_list->bo_list_mutex);
+
        /* One for TTM and one for the CS job */
        amdgpu_bo_list_for_each_entry(e, p->bo_list)
                e->tv.num_shared = 2;
@@ -651,6 +653,7 @@ out_free_user_pages:
                        kvfree(e->user_pages);
                        e->user_pages = NULL;
                }
+               mutex_unlock(&p->bo_list->bo_list_mutex);
        }
        return r;
 }
@@ -690,9 +693,11 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error,
 {
        unsigned i;
 
-       if (error && backoff)
+       if (error && backoff) {
                ttm_eu_backoff_reservation(&parser->ticket,
                                           &parser->validated);
+               mutex_unlock(&parser->bo_list->bo_list_mutex);
+       }
 
        for (i = 0; i < parser->num_post_deps; i++) {
                drm_syncobj_put(parser->post_deps[i].syncobj);
@@ -832,12 +837,16 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
                        continue;
 
                r = amdgpu_vm_bo_update(adev, bo_va, false);
-               if (r)
+               if (r) {
+                       mutex_unlock(&p->bo_list->bo_list_mutex);
                        return r;
+               }
 
                r = amdgpu_sync_fence(&p->job->sync, bo_va->last_pt_update);
-               if (r)
+               if (r) {
+                       mutex_unlock(&p->bo_list->bo_list_mutex);
                        return r;
+               }
        }
 
        r = amdgpu_vm_handle_moved(adev, vm);
@@ -1278,6 +1287,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
 
        ttm_eu_fence_buffer_objects(&p->ticket, &p->validated, p->fence);
        mutex_unlock(&p->adev->notifier_lock);
+       mutex_unlock(&p->bo_list->bo_list_mutex);
 
        return 0;
 
index 17c9bbe0cbc59fadbc64d303e5872f7766230397..4dfd6724b3caa82cb62199ca482dcf509108d476 100644 (file)
@@ -1528,6 +1528,21 @@ bool amdgpu_crtc_get_scanout_position(struct drm_crtc *crtc,
                                                  stime, etime, mode);
 }
 
+static bool
+amdgpu_display_robj_is_fb(struct amdgpu_device *adev, struct amdgpu_bo *robj)
+{
+       struct drm_device *dev = adev_to_drm(adev);
+       struct drm_fb_helper *fb_helper = dev->fb_helper;
+
+       if (!fb_helper || !fb_helper->buffer)
+               return false;
+
+       if (gem_to_amdgpu_bo(fb_helper->buffer->gem) != robj)
+               return false;
+
+       return true;
+}
+
 int amdgpu_display_suspend_helper(struct amdgpu_device *adev)
 {
        struct drm_device *dev = adev_to_drm(adev);
@@ -1563,10 +1578,12 @@ int amdgpu_display_suspend_helper(struct amdgpu_device *adev)
                        continue;
                }
                robj = gem_to_amdgpu_bo(fb->obj[0]);
-               r = amdgpu_bo_reserve(robj, true);
-               if (r == 0) {
-                       amdgpu_bo_unpin(robj);
-                       amdgpu_bo_unreserve(robj);
+               if (!amdgpu_display_robj_is_fb(adev, robj)) {
+                       r = amdgpu_bo_reserve(robj, true);
+                       if (r == 0) {
+                               amdgpu_bo_unpin(robj);
+                               amdgpu_bo_unreserve(robj);
+                       }
                }
        }
        return 0;
index 6546552e596ce4ace56d57712ba7d47528ea1d90..acfa207cf970462d9a23de925669fd4a00756567 100644 (file)
 #include <drm/ttm/ttm_resource.h>
 #include <drm/ttm/ttm_range_manager.h>
 
-#include "amdgpu_vram_mgr.h"
-
 /* state back for walking over vram_mgr and gtt_mgr allocations */
 struct amdgpu_res_cursor {
        uint64_t                start;
        uint64_t                size;
        uint64_t                remaining;
-       void                    *node;
-       uint32_t                mem_type;
+       struct drm_mm_node      *node;
 };
 
 /**
@@ -55,63 +52,27 @@ static inline void amdgpu_res_first(struct ttm_resource *res,
                                    uint64_t start, uint64_t size,
                                    struct amdgpu_res_cursor *cur)
 {
-       struct drm_buddy_block *block;
-       struct list_head *head, *next;
        struct drm_mm_node *node;
 
-       if (!res)
-               goto fallback;
-
-       BUG_ON(start + size > res->num_pages << PAGE_SHIFT);
-
-       cur->mem_type = res->mem_type;
-
-       switch (cur->mem_type) {
-       case TTM_PL_VRAM:
-               head = &to_amdgpu_vram_mgr_resource(res)->blocks;
-
-               block = list_first_entry_or_null(head,
-                                                struct drm_buddy_block,
-                                                link);
-               if (!block)
-                       goto fallback;
-
-               while (start >= amdgpu_vram_mgr_block_size(block)) {
-                       start -= amdgpu_vram_mgr_block_size(block);
-
-                       next = block->link.next;
-                       if (next != head)
-                               block = list_entry(next, struct drm_buddy_block, link);
-               }
-
-               cur->start = amdgpu_vram_mgr_block_start(block) + start;
-               cur->size = min(amdgpu_vram_mgr_block_size(block) - start, size);
-               cur->remaining = size;
-               cur->node = block;
-               break;
-       case TTM_PL_TT:
-               node = to_ttm_range_mgr_node(res)->mm_nodes;
-               while (start >= node->size << PAGE_SHIFT)
-                       start -= node++->size << PAGE_SHIFT;
-
-               cur->start = (node->start << PAGE_SHIFT) + start;
-               cur->size = min((node->size << PAGE_SHIFT) - start, size);
+       if (!res || res->mem_type == TTM_PL_SYSTEM) {
+               cur->start = start;
+               cur->size = size;
                cur->remaining = size;
-               cur->node = node;
-               break;
-       default:
-               goto fallback;
+               cur->node = NULL;
+               WARN_ON(res && start + size > res->num_pages << PAGE_SHIFT);
+               return;
        }
 
-       return;
+       BUG_ON(start + size > res->num_pages << PAGE_SHIFT);
 
-fallback:
-       cur->start = start;
-       cur->size = size;
+       node = to_ttm_range_mgr_node(res)->mm_nodes;
+       while (start >= node->size << PAGE_SHIFT)
+               start -= node++->size << PAGE_SHIFT;
+
+       cur->start = (node->start << PAGE_SHIFT) + start;
+       cur->size = min((node->size << PAGE_SHIFT) - start, size);
        cur->remaining = size;
-       cur->node = NULL;
-       WARN_ON(res && start + size > res->num_pages << PAGE_SHIFT);
-       return;
+       cur->node = node;
 }
 
 /**
@@ -124,9 +85,7 @@ fallback:
  */
 static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size)
 {
-       struct drm_buddy_block *block;
-       struct drm_mm_node *node;
-       struct list_head *next;
+       struct drm_mm_node *node = cur->node;
 
        BUG_ON(size > cur->remaining);
 
@@ -140,27 +99,9 @@ static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size)
                return;
        }
 
-       switch (cur->mem_type) {
-       case TTM_PL_VRAM:
-               block = cur->node;
-
-               next = block->link.next;
-               block = list_entry(next, struct drm_buddy_block, link);
-
-               cur->node = block;
-               cur->start = amdgpu_vram_mgr_block_start(block);
-               cur->size = min(amdgpu_vram_mgr_block_size(block), cur->remaining);
-               break;
-       case TTM_PL_TT:
-               node = cur->node;
-
-               cur->node = ++node;
-               cur->start = node->start << PAGE_SHIFT;
-               cur->size = min(node->size << PAGE_SHIFT, cur->remaining);
-               break;
-       default:
-               return;
-       }
+       cur->node = ++node;
+       cur->start = node->start << PAGE_SHIFT;
+       cur->size = min(node->size << PAGE_SHIFT, cur->remaining);
 }
 
 #endif
index 6a70818039dda61380d5fbaeb4dcc386de26b906..9120ae80ef5238cb755e19d0ad320d602e28bab7 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <linux/dma-direction.h>
 #include <drm/gpu_scheduler.h>
-#include "amdgpu_vram_mgr.h"
 #include "amdgpu.h"
 
 #define AMDGPU_PL_GDS          (TTM_PL_PRIV + 0)
 
 #define AMDGPU_POISON  0xd0bed0be
 
+struct amdgpu_vram_mgr {
+       struct ttm_resource_manager manager;
+       struct drm_mm mm;
+       spinlock_t lock;
+       struct list_head reservations_pending;
+       struct list_head reserved_pages;
+       atomic64_t vis_usage;
+};
+
 struct amdgpu_gtt_mgr {
        struct ttm_resource_manager manager;
        struct drm_mm mm;
index 576849e9529642a033d6ab768c1560dbb02aaf6c..108e8e8a1a367e670eeab174d968cad612fbf8fe 100644 (file)
@@ -496,7 +496,8 @@ static int amdgpu_vkms_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_height = YRES_MAX;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
 
        adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base;
 
index 49e4092f447f3da955f3f6c8fda818a1a5a93a40..0a76116485738e25bac8c8876100e0a91a71be21 100644 (file)
 #include "atom.h"
 
 struct amdgpu_vram_reservation {
-       u64 start;
-       u64 size;
-       struct list_head allocated;
-       struct list_head blocks;
+       struct list_head node;
+       struct drm_mm_node mm_node;
 };
 
 static inline struct amdgpu_vram_mgr *
@@ -188,18 +186,18 @@ const struct attribute_group amdgpu_vram_mgr_attr_group = {
 };
 
 /**
- * amdgpu_vram_mgr_vis_size - Calculate visible block size
+ * amdgpu_vram_mgr_vis_size - Calculate visible node size
  *
  * @adev: amdgpu_device pointer
- * @block: DRM BUDDY block structure
+ * @node: MM node structure
  *
- * Calculate how many bytes of the DRM BUDDY block are inside visible VRAM
+ * Calculate how many bytes of the MM node are inside visible VRAM
  */
 static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev,
-                                   struct drm_buddy_block *block)
+                                   struct drm_mm_node *node)
 {
-       u64 start = amdgpu_vram_mgr_block_start(block);
-       u64 end = start + amdgpu_vram_mgr_block_size(block);
+       uint64_t start = node->start << PAGE_SHIFT;
+       uint64_t end = (node->size + node->start) << PAGE_SHIFT;
 
        if (start >= adev->gmc.visible_vram_size)
                return 0;
@@ -220,9 +218,9 @@ u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
 {
        struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
        struct ttm_resource *res = bo->tbo.resource;
-       struct amdgpu_vram_mgr_resource *vres = to_amdgpu_vram_mgr_resource(res);
-       struct drm_buddy_block *block;
-       u64 usage = 0;
+       unsigned pages = res->num_pages;
+       struct drm_mm_node *mm;
+       u64 usage;
 
        if (amdgpu_gmc_vram_full_visible(&adev->gmc))
                return amdgpu_bo_size(bo);
@@ -230,8 +228,9 @@ u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
        if (res->start >= adev->gmc.visible_vram_size >> PAGE_SHIFT)
                return 0;
 
-       list_for_each_entry(block, &vres->blocks, link)
-               usage += amdgpu_vram_mgr_vis_size(adev, block);
+       mm = &container_of(res, struct ttm_range_mgr_node, base)->mm_nodes[0];
+       for (usage = 0; pages; pages -= mm->size, mm++)
+               usage += amdgpu_vram_mgr_vis_size(adev, mm);
 
        return usage;
 }
@@ -241,30 +240,23 @@ static void amdgpu_vram_mgr_do_reserve(struct ttm_resource_manager *man)
 {
        struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
        struct amdgpu_device *adev = to_amdgpu_device(mgr);
-       struct drm_buddy *mm = &mgr->mm;
+       struct drm_mm *mm = &mgr->mm;
        struct amdgpu_vram_reservation *rsv, *temp;
-       struct drm_buddy_block *block;
        uint64_t vis_usage;
 
-       list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, blocks) {
-               if (drm_buddy_alloc_blocks(mm, rsv->start, rsv->start + rsv->size,
-                                          rsv->size, mm->chunk_size, &rsv->allocated,
-                                          DRM_BUDDY_RANGE_ALLOCATION))
-                       continue;
-
-               block = amdgpu_vram_mgr_first_block(&rsv->allocated);
-               if (!block)
+       list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, node) {
+               if (drm_mm_reserve_node(mm, &rsv->mm_node))
                        continue;
 
                dev_dbg(adev->dev, "Reservation 0x%llx - %lld, Succeeded\n",
-                       rsv->start, rsv->size);
+                       rsv->mm_node.start, rsv->mm_node.size);
 
-               vis_usage = amdgpu_vram_mgr_vis_size(adev, block);
+               vis_usage = amdgpu_vram_mgr_vis_size(adev, &rsv->mm_node);
                atomic64_add(vis_usage, &mgr->vis_usage);
                spin_lock(&man->bdev->lru_lock);
-               man->usage += rsv->size;
+               man->usage += rsv->mm_node.size << PAGE_SHIFT;
                spin_unlock(&man->bdev->lru_lock);
-               list_move(&rsv->blocks, &mgr->reserved_pages);
+               list_move(&rsv->node, &mgr->reserved_pages);
        }
 }
 
@@ -286,16 +278,14 @@ int amdgpu_vram_mgr_reserve_range(struct amdgpu_vram_mgr *mgr,
        if (!rsv)
                return -ENOMEM;
 
-       INIT_LIST_HEAD(&rsv->allocated);
-       INIT_LIST_HEAD(&rsv->blocks);
+       INIT_LIST_HEAD(&rsv->node);
+       rsv->mm_node.start = start >> PAGE_SHIFT;
+       rsv->mm_node.size = size >> PAGE_SHIFT;
 
-       rsv->start = start;
-       rsv->size = size;
-
-       mutex_lock(&mgr->lock);
-       list_add_tail(&rsv->blocks, &mgr->reservations_pending);
+       spin_lock(&mgr->lock);
+       list_add_tail(&rsv->node, &mgr->reservations_pending);
        amdgpu_vram_mgr_do_reserve(&mgr->manager);
-       mutex_unlock(&mgr->lock);
+       spin_unlock(&mgr->lock);
 
        return 0;
 }
@@ -317,19 +307,19 @@ int amdgpu_vram_mgr_query_page_status(struct amdgpu_vram_mgr *mgr,
        struct amdgpu_vram_reservation *rsv;
        int ret;
 
-       mutex_lock(&mgr->lock);
+       spin_lock(&mgr->lock);
 
-       list_for_each_entry(rsv, &mgr->reservations_pending, blocks) {
-               if (rsv->start <= start &&
-                   (start < (rsv->start + rsv->size))) {
+       list_for_each_entry(rsv, &mgr->reservations_pending, node) {
+               if ((rsv->mm_node.start <= start) &&
+                   (start < (rsv->mm_node.start + rsv->mm_node.size))) {
                        ret = -EBUSY;
                        goto out;
                }
        }
 
-       list_for_each_entry(rsv, &mgr->reserved_pages, blocks) {
-               if (rsv->start <= start &&
-                   (start < (rsv->start + rsv->size))) {
+       list_for_each_entry(rsv, &mgr->reserved_pages, node) {
+               if ((rsv->mm_node.start <= start) &&
+                   (start < (rsv->mm_node.start + rsv->mm_node.size))) {
                        ret = 0;
                        goto out;
                }
@@ -337,10 +327,32 @@ int amdgpu_vram_mgr_query_page_status(struct amdgpu_vram_mgr *mgr,
 
        ret = -ENOENT;
 out:
-       mutex_unlock(&mgr->lock);
+       spin_unlock(&mgr->lock);
        return ret;
 }
 
+/**
+ * amdgpu_vram_mgr_virt_start - update virtual start address
+ *
+ * @mem: ttm_resource to update
+ * @node: just allocated node
+ *
+ * Calculate a virtual BO start address to easily check if everything is CPU
+ * accessible.
+ */
+static void amdgpu_vram_mgr_virt_start(struct ttm_resource *mem,
+                                      struct drm_mm_node *node)
+{
+       unsigned long start;
+
+       start = node->start + node->size;
+       if (start > mem->num_pages)
+               start -= mem->num_pages;
+       else
+               start = 0;
+       mem->start = max(mem->start, start);
+}
+
 /**
  * amdgpu_vram_mgr_new - allocate new ranges
  *
@@ -356,44 +368,46 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
                               const struct ttm_place *place,
                               struct ttm_resource **res)
 {
-       u64 vis_usage = 0, max_bytes, cur_size, min_block_size;
+       unsigned long lpfn, num_nodes, pages_per_node, pages_left, pages;
        struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
        struct amdgpu_device *adev = to_amdgpu_device(mgr);
-       struct amdgpu_vram_mgr_resource *vres;
-       u64 size, remaining_size, lpfn, fpfn;
-       struct drm_buddy *mm = &mgr->mm;
-       struct drm_buddy_block *block;
-       unsigned long pages_per_block;
+       uint64_t vis_usage = 0, mem_bytes, max_bytes;
+       struct ttm_range_mgr_node *node;
+       struct drm_mm *mm = &mgr->mm;
+       enum drm_mm_insert_mode mode;
+       unsigned i;
        int r;
 
-       lpfn = place->lpfn << PAGE_SHIFT;
+       lpfn = place->lpfn;
        if (!lpfn)
-               lpfn = man->size;
-
-       fpfn = place->fpfn << PAGE_SHIFT;
+               lpfn = man->size >> PAGE_SHIFT;
 
        max_bytes = adev->gmc.mc_vram_size;
        if (tbo->type != ttm_bo_type_kernel)
                max_bytes -= AMDGPU_VM_RESERVED_VRAM;
 
+       mem_bytes = tbo->base.size;
        if (place->flags & TTM_PL_FLAG_CONTIGUOUS) {
-               pages_per_block = ~0ul;
+               pages_per_node = ~0ul;
+               num_nodes = 1;
        } else {
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-               pages_per_block = HPAGE_PMD_NR;
+               pages_per_node = HPAGE_PMD_NR;
 #else
                /* default to 2MB */
-               pages_per_block = 2UL << (20UL - PAGE_SHIFT);
+               pages_per_node = 2UL << (20UL - PAGE_SHIFT);
 #endif
-               pages_per_block = max_t(uint32_t, pages_per_block,
-                                       tbo->page_alignment);
+               pages_per_node = max_t(uint32_t, pages_per_node,
+                                      tbo->page_alignment);
+               num_nodes = DIV_ROUND_UP_ULL(PFN_UP(mem_bytes), pages_per_node);
        }
 
-       vres = kzalloc(sizeof(*vres), GFP_KERNEL);
-       if (!vres)
+       node = kvmalloc(struct_size(node, mm_nodes, num_nodes),
+                       GFP_KERNEL | __GFP_ZERO);
+       if (!node)
                return -ENOMEM;
 
-       ttm_resource_init(tbo, place, &vres->base);
+       ttm_resource_init(tbo, place, &node->base);
 
        /* bail out quickly if there's likely not enough VRAM for this BO */
        if (ttm_resource_manager_usage(man) > max_bytes) {
@@ -401,130 +415,66 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
                goto error_fini;
        }
 
-       INIT_LIST_HEAD(&vres->blocks);
-
+       mode = DRM_MM_INSERT_BEST;
        if (place->flags & TTM_PL_FLAG_TOPDOWN)
-               vres->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION;
-
-       if (fpfn || lpfn != man->size)
-               /* Allocate blocks in desired range */
-               vres->flags |= DRM_BUDDY_RANGE_ALLOCATION;
-
-       remaining_size = vres->base.num_pages << PAGE_SHIFT;
-
-       mutex_lock(&mgr->lock);
-       while (remaining_size) {
-               if (tbo->page_alignment)
-                       min_block_size = tbo->page_alignment << PAGE_SHIFT;
-               else
-                       min_block_size = mgr->default_page_size;
-
-               BUG_ON(min_block_size < mm->chunk_size);
-
-               /* Limit maximum size to 2GiB due to SG table limitations */
-               size = min(remaining_size, 2ULL << 30);
-
-               if (size >= pages_per_block << PAGE_SHIFT)
-                       min_block_size = pages_per_block << PAGE_SHIFT;
-
-               cur_size = size;
-
-               if (fpfn + size != place->lpfn << PAGE_SHIFT) {
-                       /*
-                        * Except for actual range allocation, modify the size and
-                        * min_block_size conforming to continuous flag enablement
-                        */
-                       if (place->flags & TTM_PL_FLAG_CONTIGUOUS) {
-                               size = roundup_pow_of_two(size);
-                               min_block_size = size;
-                       /*
-                        * Modify the size value if size is not
-                        * aligned with min_block_size
-                        */
-                       } else if (!IS_ALIGNED(size, min_block_size)) {
-                               size = round_up(size, min_block_size);
+               mode = DRM_MM_INSERT_HIGH;
+
+       pages_left = node->base.num_pages;
+
+       /* Limit maximum size to 2GB due to SG table limitations */
+       pages = min(pages_left, 2UL << (30 - PAGE_SHIFT));
+
+       i = 0;
+       spin_lock(&mgr->lock);
+       while (pages_left) {
+               uint32_t alignment = tbo->page_alignment;
+
+               if (pages >= pages_per_node)
+                       alignment = pages_per_node;
+
+               r = drm_mm_insert_node_in_range(mm, &node->mm_nodes[i], pages,
+                                               alignment, 0, place->fpfn,
+                                               lpfn, mode);
+               if (unlikely(r)) {
+                       if (pages > pages_per_node) {
+                               if (is_power_of_2(pages))
+                                       pages = pages / 2;
+                               else
+                                       pages = rounddown_pow_of_two(pages);
+                               continue;
                        }
+                       goto error_free;
                }
 
-               r = drm_buddy_alloc_blocks(mm, fpfn,
-                                          lpfn,
-                                          size,
-                                          min_block_size,
-                                          &vres->blocks,
-                                          vres->flags);
-               if (unlikely(r))
-                       goto error_free_blocks;
-
-               if (size > remaining_size)
-                       remaining_size = 0;
-               else
-                       remaining_size -= size;
-       }
-       mutex_unlock(&mgr->lock);
-
-       if (cur_size != size) {
-               struct drm_buddy_block *block;
-               struct list_head *trim_list;
-               u64 original_size;
-               LIST_HEAD(temp);
-
-               trim_list = &vres->blocks;
-               original_size = vres->base.num_pages << PAGE_SHIFT;
-
-               /*
-                * If size value is rounded up to min_block_size, trim the last
-                * block to the required size
-                */
-               if (!list_is_singular(&vres->blocks)) {
-                       block = list_last_entry(&vres->blocks, typeof(*block), link);
-                       list_move_tail(&block->link, &temp);
-                       trim_list = &temp;
-                       /*
-                        * Compute the original_size value by subtracting the
-                        * last block size with (aligned size - original size)
-                        */
-                       original_size = amdgpu_vram_mgr_block_size(block) - (size - cur_size);
-               }
+               vis_usage += amdgpu_vram_mgr_vis_size(adev, &node->mm_nodes[i]);
+               amdgpu_vram_mgr_virt_start(&node->base, &node->mm_nodes[i]);
+               pages_left -= pages;
+               ++i;
 
-               mutex_lock(&mgr->lock);
-               drm_buddy_block_trim(mm,
-                                    original_size,
-                                    trim_list);
-               mutex_unlock(&mgr->lock);
-
-               if (!list_empty(&temp))
-                       list_splice_tail(trim_list, &vres->blocks);
-       }
-
-       list_for_each_entry(block, &vres->blocks, link)
-               vis_usage += amdgpu_vram_mgr_vis_size(adev, block);
-
-       block = amdgpu_vram_mgr_first_block(&vres->blocks);
-       if (!block) {
-               r = -EINVAL;
-               goto error_fini;
+               if (pages > pages_left)
+                       pages = pages_left;
        }
+       spin_unlock(&mgr->lock);
 
-       vres->base.start = amdgpu_vram_mgr_block_start(block) >> PAGE_SHIFT;
-
-       if (amdgpu_is_vram_mgr_blocks_contiguous(&vres->blocks))
-               vres->base.placement |= TTM_PL_FLAG_CONTIGUOUS;
+       if (i == 1)
+               node->base.placement |= TTM_PL_FLAG_CONTIGUOUS;
 
        if (adev->gmc.xgmi.connected_to_cpu)
-               vres->base.bus.caching = ttm_cached;
+               node->base.bus.caching = ttm_cached;
        else
-               vres->base.bus.caching = ttm_write_combined;
+               node->base.bus.caching = ttm_write_combined;
 
        atomic64_add(vis_usage, &mgr->vis_usage);
-       *res = &vres->base;
+       *res = &node->base;
        return 0;
 
-error_free_blocks:
-       drm_buddy_free_list(mm, &vres->blocks);
-       mutex_unlock(&mgr->lock);
+error_free:
+       while (i--)
+               drm_mm_remove_node(&node->mm_nodes[i]);
+       spin_unlock(&mgr->lock);
 error_fini:
-       ttm_resource_fini(man, &vres->base);
-       kfree(vres);
+       ttm_resource_fini(man, &node->base);
+       kvfree(node);
 
        return r;
 }
@@ -540,26 +490,27 @@ error_fini:
 static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man,
                                struct ttm_resource *res)
 {
-       struct amdgpu_vram_mgr_resource *vres = to_amdgpu_vram_mgr_resource(res);
+       struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
        struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
        struct amdgpu_device *adev = to_amdgpu_device(mgr);
-       struct drm_buddy *mm = &mgr->mm;
-       struct drm_buddy_block *block;
        uint64_t vis_usage = 0;
+       unsigned i, pages;
 
-       mutex_lock(&mgr->lock);
-       list_for_each_entry(block, &vres->blocks, link)
-               vis_usage += amdgpu_vram_mgr_vis_size(adev, block);
+       spin_lock(&mgr->lock);
+       for (i = 0, pages = res->num_pages; pages;
+            pages -= node->mm_nodes[i].size, ++i) {
+               struct drm_mm_node *mm = &node->mm_nodes[i];
 
+               drm_mm_remove_node(mm);
+               vis_usage += amdgpu_vram_mgr_vis_size(adev, mm);
+       }
        amdgpu_vram_mgr_do_reserve(man);
-
-       drm_buddy_free_list(mm, &vres->blocks);
-       mutex_unlock(&mgr->lock);
+       spin_unlock(&mgr->lock);
 
        atomic64_sub(vis_usage, &mgr->vis_usage);
 
        ttm_resource_fini(man, res);
-       kfree(vres);
+       kvfree(node);
 }
 
 /**
@@ -591,7 +542,7 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
        if (!*sgt)
                return -ENOMEM;
 
-       /* Determine the number of DRM_BUDDY blocks to export */
+       /* Determine the number of DRM_MM nodes to export */
        amdgpu_res_first(res, offset, length, &cursor);
        while (cursor.remaining) {
                num_entries++;
@@ -607,10 +558,10 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
                sg->length = 0;
 
        /*
-        * Walk down DRM_BUDDY blocks to populate scatterlist nodes
-        * @note: Use iterator api to get first the DRM_BUDDY block
+        * Walk down DRM_MM nodes to populate scatterlist nodes
+        * @note: Use iterator api to get first the DRM_MM node
         * and the number of bytes from it. Access the following
-        * DRM_BUDDY block(s) if more buffer needs to exported
+        * DRM_MM node(s) if more buffer needs to exported
         */
        amdgpu_res_first(res, offset, length, &cursor);
        for_each_sgtable_sg((*sgt), sg, i) {
@@ -697,22 +648,13 @@ static void amdgpu_vram_mgr_debug(struct ttm_resource_manager *man,
                                  struct drm_printer *printer)
 {
        struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
-       struct drm_buddy *mm = &mgr->mm;
-       struct drm_buddy_block *block;
 
        drm_printf(printer, "  vis usage:%llu\n",
                   amdgpu_vram_mgr_vis_usage(mgr));
 
-       mutex_lock(&mgr->lock);
-       drm_printf(printer, "default_page_size: %lluKiB\n",
-                  mgr->default_page_size >> 10);
-
-       drm_buddy_print(mm, printer);
-
-       drm_printf(printer, "reserved:\n");
-       list_for_each_entry(block, &mgr->reserved_pages, link)
-               drm_buddy_block_print(mm, block, printer);
-       mutex_unlock(&mgr->lock);
+       spin_lock(&mgr->lock);
+       drm_mm_print(&mgr->mm, printer);
+       spin_unlock(&mgr->lock);
 }
 
 static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = {
@@ -732,21 +674,16 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
 {
        struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
        struct ttm_resource_manager *man = &mgr->manager;
-       int err;
 
        ttm_resource_manager_init(man, &adev->mman.bdev,
                                  adev->gmc.real_vram_size);
 
        man->func = &amdgpu_vram_mgr_func;
 
-       err = drm_buddy_init(&mgr->mm, man->size, PAGE_SIZE);
-       if (err)
-               return err;
-
-       mutex_init(&mgr->lock);
+       drm_mm_init(&mgr->mm, 0, man->size >> PAGE_SHIFT);
+       spin_lock_init(&mgr->lock);
        INIT_LIST_HEAD(&mgr->reservations_pending);
        INIT_LIST_HEAD(&mgr->reserved_pages);
-       mgr->default_page_size = PAGE_SIZE;
 
        ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager);
        ttm_resource_manager_set_used(man, true);
@@ -774,16 +711,16 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev)
        if (ret)
                return;
 
-       mutex_lock(&mgr->lock);
-       list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, blocks)
+       spin_lock(&mgr->lock);
+       list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, node)
                kfree(rsv);
 
-       list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, blocks) {
-               drm_buddy_free_list(&mgr->mm, &rsv->blocks);
+       list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, node) {
+               drm_mm_remove_node(&rsv->mm_node);
                kfree(rsv);
        }
-       drm_buddy_fini(&mgr->mm);
-       mutex_unlock(&mgr->lock);
+       drm_mm_takedown(&mgr->mm);
+       spin_unlock(&mgr->lock);
 
        ttm_resource_manager_cleanup(man);
        ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, NULL);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h
deleted file mode 100644 (file)
index 9a2db87..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/* SPDX-License-Identifier: MIT
- * Copyright 2021 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#ifndef __AMDGPU_VRAM_MGR_H__
-#define __AMDGPU_VRAM_MGR_H__
-
-#include <drm/drm_buddy.h>
-
-struct amdgpu_vram_mgr {
-       struct ttm_resource_manager manager;
-       struct drm_buddy mm;
-       /* protects access to buffer objects */
-       struct mutex lock;
-       struct list_head reservations_pending;
-       struct list_head reserved_pages;
-       atomic64_t vis_usage;
-       u64 default_page_size;
-};
-
-struct amdgpu_vram_mgr_resource {
-       struct ttm_resource base;
-       struct list_head blocks;
-       unsigned long flags;
-};
-
-static inline u64 amdgpu_vram_mgr_block_start(struct drm_buddy_block *block)
-{
-       return drm_buddy_block_offset(block);
-}
-
-static inline u64 amdgpu_vram_mgr_block_size(struct drm_buddy_block *block)
-{
-       return PAGE_SIZE << drm_buddy_block_order(block);
-}
-
-static inline struct drm_buddy_block *
-amdgpu_vram_mgr_first_block(struct list_head *list)
-{
-       return list_first_entry_or_null(list, struct drm_buddy_block, link);
-}
-
-static inline bool amdgpu_is_vram_mgr_blocks_contiguous(struct list_head *head)
-{
-       struct drm_buddy_block *block;
-       u64 start, size;
-
-       block = amdgpu_vram_mgr_first_block(head);
-       if (!block)
-               return false;
-
-       while (head != block->link.next) {
-               start = amdgpu_vram_mgr_block_start(block);
-               size = amdgpu_vram_mgr_block_size(block);
-
-               block = list_entry(block->link.next, struct drm_buddy_block, link);
-               if (start + size != amdgpu_vram_mgr_block_start(block))
-                       return false;
-       }
-
-       return true;
-}
-
-static inline struct amdgpu_vram_mgr_resource *
-to_amdgpu_vram_mgr_resource(struct ttm_resource *res)
-{
-       return container_of(res, struct amdgpu_vram_mgr_resource, base);
-}
-
-#endif
index 288fce7dc0ed178305b443d93fe72906e603bbf6..9c964cd3b5d4e24fec07595e172bc6e8bf1aaa59 100644 (file)
@@ -2796,7 +2796,8 @@ static int dce_v10_0_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_height = 16384;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
 
        adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
 
index cbe5250b31cb4e33ac7460a323690df56f955f70..e0ad9f27dc3f943dbe02d7bbbd491e241e202cad 100644 (file)
@@ -2914,7 +2914,8 @@ static int dce_v11_0_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_height = 16384;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
 
        adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
 
index 982855e6cf52e95f1abb59568301ff276e3779ff..3caf6f386042f9053683a72ae1e0799b1cf8a4c9 100644 (file)
@@ -2673,7 +2673,8 @@ static int dce_v6_0_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_width = 16384;
        adev_to_drm(adev)->mode_config.max_height = 16384;
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
        adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
        adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base;
 
index 84440741c60bcc542b569d9039c28f26ed2a116a..7c75df5bffed3be847778999162d014cfde8b3f7 100644 (file)
@@ -2693,7 +2693,8 @@ static int dce_v8_0_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_height = 16384;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
 
        adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
 
index bf420045777221ecf0e6769e18c24b4418ea5bdb..a08769c5e94b0acc825e49584487af624a19d062 100644 (file)
@@ -184,6 +184,8 @@ static void kfd_device_info_init(struct kfd_dev *kfd,
                        /* Navi2x+, Navi1x+ */
                        if (gc_version == IP_VERSION(10, 3, 6))
                                kfd->device_info.no_atomic_fw_version = 14;
+                       else if (gc_version == IP_VERSION(10, 3, 7))
+                               kfd->device_info.no_atomic_fw_version = 3;
                        else if (gc_version >= IP_VERSION(10, 3, 0))
                                kfd->device_info.no_atomic_fw_version = 92;
                        else if (gc_version >= IP_VERSION(10, 1, 1))
index b4029c0d5d8c5e9abbf98d285d3a5a17d3e7eabb..0ba0598eba20662d149157e41a607fd6016ce7be 100644 (file)
@@ -6,7 +6,7 @@ config DRM_AMD_DC
        bool "AMD DC - Enable new display engine"
        default y
        select SND_HDA_COMPONENT if SND_HDA_CORE
-       select DRM_AMD_DC_DCN if (X86 || PPC64) && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS)
+       select DRM_AMD_DC_DCN if X86 && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS)
        help
          Choose this option if you want to use the new display engine
          support for AMDGPU. This adds required support for Vega and
index 9dd2e0601ea8ce0d050d6bf87fa7131c5e9aa20c..3087dd1a1856cd00fb9c35577ae491395414e346 100644 (file)
@@ -72,6 +72,7 @@
 #include <linux/pci.h>
 #include <linux/firmware.h>
 #include <linux/component.h>
+#include <linux/dmi.h>
 
 #include <drm/display/drm_dp_mst_helper.h>
 #include <drm/display/drm_hdmi_helper.h>
@@ -462,6 +463,26 @@ static void dm_pflip_high_irq(void *interrupt_params)
                     vrr_active, (int) !e);
 }
 
+static void dm_crtc_handle_vblank(struct amdgpu_crtc *acrtc)
+{
+       struct drm_crtc *crtc = &acrtc->base;
+       struct drm_device *dev = crtc->dev;
+       unsigned long flags;
+
+       drm_crtc_handle_vblank(crtc);
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+
+       /* Send completion event for cursor-only commits */
+       if (acrtc->event && acrtc->pflip_status != AMDGPU_FLIP_SUBMITTED) {
+               drm_crtc_send_vblank_event(crtc, acrtc->event);
+               drm_crtc_vblank_put(crtc);
+               acrtc->event = NULL;
+       }
+
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
 static void dm_vupdate_high_irq(void *interrupt_params)
 {
        struct common_irq_params *irq_params = interrupt_params;
@@ -500,7 +521,7 @@ static void dm_vupdate_high_irq(void *interrupt_params)
                 * if a pageflip happened inside front-porch.
                 */
                if (vrr_active) {
-                       drm_crtc_handle_vblank(&acrtc->base);
+                       dm_crtc_handle_vblank(acrtc);
 
                        /* BTR processing for pre-DCE12 ASICs */
                        if (acrtc->dm_irq_params.stream &&
@@ -552,7 +573,7 @@ static void dm_crtc_high_irq(void *interrupt_params)
         * to dm_vupdate_high_irq after end of front-porch.
         */
        if (!vrr_active)
-               drm_crtc_handle_vblank(&acrtc->base);
+               dm_crtc_handle_vblank(acrtc);
 
        /**
         * Following stuff must happen at start of vblank, for crc
@@ -1382,6 +1403,41 @@ static bool dm_should_disable_stutter(struct pci_dev *pdev)
        return false;
 }
 
+static const struct dmi_system_id hpd_disconnect_quirk_table[] = {
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3660"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3260"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3460"),
+               },
+       },
+       {}
+};
+
+static void retrieve_dmi_info(struct amdgpu_display_manager *dm)
+{
+       const struct dmi_system_id *dmi_id;
+
+       dm->aux_hpd_discon_quirk = false;
+
+       dmi_id = dmi_first_match(hpd_disconnect_quirk_table);
+       if (dmi_id) {
+               dm->aux_hpd_discon_quirk = true;
+               DRM_INFO("aux_hpd_discon_quirk attached\n");
+       }
+}
+
 static int amdgpu_dm_init(struct amdgpu_device *adev)
 {
        struct dc_init_data init_data;
@@ -1508,6 +1564,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
        }
 
        INIT_LIST_HEAD(&adev->dm.da_list);
+
+       retrieve_dmi_info(&adev->dm);
+
        /* Display Core create. */
        adev->dm.dc = dc_create(&init_data);
 
@@ -1594,7 +1653,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
 #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
        adev->dm.crc_rd_wrk = amdgpu_dm_crtc_secure_display_create_work();
 #endif
-       if (dc_enable_dmub_notifications(adev->dm.dc)) {
+       if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
                init_completion(&adev->dm.dmub_aux_transfer_done);
                adev->dm.dmub_notify = kzalloc(sizeof(struct dmub_notification), GFP_KERNEL);
                if (!adev->dm.dmub_notify) {
@@ -1630,6 +1689,13 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
                goto error;
        }
 
+       /* Enable outbox notification only after IRQ handlers are registered and DMUB is alive.
+        * It is expected that DMUB will resend any pending notifications at this point, for
+        * example HPD from DPIA.
+        */
+       if (dc_is_dmub_outbox_supported(adev->dm.dc))
+               dc_enable_dmub_outbox(adev->dm.dc);
+
        /* create fake encoders for MST */
        dm_dp_create_fake_mst_encoders(adev);
 
@@ -2619,9 +2685,6 @@ static int dm_resume(void *handle)
                 */
                link_enc_cfg_copy(adev->dm.dc->current_state, dc_state);
 
-               if (dc_enable_dmub_notifications(adev->dm.dc))
-                       amdgpu_dm_outbox_init(adev);
-
                r = dm_dmub_hw_init(adev);
                if (r)
                        DRM_ERROR("DMUB interface failed to initialize: status=%d\n", r);
@@ -2639,6 +2702,11 @@ static int dm_resume(void *handle)
                        }
                }
 
+               if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
+                       amdgpu_dm_outbox_init(adev);
+                       dc_enable_dmub_outbox(adev->dm.dc);
+               }
+
                WARN_ON(!dc_commit_state(dm->dc, dc_state));
 
                dm_gpureset_commit_state(dm->cached_dc_state, dm);
@@ -2660,13 +2728,15 @@ static int dm_resume(void *handle)
        /* TODO: Remove dc_state->dccg, use dc->dccg directly. */
        dc_resource_state_construct(dm->dc, dm_state->context);
 
-       /* Re-enable outbox interrupts for DPIA. */
-       if (dc_enable_dmub_notifications(adev->dm.dc))
-               amdgpu_dm_outbox_init(adev);
-
        /* Before powering on DC we need to re-initialize DMUB. */
        dm_dmub_hw_resume(adev);
 
+       /* Re-enable outbox interrupts for DPIA. */
+       if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
+               amdgpu_dm_outbox_init(adev);
+               dc_enable_dmub_outbox(adev->dm.dc);
+       }
+
        /* power on hardware */
        dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0);
 
@@ -3822,7 +3892,8 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
        adev_to_drm(adev)->mode_config.max_height = 16384;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
        /* indicates support for immediate flip */
        adev_to_drm(adev)->mode_config.async_page_flip = true;
 
@@ -5406,7 +5477,7 @@ fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
                        }
                }
 
-               if (per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE)
+               if (*per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE)
                        *pre_multiplied_alpha = false;
        }
 
@@ -9134,6 +9205,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
        struct amdgpu_bo *abo;
        uint32_t target_vblank, last_flip_vblank;
        bool vrr_active = amdgpu_dm_vrr_active(acrtc_state);
+       bool cursor_update = false;
        bool pflip_present = false;
        struct {
                struct dc_surface_update surface_updates[MAX_SURFACES];
@@ -9169,8 +9241,13 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                struct dm_plane_state *dm_new_plane_state = to_dm_plane_state(new_plane_state);
 
                /* Cursor plane is handled after stream updates */
-               if (plane->type == DRM_PLANE_TYPE_CURSOR)
+               if (plane->type == DRM_PLANE_TYPE_CURSOR) {
+                       if ((fb && crtc == pcrtc) ||
+                           (old_plane_state->fb && old_plane_state->crtc == pcrtc))
+                               cursor_update = true;
+
                        continue;
+               }
 
                if (!fb || !crtc || pcrtc != crtc)
                        continue;
@@ -9333,6 +9410,17 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                                bundle->stream_update.vrr_infopacket =
                                        &acrtc_state->stream->vrr_infopacket;
                }
+       } else if (cursor_update && acrtc_state->active_planes > 0 &&
+                  !acrtc_state->force_dpms_off &&
+                  acrtc_attach->base.state->event) {
+               drm_crtc_vblank_get(pcrtc);
+
+               spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
+
+               acrtc_attach->event = acrtc_attach->base.state->event;
+               acrtc_attach->base.state->event = NULL;
+
+               spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
        }
 
        /* Update the planes if changed or disable if we don't have any. */
index aa34c0068f4108915401e9b11daef39f9132d80a..e80ef93f6550f9d12e07d566c62578222e7c84cf 100644 (file)
@@ -540,6 +540,14 @@ struct amdgpu_display_manager {
         * last successfully applied backlight values.
         */
        u32 actual_brightness[AMDGPU_DM_MAX_NUM_EDP];
+
+       /**
+        * @aux_hpd_discon_quirk:
+        *
+        * quirk for hpd discon while aux is on-going.
+        * occurred on certain intel platform
+        */
+       bool aux_hpd_discon_quirk;
 };
 
 enum dsc_clock_force_state {
index 9221b6690a4a920e3bf60a204e6a162a8f64cc56..2b9b095e5f03d0248f1dae6d4e5fc2ac17394511 100644 (file)
@@ -56,6 +56,8 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux,
        ssize_t result = 0;
        struct aux_payload payload;
        enum aux_return_code_type operation_result;
+       struct amdgpu_device *adev;
+       struct ddc_service *ddc;
 
        if (WARN_ON(msg->size > 16))
                return -E2BIG;
@@ -74,6 +76,21 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux,
        result = dc_link_aux_transfer_raw(TO_DM_AUX(aux)->ddc_service, &payload,
                                      &operation_result);
 
+       /*
+        * w/a on certain intel platform where hpd is unexpected to pull low during
+        * 1st sideband message transaction by return AUX_RET_ERROR_HPD_DISCON
+        * aux transaction is succuess in such case, therefore bypass the error
+        */
+       ddc = TO_DM_AUX(aux)->ddc_service;
+       adev = ddc->ctx->driver_context;
+       if (adev->dm.aux_hpd_discon_quirk) {
+               if (msg->address == DP_SIDEBAND_MSG_DOWN_REQ_BASE &&
+                       operation_result == AUX_RET_ERROR_HPD_DISCON) {
+                       result = 0;
+                       operation_result = AUX_RET_SUCCESS;
+               }
+       }
+
        if (payload.write && result >= 0)
                result = msg->size;
 
index 6774dd8bb53e10c311019fe31e1762e2175c8d36..3fe3fbac1e6356981c81a94c698f3de0a76d98fe 100644 (file)
@@ -1117,12 +1117,13 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
         * on certain displays, such as the Sharp 4k. 36bpp is needed
         * to support SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 and
         * SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 with actual > 10 bpc
-        * precision on at least DCN display engines. However, at least
-        * Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth,
-        * so use only 30 bpp on DCE_VERSION_11_0. Testing with DCE 11.2 and 8.3
-        * did not show such problems, so this seems to be the exception.
+        * precision on DCN display engines, but apparently not for DCE, as
+        * far as testing on DCE-11.2 and DCE-8 showed. Various DCE parts have
+        * problems: Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth,
+        * neither do DCE-8 at 4k resolution, or DCE-11.2 (broken identify pixel
+        * passthrough). Therefore only use 36 bpp on DCN where it is actually needed.
         */
-       if (plane_state->ctx->dce_version > DCE_VERSION_11_0)
+       if (plane_state->ctx->dce_version > DCE_VERSION_MAX)
                pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP;
        else
                pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
index 5f8809f6990dd12a323fbedc3f810848f5ea9bb9..2fbd2926a5310b59059fc5347d63182bf7395c0b 100644 (file)
@@ -1228,6 +1228,8 @@ int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu,
        uint32_t crystal_clock_freq = 2500;
        uint32_t tach_period;
 
+       if (speed == 0)
+               return -EINVAL;
        /*
         * To prevent from possible overheat, some ASICs may have requirement
         * for minimum fan speed:
index b2675c769a5505dfd0258adaaee0453e1055c841..4b503c54425637c8b0ac21903834ba3015207e16 100644 (file)
@@ -74,22 +74,6 @@ static int fsl_ldb_attach(struct drm_bridge *bridge,
                                 bridge, flags);
 }
 
-static int fsl_ldb_atomic_check(struct drm_bridge *bridge,
-                               struct drm_bridge_state *bridge_state,
-                               struct drm_crtc_state *crtc_state,
-                               struct drm_connector_state *conn_state)
-{
-       /* Invert DE signal polarity. */
-       bridge_state->input_bus_cfg.flags &= ~(DRM_BUS_FLAG_DE_LOW |
-                                              DRM_BUS_FLAG_DE_HIGH);
-       if (bridge_state->output_bus_cfg.flags & DRM_BUS_FLAG_DE_LOW)
-               bridge_state->input_bus_cfg.flags |= DRM_BUS_FLAG_DE_HIGH;
-       else if (bridge_state->output_bus_cfg.flags & DRM_BUS_FLAG_DE_HIGH)
-               bridge_state->input_bus_cfg.flags |= DRM_BUS_FLAG_DE_LOW;
-
-       return 0;
-}
-
 static void fsl_ldb_atomic_enable(struct drm_bridge *bridge,
                                  struct drm_bridge_state *old_bridge_state)
 {
@@ -153,7 +137,7 @@ static void fsl_ldb_atomic_enable(struct drm_bridge *bridge,
        reg = LDB_CTRL_CH0_ENABLE;
 
        if (fsl_ldb->lvds_dual_link)
-               reg |= LDB_CTRL_CH1_ENABLE;
+               reg |= LDB_CTRL_CH1_ENABLE | LDB_CTRL_SPLIT_MODE;
 
        if (lvds_format_24bpp) {
                reg |= LDB_CTRL_CH0_DATA_WIDTH;
@@ -233,7 +217,7 @@ fsl_ldb_mode_valid(struct drm_bridge *bridge,
 {
        struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
 
-       if (mode->clock > (fsl_ldb->lvds_dual_link ? 80000 : 160000))
+       if (mode->clock > (fsl_ldb->lvds_dual_link ? 160000 : 80000))
                return MODE_CLOCK_HIGH;
 
        return MODE_OK;
@@ -241,7 +225,6 @@ fsl_ldb_mode_valid(struct drm_bridge *bridge,
 
 static const struct drm_bridge_funcs funcs = {
        .attach = fsl_ldb_attach,
-       .atomic_check = fsl_ldb_atomic_check,
        .atomic_enable = fsl_ldb_atomic_enable,
        .atomic_disable = fsl_ldb_atomic_disable,
        .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
index 74bd4a76b253cf9c4b659e3cbc7d7e6f8a0fdfca..059fd71424f6b6081dd19f9b19ccf853f67f2aa5 100644 (file)
@@ -329,7 +329,20 @@ int drm_aperture_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
                                                     const struct drm_driver *req_driver)
 {
        resource_size_t base, size;
-       int bar, ret = 0;
+       int bar, ret;
+
+       /*
+        * WARNING: Apparently we must kick fbdev drivers before vgacon,
+        * otherwise the vga fbdev driver falls over.
+        */
+#if IS_REACHABLE(CONFIG_FB)
+       ret = remove_conflicting_pci_framebuffers(pdev, req_driver->name);
+       if (ret)
+               return ret;
+#endif
+       ret = vga_remove_vgacon(pdev);
+       if (ret)
+               return ret;
 
        for (bar = 0; bar < PCI_STD_NUM_BARS; ++bar) {
                if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
@@ -339,15 +352,6 @@ int drm_aperture_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
                drm_aperture_detach_drivers(base, size);
        }
 
-       /*
-        * WARNING: Apparently we must kick fbdev drivers before vgacon,
-        * otherwise the vga fbdev driver falls over.
-        */
-#if IS_REACHABLE(CONFIG_FB)
-       ret = remove_conflicting_pci_framebuffers(pdev, req_driver->name);
-#endif
-       if (ret == 0)
-               ret = vga_remove_vgacon(pdev);
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL(drm_aperture_remove_conflicting_pci_framebuffers);
index d5962a34c01d5ff1a82b9044aa2382c3ef07e6fc..e5fc875990c4f3308e0134f9dc0455e84d1f2ec0 100644 (file)
@@ -64,8 +64,13 @@ int drm_gem_ttm_vmap(struct drm_gem_object *gem,
                     struct iosys_map *map)
 {
        struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem);
+       int ret;
+
+       dma_resv_lock(gem->resv, NULL);
+       ret = ttm_bo_vmap(bo, map);
+       dma_resv_unlock(gem->resv);
 
-       return ttm_bo_vmap(bo, map);
+       return ret;
 }
 EXPORT_SYMBOL(drm_gem_ttm_vmap);
 
@@ -82,7 +87,9 @@ void drm_gem_ttm_vunmap(struct drm_gem_object *gem,
 {
        struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem);
 
+       dma_resv_lock(gem->resv, NULL);
        ttm_bo_vunmap(bo, map);
+       dma_resv_unlock(gem->resv);
 }
 EXPORT_SYMBOL(drm_gem_ttm_vunmap);
 
index df87ba99a87c053a59b58b013a7a343ffcd58573..d4e0f2e855488c21502f5e0ba7fb36d01e3436bb 100644 (file)
@@ -286,6 +286,21 @@ static const struct dmi_system_id orientation_data[] = {
                  DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9"),
                },
                .driver_data = (void *)&lcd1200x1920_rightside_up,
+       }, {    /* Lenovo Yoga Tablet 2 830F / 830L */
+               .matches = {
+                /*
+                 * Note this also matches the Lenovo Yoga Tablet 2 1050F/L
+                 * since that uses the same mainboard. The resolution match
+                 * will limit this to only matching on the 830F/L. Neither has
+                 * any external video outputs so those are not a concern.
+                 */
+                DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."),
+                DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM"),
+                DMI_MATCH(DMI_BOARD_NAME, "BYT-T FFD8"),
+                /* Partial match on beginning of BIOS version */
+                DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21"),
+               },
+               .driver_data = (void *)&lcd1200x1920_rightside_up,
        }, {    /* OneGX1 Pro */
                .matches = {
                  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SYSTEM_MANUFACTURER"),
index 061b277e5ce783c0c45b6ee9f1fcdcda911decf1..14d2a64193b2df9c975a6271f46deefedfd4b736 100644 (file)
@@ -839,6 +839,7 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo
        ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs,
                                 DRM_MODE_CONNECTOR_DisplayPort);
        if (ret) {
+               drm_dp_mst_put_port_malloc(port);
                intel_connector_free(intel_connector);
                return NULL;
        }
index f46ee16a323a98aa9191433b60a5df28c67416f5..a4fb577eceb412e3406ad9eb246f2b04f62c10a2 100644 (file)
@@ -60,6 +60,8 @@ __i915_gem_object_create_region(struct intel_memory_region *mem,
        if (page_size)
                default_page_size = page_size;
 
+       /* We should be able to fit a page within an sg entry */
+       GEM_BUG_ON(overflows_type(default_page_size, u32));
        GEM_BUG_ON(!is_power_of_2_u64(default_page_size));
        GEM_BUG_ON(default_page_size < PAGE_SIZE);
 
index 4c25d9b2f138e57a06d47df654d493f4b16356e9..8f1bb6a4b7d1fe71d63818c64e3e0a9fcaf94935 100644 (file)
@@ -620,10 +620,15 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
                         struct ttm_resource *res)
 {
        struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
+       u32 page_alignment;
 
        if (!i915_ttm_gtt_binds_lmem(res))
                return i915_ttm_tt_get_st(bo->ttm);
 
+       page_alignment = bo->page_alignment << PAGE_SHIFT;
+       if (!page_alignment)
+               page_alignment = obj->mm.region->min_page_size;
+
        /*
         * If CPU mapping differs, we need to add the ttm_tt pages to
         * the resulting st. Might make sense for GGTT.
@@ -634,7 +639,8 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
                        struct i915_refct_sgt *rsgt;
 
                        rsgt = intel_region_ttm_resource_to_rsgt(obj->mm.region,
-                                                                res);
+                                                                res,
+                                                                page_alignment);
                        if (IS_ERR(rsgt))
                                return rsgt;
 
@@ -643,7 +649,8 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
                return i915_refct_sgt_get(obj->ttm.cached_io_rsgt);
        }
 
-       return intel_region_ttm_resource_to_rsgt(obj->mm.region, res);
+       return intel_region_ttm_resource_to_rsgt(obj->mm.region, res,
+                                                page_alignment);
 }
 
 static int i915_ttm_truncate(struct drm_i915_gem_object *obj)
index 319936f91ac591ea42d7918a936477535b9a39b7..e6e01c2a74a65261958dfd0fcaecff4dee2ed6f2 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/jiffies.h>
 
 #include "gt/intel_engine.h"
+#include "gt/intel_rps.h"
 
 #include "i915_gem_ioctls.h"
 #include "i915_gem_object.h"
@@ -31,6 +32,37 @@ i915_gem_object_wait_fence(struct dma_fence *fence,
                                      timeout);
 }
 
+static void
+i915_gem_object_boost(struct dma_resv *resv, unsigned int flags)
+{
+       struct dma_resv_iter cursor;
+       struct dma_fence *fence;
+
+       /*
+        * Prescan all fences for potential boosting before we begin waiting.
+        *
+        * When we wait, we wait on outstanding fences serially. If the
+        * dma-resv contains a sequence such as 1:1, 1:2 instead of a reduced
+        * form 1:2, then as we look at each wait in turn we see that each
+        * request is currently executing and not worthy of boosting. But if
+        * we only happen to look at the final fence in the sequence (because
+        * of request coalescing or splitting between read/write arrays by
+        * the iterator), then we would boost. As such our decision to boost
+        * or not is delicately balanced on the order we wait on fences.
+        *
+        * So instead of looking for boosts sequentially, look for all boosts
+        * upfront and then wait on the outstanding fences.
+        */
+
+       dma_resv_iter_begin(&cursor, resv,
+                           dma_resv_usage_rw(flags & I915_WAIT_ALL));
+       dma_resv_for_each_fence_unlocked(&cursor, fence)
+               if (dma_fence_is_i915(fence) &&
+                   !i915_request_started(to_request(fence)))
+                       intel_rps_boost(to_request(fence));
+       dma_resv_iter_end(&cursor);
+}
+
 static long
 i915_gem_object_wait_reservation(struct dma_resv *resv,
                                 unsigned int flags,
@@ -40,6 +72,8 @@ i915_gem_object_wait_reservation(struct dma_resv *resv,
        struct dma_fence *fence;
        long ret = timeout ?: 1;
 
+       i915_gem_object_boost(resv, flags);
+
        dma_resv_iter_begin(&cursor, resv,
                            dma_resv_usage_rw(flags & I915_WAIT_ALL));
        dma_resv_for_each_fence_unlocked(&cursor, fence) {
index 09f82545789f194b305cbadd42305d82d66b22d4..44e7339e7a4aea6fd4d33e3119d147dbe6ae6bcc 100644 (file)
@@ -273,10 +273,17 @@ struct intel_context {
                u8 child_index;
                /** @guc: GuC specific members for parallel submission */
                struct {
-                       /** @wqi_head: head pointer in work queue */
+                       /** @wqi_head: cached head pointer in work queue */
                        u16 wqi_head;
-                       /** @wqi_tail: tail pointer in work queue */
+                       /** @wqi_tail: cached tail pointer in work queue */
                        u16 wqi_tail;
+                       /** @wq_head: pointer to the actual head in work queue */
+                       u32 *wq_head;
+                       /** @wq_tail: pointer to the actual head in work queue */
+                       u32 *wq_tail;
+                       /** @wq_status: pointer to the status in work queue */
+                       u32 *wq_status;
+
                        /**
                         * @parent_page: page in context state (ce->state) used
                         * by parent for work queue, process descriptor
index 86f7a9ac1c394b4a4a9d90bcb1e2c4fb1068119b..2b0266cab66b93a579a65b5f36a1268a4e44d1b7 100644 (file)
@@ -661,6 +661,16 @@ static inline void execlists_schedule_out(struct i915_request *rq)
        i915_request_put(rq);
 }
 
+static u32 map_i915_prio_to_lrc_desc_prio(int prio)
+{
+       if (prio > I915_PRIORITY_NORMAL)
+               return GEN12_CTX_PRIORITY_HIGH;
+       else if (prio < I915_PRIORITY_NORMAL)
+               return GEN12_CTX_PRIORITY_LOW;
+       else
+               return GEN12_CTX_PRIORITY_NORMAL;
+}
+
 static u64 execlists_update_context(struct i915_request *rq)
 {
        struct intel_context *ce = rq->context;
@@ -669,7 +679,7 @@ static u64 execlists_update_context(struct i915_request *rq)
 
        desc = ce->lrc.desc;
        if (rq->engine->flags & I915_ENGINE_HAS_EU_PRIORITY)
-               desc |= lrc_desc_priority(rq_prio(rq));
+               desc |= map_i915_prio_to_lrc_desc_prio(rq_prio(rq));
 
        /*
         * WaIdleLiteRestore:bdw,skl
index 51a0fe60c050d13e5ba74162b832483d7d224139..531af6ad700713c1644e0e0e13affc7d1d559788 100644 (file)
@@ -1209,6 +1209,20 @@ void intel_gt_invalidate_tlbs(struct intel_gt *gt)
        mutex_lock(&gt->tlb_invalidate_lock);
        intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
 
+       spin_lock_irq(&uncore->lock); /* serialise invalidate with GT reset */
+
+       for_each_engine(engine, gt, id) {
+               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);
+       }
+
+       spin_unlock_irq(&uncore->lock);
+
        for_each_engine(engine, gt, id) {
                /*
                 * HW architecture suggest typical invalidation time at 40us,
@@ -1223,7 +1237,6 @@ void intel_gt_invalidate_tlbs(struct intel_gt *gt)
                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,
index 31be734010db3bc5cd7234caff95a42268e035a3..a390f0813c8b64e5b0ee08a48a9ca7e875ad9e94 100644 (file)
@@ -111,16 +111,6 @@ enum {
 #define XEHP_SW_COUNTER_SHIFT                  58
 #define XEHP_SW_COUNTER_WIDTH                  6
 
-static inline u32 lrc_desc_priority(int prio)
-{
-       if (prio > I915_PRIORITY_NORMAL)
-               return GEN12_CTX_PRIORITY_HIGH;
-       else if (prio < I915_PRIORITY_NORMAL)
-               return GEN12_CTX_PRIORITY_LOW;
-       else
-               return GEN12_CTX_PRIORITY_NORMAL;
-}
-
 static inline void lrc_runtime_start(struct intel_context *ce)
 {
        struct intel_context_stats *stats = &ce->stats;
index a5338c3fde7a0e9ba58f65e5379da3319451a114..c68d36fb5bbdd997b7c2732f459a59249273e5f2 100644 (file)
@@ -300,9 +300,9 @@ static int gen6_hw_domain_reset(struct intel_gt *gt, u32 hw_domain_mask)
        return err;
 }
 
-static int gen6_reset_engines(struct intel_gt *gt,
-                             intel_engine_mask_t engine_mask,
-                             unsigned int retry)
+static int __gen6_reset_engines(struct intel_gt *gt,
+                               intel_engine_mask_t engine_mask,
+                               unsigned int retry)
 {
        struct intel_engine_cs *engine;
        u32 hw_mask;
@@ -321,6 +321,20 @@ static int gen6_reset_engines(struct intel_gt *gt,
        return gen6_hw_domain_reset(gt, hw_mask);
 }
 
+static int gen6_reset_engines(struct intel_gt *gt,
+                             intel_engine_mask_t engine_mask,
+                             unsigned int retry)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&gt->uncore->lock, flags);
+       ret = __gen6_reset_engines(gt, engine_mask, retry);
+       spin_unlock_irqrestore(&gt->uncore->lock, flags);
+
+       return ret;
+}
+
 static struct intel_engine_cs *find_sfc_paired_vecs_engine(struct intel_engine_cs *engine)
 {
        int vecs_id;
@@ -487,9 +501,9 @@ static void gen11_unlock_sfc(struct intel_engine_cs *engine)
        rmw_clear_fw(uncore, sfc_lock.lock_reg, sfc_lock.lock_bit);
 }
 
-static int gen11_reset_engines(struct intel_gt *gt,
-                              intel_engine_mask_t engine_mask,
-                              unsigned int retry)
+static int __gen11_reset_engines(struct intel_gt *gt,
+                                intel_engine_mask_t engine_mask,
+                                unsigned int retry)
 {
        struct intel_engine_cs *engine;
        intel_engine_mask_t tmp;
@@ -583,8 +597,11 @@ static int gen8_reset_engines(struct intel_gt *gt,
        struct intel_engine_cs *engine;
        const bool reset_non_ready = retry >= 1;
        intel_engine_mask_t tmp;
+       unsigned long flags;
        int ret;
 
+       spin_lock_irqsave(&gt->uncore->lock, flags);
+
        for_each_engine_masked(engine, gt, engine_mask, tmp) {
                ret = gen8_engine_reset_prepare(engine);
                if (ret && !reset_non_ready)
@@ -612,17 +629,19 @@ static int gen8_reset_engines(struct intel_gt *gt,
         * This is best effort, so ignore any error from the initial reset.
         */
        if (IS_DG2(gt->i915) && engine_mask == ALL_ENGINES)
-               gen11_reset_engines(gt, gt->info.engine_mask, 0);
+               __gen11_reset_engines(gt, gt->info.engine_mask, 0);
 
        if (GRAPHICS_VER(gt->i915) >= 11)
-               ret = gen11_reset_engines(gt, engine_mask, retry);
+               ret = __gen11_reset_engines(gt, engine_mask, retry);
        else
-               ret = gen6_reset_engines(gt, engine_mask, retry);
+               ret = __gen6_reset_engines(gt, engine_mask, retry);
 
 skip_reset:
        for_each_engine_masked(engine, gt, engine_mask, tmp)
                gen8_engine_reset_cancel(engine);
 
+       spin_unlock_irqrestore(&gt->uncore->lock, flags);
+
        return ret;
 }
 
index 8b2c11dbe354f604b99779acafc1ef9b1571ae5b..1109088fe8f632e2a533791af40d80bfe5374cac 100644 (file)
@@ -176,8 +176,8 @@ static int live_lrc_layout(void *arg)
                        continue;
 
                hw = shmem_pin_map(engine->default_state);
-               if (IS_ERR(hw)) {
-                       err = PTR_ERR(hw);
+               if (!hw) {
+                       err = -ENOMEM;
                        break;
                }
                hw += LRC_STATE_OFFSET / sizeof(*hw);
@@ -365,8 +365,8 @@ static int live_lrc_fixed(void *arg)
                        continue;
 
                hw = shmem_pin_map(engine->default_state);
-               if (IS_ERR(hw)) {
-                       err = PTR_ERR(hw);
+               if (!hw) {
+                       err = -ENOMEM;
                        break;
                }
                hw += LRC_STATE_OFFSET / sizeof(*hw);
index 4ef9990ed7f8be3040b3fc92d56cd3fb2f00bae4..29ef8afc8c2e45699f88fd064a40051c329e5ce2 100644 (file)
@@ -122,6 +122,9 @@ enum intel_guc_action {
        INTEL_GUC_ACTION_SCHED_CONTEXT_MODE_DONE = 0x1002,
        INTEL_GUC_ACTION_SCHED_ENGINE_MODE_SET = 0x1003,
        INTEL_GUC_ACTION_SCHED_ENGINE_MODE_DONE = 0x1004,
+       INTEL_GUC_ACTION_V69_SET_CONTEXT_PRIORITY = 0x1005,
+       INTEL_GUC_ACTION_V69_SET_CONTEXT_EXECUTION_QUANTUM = 0x1006,
+       INTEL_GUC_ACTION_V69_SET_CONTEXT_PREEMPTION_TIMEOUT = 0x1007,
        INTEL_GUC_ACTION_CONTEXT_RESET_NOTIFICATION = 0x1008,
        INTEL_GUC_ACTION_ENGINE_FAILURE_NOTIFICATION = 0x1009,
        INTEL_GUC_ACTION_HOST2GUC_UPDATE_CONTEXT_POLICIES = 0x100B,
index 966e69a8b1c124d3b9ab107b9f65f774589c2b10..9feda105f9131f7e6f1398111a1de7d17583c1ee 100644 (file)
@@ -170,6 +170,11 @@ struct intel_guc {
        /** @ads_engine_usage_size: size of engine usage in the ADS */
        u32 ads_engine_usage_size;
 
+       /** @lrc_desc_pool_v69: object allocated to hold the GuC LRC descriptor pool */
+       struct i915_vma *lrc_desc_pool_v69;
+       /** @lrc_desc_pool_vaddr_v69: contents of the GuC LRC descriptor pool */
+       void *lrc_desc_pool_vaddr_v69;
+
        /**
         * @context_lookup: used to resolve intel_context from guc_id, if a
         * context is present in this structure it is registered with the GuC
index 42cb7a9a6199c79f8350efd259bbeb0fd46b57c3..89a7e5ec0614eaf2f32cabb8ae76bdad1ea5e3ff 100644 (file)
@@ -203,6 +203,20 @@ struct guc_wq_item {
        u32 fence_id;
 } __packed;
 
+struct guc_process_desc_v69 {
+       u32 stage_id;
+       u64 db_base_addr;
+       u32 head;
+       u32 tail;
+       u32 error_offset;
+       u64 wq_base_addr;
+       u32 wq_size_bytes;
+       u32 wq_status;
+       u32 engine_presence;
+       u32 priority;
+       u32 reserved[36];
+} __packed;
+
 struct guc_sched_wq_desc {
        u32 head;
        u32 tail;
@@ -227,6 +241,37 @@ struct guc_ctxt_registration_info {
 };
 #define CONTEXT_REGISTRATION_FLAG_KMD  BIT(0)
 
+/* Preempt to idle on quantum expiry */
+#define CONTEXT_POLICY_FLAG_PREEMPT_TO_IDLE_V69        BIT(0)
+
+/*
+ * GuC Context registration descriptor.
+ * FIXME: This is only required to exist during context registration.
+ * The current 1:1 between guc_lrc_desc and LRCs for the lifetime of the LRC
+ * is not required.
+ */
+struct guc_lrc_desc_v69 {
+       u32 hw_context_desc;
+       u32 slpm_perf_mode_hint;        /* SPLC v1 only */
+       u32 slpm_freq_hint;
+       u32 engine_submit_mask;         /* In logical space */
+       u8 engine_class;
+       u8 reserved0[3];
+       u32 priority;
+       u32 process_desc;
+       u32 wq_addr;
+       u32 wq_size;
+       u32 context_flags;              /* CONTEXT_REGISTRATION_* */
+       /* Time for one workload to execute. (in micro seconds) */
+       u32 execution_quantum;
+       /* Time to wait for a preemption request to complete before issuing a
+        * reset. (in micro seconds).
+        */
+       u32 preemption_timeout;
+       u32 policy_flags;               /* CONTEXT_POLICY_* */
+       u32 reserved1[19];
+} __packed;
+
 /* 32-bit KLV structure as used by policy updates and others */
 struct guc_klv_generic_dw_t {
        u32 kl;
index 1726f0f19901097551de288ec80bdf37a4744a52..9ffb343d0f7973cea811fec8564c0014170a66d5 100644 (file)
@@ -414,12 +414,15 @@ struct sync_semaphore {
 };
 
 struct parent_scratch {
-       struct guc_sched_wq_desc wq_desc;
+       union guc_descs {
+               struct guc_sched_wq_desc wq_desc;
+               struct guc_process_desc_v69 pdesc;
+       } descs;
 
        struct sync_semaphore go;
        struct sync_semaphore join[MAX_ENGINE_INSTANCE + 1];
 
-       u8 unused[WQ_OFFSET - sizeof(struct guc_sched_wq_desc) -
+       u8 unused[WQ_OFFSET - sizeof(union guc_descs) -
                sizeof(struct sync_semaphore) * (MAX_ENGINE_INSTANCE + 2)];
 
        u32 wq[WQ_SIZE / sizeof(u32)];
@@ -456,17 +459,23 @@ __get_parent_scratch(struct intel_context *ce)
                   LRC_STATE_OFFSET) / sizeof(u32)));
 }
 
+static struct guc_process_desc_v69 *
+__get_process_desc_v69(struct intel_context *ce)
+{
+       struct parent_scratch *ps = __get_parent_scratch(ce);
+
+       return &ps->descs.pdesc;
+}
+
 static struct guc_sched_wq_desc *
-__get_wq_desc(struct intel_context *ce)
+__get_wq_desc_v70(struct intel_context *ce)
 {
        struct parent_scratch *ps = __get_parent_scratch(ce);
 
-       return &ps->wq_desc;
+       return &ps->descs.wq_desc;
 }
 
-static u32 *get_wq_pointer(struct guc_sched_wq_desc *wq_desc,
-                          struct intel_context *ce,
-                          u32 wqi_size)
+static u32 *get_wq_pointer(struct intel_context *ce, u32 wqi_size)
 {
        /*
         * Check for space in work queue. Caching a value of head pointer in
@@ -476,7 +485,7 @@ static u32 *get_wq_pointer(struct guc_sched_wq_desc *wq_desc,
 #define AVAILABLE_SPACE        \
        CIRC_SPACE(ce->parallel.guc.wqi_tail, ce->parallel.guc.wqi_head, WQ_SIZE)
        if (wqi_size > AVAILABLE_SPACE) {
-               ce->parallel.guc.wqi_head = READ_ONCE(wq_desc->head);
+               ce->parallel.guc.wqi_head = READ_ONCE(*ce->parallel.guc.wq_head);
 
                if (wqi_size > AVAILABLE_SPACE)
                        return NULL;
@@ -495,11 +504,55 @@ static inline struct intel_context *__get_context(struct intel_guc *guc, u32 id)
        return ce;
 }
 
+static struct guc_lrc_desc_v69 *__get_lrc_desc_v69(struct intel_guc *guc, u32 index)
+{
+       struct guc_lrc_desc_v69 *base = guc->lrc_desc_pool_vaddr_v69;
+
+       if (!base)
+               return NULL;
+
+       GEM_BUG_ON(index >= GUC_MAX_CONTEXT_ID);
+
+       return &base[index];
+}
+
+static int guc_lrc_desc_pool_create_v69(struct intel_guc *guc)
+{
+       u32 size;
+       int ret;
+
+       size = PAGE_ALIGN(sizeof(struct guc_lrc_desc_v69) *
+                         GUC_MAX_CONTEXT_ID);
+       ret = intel_guc_allocate_and_map_vma(guc, size, &guc->lrc_desc_pool_v69,
+                                            (void **)&guc->lrc_desc_pool_vaddr_v69);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static void guc_lrc_desc_pool_destroy_v69(struct intel_guc *guc)
+{
+       if (!guc->lrc_desc_pool_vaddr_v69)
+               return;
+
+       guc->lrc_desc_pool_vaddr_v69 = NULL;
+       i915_vma_unpin_and_release(&guc->lrc_desc_pool_v69, I915_VMA_RELEASE_MAP);
+}
+
 static inline bool guc_submission_initialized(struct intel_guc *guc)
 {
        return guc->submission_initialized;
 }
 
+static inline void _reset_lrc_desc_v69(struct intel_guc *guc, u32 id)
+{
+       struct guc_lrc_desc_v69 *desc = __get_lrc_desc_v69(guc, id);
+
+       if (desc)
+               memset(desc, 0, sizeof(*desc));
+}
+
 static inline bool ctx_id_mapped(struct intel_guc *guc, u32 id)
 {
        return __get_context(guc, id);
@@ -526,6 +579,8 @@ static inline void clr_ctx_id_mapping(struct intel_guc *guc, u32 id)
        if (unlikely(!guc_submission_initialized(guc)))
                return;
 
+       _reset_lrc_desc_v69(guc, id);
+
        /*
         * xarray API doesn't have xa_erase_irqsave wrapper, so calling
         * the lower level functions directly.
@@ -611,7 +666,7 @@ int intel_guc_wait_for_idle(struct intel_guc *guc, long timeout)
                                              true, timeout);
 }
 
-static int guc_context_policy_init(struct intel_context *ce, bool loop);
+static int guc_context_policy_init_v70(struct intel_context *ce, bool loop);
 static int try_context_registration(struct intel_context *ce, bool loop);
 
 static int __guc_add_request(struct intel_guc *guc, struct i915_request *rq)
@@ -639,7 +694,7 @@ static int __guc_add_request(struct intel_guc *guc, struct i915_request *rq)
        GEM_BUG_ON(context_guc_id_invalid(ce));
 
        if (context_policy_required(ce)) {
-               err = guc_context_policy_init(ce, false);
+               err = guc_context_policy_init_v70(ce, false);
                if (err)
                        return err;
        }
@@ -737,9 +792,7 @@ static u32 wq_space_until_wrap(struct intel_context *ce)
        return (WQ_SIZE - ce->parallel.guc.wqi_tail);
 }
 
-static void write_wqi(struct guc_sched_wq_desc *wq_desc,
-                     struct intel_context *ce,
-                     u32 wqi_size)
+static void write_wqi(struct intel_context *ce, u32 wqi_size)
 {
        BUILD_BUG_ON(!is_power_of_2(WQ_SIZE));
 
@@ -750,13 +803,12 @@ static void write_wqi(struct guc_sched_wq_desc *wq_desc,
 
        ce->parallel.guc.wqi_tail = (ce->parallel.guc.wqi_tail + wqi_size) &
                (WQ_SIZE - 1);
-       WRITE_ONCE(wq_desc->tail, ce->parallel.guc.wqi_tail);
+       WRITE_ONCE(*ce->parallel.guc.wq_tail, ce->parallel.guc.wqi_tail);
 }
 
 static int guc_wq_noop_append(struct intel_context *ce)
 {
-       struct guc_sched_wq_desc *wq_desc = __get_wq_desc(ce);
-       u32 *wqi = get_wq_pointer(wq_desc, ce, wq_space_until_wrap(ce));
+       u32 *wqi = get_wq_pointer(ce, wq_space_until_wrap(ce));
        u32 len_dw = wq_space_until_wrap(ce) / sizeof(u32) - 1;
 
        if (!wqi)
@@ -775,7 +827,6 @@ static int __guc_wq_item_append(struct i915_request *rq)
 {
        struct intel_context *ce = request_to_scheduling_context(rq);
        struct intel_context *child;
-       struct guc_sched_wq_desc *wq_desc = __get_wq_desc(ce);
        unsigned int wqi_size = (ce->parallel.number_children + 4) *
                sizeof(u32);
        u32 *wqi;
@@ -795,7 +846,7 @@ static int __guc_wq_item_append(struct i915_request *rq)
                        return ret;
        }
 
-       wqi = get_wq_pointer(wq_desc, ce, wqi_size);
+       wqi = get_wq_pointer(ce, wqi_size);
        if (!wqi)
                return -EBUSY;
 
@@ -810,7 +861,7 @@ static int __guc_wq_item_append(struct i915_request *rq)
        for_each_child(ce, child)
                *wqi++ = child->ring->tail / sizeof(u64);
 
-       write_wqi(wq_desc, ce, wqi_size);
+       write_wqi(ce, wqi_size);
 
        return 0;
 }
@@ -1868,20 +1919,34 @@ static void reset_fail_worker_func(struct work_struct *w);
 int intel_guc_submission_init(struct intel_guc *guc)
 {
        struct intel_gt *gt = guc_to_gt(guc);
+       int ret;
 
        if (guc->submission_initialized)
                return 0;
 
+       if (guc->fw.major_ver_found < 70) {
+               ret = guc_lrc_desc_pool_create_v69(guc);
+               if (ret)
+                       return ret;
+       }
+
        guc->submission_state.guc_ids_bitmap =
                bitmap_zalloc(NUMBER_MULTI_LRC_GUC_ID(guc), GFP_KERNEL);
-       if (!guc->submission_state.guc_ids_bitmap)
-               return -ENOMEM;
+       if (!guc->submission_state.guc_ids_bitmap) {
+               ret = -ENOMEM;
+               goto destroy_pool;
+       }
 
        guc->timestamp.ping_delay = (POLL_TIME_CLKS / gt->clock_frequency + 1) * HZ;
        guc->timestamp.shift = gpm_timestamp_shift(gt);
        guc->submission_initialized = true;
 
        return 0;
+
+destroy_pool:
+       guc_lrc_desc_pool_destroy_v69(guc);
+
+       return ret;
 }
 
 void intel_guc_submission_fini(struct intel_guc *guc)
@@ -1890,6 +1955,7 @@ void intel_guc_submission_fini(struct intel_guc *guc)
                return;
 
        guc_flush_destroyed_contexts(guc);
+       guc_lrc_desc_pool_destroy_v69(guc);
        i915_sched_engine_put(guc->sched_engine);
        bitmap_free(guc->submission_state.guc_ids_bitmap);
        guc->submission_initialized = false;
@@ -2147,10 +2213,34 @@ static void unpin_guc_id(struct intel_guc *guc, struct intel_context *ce)
        spin_unlock_irqrestore(&guc->submission_state.lock, flags);
 }
 
-static int __guc_action_register_multi_lrc(struct intel_guc *guc,
-                                          struct intel_context *ce,
-                                          struct guc_ctxt_registration_info *info,
-                                          bool loop)
+static int __guc_action_register_multi_lrc_v69(struct intel_guc *guc,
+                                              struct intel_context *ce,
+                                              u32 guc_id,
+                                              u32 offset,
+                                              bool loop)
+{
+       struct intel_context *child;
+       u32 action[4 + MAX_ENGINE_INSTANCE];
+       int len = 0;
+
+       GEM_BUG_ON(ce->parallel.number_children > MAX_ENGINE_INSTANCE);
+
+       action[len++] = INTEL_GUC_ACTION_REGISTER_CONTEXT_MULTI_LRC;
+       action[len++] = guc_id;
+       action[len++] = ce->parallel.number_children + 1;
+       action[len++] = offset;
+       for_each_child(ce, child) {
+               offset += sizeof(struct guc_lrc_desc_v69);
+               action[len++] = offset;
+       }
+
+       return guc_submission_send_busy_loop(guc, action, len, 0, loop);
+}
+
+static int __guc_action_register_multi_lrc_v70(struct intel_guc *guc,
+                                              struct intel_context *ce,
+                                              struct guc_ctxt_registration_info *info,
+                                              bool loop)
 {
        struct intel_context *child;
        u32 action[13 + (MAX_ENGINE_INSTANCE * 2)];
@@ -2190,9 +2280,24 @@ static int __guc_action_register_multi_lrc(struct intel_guc *guc,
        return guc_submission_send_busy_loop(guc, action, len, 0, loop);
 }
 
-static int __guc_action_register_context(struct intel_guc *guc,
-                                        struct guc_ctxt_registration_info *info,
-                                        bool loop)
+static int __guc_action_register_context_v69(struct intel_guc *guc,
+                                            u32 guc_id,
+                                            u32 offset,
+                                            bool loop)
+{
+       u32 action[] = {
+               INTEL_GUC_ACTION_REGISTER_CONTEXT,
+               guc_id,
+               offset,
+       };
+
+       return guc_submission_send_busy_loop(guc, action, ARRAY_SIZE(action),
+                                            0, loop);
+}
+
+static int __guc_action_register_context_v70(struct intel_guc *guc,
+                                            struct guc_ctxt_registration_info *info,
+                                            bool loop)
 {
        u32 action[] = {
                INTEL_GUC_ACTION_REGISTER_CONTEXT,
@@ -2213,24 +2318,52 @@ static int __guc_action_register_context(struct intel_guc *guc,
                                             0, loop);
 }
 
-static void prepare_context_registration_info(struct intel_context *ce,
-                                             struct guc_ctxt_registration_info *info);
+static void prepare_context_registration_info_v69(struct intel_context *ce);
+static void prepare_context_registration_info_v70(struct intel_context *ce,
+                                                 struct guc_ctxt_registration_info *info);
 
-static int register_context(struct intel_context *ce, bool loop)
+static int
+register_context_v69(struct intel_guc *guc, struct intel_context *ce, bool loop)
+{
+       u32 offset = intel_guc_ggtt_offset(guc, guc->lrc_desc_pool_v69) +
+               ce->guc_id.id * sizeof(struct guc_lrc_desc_v69);
+
+       prepare_context_registration_info_v69(ce);
+
+       if (intel_context_is_parent(ce))
+               return __guc_action_register_multi_lrc_v69(guc, ce, ce->guc_id.id,
+                                                          offset, loop);
+       else
+               return __guc_action_register_context_v69(guc, ce->guc_id.id,
+                                                        offset, loop);
+}
+
+static int
+register_context_v70(struct intel_guc *guc, struct intel_context *ce, bool loop)
 {
        struct guc_ctxt_registration_info info;
+
+       prepare_context_registration_info_v70(ce, &info);
+
+       if (intel_context_is_parent(ce))
+               return __guc_action_register_multi_lrc_v70(guc, ce, &info, loop);
+       else
+               return __guc_action_register_context_v70(guc, &info, loop);
+}
+
+static int register_context(struct intel_context *ce, bool loop)
+{
        struct intel_guc *guc = ce_to_guc(ce);
        int ret;
 
        GEM_BUG_ON(intel_context_is_child(ce));
        trace_intel_context_register(ce);
 
-       prepare_context_registration_info(ce, &info);
-
-       if (intel_context_is_parent(ce))
-               ret = __guc_action_register_multi_lrc(guc, ce, &info, loop);
+       if (guc->fw.major_ver_found >= 70)
+               ret = register_context_v70(guc, ce, loop);
        else
-               ret = __guc_action_register_context(guc, &info, loop);
+               ret = register_context_v69(guc, ce, loop);
+
        if (likely(!ret)) {
                unsigned long flags;
 
@@ -2238,7 +2371,8 @@ static int register_context(struct intel_context *ce, bool loop)
                set_context_registered(ce);
                spin_unlock_irqrestore(&ce->guc_state.lock, flags);
 
-               guc_context_policy_init(ce, loop);
+               if (guc->fw.major_ver_found >= 70)
+                       guc_context_policy_init_v70(ce, loop);
        }
 
        return ret;
@@ -2335,7 +2469,7 @@ static int __guc_context_set_context_policies(struct intel_guc *guc,
                                        0, loop);
 }
 
-static int guc_context_policy_init(struct intel_context *ce, bool loop)
+static int guc_context_policy_init_v70(struct intel_context *ce, bool loop)
 {
        struct intel_engine_cs *engine = ce->engine;
        struct intel_guc *guc = &engine->gt->uc.guc;
@@ -2394,8 +2528,108 @@ static int guc_context_policy_init(struct intel_context *ce, bool loop)
        return ret;
 }
 
-static void prepare_context_registration_info(struct intel_context *ce,
-                                             struct guc_ctxt_registration_info *info)
+static void guc_context_policy_init_v69(struct intel_engine_cs *engine,
+                                       struct guc_lrc_desc_v69 *desc)
+{
+       desc->policy_flags = 0;
+
+       if (engine->flags & I915_ENGINE_WANT_FORCED_PREEMPTION)
+               desc->policy_flags |= CONTEXT_POLICY_FLAG_PREEMPT_TO_IDLE_V69;
+
+       /* NB: For both of these, zero means disabled. */
+       desc->execution_quantum = engine->props.timeslice_duration_ms * 1000;
+       desc->preemption_timeout = engine->props.preempt_timeout_ms * 1000;
+}
+
+static u32 map_guc_prio_to_lrc_desc_prio(u8 prio)
+{
+       /*
+        * this matches the mapping we do in map_i915_prio_to_guc_prio()
+        * (e.g. prio < I915_PRIORITY_NORMAL maps to GUC_CLIENT_PRIORITY_NORMAL)
+        */
+       switch (prio) {
+       default:
+               MISSING_CASE(prio);
+               fallthrough;
+       case GUC_CLIENT_PRIORITY_KMD_NORMAL:
+               return GEN12_CTX_PRIORITY_NORMAL;
+       case GUC_CLIENT_PRIORITY_NORMAL:
+               return GEN12_CTX_PRIORITY_LOW;
+       case GUC_CLIENT_PRIORITY_HIGH:
+       case GUC_CLIENT_PRIORITY_KMD_HIGH:
+               return GEN12_CTX_PRIORITY_HIGH;
+       }
+}
+
+static void prepare_context_registration_info_v69(struct intel_context *ce)
+{
+       struct intel_engine_cs *engine = ce->engine;
+       struct intel_guc *guc = &engine->gt->uc.guc;
+       u32 ctx_id = ce->guc_id.id;
+       struct guc_lrc_desc_v69 *desc;
+       struct intel_context *child;
+
+       GEM_BUG_ON(!engine->mask);
+
+       /*
+        * Ensure LRC + CT vmas are is same region as write barrier is done
+        * based on CT vma region.
+        */
+       GEM_BUG_ON(i915_gem_object_is_lmem(guc->ct.vma->obj) !=
+                  i915_gem_object_is_lmem(ce->ring->vma->obj));
+
+       desc = __get_lrc_desc_v69(guc, ctx_id);
+       desc->engine_class = engine_class_to_guc_class(engine->class);
+       desc->engine_submit_mask = engine->logical_mask;
+       desc->hw_context_desc = ce->lrc.lrca;
+       desc->priority = ce->guc_state.prio;
+       desc->context_flags = CONTEXT_REGISTRATION_FLAG_KMD;
+       guc_context_policy_init_v69(engine, desc);
+
+       /*
+        * If context is a parent, we need to register a process descriptor
+        * describing a work queue and register all child contexts.
+        */
+       if (intel_context_is_parent(ce)) {
+               struct guc_process_desc_v69 *pdesc;
+
+               ce->parallel.guc.wqi_tail = 0;
+               ce->parallel.guc.wqi_head = 0;
+
+               desc->process_desc = i915_ggtt_offset(ce->state) +
+                       __get_parent_scratch_offset(ce);
+               desc->wq_addr = i915_ggtt_offset(ce->state) +
+                       __get_wq_offset(ce);
+               desc->wq_size = WQ_SIZE;
+
+               pdesc = __get_process_desc_v69(ce);
+               memset(pdesc, 0, sizeof(*(pdesc)));
+               pdesc->stage_id = ce->guc_id.id;
+               pdesc->wq_base_addr = desc->wq_addr;
+               pdesc->wq_size_bytes = desc->wq_size;
+               pdesc->wq_status = WQ_STATUS_ACTIVE;
+
+               ce->parallel.guc.wq_head = &pdesc->head;
+               ce->parallel.guc.wq_tail = &pdesc->tail;
+               ce->parallel.guc.wq_status = &pdesc->wq_status;
+
+               for_each_child(ce, child) {
+                       desc = __get_lrc_desc_v69(guc, child->guc_id.id);
+
+                       desc->engine_class =
+                               engine_class_to_guc_class(engine->class);
+                       desc->hw_context_desc = child->lrc.lrca;
+                       desc->priority = ce->guc_state.prio;
+                       desc->context_flags = CONTEXT_REGISTRATION_FLAG_KMD;
+                       guc_context_policy_init_v69(engine, desc);
+               }
+
+               clear_children_join_go_memory(ce);
+       }
+}
+
+static void prepare_context_registration_info_v70(struct intel_context *ce,
+                                                 struct guc_ctxt_registration_info *info)
 {
        struct intel_engine_cs *engine = ce->engine;
        struct intel_guc *guc = &engine->gt->uc.guc;
@@ -2420,6 +2654,8 @@ static void prepare_context_registration_info(struct intel_context *ce,
         */
        info->hwlrca_lo = lower_32_bits(ce->lrc.lrca);
        info->hwlrca_hi = upper_32_bits(ce->lrc.lrca);
+       if (engine->flags & I915_ENGINE_HAS_EU_PRIORITY)
+               info->hwlrca_lo |= map_guc_prio_to_lrc_desc_prio(ce->guc_state.prio);
        info->flags = CONTEXT_REGISTRATION_FLAG_KMD;
 
        /*
@@ -2443,10 +2679,14 @@ static void prepare_context_registration_info(struct intel_context *ce,
                info->wq_base_hi = upper_32_bits(wq_base_offset);
                info->wq_size = WQ_SIZE;
 
-               wq_desc = __get_wq_desc(ce);
+               wq_desc = __get_wq_desc_v70(ce);
                memset(wq_desc, 0, sizeof(*wq_desc));
                wq_desc->wq_status = WQ_STATUS_ACTIVE;
 
+               ce->parallel.guc.wq_head = &wq_desc->head;
+               ce->parallel.guc.wq_tail = &wq_desc->tail;
+               ce->parallel.guc.wq_status = &wq_desc->wq_status;
+
                clear_children_join_go_memory(ce);
        }
 }
@@ -2761,11 +3001,21 @@ static void __guc_context_set_preemption_timeout(struct intel_guc *guc,
                                                 u16 guc_id,
                                                 u32 preemption_timeout)
 {
-       struct context_policy policy;
+       if (guc->fw.major_ver_found >= 70) {
+               struct context_policy policy;
 
-       __guc_context_policy_start_klv(&policy, guc_id);
-       __guc_context_policy_add_preemption_timeout(&policy, preemption_timeout);
-       __guc_context_set_context_policies(guc, &policy, true);
+               __guc_context_policy_start_klv(&policy, guc_id);
+               __guc_context_policy_add_preemption_timeout(&policy, preemption_timeout);
+               __guc_context_set_context_policies(guc, &policy, true);
+       } else {
+               u32 action[] = {
+                       INTEL_GUC_ACTION_V69_SET_CONTEXT_PREEMPTION_TIMEOUT,
+                       guc_id,
+                       preemption_timeout
+               };
+
+               intel_guc_send_busy_loop(guc, action, ARRAY_SIZE(action), 0, true);
+       }
 }
 
 static void guc_context_ban(struct intel_context *ce, struct i915_request *rq)
@@ -3013,11 +3263,21 @@ static int guc_context_alloc(struct intel_context *ce)
 static void __guc_context_set_prio(struct intel_guc *guc,
                                   struct intel_context *ce)
 {
-       struct context_policy policy;
+       if (guc->fw.major_ver_found >= 70) {
+               struct context_policy policy;
 
-       __guc_context_policy_start_klv(&policy, ce->guc_id.id);
-       __guc_context_policy_add_priority(&policy, ce->guc_state.prio);
-       __guc_context_set_context_policies(guc, &policy, true);
+               __guc_context_policy_start_klv(&policy, ce->guc_id.id);
+               __guc_context_policy_add_priority(&policy, ce->guc_state.prio);
+               __guc_context_set_context_policies(guc, &policy, true);
+       } else {
+               u32 action[] = {
+                       INTEL_GUC_ACTION_V69_SET_CONTEXT_PRIORITY,
+                       ce->guc_id.id,
+                       ce->guc_state.prio,
+               };
+
+               guc_submission_send_busy_loop(guc, action, ARRAY_SIZE(action), 0, true);
+       }
 }
 
 static void guc_context_set_prio(struct intel_guc *guc,
@@ -4527,17 +4787,19 @@ void intel_guc_submission_print_context_info(struct intel_guc *guc,
                guc_log_context_priority(p, ce);
 
                if (intel_context_is_parent(ce)) {
-                       struct guc_sched_wq_desc *wq_desc = __get_wq_desc(ce);
                        struct intel_context *child;
 
                        drm_printf(p, "\t\tNumber children: %u\n",
                                   ce->parallel.number_children);
-                       drm_printf(p, "\t\tWQI Head: %u\n",
-                                  READ_ONCE(wq_desc->head));
-                       drm_printf(p, "\t\tWQI Tail: %u\n",
-                                  READ_ONCE(wq_desc->tail));
-                       drm_printf(p, "\t\tWQI Status: %u\n\n",
-                                  READ_ONCE(wq_desc->wq_status));
+
+                       if (ce->parallel.guc.wq_status) {
+                               drm_printf(p, "\t\tWQI Head: %u\n",
+                                          READ_ONCE(*ce->parallel.guc.wq_head));
+                               drm_printf(p, "\t\tWQI Tail: %u\n",
+                                          READ_ONCE(*ce->parallel.guc.wq_tail));
+                               drm_printf(p, "\t\tWQI Status: %u\n\n",
+                                          READ_ONCE(*ce->parallel.guc.wq_status));
+                       }
 
                        if (ce->engine->emit_bb_start ==
                            emit_bb_start_parent_no_preempt_mid_batch) {
index f0d7b57b741e76f83e74b612141bfde4edf419f7..703f42ba5ddd6af6c6167fe887e0751ea6347d06 100644 (file)
@@ -70,6 +70,10 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
        fw_def(BROXTON,      0, guc_def(bxt,  70, 1, 1)) \
        fw_def(SKYLAKE,      0, guc_def(skl,  70, 1, 1))
 
+#define INTEL_GUC_FIRMWARE_DEFS_FALLBACK(fw_def, guc_def) \
+       fw_def(ALDERLAKE_P,  0, guc_def(adlp, 69, 0, 3)) \
+       fw_def(ALDERLAKE_S,  0, guc_def(tgl,  69, 0, 3))
+
 #define INTEL_HUC_FIRMWARE_DEFS(fw_def, huc_def) \
        fw_def(ALDERLAKE_P,  0, huc_def(tgl,  7, 9, 3)) \
        fw_def(ALDERLAKE_S,  0, huc_def(tgl,  7, 9, 3)) \
@@ -105,6 +109,7 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
        MODULE_FIRMWARE(uc_);
 
 INTEL_GUC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_GUC_FW_PATH)
+INTEL_GUC_FIRMWARE_DEFS_FALLBACK(INTEL_UC_MODULE_FW, MAKE_GUC_FW_PATH)
 INTEL_HUC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_HUC_FW_PATH)
 
 /* The below structs and macros are used to iterate across the list of blobs */
@@ -149,6 +154,9 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
        static const struct uc_fw_platform_requirement blobs_guc[] = {
                INTEL_GUC_FIRMWARE_DEFS(MAKE_FW_LIST, GUC_FW_BLOB)
        };
+       static const struct uc_fw_platform_requirement blobs_guc_fallback[] = {
+               INTEL_GUC_FIRMWARE_DEFS_FALLBACK(MAKE_FW_LIST, GUC_FW_BLOB)
+       };
        static const struct uc_fw_platform_requirement blobs_huc[] = {
                INTEL_HUC_FIRMWARE_DEFS(MAKE_FW_LIST, HUC_FW_BLOB)
        };
@@ -162,6 +170,15 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
        u8 rev = INTEL_REVID(i915);
        int i;
 
+       /*
+        * The only difference between the ADL GuC FWs is the HWConfig support.
+        * ADL-N does not support HWConfig, so we should use the same binary as
+        * ADL-S, otherwise the GuC might attempt to fetch a config table that
+        * does not exist.
+        */
+       if (IS_ADLP_N(i915))
+               p = INTEL_ALDERLAKE_S;
+
        GEM_BUG_ON(uc_fw->type >= ARRAY_SIZE(blobs_all));
        fw_blobs = blobs_all[uc_fw->type].blobs;
        fw_count = blobs_all[uc_fw->type].count;
@@ -170,12 +187,29 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
                if (p == fw_blobs[i].p && rev >= fw_blobs[i].rev) {
                        const struct uc_fw_blob *blob = &fw_blobs[i].blob;
                        uc_fw->path = blob->path;
+                       uc_fw->wanted_path = blob->path;
                        uc_fw->major_ver_wanted = blob->major;
                        uc_fw->minor_ver_wanted = blob->minor;
                        break;
                }
        }
 
+       if (uc_fw->type == INTEL_UC_FW_TYPE_GUC) {
+               const struct uc_fw_platform_requirement *blobs = blobs_guc_fallback;
+               u32 count = ARRAY_SIZE(blobs_guc_fallback);
+
+               for (i = 0; i < count && p <= blobs[i].p; i++) {
+                       if (p == blobs[i].p && rev >= blobs[i].rev) {
+                               const struct uc_fw_blob *blob = &blobs[i].blob;
+
+                               uc_fw->fallback.path = blob->path;
+                               uc_fw->fallback.major_ver = blob->major;
+                               uc_fw->fallback.minor_ver = blob->minor;
+                               break;
+                       }
+               }
+       }
+
        /* make sure the list is ordered as expected */
        if (IS_ENABLED(CONFIG_DRM_I915_SELFTEST)) {
                for (i = 1; i < fw_count; i++) {
@@ -329,7 +363,24 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
        __force_fw_fetch_failures(uc_fw, -EINVAL);
        __force_fw_fetch_failures(uc_fw, -ESTALE);
 
-       err = request_firmware(&fw, uc_fw->path, dev);
+       err = firmware_request_nowarn(&fw, uc_fw->path, dev);
+       if (err && !intel_uc_fw_is_overridden(uc_fw) && uc_fw->fallback.path) {
+               err = firmware_request_nowarn(&fw, uc_fw->fallback.path, dev);
+               if (!err) {
+                       drm_notice(&i915->drm,
+                                  "%s firmware %s is recommended, but only %s was found\n",
+                                  intel_uc_fw_type_repr(uc_fw->type),
+                                  uc_fw->wanted_path,
+                                  uc_fw->fallback.path);
+                       drm_info(&i915->drm,
+                                "Consider updating your linux-firmware pkg or downloading from %s\n",
+                                INTEL_UC_FIRMWARE_URL);
+
+                       uc_fw->path = uc_fw->fallback.path;
+                       uc_fw->major_ver_wanted = uc_fw->fallback.major_ver;
+                       uc_fw->minor_ver_wanted = uc_fw->fallback.minor_ver;
+               }
+       }
        if (err)
                goto fail;
 
@@ -428,8 +479,8 @@ fail:
                                  INTEL_UC_FIRMWARE_MISSING :
                                  INTEL_UC_FIRMWARE_ERROR);
 
-       drm_notice(&i915->drm, "%s firmware %s: fetch failed with error %d\n",
-                  intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err);
+       i915_probe_error(i915, "%s firmware %s: fetch failed with error %d\n",
+                        intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err);
        drm_info(&i915->drm, "%s firmware(s) can be downloaded from %s\n",
                 intel_uc_fw_type_repr(uc_fw->type), INTEL_UC_FIRMWARE_URL);
 
@@ -787,7 +838,13 @@ size_t intel_uc_fw_copy_rsa(struct intel_uc_fw *uc_fw, void *dst, u32 max_len)
 void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p)
 {
        drm_printf(p, "%s firmware: %s\n",
-                  intel_uc_fw_type_repr(uc_fw->type), uc_fw->path);
+                  intel_uc_fw_type_repr(uc_fw->type), uc_fw->wanted_path);
+       if (uc_fw->fallback.path) {
+               drm_printf(p, "%s firmware fallback: %s\n",
+                          intel_uc_fw_type_repr(uc_fw->type), uc_fw->fallback.path);
+               drm_printf(p, "fallback selected: %s\n",
+                          str_yes_no(uc_fw->path == uc_fw->fallback.path));
+       }
        drm_printf(p, "\tstatus: %s\n",
                   intel_uc_fw_status_repr(uc_fw->status));
        drm_printf(p, "\tversion: wanted %u.%u, found %u.%u\n",
index 3229018877d3dbc63fa52e395ca647a606dd2a78..562acdf88adb8943f0689606cfad505eb66fb2f0 100644 (file)
@@ -74,6 +74,7 @@ struct intel_uc_fw {
                const enum intel_uc_fw_status status;
                enum intel_uc_fw_status __status; /* no accidental overwrites */
        };
+       const char *wanted_path;
        const char *path;
        bool user_overridden;
        size_t size;
@@ -98,6 +99,12 @@ struct intel_uc_fw {
        u16 major_ver_found;
        u16 minor_ver_found;
 
+       struct {
+               const char *path;
+               u16 major_ver;
+               u16 minor_ver;
+       } fallback;
+
        u32 rsa_size;
        u32 ucode_size;
 
index b9eb75a2b4002a4463e3d6584a2f8fe2797d8635..1c35a41620ae657fc34e06b0944a003ebd1c2004 100644 (file)
@@ -3117,9 +3117,9 @@ void intel_gvt_update_reg_whitelist(struct intel_vgpu *vgpu)
                        continue;
 
                vaddr = shmem_pin_map(engine->default_state);
-               if (IS_ERR(vaddr)) {
-                       gvt_err("failed to map %s->default state, err:%zd\n",
-                               engine->name, PTR_ERR(vaddr));
+               if (!vaddr) {
+                       gvt_err("failed to map %s->default state\n",
+                               engine->name);
                        return;
                }
 
index 159571b9bd247899aa9d15a92701c243cec86835..dcc081874ec8de27e2063b4dc4ab53820633fb57 100644 (file)
@@ -68,6 +68,7 @@ void i915_refct_sgt_init(struct i915_refct_sgt *rsgt, size_t size)
  * drm_mm_node
  * @node: The drm_mm_node.
  * @region_start: An offset to add to the dma addresses of the sg list.
+ * @page_alignment: Required page alignment for each sg entry. Power of two.
  *
  * Create a struct sg_table, initializing it from a struct drm_mm_node,
  * taking a maximum segment length into account, splitting into segments
@@ -77,22 +78,25 @@ void i915_refct_sgt_init(struct i915_refct_sgt *rsgt, size_t size)
  * error code cast to an error pointer on failure.
  */
 struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
-                                             u64 region_start)
+                                             u64 region_start,
+                                             u32 page_alignment)
 {
-       const u64 max_segment = SZ_1G; /* Do we have a limit on this? */
-       u64 segment_pages = max_segment >> PAGE_SHIFT;
+       const u32 max_segment = round_down(UINT_MAX, page_alignment);
+       const u32 segment_pages = max_segment >> PAGE_SHIFT;
        u64 block_size, offset, prev_end;
        struct i915_refct_sgt *rsgt;
        struct sg_table *st;
        struct scatterlist *sg;
 
+       GEM_BUG_ON(!max_segment);
+
        rsgt = kmalloc(sizeof(*rsgt), GFP_KERNEL);
        if (!rsgt)
                return ERR_PTR(-ENOMEM);
 
        i915_refct_sgt_init(rsgt, node->size << PAGE_SHIFT);
        st = &rsgt->table;
-       if (sg_alloc_table(st, DIV_ROUND_UP(node->size, segment_pages),
+       if (sg_alloc_table(st, DIV_ROUND_UP_ULL(node->size, segment_pages),
                           GFP_KERNEL)) {
                i915_refct_sgt_put(rsgt);
                return ERR_PTR(-ENOMEM);
@@ -112,12 +116,14 @@ struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
                                sg = __sg_next(sg);
 
                        sg_dma_address(sg) = region_start + offset;
+                       GEM_BUG_ON(!IS_ALIGNED(sg_dma_address(sg),
+                                              page_alignment));
                        sg_dma_len(sg) = 0;
                        sg->length = 0;
                        st->nents++;
                }
 
-               len = min(block_size, max_segment - sg->length);
+               len = min_t(u64, block_size, max_segment - sg->length);
                sg->length += len;
                sg_dma_len(sg) += len;
 
@@ -138,6 +144,7 @@ struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
  * i915_buddy_block list
  * @res: The struct i915_ttm_buddy_resource.
  * @region_start: An offset to add to the dma addresses of the sg list.
+ * @page_alignment: Required page alignment for each sg entry. Power of two.
  *
  * Create a struct sg_table, initializing it from struct i915_buddy_block list,
  * taking a maximum segment length into account, splitting into segments
@@ -147,11 +154,12 @@ struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
  * error code cast to an error pointer on failure.
  */
 struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
-                                                    u64 region_start)
+                                                    u64 region_start,
+                                                    u32 page_alignment)
 {
        struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res);
        const u64 size = res->num_pages << PAGE_SHIFT;
-       const u64 max_segment = rounddown(UINT_MAX, PAGE_SIZE);
+       const u32 max_segment = round_down(UINT_MAX, page_alignment);
        struct drm_buddy *mm = bman_res->mm;
        struct list_head *blocks = &bman_res->blocks;
        struct drm_buddy_block *block;
@@ -161,6 +169,7 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
        resource_size_t prev_end;
 
        GEM_BUG_ON(list_empty(blocks));
+       GEM_BUG_ON(!max_segment);
 
        rsgt = kmalloc(sizeof(*rsgt), GFP_KERNEL);
        if (!rsgt)
@@ -191,12 +200,14 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
                                        sg = __sg_next(sg);
 
                                sg_dma_address(sg) = region_start + offset;
+                               GEM_BUG_ON(!IS_ALIGNED(sg_dma_address(sg),
+                                                      page_alignment));
                                sg_dma_len(sg) = 0;
                                sg->length = 0;
                                st->nents++;
                        }
 
-                       len = min(block_size, max_segment - sg->length);
+                       len = min_t(u64, block_size, max_segment - sg->length);
                        sg->length += len;
                        sg_dma_len(sg) += len;
 
index 12c6a1684081487066b7493fab7b240d1da18ec8..9ddb3e743a3e517dfe5d4006c822d396cef9492d 100644 (file)
@@ -213,9 +213,11 @@ static inline void __i915_refct_sgt_init(struct i915_refct_sgt *rsgt,
 void i915_refct_sgt_init(struct i915_refct_sgt *rsgt, size_t size);
 
 struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
-                                             u64 region_start);
+                                             u64 region_start,
+                                             u32 page_alignment);
 
 struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
-                                                    u64 region_start);
+                                                    u64 region_start,
+                                                    u32 page_alignment);
 
 #endif
index 0bffb70b3c5f5303314aa0863590d19beae31e29..04d12f278f572f243a859eabb49339f9f6f327c7 100644 (file)
@@ -1637,10 +1637,10 @@ static void force_unbind(struct i915_vma *vma)
        GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
 }
 
-static void release_references(struct i915_vma *vma, bool vm_ddestroy)
+static void release_references(struct i915_vma *vma, struct intel_gt *gt,
+                              bool vm_ddestroy)
 {
        struct drm_i915_gem_object *obj = vma->obj;
-       struct intel_gt *gt = vma->vm->gt;
 
        GEM_BUG_ON(i915_vma_is_active(vma));
 
@@ -1695,11 +1695,12 @@ void i915_vma_destroy_locked(struct i915_vma *vma)
 
        force_unbind(vma);
        list_del_init(&vma->vm_link);
-       release_references(vma, false);
+       release_references(vma, vma->vm->gt, false);
 }
 
 void i915_vma_destroy(struct i915_vma *vma)
 {
+       struct intel_gt *gt;
        bool vm_ddestroy;
 
        mutex_lock(&vma->vm->mutex);
@@ -1707,8 +1708,11 @@ void i915_vma_destroy(struct i915_vma *vma)
        list_del_init(&vma->vm_link);
        vm_ddestroy = vma->vm_ddestroy;
        vma->vm_ddestroy = false;
+
+       /* vma->vm may be freed when releasing vma->vm->mutex. */
+       gt = vma->vm->gt;
        mutex_unlock(&vma->vm->mutex);
-       release_references(vma, vm_ddestroy);
+       release_references(vma, gt, vm_ddestroy);
 }
 
 void i915_vma_parked(struct intel_gt *gt)
index 62ff77445b01bafff4be69e17bc5c0a1d5f71e8b..575d67bc6ffede89d3adda423ee2df4dc635a6c6 100644 (file)
@@ -152,6 +152,7 @@ int intel_region_ttm_fini(struct intel_memory_region *mem)
  * Convert an opaque TTM resource manager resource to a refcounted sg_table.
  * @mem: The memory region.
  * @res: The resource manager resource obtained from the TTM resource manager.
+ * @page_alignment: Required page alignment for each sg entry. Power of two.
  *
  * The gem backends typically use sg-tables for operations on the underlying
  * io_memory. So provide a way for the backends to translate the
@@ -161,16 +162,19 @@ int intel_region_ttm_fini(struct intel_memory_region *mem)
  */
 struct i915_refct_sgt *
 intel_region_ttm_resource_to_rsgt(struct intel_memory_region *mem,
-                                 struct ttm_resource *res)
+                                 struct ttm_resource *res,
+                                 u32 page_alignment)
 {
        if (mem->is_range_manager) {
                struct ttm_range_mgr_node *range_node =
                        to_ttm_range_mgr_node(res);
 
                return i915_rsgt_from_mm_node(&range_node->mm_nodes[0],
-                                             mem->region.start);
+                                             mem->region.start,
+                                             page_alignment);
        } else {
-               return i915_rsgt_from_buddy_resource(res, mem->region.start);
+               return i915_rsgt_from_buddy_resource(res, mem->region.start,
+                                                    page_alignment);
        }
 }
 
index cf9d86dcf409c7f9e55819fda62922bbe05a05ed..5bb8d8b582ae49c8e9238bcfb7a7e20876f57a13 100644 (file)
@@ -24,7 +24,8 @@ int intel_region_ttm_fini(struct intel_memory_region *mem);
 
 struct i915_refct_sgt *
 intel_region_ttm_resource_to_rsgt(struct intel_memory_region *mem,
-                                 struct ttm_resource *res);
+                                 struct ttm_resource *res,
+                                 u32 page_alignment);
 
 void intel_region_ttm_resource_free(struct intel_memory_region *mem,
                                    struct ttm_resource *res);
index 8633bec18fa75e1efb16407b181a7767234c2b7f..ab9f17fc85bcf2682c094d698540100f8df3a912 100644 (file)
@@ -742,7 +742,7 @@ static int pot_hole(struct i915_address_space *vm,
                u64 addr;
 
                for (addr = round_up(hole_start + min_alignment, step) - min_alignment;
-                    addr <= round_down(hole_end - (2 * min_alignment), step) - min_alignment;
+                    hole_end > addr && hole_end - addr >= 2 * min_alignment;
                     addr += step) {
                        err = i915_vma_pin(vma, 0, 0, addr | flags);
                        if (err) {
index 73eb53edb8de030429ef1976090ca26e65f9a084..3b18e5905c86b717e6c45ea9fe85efb77f87c35d 100644 (file)
@@ -451,7 +451,6 @@ out_put:
 
 static int igt_mock_max_segment(void *arg)
 {
-       const unsigned int max_segment = rounddown(UINT_MAX, PAGE_SIZE);
        struct intel_memory_region *mem = arg;
        struct drm_i915_private *i915 = mem->i915;
        struct i915_ttm_buddy_resource *res;
@@ -460,7 +459,10 @@ static int igt_mock_max_segment(void *arg)
        struct drm_buddy *mm;
        struct list_head *blocks;
        struct scatterlist *sg;
+       I915_RND_STATE(prng);
        LIST_HEAD(objects);
+       unsigned int max_segment;
+       unsigned int ps;
        u64 size;
        int err = 0;
 
@@ -472,7 +474,13 @@ static int igt_mock_max_segment(void *arg)
         */
 
        size = SZ_8G;
-       mem = mock_region_create(i915, 0, size, PAGE_SIZE, 0, 0);
+       ps = PAGE_SIZE;
+       if (i915_prandom_u64_state(&prng) & 1)
+               ps = SZ_64K; /* For something like DG2 */
+
+       max_segment = round_down(UINT_MAX, ps);
+
+       mem = mock_region_create(i915, 0, size, ps, 0, 0);
        if (IS_ERR(mem))
                return PTR_ERR(mem);
 
@@ -498,12 +506,21 @@ static int igt_mock_max_segment(void *arg)
        }
 
        for (sg = obj->mm.pages->sgl; sg; sg = sg_next(sg)) {
+               dma_addr_t daddr = sg_dma_address(sg);
+
                if (sg->length > max_segment) {
                        pr_err("%s: Created an oversized scatterlist entry, %u > %u\n",
                               __func__, sg->length, max_segment);
                        err = -EINVAL;
                        goto out_close;
                }
+
+               if (!IS_ALIGNED(daddr, ps)) {
+                       pr_err("%s: Created an unaligned scatterlist entry, addr=%pa, ps=%u\n",
+                              __func__,  &daddr, ps);
+                       err = -EINVAL;
+                       goto out_close;
+               }
        }
 
 out_close:
index 670557ce1024aa6203a0a864ca247f354bb1ed57..bac21fe84ca5685dd91480e6bbabd54e4c55aeb5 100644 (file)
@@ -33,7 +33,8 @@ static int mock_region_get_pages(struct drm_i915_gem_object *obj)
                return PTR_ERR(obj->mm.res);
 
        obj->mm.rsgt = intel_region_ttm_resource_to_rsgt(obj->mm.region,
-                                                        obj->mm.res);
+                                                        obj->mm.res,
+                                                        obj->mm.region->min_page_size);
        if (IS_ERR(obj->mm.rsgt)) {
                err = PTR_ERR(obj->mm.rsgt);
                goto err_free_resource;
index c849533ca83e31942de0e5ce2fe738e237108a42..3f5750cc2673e7f99845e442708a1a7dce94d36a 100644 (file)
@@ -207,6 +207,7 @@ struct dcss_dev *dcss_dev_create(struct device *dev, bool hdmi_output)
 
        ret = dcss_submodules_init(dcss);
        if (ret) {
+               of_node_put(dcss->of_port);
                dev_err(dev, "submodules initialization failed\n");
                goto clks_err;
        }
@@ -237,6 +238,8 @@ void dcss_dev_destroy(struct dcss_dev *dcss)
                dcss_clocks_disable(dcss);
        }
 
+       of_node_put(dcss->of_port);
+
        pm_runtime_disable(dcss->dev);
 
        dcss_submodules_stop(dcss);
index c96014464355c3e26a18039a6ed88df6d9274eea..a189982601a48ac753b7ebabaa74cd6b180c7dfb 100644 (file)
@@ -713,7 +713,7 @@ static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
        of_property_read_u32(dev->of_node, "hpd-reliable-delay-ms", &reliable_ms);
        desc->delay.hpd_reliable = reliable_ms;
        of_property_read_u32(dev->of_node, "hpd-absent-delay-ms", &absent_ms);
-       desc->delay.hpd_reliable = absent_ms;
+       desc->delay.hpd_absent = absent_ms;
 
        /* Power the panel on so we can read the EDID */
        ret = pm_runtime_get_sync(dev);
index 087e69b98d0694b8ce1037c8df8b7277e309b9e1..b1e6d238674ffc0bbf5a1ffb2b17ff1c8d8a2628 100644 (file)
@@ -433,8 +433,8 @@ static int panfrost_ioctl_madvise(struct drm_device *dev, void *data,
 
        if (args->retained) {
                if (args->madv == PANFROST_MADV_DONTNEED)
-                       list_add_tail(&bo->base.madv_list,
-                                     &pfdev->shrinker_list);
+                       list_move_tail(&bo->base.madv_list,
+                                      &pfdev->shrinker_list);
                else if (args->madv == PANFROST_MADV_WILLNEED)
                        list_del_init(&bo->base.madv_list);
        }
index d3f82b26a631dbbb45e7ab15abb9c4acb85d1def..b285a8001b1d22fe446cb5a91fe379af8f812844 100644 (file)
@@ -518,7 +518,7 @@ err_map:
 err_pages:
        drm_gem_shmem_put_pages(&bo->base);
 err_bo:
-       drm_gem_object_put(&bo->base.base);
+       panfrost_gem_mapping_put(bomapping);
        return ret;
 }
 
index 67d38f53d3e506d5e72591ef4005e44b002e9268..13ed33e7445781a995e70eab7beb96574b287415 100644 (file)
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_vblank.h>
 
+#if defined(CONFIG_ARM_DMA_USE_IOMMU)
+#include <asm/dma-iommu.h>
+#else
+#define arm_iommu_detach_device(...)   ({ })
+#define arm_iommu_release_mapping(...) ({ })
+#define to_dma_iommu_mapping(dev) NULL
+#endif
+
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_fb.h"
 #include "rockchip_drm_gem.h"
@@ -49,6 +57,15 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
        if (!private->domain)
                return 0;
 
+       if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
+               struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
+
+               if (mapping) {
+                       arm_iommu_detach_device(dev);
+                       arm_iommu_release_mapping(mapping);
+               }
+       }
+
        ret = iommu_attach_device(private->domain, dev);
        if (ret) {
                DRM_DEV_ERROR(dev, "Failed to attach iommu device\n");
index 191c56064f196bfd2af5f929e2767dc561ee495b..6b25b2f4f5a308185f5ca1777d47671e7f8dc864 100644 (file)
@@ -190,7 +190,7 @@ long drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout)
 }
 EXPORT_SYMBOL(drm_sched_entity_flush);
 
-static void drm_sched_entity_kill_jobs_irq_work(struct irq_work *wrk)
+static void drm_sched_entity_kill_jobs_work(struct work_struct *wrk)
 {
        struct drm_sched_job *job = container_of(wrk, typeof(*job), work);
 
@@ -207,8 +207,8 @@ static void drm_sched_entity_kill_jobs_cb(struct dma_fence *f,
        struct drm_sched_job *job = container_of(cb, struct drm_sched_job,
                                                 finish_cb);
 
-       init_irq_work(&job->work, drm_sched_entity_kill_jobs_irq_work);
-       irq_work_queue(&job->work);
+       INIT_WORK(&job->work, drm_sched_entity_kill_jobs_work);
+       schedule_work(&job->work);
 }
 
 static struct dma_fence *
index 08394444dd6e3f417ee7ebf6e6ed69163891d678..f4886e66ff3420da4429145aedf173fc7be35201 100644 (file)
@@ -350,7 +350,7 @@ static int ssd130x_init(struct ssd130x_device *ssd130x)
 
        /* Set precharge period in number of ticks from the internal clock */
        precharge = (SSD130X_SET_PRECHARGE_PERIOD1_SET(ssd130x->prechargep1) |
-                    SSD130X_SET_PRECHARGE_PERIOD1_SET(ssd130x->prechargep2));
+                    SSD130X_SET_PRECHARGE_PERIOD2_SET(ssd130x->prechargep2));
        ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_PRECHARGE_PERIOD, precharge);
        if (ret < 0)
                return ret;
index b4c1ad19cdaec154f2a39186dca5f38932163a4f..630cfa4ddd468c5b3ee4d4bda56b792aba2806e6 100644 (file)
@@ -388,9 +388,9 @@ static irqreturn_t cdns_i2c_slave_isr(void *ptr)
  */
 static irqreturn_t cdns_i2c_master_isr(void *ptr)
 {
-       unsigned int isr_status, avail_bytes, updatetx;
+       unsigned int isr_status, avail_bytes;
        unsigned int bytes_to_send;
-       bool hold_quirk;
+       bool updatetx;
        struct cdns_i2c *id = ptr;
        /* Signal completion only after everything is updated */
        int done_flag = 0;
@@ -410,11 +410,7 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)
         * Check if transfer size register needs to be updated again for a
         * large data receive operation.
         */
-       updatetx = 0;
-       if (id->recv_count > id->curr_recv_count)
-               updatetx = 1;
-
-       hold_quirk = (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT) && updatetx;
+       updatetx = id->recv_count > id->curr_recv_count;
 
        /* When receiving, handle data interrupt and completion interrupt */
        if (id->p_recv_buf &&
@@ -445,7 +441,7 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)
                                break;
                        }
 
-                       if (cdns_is_holdquirk(id, hold_quirk))
+                       if (cdns_is_holdquirk(id, updatetx))
                                break;
                }
 
@@ -456,7 +452,7 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)
                 * maintain transfer size non-zero while performing a large
                 * receive operation.
                 */
-               if (cdns_is_holdquirk(id, hold_quirk)) {
+               if (cdns_is_holdquirk(id, updatetx)) {
                        /* wait while fifo is full */
                        while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
                               (id->curr_recv_count - CDNS_I2C_FIFO_DEPTH))
@@ -478,22 +474,6 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)
                                                  CDNS_I2C_XFER_SIZE_OFFSET);
                                id->curr_recv_count = id->recv_count;
                        }
-               } else if (id->recv_count && !hold_quirk &&
-                                               !id->curr_recv_count) {
-
-                       /* Set the slave address in address register*/
-                       cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
-                                               CDNS_I2C_ADDR_OFFSET);
-
-                       if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) {
-                               cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
-                                               CDNS_I2C_XFER_SIZE_OFFSET);
-                               id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
-                       } else {
-                               cdns_i2c_writereg(id->recv_count,
-                                               CDNS_I2C_XFER_SIZE_OFFSET);
-                               id->curr_recv_count = id->recv_count;
-                       }
                }
 
                /* Clear hold (if not repeated start) and signal completion */
@@ -1338,6 +1318,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
        return 0;
 
 err_clk_dis:
+       clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
        clk_disable_unprepare(id->clk);
        pm_runtime_disable(&pdev->dev);
        pm_runtime_set_suspended(&pdev->dev);
index e9e2db68b9fb62f1bc3e47bf0770827667cc5063..78fb1a4274a6c3e04d4e697f8180179e0f616be3 100644 (file)
@@ -66,7 +66,7 @@
 
 /* IMX I2C registers:
  * the I2C register offset is different between SoCs,
- * to provid support for all these chips, split the
+ * to provide support for all these chips, split the
  * register offset into a fixed base address and a
  * variable shift value, then the full register offset
  * will be calculated by
index 56aa424fd71d5ce452885829fedf218a7728c6c8..815cc561386b021b9556f15e3686fa8d29c85cdf 100644 (file)
@@ -49,7 +49,7 @@
 #define MLXCPLD_LPCI2C_NACK_IND                2
 
 #define MLXCPLD_I2C_FREQ_1000KHZ_SET   0x04
-#define MLXCPLD_I2C_FREQ_400KHZ_SET    0x0c
+#define MLXCPLD_I2C_FREQ_400KHZ_SET    0x0e
 #define MLXCPLD_I2C_FREQ_100KHZ_SET    0x42
 
 enum mlxcpld_i2c_frequency {
index ac8e7d60672a1b49322cbfeb85c9e96015de7b45..39cb1b7bb8656c6f34bc194b9ed7537ad70cf293 100644 (file)
@@ -161,7 +161,6 @@ static const char *piix4_aux_port_name_sb800 = " port 1";
 
 struct sb800_mmio_cfg {
        void __iomem *addr;
-       struct resource *res;
        bool use_mmio;
 };
 
@@ -179,13 +178,11 @@ static int piix4_sb800_region_request(struct device *dev,
                                      struct sb800_mmio_cfg *mmio_cfg)
 {
        if (mmio_cfg->use_mmio) {
-               struct resource *res;
                void __iomem *addr;
 
-               res = request_mem_region_muxed(SB800_PIIX4_FCH_PM_ADDR,
-                                              SB800_PIIX4_FCH_PM_SIZE,
-                                              "sb800_piix4_smb");
-               if (!res) {
+               if (!request_mem_region_muxed(SB800_PIIX4_FCH_PM_ADDR,
+                                             SB800_PIIX4_FCH_PM_SIZE,
+                                             "sb800_piix4_smb")) {
                        dev_err(dev,
                                "SMBus base address memory region 0x%x already in use.\n",
                                SB800_PIIX4_FCH_PM_ADDR);
@@ -195,12 +192,12 @@ static int piix4_sb800_region_request(struct device *dev,
                addr = ioremap(SB800_PIIX4_FCH_PM_ADDR,
                               SB800_PIIX4_FCH_PM_SIZE);
                if (!addr) {
-                       release_resource(res);
+                       release_mem_region(SB800_PIIX4_FCH_PM_ADDR,
+                                          SB800_PIIX4_FCH_PM_SIZE);
                        dev_err(dev, "SMBus base address mapping failed.\n");
                        return -ENOMEM;
                }
 
-               mmio_cfg->res = res;
                mmio_cfg->addr = addr;
 
                return 0;
@@ -222,7 +219,8 @@ static void piix4_sb800_region_release(struct device *dev,
 {
        if (mmio_cfg->use_mmio) {
                iounmap(mmio_cfg->addr);
-               release_resource(mmio_cfg->res);
+               release_mem_region(SB800_PIIX4_FCH_PM_ADDR,
+                                  SB800_PIIX4_FCH_PM_SIZE);
                return;
        }
 
index 424ef470223df4d687b2609c952147299de620ec..9515a3146dc977bad04a525e737729c497434f7c 100644 (file)
 #include <linux/tick.h>
 #include <trace/events/power.h>
 #include <linux/sched.h>
+#include <linux/sched/smt.h>
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/moduleparam.h>
 #include <asm/cpu_device_id.h>
 #include <asm/intel-family.h>
+#include <asm/nospec-branch.h>
 #include <asm/mwait.h>
 #include <asm/msr.h>
 
@@ -105,6 +107,12 @@ static unsigned int mwait_substates __initdata;
  */
 #define CPUIDLE_FLAG_ALWAYS_ENABLE     BIT(15)
 
+/*
+ * Disable IBRS across idle (when KERNEL_IBRS), is exclusive vs IRQ_ENABLE
+ * above.
+ */
+#define CPUIDLE_FLAG_IBRS              BIT(16)
+
 /*
  * MWAIT takes an 8-bit "hint" in EAX "suggesting"
  * the C-state (top nibble) and sub-state (bottom nibble)
@@ -154,7 +162,31 @@ static __cpuidle int intel_idle_irq(struct cpuidle_device *dev,
 
        raw_local_irq_enable();
        ret = __intel_idle(dev, drv, index);
-       raw_local_irq_disable();
+
+       /*
+        * The lockdep hardirqs state may be changed to 'on' with timer
+        * tick interrupt followed by __do_softirq(). Use local_irq_disable()
+        * to keep the hardirqs state correct.
+        */
+       local_irq_disable();
+
+       return ret;
+}
+
+static __cpuidle int intel_idle_ibrs(struct cpuidle_device *dev,
+                                    struct cpuidle_driver *drv, int index)
+{
+       bool smt_active = sched_smt_active();
+       u64 spec_ctrl = spec_ctrl_current();
+       int ret;
+
+       if (smt_active)
+               wrmsrl(MSR_IA32_SPEC_CTRL, 0);
+
+       ret = __intel_idle(dev, drv, index);
+
+       if (smt_active)
+               wrmsrl(MSR_IA32_SPEC_CTRL, spec_ctrl);
 
        return ret;
 }
@@ -680,7 +712,7 @@ static struct cpuidle_state skl_cstates[] __initdata = {
        {
                .name = "C6",
                .desc = "MWAIT 0x20",
-               .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 85,
                .target_residency = 200,
                .enter = &intel_idle,
@@ -688,7 +720,7 @@ static struct cpuidle_state skl_cstates[] __initdata = {
        {
                .name = "C7s",
                .desc = "MWAIT 0x33",
-               .flags = MWAIT2flg(0x33) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x33) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 124,
                .target_residency = 800,
                .enter = &intel_idle,
@@ -696,7 +728,7 @@ static struct cpuidle_state skl_cstates[] __initdata = {
        {
                .name = "C8",
                .desc = "MWAIT 0x40",
-               .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 200,
                .target_residency = 800,
                .enter = &intel_idle,
@@ -704,7 +736,7 @@ static struct cpuidle_state skl_cstates[] __initdata = {
        {
                .name = "C9",
                .desc = "MWAIT 0x50",
-               .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 480,
                .target_residency = 5000,
                .enter = &intel_idle,
@@ -712,7 +744,7 @@ static struct cpuidle_state skl_cstates[] __initdata = {
        {
                .name = "C10",
                .desc = "MWAIT 0x60",
-               .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 890,
                .target_residency = 5000,
                .enter = &intel_idle,
@@ -741,7 +773,7 @@ static struct cpuidle_state skx_cstates[] __initdata = {
        {
                .name = "C6",
                .desc = "MWAIT 0x20",
-               .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 133,
                .target_residency = 600,
                .enter = &intel_idle,
@@ -879,16 +911,6 @@ static struct cpuidle_state adl_l_cstates[] __initdata = {
                .enter = NULL }
 };
 
-/*
- * On Sapphire Rapids Xeon C1 has to be disabled if C1E is enabled, and vice
- * versa. On SPR C1E is enabled only if "C1E promotion" bit is set in
- * MSR_IA32_POWER_CTL. But in this case there effectively no C1, because C1
- * requests are promoted to C1E. If the "C1E promotion" bit is cleared, then
- * both C1 and C1E requests end up with C1, so there is effectively no C1E.
- *
- * By default we enable C1 and disable C1E by marking it with
- * 'CPUIDLE_FLAG_UNUSABLE'.
- */
 static struct cpuidle_state spr_cstates[] __initdata = {
        {
                .name = "C1",
@@ -901,8 +923,7 @@ static struct cpuidle_state spr_cstates[] __initdata = {
        {
                .name = "C1E",
                .desc = "MWAIT 0x01",
-               .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE |
-                                          CPUIDLE_FLAG_UNUSABLE,
+               .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE,
                .exit_latency = 2,
                .target_residency = 4,
                .enter = &intel_idle,
@@ -1724,17 +1745,6 @@ static void __init spr_idle_state_table_update(void)
 {
        unsigned long long msr;
 
-       /* Check if user prefers C1E over C1. */
-       if ((preferred_states_mask & BIT(2)) &&
-           !(preferred_states_mask & BIT(1))) {
-               /* Disable C1 and enable C1E. */
-               spr_cstates[0].flags |= CPUIDLE_FLAG_UNUSABLE;
-               spr_cstates[1].flags &= ~CPUIDLE_FLAG_UNUSABLE;
-
-               /* Enable C1E using the "C1E promotion" bit. */
-               c1e_promotion = C1E_PROMOTION_ENABLE;
-       }
-
        /*
         * By default, the C6 state assumes the worst-case scenario of package
         * C6. However, if PC6 is disabled, we update the numbers to match
@@ -1819,6 +1829,12 @@ static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv)
                if (cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IRQ_ENABLE)
                        drv->states[drv->state_count].enter = intel_idle_irq;
 
+               if (cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS) &&
+                   cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IBRS) {
+                       WARN_ON_ONCE(cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IRQ_ENABLE);
+                       drv->states[drv->state_count].enter = intel_idle_ibrs;
+               }
+
                if ((disabled_states_mask & BIT(drv->state_count)) ||
                    ((icpu->use_acpi || force_use_acpi) &&
                     intel_idle_off_by_default(mwait_hint) &&
index 638bf4a1ed9463d83ea11229073a3e756932f996..646fa86774909e4c91c714270d03c27ac5620a3b 100644 (file)
@@ -4231,10 +4231,6 @@ void irdma_cm_teardown_connections(struct irdma_device *iwdev, u32 *ipaddr,
        struct irdma_cm_node *cm_node;
        struct list_head teardown_list;
        struct ib_qp_attr attr;
-       struct irdma_sc_vsi *vsi = &iwdev->vsi;
-       struct irdma_sc_qp *sc_qp;
-       struct irdma_qp *qp;
-       int i;
 
        INIT_LIST_HEAD(&teardown_list);
 
@@ -4251,52 +4247,6 @@ void irdma_cm_teardown_connections(struct irdma_device *iwdev, u32 *ipaddr,
                        irdma_cm_disconn(cm_node->iwqp);
                irdma_rem_ref_cm_node(cm_node);
        }
-       if (!iwdev->roce_mode)
-               return;
-
-       INIT_LIST_HEAD(&teardown_list);
-       for (i = 0; i < IRDMA_MAX_USER_PRIORITY; i++) {
-               mutex_lock(&vsi->qos[i].qos_mutex);
-               list_for_each_safe (list_node, list_core_temp,
-                                   &vsi->qos[i].qplist) {
-                       u32 qp_ip[4];
-
-                       sc_qp = container_of(list_node, struct irdma_sc_qp,
-                                            list);
-                       if (sc_qp->qp_uk.qp_type != IRDMA_QP_TYPE_ROCE_RC)
-                               continue;
-
-                       qp = sc_qp->qp_uk.back_qp;
-                       if (!disconnect_all) {
-                               if (nfo->ipv4)
-                                       qp_ip[0] = qp->udp_info.local_ipaddr[3];
-                               else
-                                       memcpy(qp_ip,
-                                              &qp->udp_info.local_ipaddr[0],
-                                              sizeof(qp_ip));
-                       }
-
-                       if (disconnect_all ||
-                           (nfo->vlan_id == (qp->udp_info.vlan_tag & VLAN_VID_MASK) &&
-                            !memcmp(qp_ip, ipaddr, nfo->ipv4 ? 4 : 16))) {
-                               spin_lock(&iwdev->rf->qptable_lock);
-                               if (iwdev->rf->qp_table[sc_qp->qp_uk.qp_id]) {
-                                       irdma_qp_add_ref(&qp->ibqp);
-                                       list_add(&qp->teardown_entry,
-                                                &teardown_list);
-                               }
-                               spin_unlock(&iwdev->rf->qptable_lock);
-                       }
-               }
-               mutex_unlock(&vsi->qos[i].qos_mutex);
-       }
-
-       list_for_each_safe (list_node, list_core_temp, &teardown_list) {
-               qp = container_of(list_node, struct irdma_qp, teardown_entry);
-               attr.qp_state = IB_QPS_ERR;
-               irdma_modify_qp_roce(&qp->ibqp, &attr, IB_QP_STATE, NULL);
-               irdma_qp_rem_ref(&qp->ibqp);
-       }
 }
 
 /**
index e46fc110004d0e2247cf3a47b74db9baa45e06f8..50299f58b6b3194dfcb2ff83ed457b92ebb8b3e9 100644 (file)
@@ -201,6 +201,7 @@ void i40iw_init_hw(struct irdma_sc_dev *dev)
        dev->hw_attrs.uk_attrs.max_hw_read_sges = I40IW_MAX_SGE_RD;
        dev->hw_attrs.max_hw_device_pages = I40IW_MAX_PUSH_PAGE_COUNT;
        dev->hw_attrs.uk_attrs.max_hw_inline = I40IW_MAX_INLINE_DATA_SIZE;
+       dev->hw_attrs.page_size_cap = SZ_4K | SZ_2M;
        dev->hw_attrs.max_hw_ird = I40IW_MAX_IRD_SIZE;
        dev->hw_attrs.max_hw_ord = I40IW_MAX_ORD_SIZE;
        dev->hw_attrs.max_hw_wqes = I40IW_MAX_WQ_ENTRIES;
index cf53b17510cdb27cc8a362861ae4936f97c2c13d..5986fd906308cc54f1e86f5db939899944ea0e20 100644 (file)
@@ -139,6 +139,7 @@ void icrdma_init_hw(struct irdma_sc_dev *dev)
        dev->cqp_db = dev->hw_regs[IRDMA_CQPDB];
        dev->cq_ack_db = dev->hw_regs[IRDMA_CQACK];
        dev->irq_ops = &icrdma_irq_ops;
+       dev->hw_attrs.page_size_cap = SZ_4K | SZ_2M | SZ_1G;
        dev->hw_attrs.max_hw_ird = ICRDMA_MAX_IRD_SIZE;
        dev->hw_attrs.max_hw_ord = ICRDMA_MAX_ORD_SIZE;
        dev->hw_attrs.max_stat_inst = ICRDMA_MAX_STATS_COUNT;
index 46c12334c7354609f23bb7d22dafe29244775bce..4789e85d717b3e813d2d16dae7542984c5c02234 100644 (file)
@@ -127,6 +127,7 @@ struct irdma_hw_attrs {
        u64 max_hw_outbound_msg_size;
        u64 max_hw_inbound_msg_size;
        u64 max_mr_size;
+       u64 page_size_cap;
        u32 min_hw_qp_id;
        u32 min_hw_aeq_size;
        u32 max_hw_aeq_size;
index c4412ece5a6d07776ac29eed6ca69016f622bdb2..96135a228f26cb8e79bdb6c3b712176a1918038d 100644 (file)
@@ -32,7 +32,7 @@ static int irdma_query_device(struct ib_device *ibdev,
        props->vendor_part_id = pcidev->device;
 
        props->hw_ver = rf->pcidev->revision;
-       props->page_size_cap = SZ_4K | SZ_2M | SZ_1G;
+       props->page_size_cap = hw_attrs->page_size_cap;
        props->max_mr_size = hw_attrs->max_mr_size;
        props->max_qp = rf->max_qp - rf->used_qps;
        props->max_qp_wr = hw_attrs->max_qp_wr;
@@ -2781,7 +2781,7 @@ static struct ib_mr *irdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 len,
 
        if (req.reg_type == IRDMA_MEMREG_TYPE_MEM) {
                iwmr->page_size = ib_umem_find_best_pgsz(region,
-                                                        SZ_4K | SZ_2M | SZ_1G,
+                                                        iwdev->rf->sc_dev.hw_attrs.page_size_cap,
                                                         virt);
                if (unlikely(!iwmr->page_size)) {
                        kfree(iwmr);
index 3ad9870db1081f825e1a5076c60121b46410c70c..aa45a9fee6a0182d4434a2f7d246ea305546960e 100644 (file)
@@ -900,6 +900,11 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
        } else {
                dev_warn(dev, "Unexpected ACPI resources: gpio_count %d, gpio_int_idx %d\n",
                         ts->gpio_count, ts->gpio_int_idx);
+               /*
+                * On some devices _PS0 does a reset for us and
+                * sometimes this is necessary for things to work.
+                */
+               acpi_device_fix_up_power(ACPI_COMPANION(dev));
                return -EINVAL;
        }
 
index 43c521f50c851d37253151f57b9adda5fd24ebeb..3dda6eaabdab82721c844c8a18ec1f6cf6fb8fc8 100644 (file)
@@ -1654,6 +1654,9 @@ static int usbtouch_probe(struct usb_interface *intf,
        if (id->driver_info == DEVTYPE_IGNORE)
                return -ENODEV;
 
+       if (id->driver_info >= ARRAY_SIZE(usbtouch_dev_info))
+               return -ENODEV;
+
        endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting);
        if (!endpoint)
                return -ENXIO;
index 2757c7768ffe95456757d35eaa2f7dc41fddf589..f51ab561453200b8432ebdc8c2cf144c7a28e9f4 100644 (file)
@@ -758,7 +758,9 @@ batt_err:
 
 static int wm97xx_mfd_remove(struct platform_device *pdev)
 {
-       return wm97xx_remove(&pdev->dev);
+       wm97xx_remove(&pdev->dev);
+
+       return 0;
 }
 
 static int __maybe_unused wm97xx_suspend(struct device *dev)
index 592c1e1a5d4b975354db850f4dde86873af3b20d..9699ca101c6245289be61be06abcff64e3997006 100644 (file)
@@ -382,7 +382,7 @@ static int dmar_pci_bus_notifier(struct notifier_block *nb,
 
 static struct notifier_block dmar_pci_bus_nb = {
        .notifier_call = dmar_pci_bus_notifier,
-       .priority = INT_MIN,
+       .priority = 1,
 };
 
 static struct dmar_drhd_unit *
index 44016594831de562b80c59e2d964f26a4e1a27fe..5c0dce78586aa56c4927f3c35ca4c4d5e8ab0466 100644 (file)
@@ -320,30 +320,6 @@ EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
 DEFINE_SPINLOCK(device_domain_lock);
 static LIST_HEAD(device_domain_list);
 
-/*
- * Iterate over elements in device_domain_list and call the specified
- * callback @fn against each element.
- */
-int for_each_device_domain(int (*fn)(struct device_domain_info *info,
-                                    void *data), void *data)
-{
-       int ret = 0;
-       unsigned long flags;
-       struct device_domain_info *info;
-
-       spin_lock_irqsave(&device_domain_lock, flags);
-       list_for_each_entry(info, &device_domain_list, global) {
-               ret = fn(info, data);
-               if (ret) {
-                       spin_unlock_irqrestore(&device_domain_lock, flags);
-                       return ret;
-               }
-       }
-       spin_unlock_irqrestore(&device_domain_lock, flags);
-
-       return 0;
-}
-
 const struct iommu_ops intel_iommu_ops;
 
 static bool translation_pre_enabled(struct intel_iommu *iommu)
index cb4c1d0cf25c0bbbaea3694efa879208aa6f0f6b..17cad7c1f62d6e14e21a8602b706a56811c9946a 100644 (file)
@@ -86,54 +86,6 @@ void vcmd_free_pasid(struct intel_iommu *iommu, u32 pasid)
 /*
  * Per device pasid table management:
  */
-static inline void
-device_attach_pasid_table(struct device_domain_info *info,
-                         struct pasid_table *pasid_table)
-{
-       info->pasid_table = pasid_table;
-       list_add(&info->table, &pasid_table->dev);
-}
-
-static inline void
-device_detach_pasid_table(struct device_domain_info *info,
-                         struct pasid_table *pasid_table)
-{
-       info->pasid_table = NULL;
-       list_del(&info->table);
-}
-
-struct pasid_table_opaque {
-       struct pasid_table      **pasid_table;
-       int                     segment;
-       int                     bus;
-       int                     devfn;
-};
-
-static int search_pasid_table(struct device_domain_info *info, void *opaque)
-{
-       struct pasid_table_opaque *data = opaque;
-
-       if (info->iommu->segment == data->segment &&
-           info->bus == data->bus &&
-           info->devfn == data->devfn &&
-           info->pasid_table) {
-               *data->pasid_table = info->pasid_table;
-               return 1;
-       }
-
-       return 0;
-}
-
-static int get_alias_pasid_table(struct pci_dev *pdev, u16 alias, void *opaque)
-{
-       struct pasid_table_opaque *data = opaque;
-
-       data->segment = pci_domain_nr(pdev->bus);
-       data->bus = PCI_BUS_NUM(alias);
-       data->devfn = alias & 0xff;
-
-       return for_each_device_domain(&search_pasid_table, data);
-}
 
 /*
  * Allocate a pasid table for @dev. It should be called in a
@@ -143,28 +95,18 @@ int intel_pasid_alloc_table(struct device *dev)
 {
        struct device_domain_info *info;
        struct pasid_table *pasid_table;
-       struct pasid_table_opaque data;
        struct page *pages;
        u32 max_pasid = 0;
-       int ret, order;
-       int size;
+       int order, size;
 
        might_sleep();
        info = dev_iommu_priv_get(dev);
        if (WARN_ON(!info || !dev_is_pci(dev) || info->pasid_table))
                return -EINVAL;
 
-       /* DMA alias device already has a pasid table, use it: */
-       data.pasid_table = &pasid_table;
-       ret = pci_for_each_dma_alias(to_pci_dev(dev),
-                                    &get_alias_pasid_table, &data);
-       if (ret)
-               goto attach_out;
-
        pasid_table = kzalloc(sizeof(*pasid_table), GFP_KERNEL);
        if (!pasid_table)
                return -ENOMEM;
-       INIT_LIST_HEAD(&pasid_table->dev);
 
        if (info->pasid_supported)
                max_pasid = min_t(u32, pci_max_pasids(to_pci_dev(dev)),
@@ -182,9 +124,7 @@ int intel_pasid_alloc_table(struct device *dev)
        pasid_table->table = page_address(pages);
        pasid_table->order = order;
        pasid_table->max_pasid = 1 << (order + PAGE_SHIFT + 3);
-
-attach_out:
-       device_attach_pasid_table(info, pasid_table);
+       info->pasid_table = pasid_table;
 
        return 0;
 }
@@ -202,10 +142,7 @@ void intel_pasid_free_table(struct device *dev)
                return;
 
        pasid_table = info->pasid_table;
-       device_detach_pasid_table(info, pasid_table);
-
-       if (!list_empty(&pasid_table->dev))
-               return;
+       info->pasid_table = NULL;
 
        /* Free scalable mode PASID directory tables: */
        dir = pasid_table->table;
index 583ea67fc7836065392240bc9e2103557c7cf21f..bf5b937848b4195239c99ee5dbc6161cfc3cad35 100644 (file)
@@ -74,7 +74,6 @@ struct pasid_table {
        void                    *table;         /* pasid table pointer */
        int                     order;          /* page order of pasid table */
        u32                     max_pasid;      /* max pasid */
-       struct list_head        dev;            /* device list */
 };
 
 /* Get PRESENT bit of a PASID directory entry. */
index 1f23a6be7d8822e8165d0602b71d4a1add0c618a..bbb11cb8b0f73a22cf167fe2e473639141349b39 100644 (file)
@@ -298,7 +298,7 @@ config XTENSA_MX
 
 config XILINX_INTC
        bool "Xilinx Interrupt Controller IP"
-       depends on OF
+       depends on OF_ADDRESS
        select IRQ_DOMAIN
        help
          Support for the Xilinx Interrupt Controller IP core.
index 5ac83185ff4794f0af825cdd4d96bcc624630b07..1c2813ad8bbe2cd73e79d8fd7f6230901fb51504 100644 (file)
 #define AIC_TMR_EL02_PHYS      AIC_TMR_GUEST_PHYS
 #define AIC_TMR_EL02_VIRT      AIC_TMR_GUEST_VIRT
 
-DEFINE_STATIC_KEY_TRUE(use_fast_ipi);
+static DEFINE_STATIC_KEY_TRUE(use_fast_ipi);
 
 struct aic_info {
        int version;
index 5c1cf907ee68d97c07447de8fe8c43db5880ae41..2d25bca63d2a1f3e963f74fa1d863ccd692a2377 100644 (file)
@@ -2042,15 +2042,40 @@ static void __init gic_of_setup_kvm_info(struct device_node *node)
        vgic_set_kvm_info(&gic_v3_kvm_info);
 }
 
+static void gic_request_region(resource_size_t base, resource_size_t size,
+                              const char *name)
+{
+       if (!request_mem_region(base, size, name))
+               pr_warn_once(FW_BUG "%s region %pa has overlapping address\n",
+                            name, &base);
+}
+
+static void __iomem *gic_of_iomap(struct device_node *node, int idx,
+                                 const char *name, struct resource *res)
+{
+       void __iomem *base;
+       int ret;
+
+       ret = of_address_to_resource(node, idx, res);
+       if (ret)
+               return IOMEM_ERR_PTR(ret);
+
+       gic_request_region(res->start, resource_size(res), name);
+       base = of_iomap(node, idx);
+
+       return base ?: IOMEM_ERR_PTR(-ENOMEM);
+}
+
 static int __init gic_of_init(struct device_node *node, struct device_node *parent)
 {
        void __iomem *dist_base;
        struct redist_region *rdist_regs;
+       struct resource res;
        u64 redist_stride;
        u32 nr_redist_regions;
        int err, i;
 
-       dist_base = of_io_request_and_map(node, 0, "GICD");
+       dist_base = gic_of_iomap(node, 0, "GICD", &res);
        if (IS_ERR(dist_base)) {
                pr_err("%pOF: unable to map gic dist registers\n", node);
                return PTR_ERR(dist_base);
@@ -2073,12 +2098,8 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
        }
 
        for (i = 0; i < nr_redist_regions; i++) {
-               struct resource res;
-               int ret;
-
-               ret = of_address_to_resource(node, 1 + i, &res);
-               rdist_regs[i].redist_base = of_io_request_and_map(node, 1 + i, "GICR");
-               if (ret || IS_ERR(rdist_regs[i].redist_base)) {
+               rdist_regs[i].redist_base = gic_of_iomap(node, 1 + i, "GICR", &res);
+               if (IS_ERR(rdist_regs[i].redist_base)) {
                        pr_err("%pOF: couldn't map region %d\n", node, i);
                        err = -ENODEV;
                        goto out_unmap_rdist;
@@ -2151,7 +2172,7 @@ gic_acpi_parse_madt_redist(union acpi_subtable_headers *header,
                pr_err("Couldn't map GICR region @%llx\n", redist->base_address);
                return -ENOMEM;
        }
-       request_mem_region(redist->base_address, redist->length, "GICR");
+       gic_request_region(redist->base_address, redist->length, "GICR");
 
        gic_acpi_register_redist(redist->base_address, redist_base);
        return 0;
@@ -2174,7 +2195,7 @@ gic_acpi_parse_madt_gicc(union acpi_subtable_headers *header,
        redist_base = ioremap(gicc->gicr_base_address, size);
        if (!redist_base)
                return -ENOMEM;
-       request_mem_region(gicc->gicr_base_address, size, "GICR");
+       gic_request_region(gicc->gicr_base_address, size, "GICR");
 
        gic_acpi_register_redist(gicc->gicr_base_address, redist_base);
        return 0;
@@ -2376,7 +2397,7 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
                pr_err("Unable to map GICD registers\n");
                return -ENOMEM;
        }
-       request_mem_region(dist->base_address, ACPI_GICV3_DIST_MEM_SIZE, "GICD");
+       gic_request_region(dist->base_address, ACPI_GICV3_DIST_MEM_SIZE, "GICD");
 
        err = gic_validate_dist_version(acpi_data.dist_base);
        if (err) {
index 49b47e78764483b0eb01ed462446d43692897619..f289ccd952914e1e2b1fa64f0ee83fb5c65722a5 100644 (file)
@@ -66,7 +66,6 @@ static struct or1k_pic_dev or1k_pic_level = {
                .name = "or1k-PIC-level",
                .irq_unmask = or1k_pic_unmask,
                .irq_mask = or1k_pic_mask,
-               .irq_mask_ack = or1k_pic_mask_ack,
        },
        .handle = handle_level_irq,
        .flags = IRQ_LEVEL | IRQ_NOPROBE,
index 20e53b167f81f5d4dd03507edb9eb93bf3ed7411..c8539d0e12dd76841e1ffe364d30c1ea65d9ddad 100644 (file)
@@ -7304,7 +7304,9 @@ static struct r5conf *setup_conf(struct mddev *mddev)
                goto abort;
        conf->mddev = mddev;
 
-       if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL)
+       ret = -ENOMEM;
+       conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!conf->stripe_hashtbl)
                goto abort;
 
        /* We init hash_locks[0] separately to that it can be used
index 1ef9b61077c44e82fb632d79ede3096c4e05a8d0..f150d8769f1986fdab8d16aea6d7f83c4ae25a75 100644 (file)
@@ -631,16 +631,20 @@ static int rtsx_usb_probe(struct usb_interface *intf,
 
        ucr->pusb_dev = usb_dev;
 
-       ucr->iobuf = usb_alloc_coherent(ucr->pusb_dev, IOBUF_SIZE,
-                       GFP_KERNEL, &ucr->iobuf_dma);
-       if (!ucr->iobuf)
+       ucr->cmd_buf = kmalloc(IOBUF_SIZE, GFP_KERNEL);
+       if (!ucr->cmd_buf)
                return -ENOMEM;
 
+       ucr->rsp_buf = kmalloc(IOBUF_SIZE, GFP_KERNEL);
+       if (!ucr->rsp_buf) {
+               ret = -ENOMEM;
+               goto out_free_cmd_buf;
+       }
+
        usb_set_intfdata(intf, ucr);
 
        ucr->vendor_id = id->idVendor;
        ucr->product_id = id->idProduct;
-       ucr->cmd_buf = ucr->rsp_buf = ucr->iobuf;
 
        mutex_init(&ucr->dev_mutex);
 
@@ -668,8 +672,11 @@ static int rtsx_usb_probe(struct usb_interface *intf,
 
 out_init_fail:
        usb_set_intfdata(ucr->pusb_intf, NULL);
-       usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
-                       ucr->iobuf_dma);
+       kfree(ucr->rsp_buf);
+       ucr->rsp_buf = NULL;
+out_free_cmd_buf:
+       kfree(ucr->cmd_buf);
+       ucr->cmd_buf = NULL;
        return ret;
 }
 
@@ -682,8 +689,12 @@ static void rtsx_usb_disconnect(struct usb_interface *intf)
        mfd_remove_devices(&intf->dev);
 
        usb_set_intfdata(ucr->pusb_intf, NULL);
-       usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
-                       ucr->iobuf_dma);
+
+       kfree(ucr->cmd_buf);
+       ucr->cmd_buf = NULL;
+
+       kfree(ucr->rsp_buf);
+       ucr->rsp_buf = NULL;
 }
 
 #ifdef CONFIG_PM
index c9c56fd194c1301f97fea1d48b94b2e2a156d6c6..bdffc6543f6f8b7f7addb03744544e7af60c1be4 100644 (file)
@@ -80,10 +80,9 @@ static int at25_ee_read(void *priv, unsigned int offset,
        struct at25_data *at25 = priv;
        char *buf = val;
        size_t max_chunk = spi_max_transfer_size(at25->spi);
-       size_t num_msgs = DIV_ROUND_UP(count, max_chunk);
-       size_t nr_bytes = 0;
-       unsigned int msg_offset;
-       size_t msg_count;
+       unsigned int msg_offset = offset;
+       size_t bytes_left = count;
+       size_t segment;
        u8                      *cp;
        ssize_t                 status;
        struct spi_transfer     t[2];
@@ -97,9 +96,8 @@ static int at25_ee_read(void *priv, unsigned int offset,
        if (unlikely(!count))
                return -EINVAL;
 
-       msg_offset = (unsigned int)offset;
-       msg_count = min(count, max_chunk);
-       while (num_msgs) {
+       do {
+               segment = min(bytes_left, max_chunk);
                cp = at25->command;
 
                instr = AT25_READ;
@@ -131,8 +129,8 @@ static int at25_ee_read(void *priv, unsigned int offset,
                t[0].len = at25->addrlen + 1;
                spi_message_add_tail(&t[0], &m);
 
-               t[1].rx_buf = buf + nr_bytes;
-               t[1].len = msg_count;
+               t[1].rx_buf = buf;
+               t[1].len = segment;
                spi_message_add_tail(&t[1], &m);
 
                status = spi_sync(at25->spi, &m);
@@ -142,10 +140,10 @@ static int at25_ee_read(void *priv, unsigned int offset,
                if (status)
                        return status;
 
-               --num_msgs;
-               msg_offset += msg_count;
-               nr_bytes += msg_count;
-       }
+               msg_offset += segment;
+               buf += segment;
+               bytes_left -= segment;
+       } while (bytes_left > 0);
 
        dev_dbg(&at25->spi->dev, "read %zu bytes at %d\n",
                count, offset);
@@ -229,7 +227,7 @@ static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count)
        do {
                unsigned long   timeout, retries;
                unsigned        segment;
-               unsigned        offset = (unsigned) off;
+               unsigned        offset = off;
                u8              *cp = bounce;
                int             sr;
                u8              instr;
index 2e0aa74ac18503becc7cac6fa6db59b853bd6802..95ef971b5e1cb4ce836fa0d2286ee2d81e28d8ce 100644 (file)
@@ -13,10 +13,13 @@ lkdtm-$(CONFIG_LKDTM)               += cfi.o
 lkdtm-$(CONFIG_LKDTM)          += fortify.o
 lkdtm-$(CONFIG_PPC_64S_HASH_MMU)       += powerpc.o
 
-KASAN_SANITIZE_rodata.o                := n
 KASAN_SANITIZE_stackleak.o     := n
-KCOV_INSTRUMENT_rodata.o       := n
-CFLAGS_REMOVE_rodata.o         += $(CC_FLAGS_LTO)
+
+KASAN_SANITIZE_rodata.o                        := n
+KCSAN_SANITIZE_rodata.o                        := n
+KCOV_INSTRUMENT_rodata.o               := n
+OBJECT_FILES_NON_STANDARD_rodata.o     := y
+CFLAGS_REMOVE_rodata.o                 += $(CC_FLAGS_LTO) $(RETHUNK_CFLAGS)
 
 OBJCOPYFLAGS :=
 OBJCOPYFLAGS_rodata_objcopy.o  := \
index 86e867ffbb10a0e2691684ace11d1912f1fb93f7..033be559a730946882a6f954d64b89f7508b8e80 100644 (file)
@@ -1298,8 +1298,9 @@ static int sdhci_omap_probe(struct platform_device *pdev)
        /*
         * omap_device_pm_domain has callbacks to enable the main
         * functional clock, interface clock and also configure the
-        * SYSCONFIG register of omap devices. The callback will be invoked
-        * as part of pm_runtime_get_sync.
+        * SYSCONFIG register to clear any boot loader set voltage
+        * capabilities before calling sdhci_setup_host(). The
+        * callback will be invoked as part of pm_runtime_get_sync.
         */
        pm_runtime_use_autosuspend(dev);
        pm_runtime_set_autosuspend_delay(dev, 50);
@@ -1441,7 +1442,8 @@ static int __maybe_unused sdhci_omap_runtime_suspend(struct device *dev)
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
 
-       sdhci_runtime_suspend_host(host);
+       if (omap_host->con != -EINVAL)
+               sdhci_runtime_suspend_host(host);
 
        sdhci_omap_context_save(omap_host);
 
@@ -1458,10 +1460,10 @@ static int __maybe_unused sdhci_omap_runtime_resume(struct device *dev)
 
        pinctrl_pm_select_default_state(dev);
 
-       if (omap_host->con != -EINVAL)
+       if (omap_host->con != -EINVAL) {
                sdhci_omap_context_restore(omap_host);
-
-       sdhci_runtime_resume_host(host, 0);
+               sdhci_runtime_resume_host(host, 0);
+       }
 
        return 0;
 }
index 889e403299568151a7e8417cbdc7a12c47dbed60..93da23682d862c3ea2c0407ee332cc165fd54304 100644 (file)
@@ -850,9 +850,10 @@ static int gpmi_nfc_compute_timings(struct gpmi_nand_data *this,
        unsigned int tRP_ps;
        bool use_half_period;
        int sample_delay_ps, sample_delay_factor;
-       u16 busy_timeout_cycles;
+       unsigned int busy_timeout_cycles;
        u8 wrn_dly_sel;
        unsigned long clk_rate, min_rate;
+       u64 busy_timeout_ps;
 
        if (sdr->tRC_min >= 30000) {
                /* ONFI non-EDO modes [0-3] */
@@ -885,7 +886,8 @@ static int gpmi_nfc_compute_timings(struct gpmi_nand_data *this,
        addr_setup_cycles = TO_CYCLES(sdr->tALS_min, period_ps);
        data_setup_cycles = TO_CYCLES(sdr->tDS_min, period_ps);
        data_hold_cycles = TO_CYCLES(sdr->tDH_min, period_ps);
-       busy_timeout_cycles = TO_CYCLES(sdr->tWB_max + sdr->tR_max, period_ps);
+       busy_timeout_ps = max(sdr->tBERS_max, sdr->tPROG_max);
+       busy_timeout_cycles = TO_CYCLES(busy_timeout_ps, period_ps);
 
        hw->timing0 = BF_GPMI_TIMING0_ADDRESS_SETUP(addr_setup_cycles) |
                      BF_GPMI_TIMING0_DATA_HOLD(data_hold_cycles) |
index b2a4f998c180e9c72892724659c4e327db822d33..8c1eeb5a8db8373a0b277c71630d69cdc73e4a77 100644 (file)
@@ -94,6 +94,7 @@ config WIREGUARD
        select CRYPTO_CURVE25519_NEON if ARM && KERNEL_MODE_NEON
        select CRYPTO_CHACHA_MIPS if CPU_MIPS32_R2
        select CRYPTO_POLY1305_MIPS if MIPS
+       select CRYPTO_CHACHA_S390 if S390
        help
          WireGuard is a secure, fast, and easy to use replacement for IPSec
          that uses modern cryptography and clever networking tricks. It's
index be2719a3ba702b634feb190cebeebe288b8adc56..e019526e1df67527803363da684448d7f55ddae8 100644 (file)
@@ -563,7 +563,7 @@ static struct sk_buff *amt_build_igmp_gq(struct amt_dev *amt)
        ihv3->nsrcs     = 0;
        ihv3->resv      = 0;
        ihv3->suppress  = false;
-       ihv3->qrv       = amt->net->ipv4.sysctl_igmp_qrv;
+       ihv3->qrv       = READ_ONCE(amt->net->ipv4.sysctl_igmp_qrv);
        ihv3->csum      = 0;
        csum            = &ihv3->csum;
        csum_start      = (void *)ihv3;
@@ -577,14 +577,14 @@ static struct sk_buff *amt_build_igmp_gq(struct amt_dev *amt)
        return skb;
 }
 
-static void __amt_update_gw_status(struct amt_dev *amt, enum amt_status status,
-                                  bool validate)
+static void amt_update_gw_status(struct amt_dev *amt, enum amt_status status,
+                                bool validate)
 {
        if (validate && amt->status >= status)
                return;
        netdev_dbg(amt->dev, "Update GW status %s -> %s",
                   status_str[amt->status], status_str[status]);
-       amt->status = status;
+       WRITE_ONCE(amt->status, status);
 }
 
 static void __amt_update_relay_status(struct amt_tunnel_list *tunnel,
@@ -600,14 +600,6 @@ static void __amt_update_relay_status(struct amt_tunnel_list *tunnel,
        tunnel->status = status;
 }
 
-static void amt_update_gw_status(struct amt_dev *amt, enum amt_status status,
-                                bool validate)
-{
-       spin_lock_bh(&amt->lock);
-       __amt_update_gw_status(amt, status, validate);
-       spin_unlock_bh(&amt->lock);
-}
-
 static void amt_update_relay_status(struct amt_tunnel_list *tunnel,
                                    enum amt_status status, bool validate)
 {
@@ -700,9 +692,7 @@ static void amt_send_discovery(struct amt_dev *amt)
        if (unlikely(net_xmit_eval(err)))
                amt->dev->stats.tx_errors++;
 
-       spin_lock_bh(&amt->lock);
-       __amt_update_gw_status(amt, AMT_STATUS_SENT_DISCOVERY, true);
-       spin_unlock_bh(&amt->lock);
+       amt_update_gw_status(amt, AMT_STATUS_SENT_DISCOVERY, true);
 out:
        rcu_read_unlock();
 }
@@ -900,6 +890,28 @@ static void amt_send_mld_gq(struct amt_dev *amt, struct amt_tunnel_list *tunnel)
 }
 #endif
 
+static bool amt_queue_event(struct amt_dev *amt, enum amt_event event,
+                           struct sk_buff *skb)
+{
+       int index;
+
+       spin_lock_bh(&amt->lock);
+       if (amt->nr_events >= AMT_MAX_EVENTS) {
+               spin_unlock_bh(&amt->lock);
+               return 1;
+       }
+
+       index = (amt->event_idx + amt->nr_events) % AMT_MAX_EVENTS;
+       amt->events[index].event = event;
+       amt->events[index].skb = skb;
+       amt->nr_events++;
+       amt->event_idx %= AMT_MAX_EVENTS;
+       queue_work(amt_wq, &amt->event_wq);
+       spin_unlock_bh(&amt->lock);
+
+       return 0;
+}
+
 static void amt_secret_work(struct work_struct *work)
 {
        struct amt_dev *amt = container_of(to_delayed_work(work),
@@ -913,58 +925,72 @@ static void amt_secret_work(struct work_struct *work)
                         msecs_to_jiffies(AMT_SECRET_TIMEOUT));
 }
 
-static void amt_discovery_work(struct work_struct *work)
+static void amt_event_send_discovery(struct amt_dev *amt)
 {
-       struct amt_dev *amt = container_of(to_delayed_work(work),
-                                          struct amt_dev,
-                                          discovery_wq);
-
-       spin_lock_bh(&amt->lock);
        if (amt->status > AMT_STATUS_SENT_DISCOVERY)
                goto out;
        get_random_bytes(&amt->nonce, sizeof(__be32));
-       spin_unlock_bh(&amt->lock);
 
        amt_send_discovery(amt);
-       spin_lock_bh(&amt->lock);
 out:
        mod_delayed_work(amt_wq, &amt->discovery_wq,
                         msecs_to_jiffies(AMT_DISCOVERY_TIMEOUT));
-       spin_unlock_bh(&amt->lock);
 }
 
-static void amt_req_work(struct work_struct *work)
+static void amt_discovery_work(struct work_struct *work)
 {
        struct amt_dev *amt = container_of(to_delayed_work(work),
                                           struct amt_dev,
-                                          req_wq);
+                                          discovery_wq);
+
+       if (amt_queue_event(amt, AMT_EVENT_SEND_DISCOVERY, NULL))
+               mod_delayed_work(amt_wq, &amt->discovery_wq,
+                                msecs_to_jiffies(AMT_DISCOVERY_TIMEOUT));
+}
+
+static void amt_event_send_request(struct amt_dev *amt)
+{
        u32 exp;
 
-       spin_lock_bh(&amt->lock);
        if (amt->status < AMT_STATUS_RECEIVED_ADVERTISEMENT)
                goto out;
 
        if (amt->req_cnt > AMT_MAX_REQ_COUNT) {
                netdev_dbg(amt->dev, "Gateway is not ready");
                amt->qi = AMT_INIT_REQ_TIMEOUT;
-               amt->ready4 = false;
-               amt->ready6 = false;
+               WRITE_ONCE(amt->ready4, false);
+               WRITE_ONCE(amt->ready6, false);
                amt->remote_ip = 0;
-               __amt_update_gw_status(amt, AMT_STATUS_INIT, false);
+               amt_update_gw_status(amt, AMT_STATUS_INIT, false);
                amt->req_cnt = 0;
+               amt->nonce = 0;
                goto out;
        }
-       spin_unlock_bh(&amt->lock);
+
+       if (!amt->req_cnt) {
+               WRITE_ONCE(amt->ready4, false);
+               WRITE_ONCE(amt->ready6, false);
+               get_random_bytes(&amt->nonce, sizeof(__be32));
+       }
 
        amt_send_request(amt, false);
        amt_send_request(amt, true);
-       spin_lock_bh(&amt->lock);
-       __amt_update_gw_status(amt, AMT_STATUS_SENT_REQUEST, true);
+       amt_update_gw_status(amt, AMT_STATUS_SENT_REQUEST, true);
        amt->req_cnt++;
 out:
        exp = min_t(u32, (1 * (1 << amt->req_cnt)), AMT_MAX_REQ_TIMEOUT);
        mod_delayed_work(amt_wq, &amt->req_wq, msecs_to_jiffies(exp * 1000));
-       spin_unlock_bh(&amt->lock);
+}
+
+static void amt_req_work(struct work_struct *work)
+{
+       struct amt_dev *amt = container_of(to_delayed_work(work),
+                                          struct amt_dev,
+                                          req_wq);
+
+       if (amt_queue_event(amt, AMT_EVENT_SEND_REQUEST, NULL))
+               mod_delayed_work(amt_wq, &amt->req_wq,
+                                msecs_to_jiffies(100));
 }
 
 static bool amt_send_membership_update(struct amt_dev *amt,
@@ -1220,7 +1246,8 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
                /* Gateway only passes IGMP/MLD packets */
                if (!report)
                        goto free;
-               if ((!v6 && !amt->ready4) || (v6 && !amt->ready6))
+               if ((!v6 && !READ_ONCE(amt->ready4)) ||
+                   (v6 && !READ_ONCE(amt->ready6)))
                        goto free;
                if (amt_send_membership_update(amt, skb,  v6))
                        goto free;
@@ -2236,6 +2263,10 @@ static bool amt_advertisement_handler(struct amt_dev *amt, struct sk_buff *skb)
            ipv4_is_zeronet(amta->ip4))
                return true;
 
+       if (amt->status != AMT_STATUS_SENT_DISCOVERY ||
+           amt->nonce != amta->nonce)
+               return true;
+
        amt->remote_ip = amta->ip4;
        netdev_dbg(amt->dev, "advertised remote ip = %pI4\n", &amt->remote_ip);
        mod_delayed_work(amt_wq, &amt->req_wq, 0);
@@ -2251,6 +2282,9 @@ static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb)
        struct ethhdr *eth;
        struct iphdr *iph;
 
+       if (READ_ONCE(amt->status) != AMT_STATUS_SENT_UPDATE)
+               return true;
+
        hdr_size = sizeof(*amtmd) + sizeof(struct udphdr);
        if (!pskb_may_pull(skb, hdr_size))
                return true;
@@ -2325,6 +2359,9 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
        if (amtmq->reserved || amtmq->version)
                return true;
 
+       if (amtmq->nonce != amt->nonce)
+               return true;
+
        hdr_size -= sizeof(*eth);
        if (iptunnel_pull_header(skb, hdr_size, htons(ETH_P_TEB), false))
                return true;
@@ -2339,6 +2376,9 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
 
        iph = ip_hdr(skb);
        if (iph->version == 4) {
+               if (READ_ONCE(amt->ready4))
+                       return true;
+
                if (!pskb_may_pull(skb, sizeof(*iph) + AMT_IPHDR_OPTS +
                                   sizeof(*ihv3)))
                        return true;
@@ -2349,12 +2389,10 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
                ihv3 = skb_pull(skb, sizeof(*iph) + AMT_IPHDR_OPTS);
                skb_reset_transport_header(skb);
                skb_push(skb, sizeof(*iph) + AMT_IPHDR_OPTS);
-               spin_lock_bh(&amt->lock);
-               amt->ready4 = true;
+               WRITE_ONCE(amt->ready4, true);
                amt->mac = amtmq->response_mac;
                amt->req_cnt = 0;
                amt->qi = ihv3->qqic;
-               spin_unlock_bh(&amt->lock);
                skb->protocol = htons(ETH_P_IP);
                eth->h_proto = htons(ETH_P_IP);
                ip_eth_mc_map(iph->daddr, eth->h_dest);
@@ -2363,6 +2401,9 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
                struct mld2_query *mld2q;
                struct ipv6hdr *ip6h;
 
+               if (READ_ONCE(amt->ready6))
+                       return true;
+
                if (!pskb_may_pull(skb, sizeof(*ip6h) + AMT_IP6HDR_OPTS +
                                   sizeof(*mld2q)))
                        return true;
@@ -2374,12 +2415,10 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
                mld2q = skb_pull(skb, sizeof(*ip6h) + AMT_IP6HDR_OPTS);
                skb_reset_transport_header(skb);
                skb_push(skb, sizeof(*ip6h) + AMT_IP6HDR_OPTS);
-               spin_lock_bh(&amt->lock);
-               amt->ready6 = true;
+               WRITE_ONCE(amt->ready6, true);
                amt->mac = amtmq->response_mac;
                amt->req_cnt = 0;
                amt->qi = mld2q->mld2q_qqic;
-               spin_unlock_bh(&amt->lock);
                skb->protocol = htons(ETH_P_IPV6);
                eth->h_proto = htons(ETH_P_IPV6);
                ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
@@ -2392,12 +2431,14 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
        skb->pkt_type = PACKET_MULTICAST;
        skb->ip_summed = CHECKSUM_NONE;
        len = skb->len;
+       local_bh_disable();
        if (__netif_rx(skb) == NET_RX_SUCCESS) {
                amt_update_gw_status(amt, AMT_STATUS_RECEIVED_QUERY, true);
                dev_sw_netstats_rx_add(amt->dev, len);
        } else {
                amt->dev->stats.rx_dropped++;
        }
+       local_bh_enable();
 
        return false;
 }
@@ -2638,7 +2679,9 @@ static bool amt_request_handler(struct amt_dev *amt, struct sk_buff *skb)
                if (tunnel->ip4 == iph->saddr)
                        goto send;
 
+       spin_lock_bh(&amt->lock);
        if (amt->nr_tunnels >= amt->max_tunnels) {
+               spin_unlock_bh(&amt->lock);
                icmp_ndo_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
                return true;
        }
@@ -2646,8 +2689,10 @@ static bool amt_request_handler(struct amt_dev *amt, struct sk_buff *skb)
        tunnel = kzalloc(sizeof(*tunnel) +
                         (sizeof(struct hlist_head) * amt->hash_buckets),
                         GFP_ATOMIC);
-       if (!tunnel)
+       if (!tunnel) {
+               spin_unlock_bh(&amt->lock);
                return true;
+       }
 
        tunnel->source_port = udph->source;
        tunnel->ip4 = iph->saddr;
@@ -2660,10 +2705,9 @@ static bool amt_request_handler(struct amt_dev *amt, struct sk_buff *skb)
 
        INIT_DELAYED_WORK(&tunnel->gc_wq, amt_tunnel_expire);
 
-       spin_lock_bh(&amt->lock);
        list_add_tail_rcu(&tunnel->list, &amt->tunnel_list);
        tunnel->key = amt->key;
-       amt_update_relay_status(tunnel, AMT_STATUS_RECEIVED_REQUEST, true);
+       __amt_update_relay_status(tunnel, AMT_STATUS_RECEIVED_REQUEST, true);
        amt->nr_tunnels++;
        mod_delayed_work(amt_wq, &tunnel->gc_wq,
                         msecs_to_jiffies(amt_gmi(amt)));
@@ -2688,6 +2732,38 @@ send:
        return false;
 }
 
+static void amt_gw_rcv(struct amt_dev *amt, struct sk_buff *skb)
+{
+       int type = amt_parse_type(skb);
+       int err = 1;
+
+       if (type == -1)
+               goto drop;
+
+       if (amt->mode == AMT_MODE_GATEWAY) {
+               switch (type) {
+               case AMT_MSG_ADVERTISEMENT:
+                       err = amt_advertisement_handler(amt, skb);
+                       break;
+               case AMT_MSG_MEMBERSHIP_QUERY:
+                       err = amt_membership_query_handler(amt, skb);
+                       if (!err)
+                               return;
+                       break;
+               default:
+                       netdev_dbg(amt->dev, "Invalid type of Gateway\n");
+                       break;
+               }
+       }
+drop:
+       if (err) {
+               amt->dev->stats.rx_dropped++;
+               kfree_skb(skb);
+       } else {
+               consume_skb(skb);
+       }
+}
+
 static int amt_rcv(struct sock *sk, struct sk_buff *skb)
 {
        struct amt_dev *amt;
@@ -2719,8 +2795,12 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
                                err = true;
                                goto drop;
                        }
-                       err = amt_advertisement_handler(amt, skb);
-                       break;
+                       if (amt_queue_event(amt, AMT_EVENT_RECEIVE, skb)) {
+                               netdev_dbg(amt->dev, "AMT Event queue full\n");
+                               err = true;
+                               goto drop;
+                       }
+                       goto out;
                case AMT_MSG_MULTICAST_DATA:
                        if (iph->saddr != amt->remote_ip) {
                                netdev_dbg(amt->dev, "Invalid Relay IP\n");
@@ -2738,11 +2818,12 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
                                err = true;
                                goto drop;
                        }
-                       err = amt_membership_query_handler(amt, skb);
-                       if (err)
+                       if (amt_queue_event(amt, AMT_EVENT_RECEIVE, skb)) {
+                               netdev_dbg(amt->dev, "AMT Event queue full\n");
+                               err = true;
                                goto drop;
-                       else
-                               goto out;
+                       }
+                       goto out;
                default:
                        err = true;
                        netdev_dbg(amt->dev, "Invalid type of Gateway\n");
@@ -2780,6 +2861,46 @@ out:
        return 0;
 }
 
+static void amt_event_work(struct work_struct *work)
+{
+       struct amt_dev *amt = container_of(work, struct amt_dev, event_wq);
+       struct sk_buff *skb;
+       u8 event;
+       int i;
+
+       for (i = 0; i < AMT_MAX_EVENTS; i++) {
+               spin_lock_bh(&amt->lock);
+               if (amt->nr_events == 0) {
+                       spin_unlock_bh(&amt->lock);
+                       return;
+               }
+               event = amt->events[amt->event_idx].event;
+               skb = amt->events[amt->event_idx].skb;
+               amt->events[amt->event_idx].event = AMT_EVENT_NONE;
+               amt->events[amt->event_idx].skb = NULL;
+               amt->nr_events--;
+               amt->event_idx++;
+               amt->event_idx %= AMT_MAX_EVENTS;
+               spin_unlock_bh(&amt->lock);
+
+               switch (event) {
+               case AMT_EVENT_RECEIVE:
+                       amt_gw_rcv(amt, skb);
+                       break;
+               case AMT_EVENT_SEND_DISCOVERY:
+                       amt_event_send_discovery(amt);
+                       break;
+               case AMT_EVENT_SEND_REQUEST:
+                       amt_event_send_request(amt);
+                       break;
+               default:
+                       if (skb)
+                               kfree_skb(skb);
+                       break;
+               }
+       }
+}
+
 static int amt_err_lookup(struct sock *sk, struct sk_buff *skb)
 {
        struct amt_dev *amt;
@@ -2804,7 +2925,7 @@ static int amt_err_lookup(struct sock *sk, struct sk_buff *skb)
                break;
        case AMT_MSG_REQUEST:
        case AMT_MSG_MEMBERSHIP_UPDATE:
-               if (amt->status >= AMT_STATUS_RECEIVED_ADVERTISEMENT)
+               if (READ_ONCE(amt->status) >= AMT_STATUS_RECEIVED_ADVERTISEMENT)
                        mod_delayed_work(amt_wq, &amt->req_wq, 0);
                break;
        default:
@@ -2867,6 +2988,8 @@ static int amt_dev_open(struct net_device *dev)
 
        amt->ready4 = false;
        amt->ready6 = false;
+       amt->event_idx = 0;
+       amt->nr_events = 0;
 
        err = amt_socket_create(amt);
        if (err)
@@ -2874,6 +2997,7 @@ static int amt_dev_open(struct net_device *dev)
 
        amt->req_cnt = 0;
        amt->remote_ip = 0;
+       amt->nonce = 0;
        get_random_bytes(&amt->key, sizeof(siphash_key_t));
 
        amt->status = AMT_STATUS_INIT;
@@ -2892,6 +3016,8 @@ static int amt_dev_stop(struct net_device *dev)
        struct amt_dev *amt = netdev_priv(dev);
        struct amt_tunnel_list *tunnel, *tmp;
        struct socket *sock;
+       struct sk_buff *skb;
+       int i;
 
        cancel_delayed_work_sync(&amt->req_wq);
        cancel_delayed_work_sync(&amt->discovery_wq);
@@ -2904,6 +3030,15 @@ static int amt_dev_stop(struct net_device *dev)
        if (sock)
                udp_tunnel_sock_release(sock);
 
+       cancel_work_sync(&amt->event_wq);
+       for (i = 0; i < AMT_MAX_EVENTS; i++) {
+               skb = amt->events[i].skb;
+               if (skb)
+                       kfree_skb(skb);
+               amt->events[i].event = AMT_EVENT_NONE;
+               amt->events[i].skb = NULL;
+       }
+
        amt->ready4 = false;
        amt->ready6 = false;
        amt->req_cnt = 0;
@@ -3095,7 +3230,7 @@ static int amt_newlink(struct net *net, struct net_device *dev,
                goto err;
        }
        if (amt->mode == AMT_MODE_RELAY) {
-               amt->qrv = amt->net->ipv4.sysctl_igmp_qrv;
+               amt->qrv = READ_ONCE(amt->net->ipv4.sysctl_igmp_qrv);
                amt->qri = 10;
                dev->needed_headroom = amt->stream_dev->needed_headroom +
                                       AMT_RELAY_HLEN;
@@ -3146,8 +3281,8 @@ static int amt_newlink(struct net *net, struct net_device *dev,
        INIT_DELAYED_WORK(&amt->discovery_wq, amt_discovery_work);
        INIT_DELAYED_WORK(&amt->req_wq, amt_req_work);
        INIT_DELAYED_WORK(&amt->secret_wq, amt_secret_work);
+       INIT_WORK(&amt->event_wq, amt_event_work);
        INIT_LIST_HEAD(&amt->tunnel_list);
-
        return 0;
 err:
        dev_put(amt->stream_dev);
@@ -3280,7 +3415,7 @@ static int __init amt_init(void)
        if (err < 0)
                goto unregister_notifier;
 
-       amt_wq = alloc_workqueue("amt", WQ_UNBOUND, 1);
+       amt_wq = alloc_workqueue("amt", WQ_UNBOUND, 0);
        if (!amt_wq) {
                err = -ENOMEM;
                goto rtnl_unregister;
index 76df4807d3666b3dc5abc332b29f33c29f1f0591..4c47c1055eff9367c009f88352b33f60df172aad 100644 (file)
@@ -1646,7 +1646,6 @@ static int grcan_probe(struct platform_device *ofdev)
         */
        sysid_parent = of_find_node_by_path("/ambapp0");
        if (sysid_parent) {
-               of_node_get(sysid_parent);
                err = of_property_read_u32(sysid_parent, "systemid", &sysid);
                if (!err && ((sysid & GRLIB_VERSION_MASK) >=
                             GRCAN_TXBUG_SAFE_GRLIB_VERSION))
index 5d0c82d8b9a9f16a898cacd5fc657186ceb47f7b..7931f9c71ef3175cac93b702e209793d43c6b895 100644 (file)
@@ -529,7 +529,7 @@ static int m_can_read_fifo(struct net_device *dev, u32 rxfs)
        /* acknowledge rx fifo 0 */
        m_can_write(cdev, M_CAN_RXF0A, fgi);
 
-       timestamp = FIELD_GET(RX_BUF_RXTS_MASK, fifo_header.dlc);
+       timestamp = FIELD_GET(RX_BUF_RXTS_MASK, fifo_header.dlc) << 16;
 
        m_can_receive_skb(cdev, skb, timestamp);
 
@@ -1030,7 +1030,7 @@ static int m_can_echo_tx_event(struct net_device *dev)
                }
 
                msg_mark = FIELD_GET(TX_EVENT_MM_MASK, txe);
-               timestamp = FIELD_GET(TX_EVENT_TXTS_MASK, txe);
+               timestamp = FIELD_GET(TX_EVENT_TXTS_MASK, txe) << 16;
 
                /* ack txe element */
                m_can_write(cdev, M_CAN_TXEFA, FIELD_PREP(TXEFA_EFAI_MASK,
@@ -1351,7 +1351,9 @@ static void m_can_chip_config(struct net_device *dev)
        /* enable internal timestamp generation, with a prescalar of 16. The
         * prescalar is applied to the nominal bit timing
         */
-       m_can_write(cdev, M_CAN_TSCC, FIELD_PREP(TSCC_TCP_MASK, 0xf));
+       m_can_write(cdev, M_CAN_TSCC,
+                   FIELD_PREP(TSCC_TCP_MASK, 0xf) |
+                   FIELD_PREP(TSCC_TSS_MASK, TSCC_TSS_INTERNAL));
 
        m_can_config_endisable(cdev, false);
 
index 40a11445d021e98acfb3369bc47bfc556e021da9..cb0321ea853c107913499e0c547d9d15768d699d 100644 (file)
@@ -1332,7 +1332,10 @@ static void rcar_canfd_set_bittiming(struct net_device *dev)
                cfg = (RCANFD_DCFG_DTSEG1(gpriv, tseg1) | RCANFD_DCFG_DBRP(brp) |
                       RCANFD_DCFG_DSJW(sjw) | RCANFD_DCFG_DTSEG2(gpriv, tseg2));
 
-               rcar_canfd_write(priv->base, RCANFD_F_DCFG(ch), cfg);
+               if (is_v3u(gpriv))
+                       rcar_canfd_write(priv->base, RCANFD_V3U_DCFG(ch), cfg);
+               else
+                       rcar_canfd_write(priv->base, RCANFD_F_DCFG(ch), cfg);
                netdev_dbg(priv->ndev, "drate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n",
                           brp, sjw, tseg1, tseg2);
        } else {
@@ -1840,6 +1843,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
                of_child = of_get_child_by_name(pdev->dev.of_node, name);
                if (of_child && of_device_is_available(of_child))
                        channels_mask |= BIT(i);
+               of_node_put(of_child);
        }
 
        if (chip_id != RENESAS_RZG2L) {
index b212523902168eac46f73f902e094e48e5019238..bc6518504fd463ccadb9d2014109838ffe94a24b 100644 (file)
@@ -12,6 +12,7 @@
 // Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>
 //
 
+#include <asm/unaligned.h>
 #include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/device.h>
@@ -1650,6 +1651,7 @@ static int mcp251xfd_stop(struct net_device *ndev)
        netif_stop_queue(ndev);
        set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
        hrtimer_cancel(&priv->rx_irq_timer);
+       hrtimer_cancel(&priv->tx_irq_timer);
        mcp251xfd_chip_interrupts_disable(priv);
        free_irq(ndev->irq, priv);
        can_rx_offload_disable(&priv->offload);
@@ -1688,8 +1690,8 @@ static int mcp251xfd_register_chip_detect(struct mcp251xfd_priv *priv)
        u32 osc;
        int err;
 
-       /* The OSC_LPMEN is only supported on MCP2518FD, so use it to
-        * autodetect the model.
+       /* The OSC_LPMEN is only supported on MCP2518FD and MCP251863,
+        * so use it to autodetect the model.
         */
        err = regmap_update_bits(priv->map_reg, MCP251XFD_REG_OSC,
                                 MCP251XFD_REG_OSC_LPMEN,
@@ -1701,10 +1703,18 @@ static int mcp251xfd_register_chip_detect(struct mcp251xfd_priv *priv)
        if (err)
                return err;
 
-       if (osc & MCP251XFD_REG_OSC_LPMEN)
-               devtype_data = &mcp251xfd_devtype_data_mcp2518fd;
-       else
+       if (osc & MCP251XFD_REG_OSC_LPMEN) {
+               /* We cannot distinguish between MCP2518FD and
+                * MCP251863. If firmware specifies MCP251863, keep
+                * it, otherwise set to MCP2518FD.
+                */
+               if (mcp251xfd_is_251863(priv))
+                       devtype_data = &mcp251xfd_devtype_data_mcp251863;
+               else
+                       devtype_data = &mcp251xfd_devtype_data_mcp2518fd;
+       } else {
                devtype_data = &mcp251xfd_devtype_data_mcp2517fd;
+       }
 
        if (!mcp251xfd_is_251XFD(priv) &&
            priv->devtype_data.model != devtype_data->model) {
@@ -1777,7 +1787,7 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, u32 *dev_id,
        xfer[0].len = sizeof(buf_tx->cmd);
        xfer[0].speed_hz = priv->spi_max_speed_hz_slow;
        xfer[1].rx_buf = buf_rx->data;
-       xfer[1].len = sizeof(dev_id);
+       xfer[1].len = sizeof(*dev_id);
        xfer[1].speed_hz = priv->spi_max_speed_hz_fast;
 
        mcp251xfd_spi_cmd_read_nocrc(&buf_tx->cmd, MCP251XFD_REG_DEVID);
@@ -1786,7 +1796,7 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, u32 *dev_id,
        if (err)
                goto out_kfree_buf_tx;
 
-       *dev_id = be32_to_cpup((__be32 *)buf_rx->data);
+       *dev_id = get_unaligned_le32(buf_rx->data);
        *effective_speed_hz_slow = xfer[0].effective_speed_hz;
        *effective_speed_hz_fast = xfer[1].effective_speed_hz;
 
index 217510c12af5594074e229a01967cfbd0aa0348f..92b7bc7f14b9eb5b28e708b832e9a5e44ed39a8c 100644 (file)
@@ -334,19 +334,21 @@ mcp251xfd_regmap_crc_read(void *context,
                 * register. It increments once per SYS clock tick,
                 * which is 20 or 40 MHz.
                 *
-                * Observation shows that if the lowest byte (which is
-                * transferred first on the SPI bus) of that register
-                * is 0x00 or 0x80 the calculated CRC doesn't always
-                * match the transferred one.
+                * Observation on the mcp2518fd shows that if the
+                * lowest byte (which is transferred first on the SPI
+                * bus) of that register is 0x00 or 0x80 the
+                * calculated CRC doesn't always match the transferred
+                * one. On the mcp2517fd this problem is not limited
+                * to the first byte being 0x00 or 0x80.
                 *
                 * If the highest bit in the lowest byte is flipped
                 * the transferred CRC matches the calculated one. We
-                * assume for now the CRC calculation in the chip
-                * works on wrong data and the transferred data is
-                * correct.
+                * assume for now the CRC operates on the correct
+                * data.
                 */
                if (reg == MCP251XFD_REG_TBC &&
-                   (buf_rx->data[0] == 0x0 || buf_rx->data[0] == 0x80)) {
+                   ((buf_rx->data[0] & 0xf8) == 0x0 ||
+                    (buf_rx->data[0] & 0xf8) == 0x80)) {
                        /* Flip highest bit in lowest byte of le32 */
                        buf_rx->data[0] ^= 0x80;
 
@@ -356,10 +358,8 @@ mcp251xfd_regmap_crc_read(void *context,
                                                                  val_len);
                        if (!err) {
                                /* If CRC is now correct, assume
-                                * transferred data was OK, flip bit
-                                * back to original value.
+                                * flipped data is OK.
                                 */
-                               buf_rx->data[0] ^= 0x80;
                                goto out;
                        }
                }
index b29ba9138866b1d926b660095ec61211c6a818b2..d3a658b444b5f645fb7a579190fe7379bae1279c 100644 (file)
@@ -268,6 +268,8 @@ struct gs_can {
 
        struct usb_anchor tx_submitted;
        atomic_t active_tx_urbs;
+       void *rxbuf[GS_MAX_RX_URBS];
+       dma_addr_t rxbuf_dma[GS_MAX_RX_URBS];
 };
 
 /* usb interface struct */
@@ -742,6 +744,7 @@ static int gs_can_open(struct net_device *netdev)
                for (i = 0; i < GS_MAX_RX_URBS; i++) {
                        struct urb *urb;
                        u8 *buf;
+                       dma_addr_t buf_dma;
 
                        /* alloc rx urb */
                        urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -752,7 +755,7 @@ static int gs_can_open(struct net_device *netdev)
                        buf = usb_alloc_coherent(dev->udev,
                                                 dev->parent->hf_size_rx,
                                                 GFP_KERNEL,
-                                                &urb->transfer_dma);
+                                                &buf_dma);
                        if (!buf) {
                                netdev_err(netdev,
                                           "No memory left for USB buffer\n");
@@ -760,6 +763,8 @@ static int gs_can_open(struct net_device *netdev)
                                return -ENOMEM;
                        }
 
+                       urb->transfer_dma = buf_dma;
+
                        /* fill, anchor, and submit rx urb */
                        usb_fill_bulk_urb(urb,
                                          dev->udev,
@@ -781,10 +786,17 @@ static int gs_can_open(struct net_device *netdev)
                                           "usb_submit failed (err=%d)\n", rc);
 
                                usb_unanchor_urb(urb);
+                               usb_free_coherent(dev->udev,
+                                                 sizeof(struct gs_host_frame),
+                                                 buf,
+                                                 buf_dma);
                                usb_free_urb(urb);
                                break;
                        }
 
+                       dev->rxbuf[i] = buf;
+                       dev->rxbuf_dma[i] = buf_dma;
+
                        /* Drop reference,
                         * USB core will take care of freeing it
                         */
@@ -842,13 +854,20 @@ static int gs_can_close(struct net_device *netdev)
        int rc;
        struct gs_can *dev = netdev_priv(netdev);
        struct gs_usb *parent = dev->parent;
+       unsigned int i;
 
        netif_stop_queue(netdev);
 
        /* Stop polling */
        parent->active_channels--;
-       if (!parent->active_channels)
+       if (!parent->active_channels) {
                usb_kill_anchored_urbs(&parent->rx_submitted);
+               for (i = 0; i < GS_MAX_RX_URBS; i++)
+                       usb_free_coherent(dev->udev,
+                                         sizeof(struct gs_host_frame),
+                                         dev->rxbuf[i],
+                                         dev->rxbuf_dma[i]);
+       }
 
        /* Stop sending URBs */
        usb_kill_anchored_urbs(&dev->tx_submitted);
index 3a49257f9fa6547a59ba0319fac5dbed3fda81b0..eefcbe3aadce752ea513a8501bc38aa776dd2a17 100644 (file)
 #define KVASER_USB_RX_BUFFER_SIZE              3072
 #define KVASER_USB_MAX_NET_DEVICES             5
 
-/* USB devices features */
-#define KVASER_USB_HAS_SILENT_MODE             BIT(0)
-#define KVASER_USB_HAS_TXRX_ERRORS             BIT(1)
+/* Kvaser USB device quirks */
+#define KVASER_USB_QUIRK_HAS_SILENT_MODE       BIT(0)
+#define KVASER_USB_QUIRK_HAS_TXRX_ERRORS       BIT(1)
+#define KVASER_USB_QUIRK_IGNORE_CLK_FREQ       BIT(2)
 
 /* Device capabilities */
 #define KVASER_USB_CAP_BERR_CAP                        0x01
@@ -65,12 +66,7 @@ struct kvaser_usb_dev_card_data_hydra {
 struct kvaser_usb_dev_card_data {
        u32 ctrlmode_supported;
        u32 capabilities;
-       union {
-               struct {
-                       enum kvaser_usb_leaf_family family;
-               } leaf;
-               struct kvaser_usb_dev_card_data_hydra hydra;
-       };
+       struct kvaser_usb_dev_card_data_hydra hydra;
 };
 
 /* Context for an outstanding, not yet ACKed, transmission */
@@ -83,7 +79,7 @@ struct kvaser_usb {
        struct usb_device *udev;
        struct usb_interface *intf;
        struct kvaser_usb_net_priv *nets[KVASER_USB_MAX_NET_DEVICES];
-       const struct kvaser_usb_dev_ops *ops;
+       const struct kvaser_usb_driver_info *driver_info;
        const struct kvaser_usb_dev_cfg *cfg;
 
        struct usb_endpoint_descriptor *bulk_in, *bulk_out;
@@ -165,6 +161,12 @@ struct kvaser_usb_dev_ops {
                                  u16 transid);
 };
 
+struct kvaser_usb_driver_info {
+       u32 quirks;
+       enum kvaser_usb_leaf_family family;
+       const struct kvaser_usb_dev_ops *ops;
+};
+
 struct kvaser_usb_dev_cfg {
        const struct can_clock clock;
        const unsigned int timestamp_freq;
@@ -184,4 +186,7 @@ int kvaser_usb_send_cmd_async(struct kvaser_usb_net_priv *priv, void *cmd,
                              int len);
 
 int kvaser_usb_can_rx_over_error(struct net_device *netdev);
+
+extern const struct can_bittiming_const kvaser_usb_flexc_bittiming_const;
+
 #endif /* KVASER_USB_H */
index e67658b53d02f0d2f0fe32e029d2d5c65832f9f4..f211bfcb1d97e8f05f9ab2bb180619538fa1b578 100644 (file)
@@ -61,8 +61,6 @@
 #define USB_USBCAN_R_V2_PRODUCT_ID             294
 #define USB_LEAF_LIGHT_R_V2_PRODUCT_ID         295
 #define USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID   296
-#define USB_LEAF_PRODUCT_ID_END \
-       USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID
 
 /* Kvaser USBCan-II devices product ids */
 #define USB_USBCAN_REVB_PRODUCT_ID             2
 #define USB_USBCAN_PRO_4HS_PRODUCT_ID          276
 #define USB_HYBRID_CANLIN_PRODUCT_ID           277
 #define USB_HYBRID_PRO_CANLIN_PRODUCT_ID       278
-#define USB_HYDRA_PRODUCT_ID_END \
-       USB_HYBRID_PRO_CANLIN_PRODUCT_ID
 
-static inline bool kvaser_is_leaf(const struct usb_device_id *id)
-{
-       return (id->idProduct >= USB_LEAF_DEVEL_PRODUCT_ID &&
-               id->idProduct <= USB_CAN_R_PRODUCT_ID) ||
-               (id->idProduct >= USB_LEAF_LITE_V2_PRODUCT_ID &&
-                id->idProduct <= USB_LEAF_PRODUCT_ID_END);
-}
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_hydra = {
+       .quirks = 0,
+       .ops = &kvaser_usb_hydra_dev_ops,
+};
 
-static inline bool kvaser_is_usbcan(const struct usb_device_id *id)
-{
-       return id->idProduct >= USB_USBCAN_REVB_PRODUCT_ID &&
-              id->idProduct <= USB_MEMORATOR_PRODUCT_ID;
-}
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_usbcan = {
+       .quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
+                 KVASER_USB_QUIRK_HAS_SILENT_MODE,
+       .family = KVASER_USBCAN,
+       .ops = &kvaser_usb_leaf_dev_ops,
+};
 
-static inline bool kvaser_is_hydra(const struct usb_device_id *id)
-{
-       return id->idProduct >= USB_BLACKBIRD_V2_PRODUCT_ID &&
-              id->idProduct <= USB_HYDRA_PRODUCT_ID_END;
-}
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf = {
+       .quirks = KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
+       .family = KVASER_LEAF,
+       .ops = &kvaser_usb_leaf_dev_ops,
+};
+
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf_err = {
+       .quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
+                 KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
+       .family = KVASER_LEAF,
+       .ops = &kvaser_usb_leaf_dev_ops,
+};
+
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf_err_listen = {
+       .quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
+                 KVASER_USB_QUIRK_HAS_SILENT_MODE |
+                 KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
+       .family = KVASER_LEAF,
+       .ops = &kvaser_usb_leaf_dev_ops,
+};
+
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leafimx = {
+       .quirks = 0,
+       .ops = &kvaser_usb_leaf_dev_ops,
+};
 
 static const struct usb_device_id kvaser_usb_table[] = {
-       /* Leaf USB product IDs */
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
+       /* Leaf M32C USB product IDs */
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID) },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_2HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_2HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_R_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_R_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID) },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
+
+       /* Leaf i.MX28 USB product IDs */
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_2HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_2HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_R_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_R_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
 
        /* USBCANII USB product IDs */
        { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
 
        /* Minihydra USB product IDs */
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_5HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_5HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_4HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_HS_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_2HS_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_2HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_2HS_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_2CANLIN_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_USBCAN_PRO_2HS_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_MEMO_PRO_2HS_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_2CANLIN_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100P_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100S_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_4HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_CANLIN_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_CANLIN_PRODUCT_ID) },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_5HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_5HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_4HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_HS_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_2HS_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_2HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_2HS_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_2CANLIN_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_USBCAN_PRO_2HS_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_MEMO_PRO_2HS_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_2CANLIN_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100P_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100S_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_4HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_CANLIN_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_CANLIN_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
        { }
 };
 MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
@@ -285,6 +320,7 @@ int kvaser_usb_can_rx_over_error(struct net_device *netdev)
 static void kvaser_usb_read_bulk_callback(struct urb *urb)
 {
        struct kvaser_usb *dev = urb->context;
+       const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
        int err;
        unsigned int i;
 
@@ -301,8 +337,8 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb)
                goto resubmit_urb;
        }
 
-       dev->ops->dev_read_bulk_callback(dev, urb->transfer_buffer,
-                                        urb->actual_length);
+       ops->dev_read_bulk_callback(dev, urb->transfer_buffer,
+                                   urb->actual_length);
 
 resubmit_urb:
        usb_fill_bulk_urb(urb, dev->udev,
@@ -396,6 +432,7 @@ static int kvaser_usb_open(struct net_device *netdev)
 {
        struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
        struct kvaser_usb *dev = priv->dev;
+       const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
        int err;
 
        err = open_candev(netdev);
@@ -406,11 +443,11 @@ static int kvaser_usb_open(struct net_device *netdev)
        if (err)
                goto error;
 
-       err = dev->ops->dev_set_opt_mode(priv);
+       err = ops->dev_set_opt_mode(priv);
        if (err)
                goto error;
 
-       err = dev->ops->dev_start_chip(priv);
+       err = ops->dev_start_chip(priv);
        if (err) {
                netdev_warn(netdev, "Cannot start device, error %d\n", err);
                goto error;
@@ -467,22 +504,23 @@ static int kvaser_usb_close(struct net_device *netdev)
 {
        struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
        struct kvaser_usb *dev = priv->dev;
+       const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
        int err;
 
        netif_stop_queue(netdev);
 
-       err = dev->ops->dev_flush_queue(priv);
+       err = ops->dev_flush_queue(priv);
        if (err)
                netdev_warn(netdev, "Cannot flush queue, error %d\n", err);
 
-       if (dev->ops->dev_reset_chip) {
-               err = dev->ops->dev_reset_chip(dev, priv->channel);
+       if (ops->dev_reset_chip) {
+               err = ops->dev_reset_chip(dev, priv->channel);
                if (err)
                        netdev_warn(netdev, "Cannot reset card, error %d\n",
                                    err);
        }
 
-       err = dev->ops->dev_stop_chip(priv);
+       err = ops->dev_stop_chip(priv);
        if (err)
                netdev_warn(netdev, "Cannot stop device, error %d\n", err);
 
@@ -521,6 +559,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 {
        struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
        struct kvaser_usb *dev = priv->dev;
+       const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
        struct net_device_stats *stats = &netdev->stats;
        struct kvaser_usb_tx_urb_context *context = NULL;
        struct urb *urb;
@@ -563,8 +602,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
                goto freeurb;
        }
 
-       buf = dev->ops->dev_frame_to_cmd(priv, skb, &cmd_len,
-                                        context->echo_index);
+       buf = ops->dev_frame_to_cmd(priv, skb, &cmd_len, context->echo_index);
        if (!buf) {
                stats->tx_dropped++;
                dev_kfree_skb(skb);
@@ -648,15 +686,16 @@ static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev)
        }
 }
 
-static int kvaser_usb_init_one(struct kvaser_usb *dev,
-                              const struct usb_device_id *id, int channel)
+static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
 {
        struct net_device *netdev;
        struct kvaser_usb_net_priv *priv;
+       const struct kvaser_usb_driver_info *driver_info = dev->driver_info;
+       const struct kvaser_usb_dev_ops *ops = driver_info->ops;
        int err;
 
-       if (dev->ops->dev_reset_chip) {
-               err = dev->ops->dev_reset_chip(dev, channel);
+       if (ops->dev_reset_chip) {
+               err = ops->dev_reset_chip(dev, channel);
                if (err)
                        return err;
        }
@@ -685,20 +724,19 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev,
        priv->can.state = CAN_STATE_STOPPED;
        priv->can.clock.freq = dev->cfg->clock.freq;
        priv->can.bittiming_const = dev->cfg->bittiming_const;
-       priv->can.do_set_bittiming = dev->ops->dev_set_bittiming;
-       priv->can.do_set_mode = dev->ops->dev_set_mode;
-       if ((id->driver_info & KVASER_USB_HAS_TXRX_ERRORS) ||
+       priv->can.do_set_bittiming = ops->dev_set_bittiming;
+       priv->can.do_set_mode = ops->dev_set_mode;
+       if ((driver_info->quirks & KVASER_USB_QUIRK_HAS_TXRX_ERRORS) ||
            (priv->dev->card_data.capabilities & KVASER_USB_CAP_BERR_CAP))
-               priv->can.do_get_berr_counter = dev->ops->dev_get_berr_counter;
-       if (id->driver_info & KVASER_USB_HAS_SILENT_MODE)
+               priv->can.do_get_berr_counter = ops->dev_get_berr_counter;
+       if (driver_info->quirks & KVASER_USB_QUIRK_HAS_SILENT_MODE)
                priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
 
        priv->can.ctrlmode_supported |= dev->card_data.ctrlmode_supported;
 
        if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
                priv->can.data_bittiming_const = dev->cfg->data_bittiming_const;
-               priv->can.do_set_data_bittiming =
-                                       dev->ops->dev_set_data_bittiming;
+               priv->can.do_set_data_bittiming = ops->dev_set_data_bittiming;
        }
 
        netdev->flags |= IFF_ECHO;
@@ -729,29 +767,22 @@ static int kvaser_usb_probe(struct usb_interface *intf,
        struct kvaser_usb *dev;
        int err;
        int i;
+       const struct kvaser_usb_driver_info *driver_info;
+       const struct kvaser_usb_dev_ops *ops;
+
+       driver_info = (const struct kvaser_usb_driver_info *)id->driver_info;
+       if (!driver_info)
+               return -ENODEV;
 
        dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL);
        if (!dev)
                return -ENOMEM;
 
-       if (kvaser_is_leaf(id)) {
-               dev->card_data.leaf.family = KVASER_LEAF;
-               dev->ops = &kvaser_usb_leaf_dev_ops;
-       } else if (kvaser_is_usbcan(id)) {
-               dev->card_data.leaf.family = KVASER_USBCAN;
-               dev->ops = &kvaser_usb_leaf_dev_ops;
-       } else if (kvaser_is_hydra(id)) {
-               dev->ops = &kvaser_usb_hydra_dev_ops;
-       } else {
-               dev_err(&intf->dev,
-                       "Product ID (%d) is not a supported Kvaser USB device\n",
-                       id->idProduct);
-               return -ENODEV;
-       }
-
        dev->intf = intf;
+       dev->driver_info = driver_info;
+       ops = driver_info->ops;
 
-       err = dev->ops->dev_setup_endpoints(dev);
+       err = ops->dev_setup_endpoints(dev);
        if (err) {
                dev_err(&intf->dev, "Cannot get usb endpoint(s)");
                return err;
@@ -765,22 +796,22 @@ static int kvaser_usb_probe(struct usb_interface *intf,
 
        dev->card_data.ctrlmode_supported = 0;
        dev->card_data.capabilities = 0;
-       err = dev->ops->dev_init_card(dev);
+       err = ops->dev_init_card(dev);
        if (err) {
                dev_err(&intf->dev,
                        "Failed to initialize card, error %d\n", err);
                return err;
        }
 
-       err = dev->ops->dev_get_software_info(dev);
+       err = ops->dev_get_software_info(dev);
        if (err) {
                dev_err(&intf->dev,
                        "Cannot get software info, error %d\n", err);
                return err;
        }
 
-       if (dev->ops->dev_get_software_details) {
-               err = dev->ops->dev_get_software_details(dev);
+       if (ops->dev_get_software_details) {
+               err = ops->dev_get_software_details(dev);
                if (err) {
                        dev_err(&intf->dev,
                                "Cannot get software details, error %d\n", err);
@@ -798,14 +829,14 @@ static int kvaser_usb_probe(struct usb_interface *intf,
 
        dev_dbg(&intf->dev, "Max outstanding tx = %d URBs\n", dev->max_tx_urbs);
 
-       err = dev->ops->dev_get_card_info(dev);
+       err = ops->dev_get_card_info(dev);
        if (err) {
                dev_err(&intf->dev, "Cannot get card info, error %d\n", err);
                return err;
        }
 
-       if (dev->ops->dev_get_capabilities) {
-               err = dev->ops->dev_get_capabilities(dev);
+       if (ops->dev_get_capabilities) {
+               err = ops->dev_get_capabilities(dev);
                if (err) {
                        dev_err(&intf->dev,
                                "Cannot get capabilities, error %d\n", err);
@@ -815,7 +846,7 @@ static int kvaser_usb_probe(struct usb_interface *intf,
        }
 
        for (i = 0; i < dev->nchannels; i++) {
-               err = kvaser_usb_init_one(dev, id, i);
+               err = kvaser_usb_init_one(dev, i);
                if (err) {
                        kvaser_usb_remove_interfaces(dev);
                        return err;
index a26823c5b62ad8b22b160e8ff218105b416484fe..5d70844ac030036fc57bdb3d1d86004882ae5c06 100644 (file)
@@ -375,7 +375,7 @@ static const struct can_bittiming_const kvaser_usb_hydra_kcan_bittiming_c = {
        .brp_inc = 1,
 };
 
-static const struct can_bittiming_const kvaser_usb_hydra_flexc_bittiming_c = {
+const struct can_bittiming_const kvaser_usb_flexc_bittiming_const = {
        .name = "kvaser_usb_flex",
        .tseg1_min = 4,
        .tseg1_max = 16,
@@ -2052,7 +2052,7 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_flexc = {
                .freq = 24 * MEGA /* Hz */,
        },
        .timestamp_freq = 1,
-       .bittiming_const = &kvaser_usb_hydra_flexc_bittiming_c,
+       .bittiming_const = &kvaser_usb_flexc_bittiming_const,
 };
 
 static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_rt = {
index c805b999c54366d37328f0f2f123bd57fcb784e0..cc809ecd1e62246da49e58d05ea80370432cbf3e 100644 (file)
 #define USBCAN_ERROR_STATE_RX_ERROR    BIT(1)
 #define USBCAN_ERROR_STATE_BUSERROR    BIT(2)
 
-/* bittiming parameters */
-#define KVASER_USB_TSEG1_MIN           1
-#define KVASER_USB_TSEG1_MAX           16
-#define KVASER_USB_TSEG2_MIN           1
-#define KVASER_USB_TSEG2_MAX           8
-#define KVASER_USB_SJW_MAX             4
-#define KVASER_USB_BRP_MIN             1
-#define KVASER_USB_BRP_MAX             64
-#define KVASER_USB_BRP_INC             1
-
 /* ctrl modes */
 #define KVASER_CTRL_MODE_NORMAL                1
 #define KVASER_CTRL_MODE_SILENT                2
@@ -343,48 +333,68 @@ struct kvaser_usb_err_summary {
        };
 };
 
-static const struct can_bittiming_const kvaser_usb_leaf_bittiming_const = {
-       .name = "kvaser_usb",
-       .tseg1_min = KVASER_USB_TSEG1_MIN,
-       .tseg1_max = KVASER_USB_TSEG1_MAX,
-       .tseg2_min = KVASER_USB_TSEG2_MIN,
-       .tseg2_max = KVASER_USB_TSEG2_MAX,
-       .sjw_max = KVASER_USB_SJW_MAX,
-       .brp_min = KVASER_USB_BRP_MIN,
-       .brp_max = KVASER_USB_BRP_MAX,
-       .brp_inc = KVASER_USB_BRP_INC,
+static const struct can_bittiming_const kvaser_usb_leaf_m16c_bittiming_const = {
+       .name = "kvaser_usb_ucii",
+       .tseg1_min = 4,
+       .tseg1_max = 16,
+       .tseg2_min = 2,
+       .tseg2_max = 8,
+       .sjw_max = 4,
+       .brp_min = 1,
+       .brp_max = 16,
+       .brp_inc = 1,
+};
+
+static const struct can_bittiming_const kvaser_usb_leaf_m32c_bittiming_const = {
+       .name = "kvaser_usb_leaf",
+       .tseg1_min = 3,
+       .tseg1_max = 16,
+       .tseg2_min = 2,
+       .tseg2_max = 8,
+       .sjw_max = 4,
+       .brp_min = 2,
+       .brp_max = 128,
+       .brp_inc = 2,
 };
 
-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_8mhz = {
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_usbcan_dev_cfg = {
        .clock = {
                .freq = 8 * MEGA /* Hz */,
        },
        .timestamp_freq = 1,
-       .bittiming_const = &kvaser_usb_leaf_bittiming_const,
+       .bittiming_const = &kvaser_usb_leaf_m16c_bittiming_const,
+};
+
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_m32c_dev_cfg = {
+       .clock = {
+               .freq = 16 * MEGA /* Hz */,
+       },
+       .timestamp_freq = 1,
+       .bittiming_const = &kvaser_usb_leaf_m32c_bittiming_const,
 };
 
-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_16mhz = {
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_16mhz = {
        .clock = {
                .freq = 16 * MEGA /* Hz */,
        },
        .timestamp_freq = 1,
-       .bittiming_const = &kvaser_usb_leaf_bittiming_const,
+       .bittiming_const = &kvaser_usb_flexc_bittiming_const,
 };
 
-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_24mhz = {
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_24mhz = {
        .clock = {
                .freq = 24 * MEGA /* Hz */,
        },
        .timestamp_freq = 1,
-       .bittiming_const = &kvaser_usb_leaf_bittiming_const,
+       .bittiming_const = &kvaser_usb_flexc_bittiming_const,
 };
 
-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_32mhz = {
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_32mhz = {
        .clock = {
                .freq = 32 * MEGA /* Hz */,
        },
        .timestamp_freq = 1,
-       .bittiming_const = &kvaser_usb_leaf_bittiming_const,
+       .bittiming_const = &kvaser_usb_flexc_bittiming_const,
 };
 
 static void *
@@ -404,7 +414,7 @@ kvaser_usb_leaf_frame_to_cmd(const struct kvaser_usb_net_priv *priv,
                                      sizeof(struct kvaser_cmd_tx_can);
                cmd->u.tx_can.channel = priv->channel;
 
-               switch (dev->card_data.leaf.family) {
+               switch (dev->driver_info->family) {
                case KVASER_LEAF:
                        cmd_tx_can_flags = &cmd->u.tx_can.leaf.flags;
                        break;
@@ -524,16 +534,23 @@ static void kvaser_usb_leaf_get_software_info_leaf(struct kvaser_usb *dev,
        dev->fw_version = le32_to_cpu(softinfo->fw_version);
        dev->max_tx_urbs = le16_to_cpu(softinfo->max_outstanding_tx);
 
-       switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
-       case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
-               dev->cfg = &kvaser_usb_leaf_dev_cfg_16mhz;
-               break;
-       case KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK:
-               dev->cfg = &kvaser_usb_leaf_dev_cfg_24mhz;
-               break;
-       case KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK:
-               dev->cfg = &kvaser_usb_leaf_dev_cfg_32mhz;
-               break;
+       if (dev->driver_info->quirks & KVASER_USB_QUIRK_IGNORE_CLK_FREQ) {
+               /* Firmware expects bittiming parameters calculated for 16MHz
+                * clock, regardless of the actual clock
+                */
+               dev->cfg = &kvaser_usb_leaf_m32c_dev_cfg;
+       } else {
+               switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
+               case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
+                       dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_16mhz;
+                       break;
+               case KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK:
+                       dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_24mhz;
+                       break;
+               case KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK:
+                       dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_32mhz;
+                       break;
+               }
        }
 }
 
@@ -550,7 +567,7 @@ static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev)
        if (err)
                return err;
 
-       switch (dev->card_data.leaf.family) {
+       switch (dev->driver_info->family) {
        case KVASER_LEAF:
                kvaser_usb_leaf_get_software_info_leaf(dev, &cmd.u.leaf.softinfo);
                break;
@@ -558,7 +575,7 @@ static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev)
                dev->fw_version = le32_to_cpu(cmd.u.usbcan.softinfo.fw_version);
                dev->max_tx_urbs =
                        le16_to_cpu(cmd.u.usbcan.softinfo.max_outstanding_tx);
-               dev->cfg = &kvaser_usb_leaf_dev_cfg_8mhz;
+               dev->cfg = &kvaser_usb_leaf_usbcan_dev_cfg;
                break;
        }
 
@@ -597,7 +614,7 @@ static int kvaser_usb_leaf_get_card_info(struct kvaser_usb *dev)
 
        dev->nchannels = cmd.u.cardinfo.nchannels;
        if (dev->nchannels > KVASER_USB_MAX_NET_DEVICES ||
-           (dev->card_data.leaf.family == KVASER_USBCAN &&
+           (dev->driver_info->family == KVASER_USBCAN &&
             dev->nchannels > MAX_USBCAN_NET_DEVICES))
                return -EINVAL;
 
@@ -730,7 +747,7 @@ kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
            new_state < CAN_STATE_BUS_OFF)
                priv->can.can_stats.restarts++;
 
-       switch (dev->card_data.leaf.family) {
+       switch (dev->driver_info->family) {
        case KVASER_LEAF:
                if (es->leaf.error_factor) {
                        priv->can.can_stats.bus_error++;
@@ -809,7 +826,7 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,
                }
        }
 
-       switch (dev->card_data.leaf.family) {
+       switch (dev->driver_info->family) {
        case KVASER_LEAF:
                if (es->leaf.error_factor) {
                        cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
@@ -999,7 +1016,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
        stats = &priv->netdev->stats;
 
        if ((cmd->u.rx_can_header.flag & MSG_FLAG_ERROR_FRAME) &&
-           (dev->card_data.leaf.family == KVASER_LEAF &&
+           (dev->driver_info->family == KVASER_LEAF &&
             cmd->id == CMD_LEAF_LOG_MESSAGE)) {
                kvaser_usb_leaf_leaf_rx_error(dev, cmd);
                return;
@@ -1015,7 +1032,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
                return;
        }
 
-       switch (dev->card_data.leaf.family) {
+       switch (dev->driver_info->family) {
        case KVASER_LEAF:
                rx_data = cmd->u.leaf.rx_can.data;
                break;
@@ -1030,7 +1047,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
                return;
        }
 
-       if (dev->card_data.leaf.family == KVASER_LEAF && cmd->id ==
+       if (dev->driver_info->family == KVASER_LEAF && cmd->id ==
            CMD_LEAF_LOG_MESSAGE) {
                cf->can_id = le32_to_cpu(cmd->u.leaf.log_message.id);
                if (cf->can_id & KVASER_EXTENDED_FRAME)
@@ -1128,14 +1145,14 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
                break;
 
        case CMD_LEAF_LOG_MESSAGE:
-               if (dev->card_data.leaf.family != KVASER_LEAF)
+               if (dev->driver_info->family != KVASER_LEAF)
                        goto warn;
                kvaser_usb_leaf_rx_can_msg(dev, cmd);
                break;
 
        case CMD_CHIP_STATE_EVENT:
        case CMD_CAN_ERROR_EVENT:
-               if (dev->card_data.leaf.family == KVASER_LEAF)
+               if (dev->driver_info->family == KVASER_LEAF)
                        kvaser_usb_leaf_leaf_rx_error(dev, cmd);
                else
                        kvaser_usb_leaf_usbcan_rx_error(dev, cmd);
@@ -1147,12 +1164,12 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
 
        /* Ignored commands */
        case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
-               if (dev->card_data.leaf.family != KVASER_USBCAN)
+               if (dev->driver_info->family != KVASER_USBCAN)
                        goto warn;
                break;
 
        case CMD_FLUSH_QUEUE_REPLY:
-               if (dev->card_data.leaf.family != KVASER_LEAF)
+               if (dev->driver_info->family != KVASER_LEAF)
                        goto warn;
                break;
 
index 8a3b7b103ca48d02aee0d1866e6498878b2249ef..e179d311aa28841a5a7fd7b2abe44cdfa3cd3d35 100644 (file)
@@ -258,7 +258,7 @@ static const struct can_bittiming_const xcan_bittiming_const_canfd2 = {
        .tseg2_min = 1,
        .tseg2_max = 128,
        .sjw_max = 128,
-       .brp_min = 2,
+       .brp_min = 1,
        .brp_max = 256,
        .brp_inc = 1,
 };
@@ -271,7 +271,7 @@ static const struct can_bittiming_const xcan_data_bittiming_const_canfd2 = {
        .tseg2_min = 1,
        .tseg2_max = 16,
        .sjw_max = 16,
-       .brp_min = 2,
+       .brp_min = 1,
        .brp_max = 256,
        .brp_inc = 1,
 };
index 9ca8c8d7740f4d8da599be17cb84cd620af33fb3..92a500e1ccd216162ef5affc7d138b3999c01403 100644 (file)
@@ -1038,18 +1038,21 @@ int ksz_switch_register(struct ksz_device *dev,
                ports = of_get_child_by_name(dev->dev->of_node, "ethernet-ports");
                if (!ports)
                        ports = of_get_child_by_name(dev->dev->of_node, "ports");
-               if (ports)
+               if (ports) {
                        for_each_available_child_of_node(ports, port) {
                                if (of_property_read_u32(port, "reg",
                                                         &port_num))
                                        continue;
                                if (!(dev->port_mask & BIT(port_num))) {
                                        of_node_put(port);
+                                       of_node_put(ports);
                                        return -EINVAL;
                                }
                                of_get_phy_mode(port,
                                                &dev->ports[port_num].interface);
                        }
+                       of_node_put(ports);
+               }
                dev->synclko_125 = of_property_read_bool(dev->dev->of_node,
                                                         "microchip,synclko-125");
                dev->synclko_disable = of_property_read_bool(dev->dev->of_node,
index 72b6fc1932b5445518f3b2fc3907e1f7ce1baa41..698c7d1fb45cc97d4ef08c2b61b1f50f202d99b0 100644 (file)
@@ -3382,12 +3382,28 @@ static const struct of_device_id sja1105_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, sja1105_dt_ids);
 
+static const struct spi_device_id sja1105_spi_ids[] = {
+       { "sja1105e" },
+       { "sja1105t" },
+       { "sja1105p" },
+       { "sja1105q" },
+       { "sja1105r" },
+       { "sja1105s" },
+       { "sja1110a" },
+       { "sja1110b" },
+       { "sja1110c" },
+       { "sja1110d" },
+       { },
+};
+MODULE_DEVICE_TABLE(spi, sja1105_spi_ids);
+
 static struct spi_driver sja1105_driver = {
        .driver = {
                .name  = "sja1105",
                .owner = THIS_MODULE,
                .of_match_table = of_match_ptr(sja1105_dt_ids),
        },
+       .id_table = sja1105_spi_ids,
        .probe  = sja1105_probe,
        .remove = sja1105_remove,
        .shutdown = sja1105_shutdown,
index 3110895358d8dcc31715228acbe42e183c37c4fd..97a92e6da60d8b95a9209b71461dd90233c84846 100644 (file)
@@ -205,10 +205,20 @@ static const struct of_device_id vsc73xx_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, vsc73xx_of_match);
 
+static const struct spi_device_id vsc73xx_spi_ids[] = {
+       { "vsc7385" },
+       { "vsc7388" },
+       { "vsc7395" },
+       { "vsc7398" },
+       { },
+};
+MODULE_DEVICE_TABLE(spi, vsc73xx_spi_ids);
+
 static struct spi_driver vsc73xx_spi_driver = {
        .probe = vsc73xx_spi_probe,
        .remove = vsc73xx_spi_remove,
        .shutdown = vsc73xx_spi_shutdown,
+       .id_table = vsc73xx_spi_ids,
        .driver = {
                .name = "vsc73xx-spi",
                .of_match_table = vsc73xx_of_match,
index 831833911a52562a5bbb4f14020b9ad2d5c8f1ea..8647125d60aef1d14d3485b54c385e6cc687934e 100644 (file)
@@ -379,7 +379,7 @@ static void aq_pci_shutdown(struct pci_dev *pdev)
        }
 }
 
-static int aq_suspend_common(struct device *dev, bool deep)
+static int aq_suspend_common(struct device *dev)
 {
        struct aq_nic_s *nic = pci_get_drvdata(to_pci_dev(dev));
 
@@ -392,17 +392,15 @@ static int aq_suspend_common(struct device *dev, bool deep)
        if (netif_running(nic->ndev))
                aq_nic_stop(nic);
 
-       if (deep) {
-               aq_nic_deinit(nic, !nic->aq_hw->aq_nic_cfg->wol);
-               aq_nic_set_power(nic);
-       }
+       aq_nic_deinit(nic, !nic->aq_hw->aq_nic_cfg->wol);
+       aq_nic_set_power(nic);
 
        rtnl_unlock();
 
        return 0;
 }
 
-static int atl_resume_common(struct device *dev, bool deep)
+static int atl_resume_common(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct aq_nic_s *nic;
@@ -415,11 +413,6 @@ static int atl_resume_common(struct device *dev, bool deep)
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
 
-       if (deep) {
-               /* Reinitialize Nic/Vecs objects */
-               aq_nic_deinit(nic, !nic->aq_hw->aq_nic_cfg->wol);
-       }
-
        if (netif_running(nic->ndev)) {
                ret = aq_nic_init(nic);
                if (ret)
@@ -444,22 +437,22 @@ err_exit:
 
 static int aq_pm_freeze(struct device *dev)
 {
-       return aq_suspend_common(dev, true);
+       return aq_suspend_common(dev);
 }
 
 static int aq_pm_suspend_poweroff(struct device *dev)
 {
-       return aq_suspend_common(dev, true);
+       return aq_suspend_common(dev);
 }
 
 static int aq_pm_thaw(struct device *dev)
 {
-       return atl_resume_common(dev, true);
+       return atl_resume_common(dev);
 }
 
 static int aq_pm_resume_restore(struct device *dev)
 {
-       return atl_resume_common(dev, true);
+       return atl_resume_common(dev);
 }
 
 static const struct dev_pm_ops aq_pm_ops = {
index 56b46b8206a7c1c37fc8b3656360325a7d90a9a6..cf9b00576ed360a15d0c4fdc73034b292e6a9f33 100644 (file)
@@ -7790,7 +7790,7 @@ hwrm_dbg_qcaps_exit:
 
 static int bnxt_hwrm_queue_qportcfg(struct bnxt *bp);
 
-static int bnxt_hwrm_func_qcaps(struct bnxt *bp)
+int bnxt_hwrm_func_qcaps(struct bnxt *bp)
 {
        int rc;
 
@@ -10065,7 +10065,8 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up)
 
        if (flags & FUNC_DRV_IF_CHANGE_RESP_FLAGS_RESC_CHANGE)
                resc_reinit = true;
-       if (flags & FUNC_DRV_IF_CHANGE_RESP_FLAGS_HOT_FW_RESET_DONE)
+       if (flags & FUNC_DRV_IF_CHANGE_RESP_FLAGS_HOT_FW_RESET_DONE ||
+           test_bit(BNXT_STATE_FW_RESET_DET, &bp->state))
                fw_reset = true;
        else
                bnxt_remap_fw_health_regs(bp);
index a1dca8c58f540b9b47076aeab25fb2219dd81b4e..075c6206325ce387052629a00a1da74b0c0c5462 100644 (file)
@@ -2314,6 +2314,7 @@ int bnxt_cancel_reservations(struct bnxt *bp, bool fw_reset);
 int bnxt_hwrm_alloc_wol_fltr(struct bnxt *bp);
 int bnxt_hwrm_free_wol_fltr(struct bnxt *bp);
 int bnxt_hwrm_func_resc_qcaps(struct bnxt *bp, bool all);
+int bnxt_hwrm_func_qcaps(struct bnxt *bp);
 int bnxt_hwrm_fw_set_time(struct bnxt *);
 int bnxt_open_nic(struct bnxt *, bool, bool);
 int bnxt_half_open_nic(struct bnxt *bp);
index 3528ce9849e6f45654c7026a82661f7eaf9b2a01..6b3d4f4c2a75f3425ed9e515c05ac9a3c5d53d52 100644 (file)
@@ -979,9 +979,11 @@ static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
        if (rc)
                return rc;
 
-       rc = bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_SRT_PATCH);
-       if (rc)
-               return rc;
+       if (BNXT_CHIP_P5(bp)) {
+               rc = bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_SRT_PATCH);
+               if (rc)
+                       return rc;
+       }
        return bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_CRT_PATCH);
 
 }
index 562f8f68a47d8b187c93ba10ad7e99212f3fc2b3..7f3c0875b6f5834e58223a13c3cfb1d46b02cec4 100644 (file)
@@ -76,14 +76,23 @@ static int bnxt_refclk_read(struct bnxt *bp, struct ptp_system_timestamp *sts,
                            u64 *ns)
 {
        struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+       u32 high_before, high_now, low;
 
        if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
                return -EIO;
 
+       high_before = readl(bp->bar0 + ptp->refclk_mapped_regs[1]);
        ptp_read_system_prets(sts);
-       *ns = readl(bp->bar0 + ptp->refclk_mapped_regs[0]);
+       low = readl(bp->bar0 + ptp->refclk_mapped_regs[0]);
        ptp_read_system_postts(sts);
-       *ns |= (u64)readl(bp->bar0 + ptp->refclk_mapped_regs[1]) << 32;
+       high_now = readl(bp->bar0 + ptp->refclk_mapped_regs[1]);
+       if (high_now != high_before) {
+               ptp_read_system_prets(sts);
+               low = readl(bp->bar0 + ptp->refclk_mapped_regs[0]);
+               ptp_read_system_postts(sts);
+       }
+       *ns = ((u64)high_now << 32) | low;
+
        return 0;
 }
 
index ddf2f3963abeef81f35d3580f500af1c4bc223ff..a1a2c7a64fd58408fdc655e08013f750636fe793 100644 (file)
@@ -823,8 +823,10 @@ static int bnxt_sriov_enable(struct bnxt *bp, int *num_vfs)
                goto err_out2;
 
        rc = pci_enable_sriov(bp->pdev, *num_vfs);
-       if (rc)
+       if (rc) {
+               bnxt_ulp_sriov_cfg(bp, 0);
                goto err_out2;
+       }
 
        return 0;
 
@@ -832,6 +834,9 @@ err_out2:
        /* Free the resources reserved for various VF's */
        bnxt_hwrm_func_vf_resource_free(bp, *num_vfs);
 
+       /* Restore the max resources */
+       bnxt_hwrm_func_qcaps(bp);
+
 err_out1:
        bnxt_free_vf_resources(bp);
 
index f02fe906dedbaadea288cd659be42b4ab36ab484..f53387ed0167bb93dbba6659c42c0ff5c2b63cfb 100644 (file)
@@ -28,7 +28,7 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
                                   struct xdp_buff *xdp)
 {
        struct skb_shared_info *sinfo;
-       struct bnxt_sw_tx_bd *tx_buf, *first_buf;
+       struct bnxt_sw_tx_bd *tx_buf;
        struct tx_bd *txbd;
        int num_frags = 0;
        u32 flags;
@@ -43,13 +43,14 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
        /* fill up the first buffer */
        prod = txr->tx_prod;
        tx_buf = &txr->tx_buf_ring[prod];
-       first_buf = tx_buf;
        tx_buf->nr_frags = num_frags;
        if (xdp)
                tx_buf->page = virt_to_head_page(xdp->data);
 
        txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)];
-       flags = ((len) << TX_BD_LEN_SHIFT) | ((num_frags + 1) << TX_BD_FLAGS_BD_CNT_SHIFT);
+       flags = (len << TX_BD_LEN_SHIFT) |
+               ((num_frags + 1) << TX_BD_FLAGS_BD_CNT_SHIFT) |
+               bnxt_lhint_arr[len >> 9];
        txbd->tx_bd_len_flags_type = cpu_to_le32(flags);
        txbd->tx_bd_opaque = prod;
        txbd->tx_bd_haddr = cpu_to_le64(mapping);
@@ -82,7 +83,6 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
 
                flags = frag_len << TX_BD_LEN_SHIFT;
                txbd->tx_bd_len_flags_type = cpu_to_le32(flags);
-               txbd->tx_bd_opaque = prod;
                txbd->tx_bd_haddr = cpu_to_le64(frag_mapping);
 
                len = frag_len;
@@ -96,7 +96,7 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
        prod = NEXT_TX(prod);
        txr->tx_prod = prod;
 
-       return first_buf;
+       return tx_buf;
 }
 
 static void __bnxt_xmit_xdp(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
index 4af5561cbfc54cf82d92c5a3a667f2953ddbccce..ddfe9208529a5ebebbc168a7aa01919acf15c947 100644 (file)
@@ -1236,8 +1236,8 @@ static struct sock *chtls_recv_sock(struct sock *lsk,
        csk->sndbuf = newsk->sk_sndbuf;
        csk->smac_idx = ((struct port_info *)netdev_priv(ndev))->smt_idx;
        RCV_WSCALE(tp) = select_rcv_wscale(tcp_full_space(newsk),
-                                          sock_net(newsk)->
-                                               ipv4.sysctl_tcp_window_scaling,
+                                          READ_ONCE(sock_net(newsk)->
+                                                    ipv4.sysctl_tcp_window_scaling),
                                           tp->window_clamp);
        neigh_release(n);
        inet_inherit_port(&tcp_hashinfo, lsk, newsk);
@@ -1384,7 +1384,7 @@ static void chtls_pass_accept_request(struct sock *sk,
 #endif
        }
        if (req->tcpopt.wsf <= 14 &&
-           sock_net(sk)->ipv4.sysctl_tcp_window_scaling) {
+           READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_window_scaling)) {
                inet_rsk(oreq)->wscale_ok = 1;
                inet_rsk(oreq)->snd_wscale = req->tcpopt.wsf;
        }
@@ -1392,7 +1392,7 @@ static void chtls_pass_accept_request(struct sock *sk,
        th_ecn = tcph->ece && tcph->cwr;
        if (th_ecn) {
                ect = !INET_ECN_is_not_ect(ip_dsfield);
-               ecn_ok = sock_net(sk)->ipv4.sysctl_tcp_ecn;
+               ecn_ok = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn);
                if ((!ect && ecn_ok) || tcp_ca_needs_ecn(sk))
                        inet_rsk(oreq)->ecn_ok = 1;
        }
index 528eb0f223b176309d058a2d8528f70dc096785e..b4f5e57d0285cb516a26e6d1b7dd54bd9fee0ae7 100644 (file)
@@ -2287,7 +2287,7 @@ err:
 
 /* Uses sync mcc */
 int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
-                                     u8 page_num, u8 *data)
+                                     u8 page_num, u32 off, u32 len, u8 *data)
 {
        struct be_dma_mem cmd;
        struct be_mcc_wrb *wrb;
@@ -2321,10 +2321,10 @@ int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
        req->port = cpu_to_le32(adapter->hba_port_num);
        req->page_num = cpu_to_le32(page_num);
        status = be_mcc_notify_wait(adapter);
-       if (!status) {
+       if (!status && len > 0) {
                struct be_cmd_resp_port_type *resp = cmd.va;
 
-               memcpy(data, resp->page_data, PAGE_DATA_LEN);
+               memcpy(data, resp->page_data + off, len);
        }
 err:
        mutex_unlock(&adapter->mcc_lock);
@@ -2415,7 +2415,7 @@ int be_cmd_query_cable_type(struct be_adapter *adapter)
        int status;
 
        status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
-                                                  page_data);
+                                                  0, PAGE_DATA_LEN, page_data);
        if (!status) {
                switch (adapter->phy.interface_type) {
                case PHY_TYPE_QSFP:
@@ -2440,7 +2440,7 @@ int be_cmd_query_sfp_info(struct be_adapter *adapter)
        int status;
 
        status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
-                                                  page_data);
+                                                  0, PAGE_DATA_LEN, page_data);
        if (!status) {
                strlcpy(adapter->phy.vendor_name, page_data +
                        SFP_VENDOR_NAME_OFFSET, SFP_VENDOR_NAME_LEN - 1);
index db1f3b908582efe3c3a7504522325f0e2b781824..e2085c68c0ee784e8bd6f5ef41f478eb5f789a52 100644 (file)
@@ -2427,7 +2427,7 @@ int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num, u8 beacon,
 int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num,
                            u32 *state);
 int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
-                                     u8 page_num, u8 *data);
+                                     u8 page_num, u32 off, u32 len, u8 *data);
 int be_cmd_query_cable_type(struct be_adapter *adapter);
 int be_cmd_query_sfp_info(struct be_adapter *adapter);
 int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
index dfa784339781d3b8785ee6d38db6069b47cf5750..bd0df189d87192f704bb12e63c66618dfa5e800a 100644 (file)
@@ -1344,7 +1344,7 @@ static int be_get_module_info(struct net_device *netdev,
                return -EOPNOTSUPP;
 
        status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
-                                                  page_data);
+                                                  0, PAGE_DATA_LEN, page_data);
        if (!status) {
                if (!page_data[SFP_PLUS_SFF_8472_COMP]) {
                        modinfo->type = ETH_MODULE_SFF_8079;
@@ -1362,25 +1362,32 @@ static int be_get_module_eeprom(struct net_device *netdev,
 {
        struct be_adapter *adapter = netdev_priv(netdev);
        int status;
+       u32 begin, end;
 
        if (!check_privilege(adapter, MAX_PRIVILEGES))
                return -EOPNOTSUPP;
 
-       status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
-                                                  data);
-       if (status)
-               goto err;
+       begin = eeprom->offset;
+       end = eeprom->offset + eeprom->len;
+
+       if (begin < PAGE_DATA_LEN) {
+               status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0, begin,
+                                                          min_t(u32, end, PAGE_DATA_LEN) - begin,
+                                                          data);
+               if (status)
+                       goto err;
+
+               data += PAGE_DATA_LEN - begin;
+               begin = PAGE_DATA_LEN;
+       }
 
-       if (eeprom->offset + eeprom->len > PAGE_DATA_LEN) {
-               status = be_cmd_read_port_transceiver_data(adapter,
-                                                          TR_PAGE_A2,
-                                                          data +
-                                                          PAGE_DATA_LEN);
+       if (end > PAGE_DATA_LEN) {
+               status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A2,
+                                                          begin - PAGE_DATA_LEN,
+                                                          end - begin, data);
                if (status)
                        goto err;
        }
-       if (eeprom->offset)
-               memcpy(data, data + eeprom->offset, eeprom->len);
 err:
        return be_cmd_status(status);
 }
index 5231818943c6e12f8cad1dd065129a538acf83c8..c03663785a8d4f8e8cc2af95bc3d47d2f5213b49 100644 (file)
@@ -1764,6 +1764,19 @@ cleanup_clk:
        return rc;
 }
 
+static bool ftgmac100_has_child_node(struct device_node *np, const char *name)
+{
+       struct device_node *child_np = of_get_child_by_name(np, name);
+       bool ret = false;
+
+       if (child_np) {
+               ret = true;
+               of_node_put(child_np);
+       }
+
+       return ret;
+}
+
 static int ftgmac100_probe(struct platform_device *pdev)
 {
        struct resource *res;
@@ -1883,7 +1896,7 @@ static int ftgmac100_probe(struct platform_device *pdev)
 
                /* Display what we found */
                phy_attached_info(phy);
-       } else if (np && !of_get_child_by_name(np, "mdio")) {
+       } else if (np && !ftgmac100_has_child_node(np, "mdio")) {
                /* Support legacy ASPEED devicetree descriptions that decribe a
                 * MAC with an embedded MDIO controller but have no "mdio"
                 * child node. Automatically scan the MDIO bus for available
index 7e7fe5bdf1f8c4b6ccf3d810909fe2dae3c38a8c..5ab7c0f81e9afc9ec6230325cb9bac71ca33f34b 100644 (file)
@@ -5981,6 +5981,15 @@ static int ibmvnic_reset_init(struct ibmvnic_adapter *adapter, bool reset)
                        release_sub_crqs(adapter, 0);
                        rc = init_sub_crqs(adapter);
                } else {
+                       /* no need to reinitialize completely, but we do
+                        * need to clean up transmits that were in flight
+                        * when we processed the reset.  Failure to do so
+                        * will confound the upper layer, usually TCP, by
+                        * creating the illusion of transmits that are
+                        * awaiting completion.
+                        */
+                       clean_tx_pools(adapter);
+
                        rc = reset_sub_crq_queues(adapter);
                }
        } else {
index 13382df2f2eff4577128430ff55882a7434280d7..bcf680e838113ddfd9d73a712fb94eac772ea343 100644 (file)
@@ -630,7 +630,6 @@ struct e1000_phy_info {
        bool disable_polarity_correction;
        bool is_mdix;
        bool polarity_correction;
-       bool reset_disable;
        bool speed_downgraded;
        bool autoneg_wait_to_complete;
 };
index e6c8e6d5234f81d000ce63258a8b31df5d6d9d98..9466f65a6da774010c42b2e45c5190fee1f958c4 100644 (file)
@@ -2050,10 +2050,6 @@ static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
        bool blocked = false;
        int i = 0;
 
-       /* Check the PHY (LCD) reset flag */
-       if (hw->phy.reset_disable)
-               return true;
-
        while ((blocked = !(er32(FWSM) & E1000_ICH_FWSM_RSPCIPHY)) &&
               (i++ < 30))
                usleep_range(10000, 11000);
index 638a3ddd7ada8b3d9bae93e4c0c9e99527ef4cac..2504b11c3169fa6886403b163bb8705729ffda56 100644 (file)
 #define I217_CGFREG_ENABLE_MTA_RESET   0x0002
 #define I217_MEMPWR                    PHY_REG(772, 26)
 #define I217_MEMPWR_DISABLE_SMB_RELEASE        0x0010
-#define I217_MEMPWR_MOEM               0x1000
 
 /* Receive Address Initial CRC Calculation */
 #define E1000_PCH_RAICC(_n)    (0x05F50 + ((_n) * 4))
index fa06f68c8c8038c5355ff605f3854703259a739b..f1729940e46cef9c8a655c64b754f89559f4177a 100644 (file)
@@ -6494,6 +6494,10 @@ static void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter)
 
        if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID &&
            hw->mac.type >= e1000_pch_adp) {
+               /* Keep the GPT clock enabled for CSME */
+               mac_data = er32(FEXTNVM);
+               mac_data |= BIT(3);
+               ew32(FEXTNVM, mac_data);
                /* Request ME unconfigure the device from S0ix */
                mac_data = er32(H2ME);
                mac_data &= ~E1000_H2ME_START_DPG;
@@ -6987,21 +6991,8 @@ static __maybe_unused int e1000e_pm_suspend(struct device *dev)
        struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct pci_dev *pdev = to_pci_dev(dev);
-       struct e1000_hw *hw = &adapter->hw;
-       u16 phy_data;
        int rc;
 
-       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID &&
-           hw->mac.type >= e1000_pch_adp) {
-               /* Mask OEM Bits / Gig Disable / Restart AN (772_26[12] = 1) */
-               e1e_rphy(hw, I217_MEMPWR, &phy_data);
-               phy_data |= I217_MEMPWR_MOEM;
-               e1e_wphy(hw, I217_MEMPWR, phy_data);
-
-               /* Disable LCD reset */
-               hw->phy.reset_disable = true;
-       }
-
        e1000e_flush_lpic(pdev);
 
        e1000e_pm_freeze(dev);
@@ -7023,8 +7014,6 @@ static __maybe_unused int e1000e_pm_resume(struct device *dev)
        struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct pci_dev *pdev = to_pci_dev(dev);
-       struct e1000_hw *hw = &adapter->hw;
-       u16 phy_data;
        int rc;
 
        /* Introduce S0ix implementation */
@@ -7035,17 +7024,6 @@ static __maybe_unused int e1000e_pm_resume(struct device *dev)
        if (rc)
                return rc;
 
-       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID &&
-           hw->mac.type >= e1000_pch_adp) {
-               /* Unmask OEM Bits / Gig Disable / Restart AN 772_26[12] = 0 */
-               e1e_rphy(hw, I217_MEMPWR, &phy_data);
-               phy_data &= ~I217_MEMPWR_MOEM;
-               e1e_wphy(hw, I217_MEMPWR, phy_data);
-
-               /* Enable LCD reset */
-               hw->phy.reset_disable = false;
-       }
-
        return e1000e_pm_thaw(dev);
 }
 
index 18558a01935319a6d814a650d0e652f9a33697d2..407fe8f340a069e73f8433defb9b024b5a0b5edb 100644 (file)
@@ -37,6 +37,7 @@
 #include <net/tc_act/tc_mirred.h>
 #include <net/udp_tunnel.h>
 #include <net/xdp_sock.h>
+#include <linux/bitfield.h>
 #include "i40e_type.h"
 #include "i40e_prototype.h"
 #include <linux/net/intel/i40e_client.h>
@@ -1092,6 +1093,21 @@ static inline void i40e_write_fd_input_set(struct i40e_pf *pf,
                          (u32)(val & 0xFFFFFFFFULL));
 }
 
+/**
+ * i40e_get_pf_count - get PCI PF count.
+ * @hw: pointer to a hw.
+ *
+ * Reports the function number of the highest PCI physical
+ * function plus 1 as it is loaded from the NVM.
+ *
+ * Return: PCI PF count.
+ **/
+static inline u32 i40e_get_pf_count(struct i40e_hw *hw)
+{
+       return FIELD_GET(I40E_GLGEN_PCIFCNCNT_PCIPFCNT_MASK,
+                        rd32(hw, I40E_GLGEN_PCIFCNCNT));
+}
+
 /* needed by i40e_ethtool.c */
 int i40e_up(struct i40e_vsi *vsi);
 void i40e_down(struct i40e_vsi *vsi);
index 72576bb3e94d45e93158415d8840654e3e86f45d..7f1a0d90dc51eabbfef366527bdea7cfb70245f5 100644 (file)
@@ -550,6 +550,47 @@ void i40e_pf_reset_stats(struct i40e_pf *pf)
        pf->hw_csum_rx_error = 0;
 }
 
+/**
+ * i40e_compute_pci_to_hw_id - compute index form PCI function.
+ * @vsi: ptr to the VSI to read from.
+ * @hw: ptr to the hardware info.
+ **/
+static u32 i40e_compute_pci_to_hw_id(struct i40e_vsi *vsi, struct i40e_hw *hw)
+{
+       int pf_count = i40e_get_pf_count(hw);
+
+       if (vsi->type == I40E_VSI_SRIOV)
+               return (hw->port * BIT(7)) / pf_count + vsi->vf_id;
+
+       return hw->port + BIT(7);
+}
+
+/**
+ * i40e_stat_update64 - read and update a 64 bit stat from the chip.
+ * @hw: ptr to the hardware info.
+ * @hireg: the high 32 bit reg to read.
+ * @loreg: the low 32 bit reg to read.
+ * @offset_loaded: has the initial offset been loaded yet.
+ * @offset: ptr to current offset value.
+ * @stat: ptr to the stat.
+ *
+ * Since the device stats are not reset at PFReset, they will not
+ * be zeroed when the driver starts.  We'll save the first values read
+ * and use them as offsets to be subtracted from the raw values in order
+ * to report stats that count from zero.
+ **/
+static void i40e_stat_update64(struct i40e_hw *hw, u32 hireg, u32 loreg,
+                              bool offset_loaded, u64 *offset, u64 *stat)
+{
+       u64 new_data;
+
+       new_data = rd64(hw, loreg);
+
+       if (!offset_loaded || new_data < *offset)
+               *offset = new_data;
+       *stat = new_data - *offset;
+}
+
 /**
  * i40e_stat_update48 - read and update a 48 bit stat from the chip
  * @hw: ptr to the hardware info
@@ -621,6 +662,34 @@ static void i40e_stat_update_and_clear32(struct i40e_hw *hw, u32 reg, u64 *stat)
        *stat += new_data;
 }
 
+/**
+ * i40e_stats_update_rx_discards - update rx_discards.
+ * @vsi: ptr to the VSI to be updated.
+ * @hw: ptr to the hardware info.
+ * @stat_idx: VSI's stat_counter_idx.
+ * @offset_loaded: ptr to the VSI's stat_offsets_loaded.
+ * @stat_offset: ptr to stat_offset to store first read of specific register.
+ * @stat: ptr to VSI's stat to be updated.
+ **/
+static void
+i40e_stats_update_rx_discards(struct i40e_vsi *vsi, struct i40e_hw *hw,
+                             int stat_idx, bool offset_loaded,
+                             struct i40e_eth_stats *stat_offset,
+                             struct i40e_eth_stats *stat)
+{
+       u64 rx_rdpc, rx_rxerr;
+
+       i40e_stat_update32(hw, I40E_GLV_RDPC(stat_idx), offset_loaded,
+                          &stat_offset->rx_discards, &rx_rdpc);
+       i40e_stat_update64(hw,
+                          I40E_GL_RXERR1H(i40e_compute_pci_to_hw_id(vsi, hw)),
+                          I40E_GL_RXERR1L(i40e_compute_pci_to_hw_id(vsi, hw)),
+                          offset_loaded, &stat_offset->rx_discards_other,
+                          &rx_rxerr);
+
+       stat->rx_discards = rx_rdpc + rx_rxerr;
+}
+
 /**
  * i40e_update_eth_stats - Update VSI-specific ethernet statistics counters.
  * @vsi: the VSI to be updated
@@ -680,6 +749,10 @@ void i40e_update_eth_stats(struct i40e_vsi *vsi)
                           I40E_GLV_BPTCL(stat_idx),
                           vsi->stat_offsets_loaded,
                           &oes->tx_broadcast, &es->tx_broadcast);
+
+       i40e_stats_update_rx_discards(vsi, hw, stat_idx,
+                                     vsi->stat_offsets_loaded, oes, es);
+
        vsi->stat_offsets_loaded = true;
 }
 
@@ -10577,7 +10650,7 @@ static int i40e_reset(struct i40e_pf *pf)
  **/
 static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
 {
-       int old_recovery_mode_bit = test_bit(__I40E_RECOVERY_MODE, pf->state);
+       const bool is_recovery_mode_reported = i40e_check_recovery_mode(pf);
        struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
        struct i40e_hw *hw = &pf->hw;
        i40e_status ret;
@@ -10585,13 +10658,11 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
        int v;
 
        if (test_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state) &&
-           i40e_check_recovery_mode(pf)) {
+           is_recovery_mode_reported)
                i40e_set_ethtool_ops(pf->vsi[pf->lan_vsi]->netdev);
-       }
 
        if (test_bit(__I40E_DOWN, pf->state) &&
-           !test_bit(__I40E_RECOVERY_MODE, pf->state) &&
-           !old_recovery_mode_bit)
+           !test_bit(__I40E_RECOVERY_MODE, pf->state))
                goto clear_recovery;
        dev_dbg(&pf->pdev->dev, "Rebuilding internal switch\n");
 
@@ -10618,13 +10689,12 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
         * accordingly with regard to resources initialization
         * and deinitialization
         */
-       if (test_bit(__I40E_RECOVERY_MODE, pf->state) ||
-           old_recovery_mode_bit) {
+       if (test_bit(__I40E_RECOVERY_MODE, pf->state)) {
                if (i40e_get_capabilities(pf,
                                          i40e_aqc_opc_list_func_capabilities))
                        goto end_unlock;
 
-               if (test_bit(__I40E_RECOVERY_MODE, pf->state)) {
+               if (is_recovery_mode_reported) {
                        /* we're staying in recovery mode so we'll reinitialize
                         * misc vector here
                         */
index 1908eed4fa5ee946761ec807e092837e6dcfab1e..7339003aa17cd346d404c6cd4548d1f5f5f8bbcc 100644 (file)
 #define I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT 0
 #define I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT 16
 #define I40E_GLGEN_MSRWD_MDIRDDATA_MASK I40E_MASK(0xFFFF, I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT)
+#define I40E_GLGEN_PCIFCNCNT                0x001C0AB4 /* Reset: PCIR */
+#define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT 0
+#define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_MASK  I40E_MASK(0x1F, I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT)
+#define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT 16
+#define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_MASK  I40E_MASK(0xFF, I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT)
 #define I40E_GLGEN_RSTAT 0x000B8188 /* Reset: POR */
 #define I40E_GLGEN_RSTAT_DEVSTATE_SHIFT 0
 #define I40E_GLGEN_RSTAT_DEVSTATE_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_DEVSTATE_SHIFT)
 #define I40E_VFQF_HKEY1_MAX_INDEX 12
 #define I40E_VFQF_HLUT1(_i, _VF) (0x00220000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...15, _VF=0...127 */ /* Reset: CORER */
 #define I40E_VFQF_HLUT1_MAX_INDEX 15
+#define I40E_GL_RXERR1H(_i)             (0x00318004 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */
+#define I40E_GL_RXERR1H_MAX_INDEX       143
+#define I40E_GL_RXERR1H_RXERR1H_SHIFT   0
+#define I40E_GL_RXERR1H_RXERR1H_MASK    I40E_MASK(0xFFFFFFFF, I40E_GL_RXERR1H_RXERR1H_SHIFT)
+#define I40E_GL_RXERR1L(_i)             (0x00318000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */
+#define I40E_GL_RXERR1L_MAX_INDEX       143
+#define I40E_GL_RXERR1L_RXERR1L_SHIFT   0
+#define I40E_GL_RXERR1L_RXERR1L_MASK    I40E_MASK(0xFFFFFFFF, I40E_GL_RXERR1L_RXERR1L_SHIFT)
 #define I40E_GLPRT_BPRCH(_i) (0x003005E4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */
 #define I40E_GLPRT_BPRCL(_i) (0x003005E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */
 #define I40E_GLPRT_BPTCH(_i) (0x00300A04 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */
index 36a4ca1ffb1a9316ccea469145723b78c1e0006f..7b3f30beb757adbabd984601f114e662d1aa0a41 100644 (file)
@@ -1172,6 +1172,7 @@ struct i40e_eth_stats {
        u64 tx_broadcast;               /* bptc */
        u64 tx_discards;                /* tdpc */
        u64 tx_errors;                  /* tepc */
+       u64 rx_discards_other;          /* rxerr1 */
 };
 
 /* Statistics collected per VEB per TC */
index 033ea71763e3de4437800fc83a5e9366107ef7da..86b0f21287dc84999333e45a87b517e07c95f568 100644 (file)
@@ -2147,6 +2147,10 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
                /* VFs only use TC 0 */
                vfres->vsi_res[0].qset_handle
                                          = le16_to_cpu(vsi->info.qs_handle[0]);
+               if (!(vf->driver_caps & VIRTCHNL_VF_OFFLOAD_USO) && !vf->pf_set_mac) {
+                       i40e_del_mac_filter(vsi, vf->default_lan_addr.addr);
+                       eth_zero_addr(vf->default_lan_addr.addr);
+               }
                ether_addr_copy(vfres->vsi_res[0].default_mac_addr,
                                vf->default_lan_addr.addr);
        }
index 49aed3e506a66d3bee4cb9f563e1fc74fddde03a..0ea0361cd86b1f98c21291051c8c52cff9576295 100644 (file)
@@ -64,7 +64,6 @@ struct iavf_vsi {
        u16 id;
        DECLARE_BITMAP(state, __IAVF_VSI_STATE_SIZE__);
        int base_vector;
-       u16 work_limit;
        u16 qs_handle;
        void *priv;     /* client driver data reference. */
 };
@@ -159,8 +158,12 @@ struct iavf_vlan {
 struct iavf_vlan_filter {
        struct list_head list;
        struct iavf_vlan vlan;
-       bool remove;            /* filter needs to be removed */
-       bool add;               /* filter needs to be added */
+       struct {
+               u8 is_new_vlan:1;       /* filter is new, wait for PF answer */
+               u8 remove:1;            /* filter needs to be removed */
+               u8 add:1;               /* filter needs to be added */
+               u8 padding:5;
+       };
 };
 
 #define IAVF_MAX_TRAFFIC_CLASS 4
@@ -461,6 +464,10 @@ static inline const char *iavf_state_str(enum iavf_state_t state)
                return "__IAVF_INIT_VERSION_CHECK";
        case __IAVF_INIT_GET_RESOURCES:
                return "__IAVF_INIT_GET_RESOURCES";
+       case __IAVF_INIT_EXTENDED_CAPS:
+               return "__IAVF_INIT_EXTENDED_CAPS";
+       case __IAVF_INIT_CONFIG_ADAPTER:
+               return "__IAVF_INIT_CONFIG_ADAPTER";
        case __IAVF_INIT_SW:
                return "__IAVF_INIT_SW";
        case __IAVF_INIT_FAILED:
@@ -520,6 +527,7 @@ int iavf_get_vf_config(struct iavf_adapter *adapter);
 int iavf_get_vf_vlan_v2_caps(struct iavf_adapter *adapter);
 int iavf_send_vf_offload_vlan_v2_msg(struct iavf_adapter *adapter);
 void iavf_set_queue_vlan_tag_loc(struct iavf_adapter *adapter);
+u16 iavf_get_num_vlans_added(struct iavf_adapter *adapter);
 void iavf_irq_enable(struct iavf_adapter *adapter, bool flush);
 void iavf_configure_queues(struct iavf_adapter *adapter);
 void iavf_deconfigure_queues(struct iavf_adapter *adapter);
index 3bb56714beb034e2c8c483d8970a0e8634b9e297..e535d4c3da49d92e80214dc7ca39b4f75f311635 100644 (file)
@@ -692,12 +692,8 @@ static int __iavf_get_coalesce(struct net_device *netdev,
                               struct ethtool_coalesce *ec, int queue)
 {
        struct iavf_adapter *adapter = netdev_priv(netdev);
-       struct iavf_vsi *vsi = &adapter->vsi;
        struct iavf_ring *rx_ring, *tx_ring;
 
-       ec->tx_max_coalesced_frames = vsi->work_limit;
-       ec->rx_max_coalesced_frames = vsi->work_limit;
-
        /* Rx and Tx usecs per queue value. If user doesn't specify the
         * queue, return queue 0's value to represent.
         */
@@ -825,12 +821,8 @@ static int __iavf_set_coalesce(struct net_device *netdev,
                               struct ethtool_coalesce *ec, int queue)
 {
        struct iavf_adapter *adapter = netdev_priv(netdev);
-       struct iavf_vsi *vsi = &adapter->vsi;
        int i;
 
-       if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq)
-               vsi->work_limit = ec->tx_max_coalesced_frames_irq;
-
        if (ec->rx_coalesce_usecs == 0) {
                if (ec->use_adaptive_rx_coalesce)
                        netif_info(adapter, drv, netdev, "rx-usecs=0, need to disable adaptive-rx for a complete disable\n");
@@ -1969,8 +1961,6 @@ static int iavf_set_rxfh(struct net_device *netdev, const u32 *indir,
 
 static const struct ethtool_ops iavf_ethtool_ops = {
        .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
-                                    ETHTOOL_COALESCE_MAX_FRAMES |
-                                    ETHTOOL_COALESCE_MAX_FRAMES_IRQ |
                                     ETHTOOL_COALESCE_USE_ADAPTIVE,
        .get_drvinfo            = iavf_get_drvinfo,
        .get_link               = ethtool_op_get_link,
index f3ecb3bca33dde77895c7742861940c9675e9249..2e2c153ce46a3c791b0aedc73e61077478cf50c8 100644 (file)
@@ -843,7 +843,7 @@ static void iavf_restore_filters(struct iavf_adapter *adapter)
  * iavf_get_num_vlans_added - get number of VLANs added
  * @adapter: board private structure
  */
-static u16 iavf_get_num_vlans_added(struct iavf_adapter *adapter)
+u16 iavf_get_num_vlans_added(struct iavf_adapter *adapter)
 {
        return bitmap_weight(adapter->vsi.active_cvlans, VLAN_N_VID) +
                bitmap_weight(adapter->vsi.active_svlans, VLAN_N_VID);
@@ -906,11 +906,6 @@ static int iavf_vlan_rx_add_vid(struct net_device *netdev,
        if (!iavf_add_vlan(adapter, IAVF_VLAN(vid, be16_to_cpu(proto))))
                return -ENOMEM;
 
-       if (proto == cpu_to_be16(ETH_P_8021Q))
-               set_bit(vid, adapter->vsi.active_cvlans);
-       else
-               set_bit(vid, adapter->vsi.active_svlans);
-
        return 0;
 }
 
@@ -2245,7 +2240,6 @@ int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter)
 
        adapter->vsi.back = adapter;
        adapter->vsi.base_vector = 1;
-       adapter->vsi.work_limit = IAVF_DEFAULT_IRQ_WORK;
        vsi->netdev = adapter->netdev;
        vsi->qs_handle = adapter->vsi_res->qset_handle;
        if (adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
@@ -2956,6 +2950,9 @@ continue_reset:
        adapter->aq_required |= IAVF_FLAG_AQ_ADD_CLOUD_FILTER;
        iavf_misc_irq_enable(adapter);
 
+       bitmap_clear(adapter->vsi.active_cvlans, 0, VLAN_N_VID);
+       bitmap_clear(adapter->vsi.active_svlans, 0, VLAN_N_VID);
+
        mod_delayed_work(iavf_wq, &adapter->watchdog_task, 2);
 
        /* We were running when the reset started, so we need to restore some
index 978f651c6b093b5940a87720cbf2cd29bec04e21..06d18797d25a28c4406f5f3247ab360c3ceb3ef8 100644 (file)
@@ -194,7 +194,7 @@ static bool iavf_clean_tx_irq(struct iavf_vsi *vsi,
        struct iavf_tx_buffer *tx_buf;
        struct iavf_tx_desc *tx_desc;
        unsigned int total_bytes = 0, total_packets = 0;
-       unsigned int budget = vsi->work_limit;
+       unsigned int budget = IAVF_DEFAULT_IRQ_WORK;
 
        tx_buf = &tx_ring->tx_bi[i];
        tx_desc = IAVF_TX_DESC(tx_ring, i);
@@ -1285,11 +1285,10 @@ static struct iavf_rx_buffer *iavf_get_rx_buffer(struct iavf_ring *rx_ring,
 {
        struct iavf_rx_buffer *rx_buffer;
 
-       if (!size)
-               return NULL;
-
        rx_buffer = &rx_ring->rx_bi[rx_ring->next_to_clean];
        prefetchw(rx_buffer->page);
+       if (!size)
+               return rx_buffer;
 
        /* we are reusing so sync this buffer for CPU use */
        dma_sync_single_range_for_cpu(rx_ring->dev,
index 782450d5c12fc26a2c7e358093cc1791096c6b83..1603e99bae4af3737fa1b3195c443e7aee9edfd9 100644 (file)
@@ -626,6 +626,33 @@ static void iavf_mac_add_reject(struct iavf_adapter *adapter)
        spin_unlock_bh(&adapter->mac_vlan_list_lock);
 }
 
+/**
+ * iavf_vlan_add_reject
+ * @adapter: adapter structure
+ *
+ * Remove VLAN filters from list based on PF response.
+ **/
+static void iavf_vlan_add_reject(struct iavf_adapter *adapter)
+{
+       struct iavf_vlan_filter *f, *ftmp;
+
+       spin_lock_bh(&adapter->mac_vlan_list_lock);
+       list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
+               if (f->is_new_vlan) {
+                       if (f->vlan.tpid == ETH_P_8021Q)
+                               clear_bit(f->vlan.vid,
+                                         adapter->vsi.active_cvlans);
+                       else
+                               clear_bit(f->vlan.vid,
+                                         adapter->vsi.active_svlans);
+
+                       list_del(&f->list);
+                       kfree(f);
+               }
+       }
+       spin_unlock_bh(&adapter->mac_vlan_list_lock);
+}
+
 /**
  * iavf_add_vlans
  * @adapter: adapter structure
@@ -683,6 +710,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
                                vvfl->vlan_id[i] = f->vlan.vid;
                                i++;
                                f->add = false;
+                               f->is_new_vlan = true;
                                if (i == count)
                                        break;
                        }
@@ -695,10 +723,18 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
                iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_VLAN, (u8 *)vvfl, len);
                kfree(vvfl);
        } else {
+               u16 max_vlans = adapter->vlan_v2_caps.filtering.max_filters;
+               u16 current_vlans = iavf_get_num_vlans_added(adapter);
                struct virtchnl_vlan_filter_list_v2 *vvfl_v2;
 
                adapter->current_op = VIRTCHNL_OP_ADD_VLAN_V2;
 
+               if ((count + current_vlans) > max_vlans &&
+                   current_vlans < max_vlans) {
+                       count = max_vlans - iavf_get_num_vlans_added(adapter);
+                       more = true;
+               }
+
                len = sizeof(*vvfl_v2) + ((count - 1) *
                                          sizeof(struct virtchnl_vlan_filter));
                if (len > IAVF_MAX_AQ_BUF_SIZE) {
@@ -725,6 +761,9 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
                                        &adapter->vlan_v2_caps.filtering.filtering_support;
                                struct virtchnl_vlan *vlan;
 
+                               if (i == count)
+                                       break;
+
                                /* give priority over outer if it's enabled */
                                if (filtering_support->outer)
                                        vlan = &vvfl_v2->filters[i].outer;
@@ -736,8 +775,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter)
 
                                i++;
                                f->add = false;
-                               if (i == count)
-                                       break;
+                               f->is_new_vlan = true;
                        }
                }
 
@@ -2080,6 +2118,11 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
                         */
                        iavf_netdev_features_vlan_strip_set(netdev, true);
                        break;
+               case VIRTCHNL_OP_ADD_VLAN_V2:
+                       iavf_vlan_add_reject(adapter);
+                       dev_warn(&adapter->pdev->dev, "Failed to add VLAN filter, error %s\n",
+                                iavf_stat_str(&adapter->hw, v_retval));
+                       break;
                default:
                        dev_err(&adapter->pdev->dev, "PF returned error %d (%s) to our request %d\n",
                                v_retval, iavf_stat_str(&adapter->hw, v_retval),
@@ -2332,6 +2375,24 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
                spin_unlock_bh(&adapter->adv_rss_lock);
                }
                break;
+       case VIRTCHNL_OP_ADD_VLAN_V2: {
+               struct iavf_vlan_filter *f;
+
+               spin_lock_bh(&adapter->mac_vlan_list_lock);
+               list_for_each_entry(f, &adapter->vlan_filter_list, list) {
+                       if (f->is_new_vlan) {
+                               f->is_new_vlan = false;
+                               if (f->vlan.tpid == ETH_P_8021Q)
+                                       set_bit(f->vlan.vid,
+                                               adapter->vsi.active_cvlans);
+                               else
+                                       set_bit(f->vlan.vid,
+                                               adapter->vsi.active_svlans);
+                       }
+               }
+               spin_unlock_bh(&adapter->mac_vlan_list_lock);
+               }
+               break;
        case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING:
                /* PF enabled vlan strip on this VF.
                 * Update netdev->features if needed to be in sync with ethtool.
index 61dd2f18dee8ef2ad649e869414c23b08e0c56d4..b41bc3dc174547cb4f74bf8900f24b164cf680cb 100644 (file)
@@ -5,6 +5,7 @@
 #define _ICE_DEVIDS_H_
 
 /* Device IDs */
+#define ICE_DEV_ID_E822_SI_DFLT         0x1888
 /* Intel(R) Ethernet Connection E823-L for backplane */
 #define ICE_DEV_ID_E823L_BACKPLANE     0x124C
 /* Intel(R) Ethernet Connection E823-L for SFP */
index 3991d62473bfca245d870926e3093766b79c4908..3337314a7b35eccc460319d6d5a9161d6a3b27d2 100644 (file)
@@ -814,6 +814,8 @@ void ice_devlink_destroy_vf_port(struct ice_vf *vf)
        devlink_port_unregister(devlink_port);
 }
 
+#define ICE_DEVLINK_READ_BLK_SIZE (1024 * 1024)
+
 /**
  * ice_devlink_nvm_snapshot - Capture a snapshot of the NVM flash contents
  * @devlink: the devlink instance
@@ -840,8 +842,9 @@ static int ice_devlink_nvm_snapshot(struct devlink *devlink,
        struct ice_pf *pf = devlink_priv(devlink);
        struct device *dev = ice_pf_to_dev(pf);
        struct ice_hw *hw = &pf->hw;
-       void *nvm_data;
-       u32 nvm_size;
+       u8 *nvm_data, *tmp, i;
+       u32 nvm_size, left;
+       s8 num_blks;
        int status;
 
        nvm_size = hw->flash.flash_size;
@@ -849,26 +852,44 @@ static int ice_devlink_nvm_snapshot(struct devlink *devlink,
        if (!nvm_data)
                return -ENOMEM;
 
-       status = ice_acquire_nvm(hw, ICE_RES_READ);
-       if (status) {
-               dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n",
-                       status, hw->adminq.sq_last_status);
-               NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore");
-               vfree(nvm_data);
-               return status;
-       }
 
-       status = ice_read_flat_nvm(hw, 0, &nvm_size, nvm_data, false);
-       if (status) {
-               dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n",
-                       nvm_size, status, hw->adminq.sq_last_status);
-               NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM contents");
+       num_blks = DIV_ROUND_UP(nvm_size, ICE_DEVLINK_READ_BLK_SIZE);
+       tmp = nvm_data;
+       left = nvm_size;
+
+       /* Some systems take longer to read the NVM than others which causes the
+        * FW to reclaim the NVM lock before the entire NVM has been read. Fix
+        * this by breaking the reads of the NVM into smaller chunks that will
+        * probably not take as long. This has some overhead since we are
+        * increasing the number of AQ commands, but it should always work
+        */
+       for (i = 0; i < num_blks; i++) {
+               u32 read_sz = min_t(u32, ICE_DEVLINK_READ_BLK_SIZE, left);
+
+               status = ice_acquire_nvm(hw, ICE_RES_READ);
+               if (status) {
+                       dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n",
+                               status, hw->adminq.sq_last_status);
+                       NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore");
+                       vfree(nvm_data);
+                       return -EIO;
+               }
+
+               status = ice_read_flat_nvm(hw, i * ICE_DEVLINK_READ_BLK_SIZE,
+                                          &read_sz, tmp, false);
+               if (status) {
+                       dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n",
+                               read_sz, status, hw->adminq.sq_last_status);
+                       NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM contents");
+                       ice_release_nvm(hw);
+                       vfree(nvm_data);
+                       return -EIO;
+               }
                ice_release_nvm(hw);
-               vfree(nvm_data);
-               return status;
-       }
 
-       ice_release_nvm(hw);
+               tmp += read_sz;
+               left -= read_sz;
+       }
 
        *data = nvm_data;
 
index 665a344fb9c0620615d51c83655c9da9ed79ba9f..3dc5662d62a6a29ebcf940600328b7ac9a19361c 100644 (file)
@@ -736,7 +736,87 @@ static int ice_finalize_update(struct pldmfw *context)
        return 0;
 }
 
-static const struct pldmfw_ops ice_fwu_ops = {
+struct ice_pldm_pci_record_id {
+       u32 vendor;
+       u32 device;
+       u32 subsystem_vendor;
+       u32 subsystem_device;
+};
+
+/**
+ * ice_op_pci_match_record - Check if a PCI device matches the record
+ * @context: PLDM fw update structure
+ * @record: list of records extracted from the PLDM image
+ *
+ * Determine if the PCI device associated with this device matches the record
+ * data provided.
+ *
+ * Searches the descriptor TLVs and extracts the relevant descriptor data into
+ * a pldm_pci_record_id. This is then compared against the PCI device ID
+ * information.
+ *
+ * Returns: true if the device matches the record, false otherwise.
+ */
+static bool
+ice_op_pci_match_record(struct pldmfw *context, struct pldmfw_record *record)
+{
+       struct pci_dev *pdev = to_pci_dev(context->dev);
+       struct ice_pldm_pci_record_id id = {
+               .vendor = PCI_ANY_ID,
+               .device = PCI_ANY_ID,
+               .subsystem_vendor = PCI_ANY_ID,
+               .subsystem_device = PCI_ANY_ID,
+       };
+       struct pldmfw_desc_tlv *desc;
+
+       list_for_each_entry(desc, &record->descs, entry) {
+               u16 value;
+               int *ptr;
+
+               switch (desc->type) {
+               case PLDM_DESC_ID_PCI_VENDOR_ID:
+                       ptr = &id.vendor;
+                       break;
+               case PLDM_DESC_ID_PCI_DEVICE_ID:
+                       ptr = &id.device;
+                       break;
+               case PLDM_DESC_ID_PCI_SUBVENDOR_ID:
+                       ptr = &id.subsystem_vendor;
+                       break;
+               case PLDM_DESC_ID_PCI_SUBDEV_ID:
+                       ptr = &id.subsystem_device;
+                       break;
+               default:
+                       /* Skip unrelated TLVs */
+                       continue;
+               }
+
+               value = get_unaligned_le16(desc->data);
+               /* A value of zero for one of the descriptors is sometimes
+                * used when the record should ignore this field when matching
+                * device. For example if the record applies to any subsystem
+                * device or vendor.
+                */
+               if (value)
+                       *ptr = value;
+               else
+                       *ptr = PCI_ANY_ID;
+       }
+
+       /* the E822 device can have a generic device ID so check for that */
+       if ((id.vendor == PCI_ANY_ID || id.vendor == pdev->vendor) &&
+           (id.device == PCI_ANY_ID || id.device == pdev->device ||
+           id.device == ICE_DEV_ID_E822_SI_DFLT) &&
+           (id.subsystem_vendor == PCI_ANY_ID ||
+           id.subsystem_vendor == pdev->subsystem_vendor) &&
+           (id.subsystem_device == PCI_ANY_ID ||
+           id.subsystem_device == pdev->subsystem_device))
+               return true;
+
+       return false;
+}
+
+static const struct pldmfw_ops ice_fwu_ops_e810 = {
        .match_record = &pldmfw_op_pci_match_record,
        .send_package_data = &ice_send_package_data,
        .send_component_table = &ice_send_component_table,
@@ -744,6 +824,14 @@ static const struct pldmfw_ops ice_fwu_ops = {
        .finalize_update = &ice_finalize_update,
 };
 
+static const struct pldmfw_ops ice_fwu_ops_e822 = {
+       .match_record = &ice_op_pci_match_record,
+       .send_package_data = &ice_send_package_data,
+       .send_component_table = &ice_send_component_table,
+       .flash_component = &ice_flash_component,
+       .finalize_update = &ice_finalize_update,
+};
+
 /**
  * ice_get_pending_updates - Check if the component has a pending update
  * @pf: the PF driver structure
@@ -921,7 +1009,11 @@ int ice_devlink_flash_update(struct devlink *devlink,
 
        memset(&priv, 0, sizeof(priv));
 
-       priv.context.ops = &ice_fwu_ops;
+       /* the E822 device needs a slightly different ops */
+       if (hw->mac_type == ICE_MAC_GENERIC)
+               priv.context.ops = &ice_fwu_ops_e822;
+       else
+               priv.context.ops = &ice_fwu_ops_e810;
        priv.context.dev = dev;
        priv.extack = extack;
        priv.pf = pf;
index c1ac2f746714853b2f8dd64a4154206f3ab63e25..ff2eac2f8c64423eafff3dff46e9e8ce7e37366e 100644 (file)
@@ -5413,6 +5413,7 @@ static const struct pci_device_id ice_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_10G_BASE_T), 0 },
        { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_1GBE), 0 },
        { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_QSFP), 0 },
+       { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822_SI_DFLT), 0 },
        /* required last entry */
        { 0, }
 };
index ae17af44fe02502f7ad44dc428dc97e6b5dafe67..a5ebee7df4a8544c572dbe4d5f979571c183df03 100644 (file)
@@ -6171,6 +6171,9 @@ u32 igc_rd32(struct igc_hw *hw, u32 reg)
        u8 __iomem *hw_addr = READ_ONCE(hw->hw_addr);
        u32 value = 0;
 
+       if (IGC_REMOVED(hw_addr))
+               return ~value;
+
        value = readl(&hw_addr[reg]);
 
        /* reads should not return all F's */
index e197a33d93a03099eeb55881dfea1293decbfd4f..026c3b65fc37aab1ff593a221bfbb9e0512fbf39 100644 (file)
@@ -306,7 +306,8 @@ u32 igc_rd32(struct igc_hw *hw, u32 reg);
 #define wr32(reg, val) \
 do { \
        u8 __iomem *hw_addr = READ_ONCE((hw)->hw_addr); \
-       writel((val), &hw_addr[(reg)]); \
+       if (!IGC_REMOVED(hw_addr)) \
+               writel((val), &hw_addr[(reg)]); \
 } while (0)
 
 #define rd32(reg) (igc_rd32(hw, reg))
@@ -318,4 +319,6 @@ do { \
 
 #define array_rd32(reg, offset) (igc_rd32(hw, (reg) + ((offset) << 2)))
 
+#define IGC_REMOVED(h) unlikely(!(h))
+
 #endif
index 921a4d977d65137d4eb20bd97c6dfe9750122042..8813b4dd6872f5a0e4cae7ceeb1bfb768bdafe6b 100644 (file)
@@ -779,6 +779,7 @@ struct ixgbe_adapter {
 #ifdef CONFIG_IXGBE_IPSEC
        struct ixgbe_ipsec *ipsec;
 #endif /* CONFIG_IXGBE_IPSEC */
+       spinlock_t vfs_lock;
 };
 
 static inline int ixgbe_determine_xdp_q_idx(int cpu)
index 77c2e70b0860d538a17942c6fe51ce8902c21a47..55f91c9ff0478ce744553c61dae54ef057a81d7a 100644 (file)
@@ -6403,6 +6403,9 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter,
        /* n-tuple support exists, always init our spinlock */
        spin_lock_init(&adapter->fdir_perfect_lock);
 
+       /* init spinlock to avoid concurrency of VF resources */
+       spin_lock_init(&adapter->vfs_lock);
+
 #ifdef CONFIG_IXGBE_DCB
        ixgbe_init_dcb(adapter);
 #endif
index d4e63f0644c366598eb435872b1c3aed5ab1866d..a1e69c7348632d19bdd833b8c75f71232a8de7ee 100644 (file)
@@ -205,10 +205,13 @@ void ixgbe_enable_sriov(struct ixgbe_adapter *adapter, unsigned int max_vfs)
 int ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
 {
        unsigned int num_vfs = adapter->num_vfs, vf;
+       unsigned long flags;
        int rss;
 
+       spin_lock_irqsave(&adapter->vfs_lock, flags);
        /* set num VFs to 0 to prevent access to vfinfo */
        adapter->num_vfs = 0;
+       spin_unlock_irqrestore(&adapter->vfs_lock, flags);
 
        /* put the reference to all of the vf devices */
        for (vf = 0; vf < num_vfs; ++vf) {
@@ -1355,8 +1358,10 @@ static void ixgbe_rcv_ack_from_vf(struct ixgbe_adapter *adapter, u32 vf)
 void ixgbe_msg_task(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_hw *hw = &adapter->hw;
+       unsigned long flags;
        u32 vf;
 
+       spin_lock_irqsave(&adapter->vfs_lock, flags);
        for (vf = 0; vf < adapter->num_vfs; vf++) {
                /* process any reset requests */
                if (!ixgbe_check_for_rst(hw, vf))
@@ -1370,6 +1375,7 @@ void ixgbe_msg_task(struct ixgbe_adapter *adapter)
                if (!ixgbe_check_for_ack(hw, vf))
                        ixgbe_rcv_ack_from_vf(adapter, vf);
        }
+       spin_unlock_irqrestore(&adapter->vfs_lock, flags);
 }
 
 static inline void ixgbe_ping_vf(struct ixgbe_adapter *adapter, int vf)
index d43e503c644f85d496ff55761ca1b7e1d2633af5..4d93ad6a284c0318d9f4deb560c2ffa798377707 100644 (file)
@@ -167,12 +167,12 @@ static int prestera_flower_parse_meta(struct prestera_acl_rule *rule,
        }
        port = netdev_priv(ingress_dev);
 
-       mask = htons(0x1FFF);
-       key = htons(port->hw_id);
+       mask = htons(0x1FFF << 3);
+       key = htons(port->hw_id << 3);
        rule_match_set(r_match->key, SYS_PORT, key);
        rule_match_set(r_match->mask, SYS_PORT, mask);
 
-       mask = htons(0x1FF);
+       mask = htons(0x3FF);
        key = htons(port->dev_id);
        rule_match_set(r_match->key, SYS_DEV, key);
        rule_match_set(r_match->mask, SYS_DEV, mask);
index 3754d8aec76d749af7f99106b0a94f5d0b496f22..3c8116f16b4dfb0335ffe79146a3920053f46ba1 100644 (file)
@@ -588,6 +588,7 @@ err_router_lib_init:
 
 void prestera_router_fini(struct prestera_switch *sw)
 {
+       unregister_fib_notifier(&init_net, &sw->router->fib_nb);
        unregister_inetaddr_notifier(&sw->router->inetaddr_nb);
        unregister_inetaddr_validator_notifier(&sw->router->inetaddr_valid_nb);
        rhashtable_destroy(&sw->router->kern_fib_cache_ht);
index 90e7dfd011c91f0cdb20b01d9d4cba7fc9730453..5d457bc9acc1cd12ece0cad7e92cf1de34c514ba 100644 (file)
@@ -93,6 +93,9 @@ mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_i
        };
        struct net_device_path path = {};
 
+       if (!ctx.dev)
+               return -ENODEV;
+
        memcpy(ctx.daddr, addr, sizeof(ctx.daddr));
 
        if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED))
index 8f0cd3196aacffedf6f59957fdd131e7ddb6e305..29be2fcafea3bc3907fe5b90a8bdb6e7e3997578 100644 (file)
@@ -651,7 +651,7 @@ mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
         * WDMA RX.
         */
 
-       BUG_ON(idx > ARRAY_SIZE(dev->tx_ring));
+       BUG_ON(idx >= ARRAY_SIZE(dev->tx_ring));
 
        if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE))
                return -ENOMEM;
index 25f51f80a9b468e4ab3d2c3f15d9816434ebc7ca..ba171c7f0a6758daa40b579f76d876923d5a13e5 100644 (file)
@@ -76,6 +76,7 @@ struct mlx5_tc_ct_priv {
        struct mlx5_ct_fs *fs;
        struct mlx5_ct_fs_ops *fs_ops;
        spinlock_t ht_lock; /* protects ft entries */
+       struct workqueue_struct *wq;
 
        struct mlx5_tc_ct_debugfs debugfs;
 };
@@ -941,14 +942,11 @@ static void mlx5_tc_ct_entry_del_work(struct work_struct *work)
 static void
 __mlx5_tc_ct_entry_put(struct mlx5_ct_entry *entry)
 {
-       struct mlx5e_priv *priv;
-
        if (!refcount_dec_and_test(&entry->refcnt))
                return;
 
-       priv = netdev_priv(entry->ct_priv->netdev);
        INIT_WORK(&entry->work, mlx5_tc_ct_entry_del_work);
-       queue_work(priv->wq, &entry->work);
+       queue_work(entry->ct_priv->wq, &entry->work);
 }
 
 static struct mlx5_ct_counter *
@@ -1759,19 +1757,16 @@ mlx5_tc_ct_flush_ft_entry(void *ptr, void *arg)
 static void
 mlx5_tc_ct_del_ft_cb(struct mlx5_tc_ct_priv *ct_priv, struct mlx5_ct_ft *ft)
 {
-       struct mlx5e_priv *priv;
-
        if (!refcount_dec_and_test(&ft->refcount))
                return;
 
+       flush_workqueue(ct_priv->wq);
        nf_flow_table_offload_del_cb(ft->nf_ft,
                                     mlx5_tc_ct_block_flow_offload, ft);
        rhashtable_remove_fast(&ct_priv->zone_ht, &ft->node, zone_params);
        rhashtable_free_and_destroy(&ft->ct_entries_ht,
                                    mlx5_tc_ct_flush_ft_entry,
                                    ct_priv);
-       priv = netdev_priv(ct_priv->netdev);
-       flush_workqueue(priv->wq);
        mlx5_tc_ct_free_pre_ct_tables(ft);
        mapping_remove(ct_priv->zone_mapping, ft->zone_restore_id);
        kfree(ft);
@@ -2176,6 +2171,12 @@ mlx5_tc_ct_init(struct mlx5e_priv *priv, struct mlx5_fs_chains *chains,
        if (rhashtable_init(&ct_priv->ct_tuples_nat_ht, &tuples_nat_ht_params))
                goto err_ct_tuples_nat_ht;
 
+       ct_priv->wq = alloc_ordered_workqueue("mlx5e_ct_priv_wq", 0);
+       if (!ct_priv->wq) {
+               err = -ENOMEM;
+               goto err_wq;
+       }
+
        err = mlx5_tc_ct_fs_init(ct_priv);
        if (err)
                goto err_init_fs;
@@ -2184,6 +2185,8 @@ mlx5_tc_ct_init(struct mlx5e_priv *priv, struct mlx5_fs_chains *chains,
        return ct_priv;
 
 err_init_fs:
+       destroy_workqueue(ct_priv->wq);
+err_wq:
        rhashtable_destroy(&ct_priv->ct_tuples_nat_ht);
 err_ct_tuples_nat_ht:
        rhashtable_destroy(&ct_priv->ct_tuples_ht);
@@ -2213,6 +2216,7 @@ mlx5_tc_ct_clean(struct mlx5_tc_ct_priv *ct_priv)
        if (!ct_priv)
                return;
 
+       destroy_workqueue(ct_priv->wq);
        mlx5_ct_tc_remove_dbgfs(ct_priv);
        chains = ct_priv->chains;
 
index 0bb0633b75426dfac464bb72efb9edfd8f65661a..27483aa7be8a8e649cb69edf08a179400cfa3622 100644 (file)
@@ -231,8 +231,7 @@ mlx5e_set_ktls_rx_priv_ctx(struct tls_context *tls_ctx,
        struct mlx5e_ktls_offload_context_rx **ctx =
                __tls_driver_ctx(tls_ctx, TLS_OFFLOAD_CTX_DIR_RX);
 
-       BUILD_BUG_ON(sizeof(struct mlx5e_ktls_offload_context_rx *) >
-                    TLS_OFFLOAD_CONTEXT_SIZE_RX);
+       BUILD_BUG_ON(sizeof(priv_rx) > TLS_DRIVER_STATE_SIZE_RX);
 
        *ctx = priv_rx;
 }
index 4b6f0d1ea59ad729d63d087773963648694d51ca..f239fb2e832f1a4e8f563b60c62d4ae9dabac3d8 100644 (file)
@@ -68,8 +68,7 @@ mlx5e_set_ktls_tx_priv_ctx(struct tls_context *tls_ctx,
        struct mlx5e_ktls_offload_context_tx **ctx =
                __tls_driver_ctx(tls_ctx, TLS_OFFLOAD_CTX_DIR_TX);
 
-       BUILD_BUG_ON(sizeof(struct mlx5e_ktls_offload_context_tx *) >
-                    TLS_OFFLOAD_CONTEXT_SIZE_TX);
+       BUILD_BUG_ON(sizeof(priv_tx) > TLS_DRIVER_STATE_SIZE_TX);
 
        *ctx = priv_tx;
 }
index 57fa0489eeb85146b64b6804492962fa7db94f5b..1e87bb2b754186218cef528bf2ba7745a985b3f1 100644 (file)
@@ -688,7 +688,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(vnic_env)
        u32 in[MLX5_ST_SZ_DW(query_vnic_env_in)] = {};
        struct mlx5_core_dev *mdev = priv->mdev;
 
-       if (!MLX5_CAP_GEN(priv->mdev, nic_receive_steering_discard))
+       if (!mlx5e_stats_grp_vnic_env_num_stats(priv))
                return;
 
        MLX5_SET(query_vnic_env_in, in, opcode, MLX5_CMD_OP_QUERY_VNIC_ENV);
index 34bf11cdf90fc6ef7e610ffa45484c8663e60d23..9ca2c876323789a22988ce18e759e3f95bf11ab7 100644 (file)
@@ -3793,7 +3793,7 @@ static bool is_lag_dev(struct mlx5e_priv *priv,
 
 static bool is_multiport_eligible(struct mlx5e_priv *priv, struct net_device *out_dev)
 {
-       if (mlx5e_eswitch_uplink_rep(out_dev) &&
+       if (same_hw_reps(priv, out_dev) &&
            MLX5_CAP_PORT_SELECTION(priv->mdev, port_select_flow_table) &&
            MLX5_CAP_GEN(priv->mdev, create_lag_when_not_master_up))
                return true;
@@ -4529,13 +4529,6 @@ static int mlx5e_policer_validate(const struct flow_action *action,
                return -EOPNOTSUPP;
        }
 
-       if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
-           act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
-               NL_SET_ERR_MSG_MOD(extack,
-                                  "Offload not supported when conform action is not pipe or ok");
-               return -EOPNOTSUPP;
-       }
-
        if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
            !flow_action_is_last_entry(action, act)) {
                NL_SET_ERR_MSG_MOD(extack,
@@ -4586,6 +4579,12 @@ static int scan_tc_matchall_fdb_actions(struct mlx5e_priv *priv,
        flow_action_for_each(i, act, flow_action) {
                switch (act->id) {
                case FLOW_ACTION_POLICE:
+                       if (act->police.notexceed.act_id != FLOW_ACTION_CONTINUE) {
+                               NL_SET_ERR_MSG_MOD(extack,
+                                                  "Offload not supported when conform action is not continue");
+                               return -EOPNOTSUPP;
+                       }
+
                        err = mlx5e_policer_validate(flow_action, act, extack);
                        if (err)
                                return err;
index 50d14cec4894beda28f87a9a4079601131ec89ad..9a7250be229f4a17c425204f0281965130d778d4 100644 (file)
@@ -341,6 +341,26 @@ static void mlx5e_tx_check_stop(struct mlx5e_txqsq *sq)
        }
 }
 
+static void mlx5e_tx_flush(struct mlx5e_txqsq *sq)
+{
+       struct mlx5e_tx_wqe_info *wi;
+       struct mlx5e_tx_wqe *wqe;
+       u16 pi;
+
+       /* Must not be called when a MPWQE session is active but empty. */
+       mlx5e_tx_mpwqe_ensure_complete(sq);
+
+       pi = mlx5_wq_cyc_ctr2ix(&sq->wq, sq->pc);
+       wi = &sq->db.wqe_info[pi];
+
+       *wi = (struct mlx5e_tx_wqe_info) {
+               .num_wqebbs = 1,
+       };
+
+       wqe = mlx5e_post_nop(&sq->wq, sq->sqn, &sq->pc);
+       mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, &wqe->ctrl);
+}
+
 static inline void
 mlx5e_txwqe_complete(struct mlx5e_txqsq *sq, struct sk_buff *skb,
                     const struct mlx5e_tx_attr *attr,
@@ -459,6 +479,7 @@ mlx5e_sq_xmit_wqe(struct mlx5e_txqsq *sq, struct sk_buff *skb,
 err_drop:
        stats->dropped++;
        dev_kfree_skb_any(skb);
+       mlx5e_tx_flush(sq);
 }
 
 static bool mlx5e_tx_skb_supports_mpwqe(struct sk_buff *skb, struct mlx5e_tx_attr *attr)
@@ -560,6 +581,13 @@ mlx5e_sq_xmit_mpwqe(struct mlx5e_txqsq *sq, struct sk_buff *skb,
        struct mlx5_wqe_ctrl_seg *cseg;
        struct mlx5e_xmit_data txd;
 
+       txd.data = skb->data;
+       txd.len = skb->len;
+
+       txd.dma_addr = dma_map_single(sq->pdev, txd.data, txd.len, DMA_TO_DEVICE);
+       if (unlikely(dma_mapping_error(sq->pdev, txd.dma_addr)))
+               goto err_unmap;
+
        if (!mlx5e_tx_mpwqe_session_is_active(sq)) {
                mlx5e_tx_mpwqe_session_start(sq, eseg);
        } else if (!mlx5e_tx_mpwqe_same_eseg(sq, eseg)) {
@@ -569,18 +597,9 @@ mlx5e_sq_xmit_mpwqe(struct mlx5e_txqsq *sq, struct sk_buff *skb,
 
        sq->stats->xmit_more += xmit_more;
 
-       txd.data = skb->data;
-       txd.len = skb->len;
-
-       txd.dma_addr = dma_map_single(sq->pdev, txd.data, txd.len, DMA_TO_DEVICE);
-       if (unlikely(dma_mapping_error(sq->pdev, txd.dma_addr)))
-               goto err_unmap;
        mlx5e_dma_push(sq, txd.dma_addr, txd.len, MLX5E_DMA_MAP_SINGLE);
-
        mlx5e_skb_fifo_push(&sq->db.skb_fifo, skb);
-
        mlx5e_tx_mpwqe_add_dseg(sq, &txd);
-
        mlx5e_tx_skb_update_hwts_flags(skb);
 
        if (unlikely(mlx5e_tx_mpwqe_is_full(&sq->mpwqe, sq->max_sq_mpw_wqebbs))) {
@@ -602,6 +621,7 @@ err_unmap:
        mlx5e_dma_unmap_wqe_err(sq, 1);
        sq->stats->dropped++;
        dev_kfree_skb_any(skb);
+       mlx5e_tx_flush(sq);
 }
 
 void mlx5e_tx_mpwqe_ensure_complete(struct mlx5e_txqsq *sq)
@@ -1006,5 +1026,6 @@ void mlx5i_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb,
 err_drop:
        stats->dropped++;
        dev_kfree_skb_any(skb);
+       mlx5e_tx_flush(sq);
 }
 #endif
index 9d17206d16251985ff2763eca183bf7558126123..fabe49a35a5c963a12dfbd4bd4aabdf8f98b4638 100644 (file)
@@ -11,6 +11,7 @@
 #include "mlx5_core.h"
 #include "eswitch.h"
 #include "fs_core.h"
+#include "fs_ft_pool.h"
 #include "esw/qos.h"
 
 enum {
@@ -95,8 +96,7 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw)
        if (!flow_group_in)
                return -ENOMEM;
 
-       table_size = BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
-       ft_attr.max_fte = table_size;
+       ft_attr.max_fte = POOL_NEXT_SIZE;
        ft_attr.prio = LEGACY_FDB_PRIO;
        fdb = mlx5_create_flow_table(root_ns, &ft_attr);
        if (IS_ERR(fdb)) {
@@ -105,6 +105,7 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw)
                goto out;
        }
        esw->fdb_table.legacy.fdb = fdb;
+       table_size = fdb->max_fte;
 
        /* Addresses group : Full match unicast/multicast addresses */
        MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
index 15e41dc84d5389d8fbb37aae60f11ff66f7139f8..b8feaf0f5c4c837242f21290d867907eddf671d0 100644 (file)
@@ -44,7 +44,7 @@ static int port_sel_mode_show(struct seq_file *file, void *priv)
        ldev = dev->priv.lag;
        mutex_lock(&ldev->lock);
        if (__mlx5_lag_is_active(ldev))
-               mode = mlx5_get_str_port_sel_mode(ldev);
+               mode = mlx5_get_str_port_sel_mode(ldev->mode, ldev->mode_flags);
        else
                ret = -EINVAL;
        mutex_unlock(&ldev->lock);
@@ -72,6 +72,7 @@ static int state_show(struct seq_file *file, void *priv)
 static int flags_show(struct seq_file *file, void *priv)
 {
        struct mlx5_core_dev *dev = file->private;
+       bool fdb_sel_mode_native;
        struct mlx5_lag *ldev;
        bool shared_fdb;
        bool lag_active;
@@ -79,14 +80,21 @@ static int flags_show(struct seq_file *file, void *priv)
        ldev = dev->priv.lag;
        mutex_lock(&ldev->lock);
        lag_active = __mlx5_lag_is_active(ldev);
-       if (lag_active)
-               shared_fdb = test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &ldev->mode_flags);
+       if (!lag_active)
+               goto unlock;
+
+       shared_fdb = test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &ldev->mode_flags);
+       fdb_sel_mode_native = test_bit(MLX5_LAG_MODE_FLAG_FDB_SEL_MODE_NATIVE,
+                                      &ldev->mode_flags);
 
+unlock:
        mutex_unlock(&ldev->lock);
        if (!lag_active)
                return -EINVAL;
 
        seq_printf(file, "%s:%s\n", "shared_fdb", shared_fdb ? "on" : "off");
+       seq_printf(file, "%s:%s\n", "fdb_selection_mode",
+                  fdb_sel_mode_native ? "native" : "affinity");
        return 0;
 }
 
index 2a8fc547eb37cb73f5a4e0bc6f78804f7bc6c9b3..5d41e19378e097deeffa5751ca995d2c94df8912 100644 (file)
@@ -68,14 +68,15 @@ static int get_port_sel_mode(enum mlx5_lag_mode mode, unsigned long flags)
 static int mlx5_cmd_create_lag(struct mlx5_core_dev *dev, u8 *ports, int mode,
                               unsigned long flags)
 {
-       bool shared_fdb = test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &flags);
+       bool fdb_sel_mode = test_bit(MLX5_LAG_MODE_FLAG_FDB_SEL_MODE_NATIVE,
+                                    &flags);
        int port_sel_mode = get_port_sel_mode(mode, flags);
        u32 in[MLX5_ST_SZ_DW(create_lag_in)] = {};
        void *lag_ctx;
 
        lag_ctx = MLX5_ADDR_OF(create_lag_in, in, ctx);
        MLX5_SET(create_lag_in, in, opcode, MLX5_CMD_OP_CREATE_LAG);
-       MLX5_SET(lagc, lag_ctx, fdb_selection_mode, shared_fdb);
+       MLX5_SET(lagc, lag_ctx, fdb_selection_mode, fdb_sel_mode);
        if (port_sel_mode == MLX5_LAG_PORT_SELECT_MODE_QUEUE_AFFINITY) {
                MLX5_SET(lagc, lag_ctx, tx_remap_affinity_1, ports[0]);
                MLX5_SET(lagc, lag_ctx, tx_remap_affinity_2, ports[1]);
@@ -471,8 +472,13 @@ static int mlx5_lag_set_flags(struct mlx5_lag *ldev, enum mlx5_lag_mode mode,
        bool roce_lag = mode == MLX5_LAG_MODE_ROCE;
 
        *flags = 0;
-       if (shared_fdb)
+       if (shared_fdb) {
                set_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, flags);
+               set_bit(MLX5_LAG_MODE_FLAG_FDB_SEL_MODE_NATIVE, flags);
+       }
+
+       if (mode == MLX5_LAG_MODE_MPESW)
+               set_bit(MLX5_LAG_MODE_FLAG_FDB_SEL_MODE_NATIVE, flags);
 
        if (roce_lag)
                return mlx5_lag_set_port_sel_mode_roce(ldev, flags);
@@ -481,9 +487,9 @@ static int mlx5_lag_set_flags(struct mlx5_lag *ldev, enum mlx5_lag_mode mode,
        return 0;
 }
 
-char *mlx5_get_str_port_sel_mode(struct mlx5_lag *ldev)
+char *mlx5_get_str_port_sel_mode(enum mlx5_lag_mode mode, unsigned long flags)
 {
-       int port_sel_mode = get_port_sel_mode(ldev->mode, ldev->mode_flags);
+       int port_sel_mode = get_port_sel_mode(mode, flags);
 
        switch (port_sel_mode) {
        case MLX5_LAG_PORT_SELECT_MODE_QUEUE_AFFINITY: return "queue_affinity";
@@ -507,7 +513,7 @@ static int mlx5_create_lag(struct mlx5_lag *ldev,
        if (tracker)
                mlx5_lag_print_mapping(dev0, ldev, tracker, flags);
        mlx5_core_info(dev0, "shared_fdb:%d mode:%s\n",
-                      shared_fdb, mlx5_get_str_port_sel_mode(ldev));
+                      shared_fdb, mlx5_get_str_port_sel_mode(mode, flags));
 
        err = mlx5_cmd_create_lag(dev0, ldev->v2p_map, mode, flags);
        if (err) {
index c81b173156d283b6a47b4d4587a9c4b46efe4f04..ce2ce8ccbd70eff22c9307d4bf9366bb28b00548 100644 (file)
@@ -24,6 +24,7 @@ enum {
 enum {
        MLX5_LAG_MODE_FLAG_HASH_BASED,
        MLX5_LAG_MODE_FLAG_SHARED_FDB,
+       MLX5_LAG_MODE_FLAG_FDB_SEL_MODE_NATIVE,
 };
 
 enum mlx5_lag_mode {
@@ -114,7 +115,7 @@ bool mlx5_shared_fdb_supported(struct mlx5_lag *ldev);
 void mlx5_lag_del_mpesw_rule(struct mlx5_core_dev *dev);
 int mlx5_lag_add_mpesw_rule(struct mlx5_core_dev *dev);
 
-char *mlx5_get_str_port_sel_mode(struct mlx5_lag *ldev);
+char *mlx5_get_str_port_sel_mode(enum mlx5_lag_mode mode, unsigned long flags);
 void mlx5_infer_tx_enabled(struct lag_tracker *tracker, u8 num_ports,
                           u8 *ports, int *num_enabled);
 
index ee4b25a50315a738cbd4c2a4ff6b697f07ab8f68..f643202b29c6c97a6bff1a161e2214d284d46b66 100644 (file)
@@ -41,7 +41,6 @@ void mlx5_lag_del_mpesw_rule(struct mlx5_core_dev *dev)
 int mlx5_lag_add_mpesw_rule(struct mlx5_core_dev *dev)
 {
        struct mlx5_lag *ldev = dev->priv.lag;
-       bool shared_fdb;
        int err = 0;
 
        if (!ldev)
@@ -55,8 +54,8 @@ int mlx5_lag_add_mpesw_rule(struct mlx5_core_dev *dev)
                err = -EINVAL;
                goto out;
        }
-       shared_fdb = mlx5_shared_fdb_supported(ldev);
-       err = mlx5_activate_lag(ldev, NULL, MLX5_LAG_MODE_MPESW, shared_fdb);
+
+       err = mlx5_activate_lag(ldev, NULL, MLX5_LAG_MODE_MPESW, false);
        if (err)
                mlx5_core_warn(dev, "Failed to create LAG in MPESW mode (%d)\n", err);
 
index 0d8a0068e4ca1c1b004ac752a9905554317cacb9..ce33dbde124d9dc4baedd125581da2d9d05bbcc6 100644 (file)
@@ -5384,7 +5384,7 @@ static bool mlxsw_sp_fi_is_gateway(const struct mlxsw_sp *mlxsw_sp,
 {
        const struct fib_nh *nh = fib_info_nh(fi, 0);
 
-       return nh->fib_nh_scope == RT_SCOPE_LINK ||
+       return nh->fib_nh_gw_family ||
               mlxsw_sp_nexthop4_ipip_type(mlxsw_sp, nh, NULL);
 }
 
@@ -10324,7 +10324,7 @@ static void mlxsw_sp_mp4_hash_init(struct mlxsw_sp *mlxsw_sp,
        unsigned long *fields = config->fields;
        u32 hash_fields;
 
-       switch (net->ipv4.sysctl_fib_multipath_hash_policy) {
+       switch (READ_ONCE(net->ipv4.sysctl_fib_multipath_hash_policy)) {
        case 0:
                mlxsw_sp_mp4_hash_outer_addr(config);
                break;
@@ -10342,7 +10342,7 @@ static void mlxsw_sp_mp4_hash_init(struct mlxsw_sp *mlxsw_sp,
                mlxsw_sp_mp_hash_inner_l3(config);
                break;
        case 3:
-               hash_fields = net->ipv4.sysctl_fib_multipath_hash_fields;
+               hash_fields = READ_ONCE(net->ipv4.sysctl_fib_multipath_hash_fields);
                /* Outer */
                MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_NOT_TCP_NOT_UDP);
                MLXSW_SP_MP_HASH_HEADER_SET(headers, IPV4_EN_TCP_UDP);
@@ -10523,13 +10523,14 @@ static int mlxsw_sp_dscp_init(struct mlxsw_sp *mlxsw_sp)
 static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
 {
        struct net *net = mlxsw_sp_net(mlxsw_sp);
-       bool usp = net->ipv4.sysctl_ip_fwd_update_priority;
        char rgcr_pl[MLXSW_REG_RGCR_LEN];
        u64 max_rifs;
+       bool usp;
 
        if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_RIFS))
                return -EIO;
        max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
+       usp = READ_ONCE(net->ipv4.sysctl_ip_fwd_update_priority);
 
        mlxsw_reg_rgcr_pack(rgcr_pl, true, true);
        mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl, max_rifs);
index 005e56ea5da1204c98e12778aa791b39b56b9dc9..5893770bfd94627139cdca7d61b88a224040ad48 100644 (file)
@@ -75,6 +75,9 @@ static int __lan966x_mac_learn(struct lan966x *lan966x, int pgid,
                               unsigned int vid,
                               enum macaccess_entry_type type)
 {
+       int ret;
+
+       spin_lock(&lan966x->mac_lock);
        lan966x_mac_select(lan966x, mac, vid);
 
        /* Issue a write command */
@@ -86,7 +89,10 @@ static int __lan966x_mac_learn(struct lan966x *lan966x, int pgid,
               ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_LEARN),
               lan966x, ANA_MACACCESS);
 
-       return lan966x_mac_wait_for_completion(lan966x);
+       ret = lan966x_mac_wait_for_completion(lan966x);
+       spin_unlock(&lan966x->mac_lock);
+
+       return ret;
 }
 
 /* The mask of the front ports is encoded inside the mac parameter via a call
@@ -113,11 +119,13 @@ int lan966x_mac_learn(struct lan966x *lan966x, int port,
        return __lan966x_mac_learn(lan966x, port, false, mac, vid, type);
 }
 
-int lan966x_mac_forget(struct lan966x *lan966x,
-                      const unsigned char mac[ETH_ALEN],
-                      unsigned int vid,
-                      enum macaccess_entry_type type)
+static int lan966x_mac_forget_locked(struct lan966x *lan966x,
+                                    const unsigned char mac[ETH_ALEN],
+                                    unsigned int vid,
+                                    enum macaccess_entry_type type)
 {
+       lockdep_assert_held(&lan966x->mac_lock);
+
        lan966x_mac_select(lan966x, mac, vid);
 
        /* Issue a forget command */
@@ -128,6 +136,20 @@ int lan966x_mac_forget(struct lan966x *lan966x,
        return lan966x_mac_wait_for_completion(lan966x);
 }
 
+int lan966x_mac_forget(struct lan966x *lan966x,
+                      const unsigned char mac[ETH_ALEN],
+                      unsigned int vid,
+                      enum macaccess_entry_type type)
+{
+       int ret;
+
+       spin_lock(&lan966x->mac_lock);
+       ret = lan966x_mac_forget_locked(lan966x, mac, vid, type);
+       spin_unlock(&lan966x->mac_lock);
+
+       return ret;
+}
+
 int lan966x_mac_cpu_learn(struct lan966x *lan966x, const char *addr, u16 vid)
 {
        return lan966x_mac_learn(lan966x, PGID_CPU, addr, vid, ENTRYTYPE_LOCKED);
@@ -161,7 +183,7 @@ static struct lan966x_mac_entry *lan966x_mac_alloc_entry(const unsigned char *ma
 {
        struct lan966x_mac_entry *mac_entry;
 
-       mac_entry = kzalloc(sizeof(*mac_entry), GFP_KERNEL);
+       mac_entry = kzalloc(sizeof(*mac_entry), GFP_ATOMIC);
        if (!mac_entry)
                return NULL;
 
@@ -179,7 +201,6 @@ static struct lan966x_mac_entry *lan966x_mac_find_entry(struct lan966x *lan966x,
        struct lan966x_mac_entry *res = NULL;
        struct lan966x_mac_entry *mac_entry;
 
-       spin_lock(&lan966x->mac_lock);
        list_for_each_entry(mac_entry, &lan966x->mac_entries, list) {
                if (mac_entry->vid == vid &&
                    ether_addr_equal(mac, mac_entry->mac) &&
@@ -188,7 +209,6 @@ static struct lan966x_mac_entry *lan966x_mac_find_entry(struct lan966x *lan966x,
                        break;
                }
        }
-       spin_unlock(&lan966x->mac_lock);
 
        return res;
 }
@@ -231,8 +251,11 @@ int lan966x_mac_add_entry(struct lan966x *lan966x, struct lan966x_port *port,
 {
        struct lan966x_mac_entry *mac_entry;
 
-       if (lan966x_mac_lookup(lan966x, addr, vid, ENTRYTYPE_NORMAL))
+       spin_lock(&lan966x->mac_lock);
+       if (lan966x_mac_lookup(lan966x, addr, vid, ENTRYTYPE_NORMAL)) {
+               spin_unlock(&lan966x->mac_lock);
                return 0;
+       }
 
        /* In case the entry already exists, don't add it again to SW,
         * just update HW, but we need to look in the actual HW because
@@ -241,21 +264,25 @@ int lan966x_mac_add_entry(struct lan966x *lan966x, struct lan966x_port *port,
         * add the entry but without the extern_learn flag.
         */
        mac_entry = lan966x_mac_find_entry(lan966x, addr, vid, port->chip_port);
-       if (mac_entry)
-               return lan966x_mac_learn(lan966x, port->chip_port,
-                                        addr, vid, ENTRYTYPE_LOCKED);
+       if (mac_entry) {
+               spin_unlock(&lan966x->mac_lock);
+               goto mac_learn;
+       }
 
        mac_entry = lan966x_mac_alloc_entry(addr, vid, port->chip_port);
-       if (!mac_entry)
+       if (!mac_entry) {
+               spin_unlock(&lan966x->mac_lock);
                return -ENOMEM;
+       }
 
-       spin_lock(&lan966x->mac_lock);
        list_add_tail(&mac_entry->list, &lan966x->mac_entries);
        spin_unlock(&lan966x->mac_lock);
 
-       lan966x_mac_learn(lan966x, port->chip_port, addr, vid, ENTRYTYPE_LOCKED);
        lan966x_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED, addr, vid, port->dev);
 
+mac_learn:
+       lan966x_mac_learn(lan966x, port->chip_port, addr, vid, ENTRYTYPE_LOCKED);
+
        return 0;
 }
 
@@ -269,8 +296,9 @@ int lan966x_mac_del_entry(struct lan966x *lan966x, const unsigned char *addr,
                                 list) {
                if (mac_entry->vid == vid &&
                    ether_addr_equal(addr, mac_entry->mac)) {
-                       lan966x_mac_forget(lan966x, mac_entry->mac, mac_entry->vid,
-                                          ENTRYTYPE_LOCKED);
+                       lan966x_mac_forget_locked(lan966x, mac_entry->mac,
+                                                 mac_entry->vid,
+                                                 ENTRYTYPE_LOCKED);
 
                        list_del(&mac_entry->list);
                        kfree(mac_entry);
@@ -288,8 +316,8 @@ void lan966x_mac_purge_entries(struct lan966x *lan966x)
        spin_lock(&lan966x->mac_lock);
        list_for_each_entry_safe(mac_entry, tmp, &lan966x->mac_entries,
                                 list) {
-               lan966x_mac_forget(lan966x, mac_entry->mac, mac_entry->vid,
-                                  ENTRYTYPE_LOCKED);
+               lan966x_mac_forget_locked(lan966x, mac_entry->mac,
+                                         mac_entry->vid, ENTRYTYPE_LOCKED);
 
                list_del(&mac_entry->list);
                kfree(mac_entry);
@@ -325,10 +353,13 @@ static void lan966x_mac_irq_process(struct lan966x *lan966x, u32 row,
 {
        struct lan966x_mac_entry *mac_entry, *tmp;
        unsigned char mac[ETH_ALEN] __aligned(2);
+       struct list_head mac_deleted_entries;
        u32 dest_idx;
        u32 column;
        u16 vid;
 
+       INIT_LIST_HEAD(&mac_deleted_entries);
+
        spin_lock(&lan966x->mac_lock);
        list_for_each_entry_safe(mac_entry, tmp, &lan966x->mac_entries, list) {
                bool found = false;
@@ -362,20 +393,26 @@ static void lan966x_mac_irq_process(struct lan966x *lan966x, u32 row,
                }
 
                if (!found) {
-                       /* Notify the bridge that the entry doesn't exist
-                        * anymore in the HW and remove the entry from the SW
-                        * list
-                        */
-                       lan966x_mac_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE,
-                                             mac_entry->mac, mac_entry->vid,
-                                             lan966x->ports[mac_entry->port_index]->dev);
-
                        list_del(&mac_entry->list);
-                       kfree(mac_entry);
+                       /* Move the entry from SW list to a tmp list such that
+                        * it would be deleted later
+                        */
+                       list_add_tail(&mac_entry->list, &mac_deleted_entries);
                }
        }
        spin_unlock(&lan966x->mac_lock);
 
+       list_for_each_entry_safe(mac_entry, tmp, &mac_deleted_entries, list) {
+               /* Notify the bridge that the entry doesn't exist
+                * anymore in the HW
+                */
+               lan966x_mac_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE,
+                                     mac_entry->mac, mac_entry->vid,
+                                     lan966x->ports[mac_entry->port_index]->dev);
+               list_del(&mac_entry->list);
+               kfree(mac_entry);
+       }
+
        /* Now go to the list of columns and see if any entry was not in the SW
         * list, then that means that the entry is new so it needs to notify the
         * bridge.
@@ -396,13 +433,20 @@ static void lan966x_mac_irq_process(struct lan966x *lan966x, u32 row,
                if (WARN_ON(dest_idx >= lan966x->num_phys_ports))
                        continue;
 
+               spin_lock(&lan966x->mac_lock);
+               mac_entry = lan966x_mac_find_entry(lan966x, mac, vid, dest_idx);
+               if (mac_entry) {
+                       spin_unlock(&lan966x->mac_lock);
+                       continue;
+               }
+
                mac_entry = lan966x_mac_alloc_entry(mac, vid, dest_idx);
-               if (!mac_entry)
+               if (!mac_entry) {
+                       spin_unlock(&lan966x->mac_lock);
                        return;
+               }
 
                mac_entry->row = row;
-
-               spin_lock(&lan966x->mac_lock);
                list_add_tail(&mac_entry->list, &lan966x->mac_entries);
                spin_unlock(&lan966x->mac_lock);
 
@@ -424,6 +468,7 @@ irqreturn_t lan966x_mac_irq_handler(struct lan966x *lan966x)
               lan966x, ANA_MACTINDX);
 
        while (1) {
+               spin_lock(&lan966x->mac_lock);
                lan_rmw(ANA_MACACCESS_MAC_TABLE_CMD_SET(MACACCESS_CMD_SYNC_GET_NEXT),
                        ANA_MACACCESS_MAC_TABLE_CMD,
                        lan966x, ANA_MACACCESS);
@@ -447,12 +492,15 @@ irqreturn_t lan966x_mac_irq_handler(struct lan966x *lan966x)
                        stop = false;
 
                if (column == LAN966X_MAC_COLUMNS - 1 &&
-                   index == 0 && stop)
+                   index == 0 && stop) {
+                       spin_unlock(&lan966x->mac_lock);
                        break;
+               }
 
                entry[column].mach = lan_rd(lan966x, ANA_MACHDATA);
                entry[column].macl = lan_rd(lan966x, ANA_MACLDATA);
                entry[column].maca = lan_rd(lan966x, ANA_MACACCESS);
+               spin_unlock(&lan966x->mac_lock);
 
                /* Once all the columns are read process them */
                if (column == LAN966X_MAC_COLUMNS - 1) {
index 5784c4161e5e6c496045b7d729a61f125ac795bc..1d6e3b641b2e666acbb787da91cc27530eeadf2b 100644 (file)
@@ -994,7 +994,7 @@ static int lan966x_probe(struct platform_device *pdev)
        struct fwnode_handle *ports, *portnp;
        struct lan966x *lan966x;
        u8 mac_addr[ETH_ALEN];
-       int err, i;
+       int err;
 
        lan966x = devm_kzalloc(&pdev->dev, sizeof(*lan966x), GFP_KERNEL);
        if (!lan966x)
@@ -1025,11 +1025,7 @@ static int lan966x_probe(struct platform_device *pdev)
        if (err)
                return dev_err_probe(&pdev->dev, err, "Reset failed");
 
-       i = 0;
-       fwnode_for_each_available_child_node(ports, portnp)
-               ++i;
-
-       lan966x->num_phys_ports = i;
+       lan966x->num_phys_ports = NUM_PHYS_PORTS;
        lan966x->ports = devm_kcalloc(&pdev->dev, lan966x->num_phys_ports,
                                      sizeof(struct lan966x_port *),
                                      GFP_KERNEL);
index 3b86ddddc7560f173dd34b81fa94b481dfde5563..2787055c1847535c09a1eb5a3086ffe42305b3ea 100644 (file)
@@ -34,6 +34,7 @@
 /* Reserved amount for (SRC, PRIO) at index 8*SRC + PRIO */
 #define QSYS_Q_RSRV                    95
 
+#define NUM_PHYS_PORTS                 8
 #define CPU_PORT                       8
 
 /* Reserved PGIDs */
index 083fddd263ec620207d852f9acc05b9a0c71f899..8e3894cf5f7cd3ee469f26bb305c9f0a72962c55 100644 (file)
@@ -94,19 +94,18 @@ static void ocelot_fdma_activate_chan(struct ocelot *ocelot, dma_addr_t dma,
        ocelot_fdma_writel(ocelot, MSCC_FDMA_CH_ACTIVATE, BIT(chan));
 }
 
+static u32 ocelot_fdma_read_ch_safe(struct ocelot *ocelot)
+{
+       return ocelot_fdma_readl(ocelot, MSCC_FDMA_CH_SAFE);
+}
+
 static int ocelot_fdma_wait_chan_safe(struct ocelot *ocelot, int chan)
 {
-       unsigned long timeout;
        u32 safe;
 
-       timeout = jiffies + usecs_to_jiffies(OCELOT_FDMA_CH_SAFE_TIMEOUT_US);
-       do {
-               safe = ocelot_fdma_readl(ocelot, MSCC_FDMA_CH_SAFE);
-               if (safe & BIT(chan))
-                       return 0;
-       } while (time_after(jiffies, timeout));
-
-       return -ETIMEDOUT;
+       return readx_poll_timeout_atomic(ocelot_fdma_read_ch_safe, ocelot, safe,
+                                        safe & BIT(chan), 0,
+                                        OCELOT_FDMA_CH_SAFE_TIMEOUT_US);
 }
 
 static void ocelot_fdma_dcb_set_data(struct ocelot_fdma_dcb *dcb,
index 0147de40536533bea52ee9f140a7933ac9b77c65..ffb6f6d05a07b764114db98e0fbe4497e2dfe80b 100644 (file)
@@ -474,7 +474,7 @@ nfp_fl_set_tun(struct nfp_app *app, struct nfp_fl_set_tun *set_tun,
                        set_tun->ttl = ip4_dst_hoplimit(&rt->dst);
                        ip_rt_put(rt);
                } else {
-                       set_tun->ttl = net->ipv4.sysctl_ip_default_ttl;
+                       set_tun->ttl = READ_ONCE(net->ipv4.sysctl_ip_default_ttl);
                }
        }
 
index 6bf3ec448e7e5b55266423577db7d2d49e5ee80d..97dcf8db7ed230490a46d4bc0ab84abaa8d109e8 100644 (file)
@@ -447,7 +447,8 @@ void nfp_tun_unlink_and_update_nn_entries(struct nfp_app *app,
 
 static void
 nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
-                   void *flow, struct neighbour *neigh, bool is_ipv6)
+                   void *flow, struct neighbour *neigh, bool is_ipv6,
+                   bool override)
 {
        bool neigh_invalid = !(neigh->nud_state & NUD_VALID) || neigh->dead;
        size_t neigh_size = is_ipv6 ? sizeof(struct nfp_tun_neigh_v6) :
@@ -546,6 +547,13 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
                if (nn_entry->flow)
                        list_del(&nn_entry->list_head);
                kfree(nn_entry);
+       } else if (nn_entry && !neigh_invalid && override) {
+               mtype = is_ipv6 ? NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6 :
+                               NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
+               nfp_tun_link_predt_entries(app, nn_entry);
+               nfp_flower_xmit_tun_conf(app, mtype, neigh_size,
+                                        nn_entry->payload,
+                                        GFP_ATOMIC);
        }
 
        spin_unlock_bh(&priv->predt_lock);
@@ -610,7 +618,7 @@ nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
 
                        dst_release(dst);
                }
-               nfp_tun_write_neigh(n->dev, app, &flow6, n, true);
+               nfp_tun_write_neigh(n->dev, app, &flow6, n, true, false);
 #else
                return NOTIFY_DONE;
 #endif /* CONFIG_IPV6 */
@@ -633,7 +641,7 @@ nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
 
                        ip_rt_put(rt);
                }
-               nfp_tun_write_neigh(n->dev, app, &flow4, n, false);
+               nfp_tun_write_neigh(n->dev, app, &flow4, n, false, false);
        }
 #else
        return NOTIFY_DONE;
@@ -676,7 +684,7 @@ void nfp_tunnel_request_route_v4(struct nfp_app *app, struct sk_buff *skb)
        ip_rt_put(rt);
        if (!n)
                goto fail_rcu_unlock;
-       nfp_tun_write_neigh(n->dev, app, &flow, n, false);
+       nfp_tun_write_neigh(n->dev, app, &flow, n, false, true);
        neigh_release(n);
        rcu_read_unlock();
        return;
@@ -718,7 +726,7 @@ void nfp_tunnel_request_route_v6(struct nfp_app *app, struct sk_buff *skb)
        if (!n)
                goto fail_rcu_unlock;
 
-       nfp_tun_write_neigh(n->dev, app, &flow, n, true);
+       nfp_tun_write_neigh(n->dev, app, &flow, n, true, true);
        neigh_release(n);
        rcu_read_unlock();
        return;
index e509d6dcba5cb3defee06d29f8157adf134deda8..805071d64a20388de19f5a49784e7c82178c6e36 100644 (file)
@@ -125,17 +125,18 @@ nfp_nfdk_tx_csum(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec,
 
 static int
 nfp_nfdk_tx_maybe_close_block(struct nfp_net_tx_ring *tx_ring,
-                             unsigned int nr_frags, struct sk_buff *skb)
+                             struct sk_buff *skb)
 {
        unsigned int n_descs, wr_p, nop_slots;
        const skb_frag_t *frag, *fend;
        struct nfp_nfdk_tx_desc *txd;
+       unsigned int nr_frags;
        unsigned int wr_idx;
        int err;
 
 recount_descs:
        n_descs = nfp_nfdk_headlen_to_segs(skb_headlen(skb));
-
+       nr_frags = skb_shinfo(skb)->nr_frags;
        frag = skb_shinfo(skb)->frags;
        fend = frag + nr_frags;
        for (; frag < fend; frag++)
@@ -281,10 +282,13 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev)
        if (unlikely((int)metadata < 0))
                goto err_flush;
 
-       nr_frags = skb_shinfo(skb)->nr_frags;
-       if (nfp_nfdk_tx_maybe_close_block(tx_ring, nr_frags, skb))
+       if (nfp_nfdk_tx_maybe_close_block(tx_ring, skb))
                goto err_flush;
 
+       /* nr_frags will change after skb_linearize so we get nr_frags after
+        * nfp_nfdk_tx_maybe_close_block function
+        */
+       nr_frags = skb_shinfo(skb)->nr_frags;
        /* DMA map all */
        wr_idx = D_IDX(tx_ring, tx_ring->wr_p);
        txd = &tx_ring->ktxds[wr_idx];
@@ -310,7 +314,16 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev)
 
        /* FIELD_PREP() implicitly truncates to chunk */
        dma_len -= 1;
-       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD, dma_len) |
+
+       /* We will do our best to pass as much data as we can in descriptor
+        * and we need to make sure the first descriptor includes whole head
+        * since there is limitation in firmware side. Sometimes the value of
+        * dma_len bitwise and NFDK_DESC_TX_DMA_LEN_HEAD will less than
+        * headlen.
+        */
+       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD,
+                              dma_len > NFDK_DESC_TX_DMA_LEN_HEAD ?
+                              NFDK_DESC_TX_DMA_LEN_HEAD : dma_len) |
                    FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type);
 
        txd->dma_len_type = cpu_to_le16(dlen_type);
@@ -925,7 +938,9 @@ nfp_nfdk_tx_xdp_buf(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring,
 
        /* FIELD_PREP() implicitly truncates to chunk */
        dma_len -= 1;
-       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD, dma_len) |
+       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD,
+                              dma_len > NFDK_DESC_TX_DMA_LEN_HEAD ?
+                              NFDK_DESC_TX_DMA_LEN_HEAD : dma_len) |
                    FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type);
 
        txd->dma_len_type = cpu_to_le16(dlen_type);
@@ -1303,7 +1318,7 @@ nfp_nfdk_ctrl_tx_one(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
                                   skb_push(skb, 4));
        }
 
-       if (nfp_nfdk_tx_maybe_close_block(tx_ring, 0, skb))
+       if (nfp_nfdk_tx_maybe_close_block(tx_ring, skb))
                goto err_free;
 
        /* DMA map all */
@@ -1328,7 +1343,9 @@ nfp_nfdk_ctrl_tx_one(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
        txbuf++;
 
        dma_len -= 1;
-       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD, dma_len) |
+       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD,
+                              dma_len > NFDK_DESC_TX_DMA_LEN_HEAD ?
+                              NFDK_DESC_TX_DMA_LEN_HEAD : dma_len) |
                    FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type);
 
        txd->dma_len_type = cpu_to_le16(dlen_type);
index 3098d667219244ea315c6df16277deeabec988d6..1b7fdb4f056bdabb918637b0dcf644d9571e6aa5 100644 (file)
@@ -4190,7 +4190,6 @@ static void rtl8169_tso_csum_v1(struct sk_buff *skb, u32 *opts)
 static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
                                struct sk_buff *skb, u32 *opts)
 {
-       u32 transport_offset = (u32)skb_transport_offset(skb);
        struct skb_shared_info *shinfo = skb_shinfo(skb);
        u32 mss = shinfo->gso_size;
 
@@ -4207,7 +4206,7 @@ static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
                        WARN_ON_ONCE(1);
                }
 
-               opts[0] |= transport_offset << GTTCPHO_SHIFT;
+               opts[0] |= skb_transport_offset(skb) << GTTCPHO_SHIFT;
                opts[1] |= mss << TD1_MSS_SHIFT;
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
                u8 ip_protocol;
@@ -4235,7 +4234,7 @@ static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
                else
                        WARN_ON_ONCE(1);
 
-               opts[1] |= transport_offset << TCPHO_SHIFT;
+               opts[1] |= skb_transport_offset(skb) << TCPHO_SHIFT;
        } else {
                unsigned int padto = rtl_quirk_packet_padto(tp, skb);
 
@@ -4402,14 +4401,13 @@ static netdev_features_t rtl8169_features_check(struct sk_buff *skb,
                                                struct net_device *dev,
                                                netdev_features_t features)
 {
-       int transport_offset = skb_transport_offset(skb);
        struct rtl8169_private *tp = netdev_priv(dev);
 
        if (skb_is_gso(skb)) {
                if (tp->mac_version == RTL_GIGA_MAC_VER_34)
                        features = rtl8168evl_fix_tso(skb, features);
 
-               if (transport_offset > GTTCPHO_MAX &&
+               if (skb_transport_offset(skb) > GTTCPHO_MAX &&
                    rtl_chip_supports_csum_v2(tp))
                        features &= ~NETIF_F_ALL_TSO;
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -4420,7 +4418,7 @@ static netdev_features_t rtl8169_features_check(struct sk_buff *skb,
                if (rtl_quirk_packet_padto(tp, skb))
                        features &= ~NETIF_F_CSUM_MASK;
 
-               if (transport_offset > TCPHO_MAX &&
+               if (skb_transport_offset(skb) > TCPHO_MAX &&
                    rtl_chip_supports_csum_v2(tp))
                        features &= ~NETIF_F_CSUM_MASK;
        }
index 186cb28c03bdb847313b755ee92e8eea0c33bcff..8b62ce21aff3da70fd982a871eaa16a676d7447f 100644 (file)
@@ -1932,7 +1932,10 @@ static int efx_ef10_try_update_nic_stats_vf(struct efx_nic *efx)
 
        efx_update_sw_stats(efx, stats);
 out:
+       /* releasing a DMA coherent buffer with BH disabled can panic */
+       spin_unlock_bh(&efx->stats_lock);
        efx_nic_free_buffer(efx, &stats_buf);
+       spin_lock_bh(&efx->stats_lock);
        return rc;
 }
 
index 7f5aa4a8c45122b909f6203953628752c327d49e..92550c7e85ce293be28a4e96bb9cf1ee56b32714 100644 (file)
@@ -408,8 +408,9 @@ fail1:
 static int efx_ef10_pci_sriov_disable(struct efx_nic *efx, bool force)
 {
        struct pci_dev *dev = efx->pci_dev;
+       struct efx_ef10_nic_data *nic_data = efx->nic_data;
        unsigned int vfs_assigned = pci_vfs_assigned(dev);
-       int rc = 0;
+       int i, rc = 0;
 
        if (vfs_assigned && !force) {
                netif_info(efx, drv, efx->net_dev, "VFs are assigned to guests; "
@@ -417,10 +418,13 @@ static int efx_ef10_pci_sriov_disable(struct efx_nic *efx, bool force)
                return -EBUSY;
        }
 
-       if (!vfs_assigned)
+       if (!vfs_assigned) {
+               for (i = 0; i < efx->vf_count; i++)
+                       nic_data->vf[i].pci_dev = NULL;
                pci_disable_sriov(dev);
-       else
+       } else {
                rc = -EBUSY;
+       }
 
        efx_ef10_sriov_free_vf_vswitching(efx);
        efx->vf_count = 0;
index bc91fd867dcd468097b671351b19e723a6be2f40..358fc26f8d1fcd6b9cb17170fbb9e132162064ac 100644 (file)
@@ -361,6 +361,7 @@ bypass_clk_reset_gpio:
        data->fix_mac_speed = tegra_eqos_fix_speed;
        data->init = tegra_eqos_init;
        data->bsp_priv = eqos;
+       data->sph_disable = 1;
 
        err = tegra_eqos_init(pdev, eqos);
        if (err < 0)
index 9a6d819b84aeadd19a0bbeebec9ac458dc770914..378b4dd826bb5e393382569a262047d309dd2b96 100644 (file)
@@ -273,7 +273,8 @@ static int ingenic_mac_probe(struct platform_device *pdev)
                        mac->tx_delay = tx_delay_ps * 1000;
                } else {
                        dev_err(&pdev->dev, "Invalid TX clock delay: %dps\n", tx_delay_ps);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto err_remove_config_dt;
                }
        }
 
@@ -283,7 +284,8 @@ static int ingenic_mac_probe(struct platform_device *pdev)
                        mac->rx_delay = rx_delay_ps * 1000;
                } else {
                        dev_err(&pdev->dev, "Invalid RX clock delay: %dps\n", rx_delay_ps);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto err_remove_config_dt;
                }
        }
 
index 38fe77d1035e306c6d3fd13c3fb547d8bfd2cbec..3fe720c5dc9fcd11654fa4a51e291d0d2fe94707 100644 (file)
@@ -298,6 +298,11 @@ static void get_arttime(struct mii_bus *mii, int intel_adhoc_addr,
        *art_time = ns;
 }
 
+static int stmmac_cross_ts_isr(struct stmmac_priv *priv)
+{
+       return (readl(priv->ioaddr + GMAC_INT_STATUS) & GMAC_INT_TSIE);
+}
+
 static int intel_crosststamp(ktime_t *device,
                             struct system_counterval_t *system,
                             void *ctx)
@@ -313,8 +318,6 @@ static int intel_crosststamp(ktime_t *device,
        u32 num_snapshot;
        u32 gpio_value;
        u32 acr_value;
-       int ret;
-       u32 v;
        int i;
 
        if (!boot_cpu_has(X86_FEATURE_ART))
@@ -328,6 +331,8 @@ static int intel_crosststamp(ktime_t *device,
        if (priv->plat->ext_snapshot_en)
                return -EBUSY;
 
+       priv->plat->int_snapshot_en = 1;
+
        mutex_lock(&priv->aux_ts_lock);
        /* Enable Internal snapshot trigger */
        acr_value = readl(ptpaddr + PTP_ACR);
@@ -347,6 +352,7 @@ static int intel_crosststamp(ktime_t *device,
                break;
        default:
                mutex_unlock(&priv->aux_ts_lock);
+               priv->plat->int_snapshot_en = 0;
                return -EINVAL;
        }
        writel(acr_value, ptpaddr + PTP_ACR);
@@ -368,13 +374,12 @@ static int intel_crosststamp(ktime_t *device,
        gpio_value |= GMAC_GPO1;
        writel(gpio_value, ioaddr + GMAC_GPIO_STATUS);
 
-       /* Poll for time sync operation done */
-       ret = readl_poll_timeout(priv->ioaddr + GMAC_INT_STATUS, v,
-                                (v & GMAC_INT_TSIE), 100, 10000);
-
-       if (ret == -ETIMEDOUT) {
-               pr_err("%s: Wait for time sync operation timeout\n", __func__);
-               return ret;
+       /* Time sync done Indication - Interrupt method */
+       if (!wait_event_interruptible_timeout(priv->tstamp_busy_wait,
+                                             stmmac_cross_ts_isr(priv),
+                                             HZ / 100)) {
+               priv->plat->int_snapshot_en = 0;
+               return -ETIMEDOUT;
        }
 
        num_snapshot = (readl(ioaddr + GMAC_TIMESTAMP_STATUS) &
@@ -392,6 +397,7 @@ static int intel_crosststamp(ktime_t *device,
        }
 
        system->cycles *= intel_priv->crossts_adj;
+       priv->plat->int_snapshot_en = 0;
 
        return 0;
 }
@@ -576,6 +582,7 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
 
        plat->has_crossts = true;
        plat->crosststamp = intel_crosststamp;
+       plat->int_snapshot_en = 0;
 
        /* Setup MSI vector offset specific to Intel mGbE controller */
        plat->msi_mac_vec = 29;
index 6ff88df5876733dd6dddd746547af0d1c939b78b..ca8ab290013ce3fd79b9251fedc8f9a59b8d8381 100644 (file)
@@ -576,32 +576,7 @@ static int mediatek_dwmac_init(struct platform_device *pdev, void *priv)
                }
        }
 
-       ret = clk_bulk_prepare_enable(variant->num_clks, plat->clks);
-       if (ret) {
-               dev_err(plat->dev, "failed to enable clks, err = %d\n", ret);
-               return ret;
-       }
-
-       ret = clk_prepare_enable(plat->rmii_internal_clk);
-       if (ret) {
-               dev_err(plat->dev, "failed to enable rmii internal clk, err = %d\n", ret);
-               goto err_clk;
-       }
-
        return 0;
-
-err_clk:
-       clk_bulk_disable_unprepare(variant->num_clks, plat->clks);
-       return ret;
-}
-
-static void mediatek_dwmac_exit(struct platform_device *pdev, void *priv)
-{
-       struct mediatek_dwmac_plat_data *plat = priv;
-       const struct mediatek_dwmac_variant *variant = plat->variant;
-
-       clk_disable_unprepare(plat->rmii_internal_clk);
-       clk_bulk_disable_unprepare(variant->num_clks, plat->clks);
 }
 
 static int mediatek_dwmac_clks_config(void *priv, bool enabled)
@@ -643,7 +618,6 @@ static int mediatek_dwmac_common_data(struct platform_device *pdev,
        plat->addr64 = priv_plat->variant->dma_bit_mask;
        plat->bsp_priv = priv_plat;
        plat->init = mediatek_dwmac_init;
-       plat->exit = mediatek_dwmac_exit;
        plat->clks_config = mediatek_dwmac_clks_config;
        if (priv_plat->variant->dwmac_fix_mac_speed)
                plat->fix_mac_speed = priv_plat->variant->dwmac_fix_mac_speed;
@@ -712,13 +686,32 @@ static int mediatek_dwmac_probe(struct platform_device *pdev)
        mediatek_dwmac_common_data(pdev, plat_dat, priv_plat);
        mediatek_dwmac_init(pdev, priv_plat);
 
+       ret = mediatek_dwmac_clks_config(priv_plat, true);
+       if (ret)
+               return ret;
+
        ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
        if (ret) {
                stmmac_remove_config_dt(pdev, plat_dat);
-               return ret;
+               goto err_drv_probe;
        }
 
        return 0;
+
+err_drv_probe:
+       mediatek_dwmac_clks_config(priv_plat, false);
+       return ret;
+}
+
+static int mediatek_dwmac_remove(struct platform_device *pdev)
+{
+       struct mediatek_dwmac_plat_data *priv_plat = get_stmmac_bsp_priv(&pdev->dev);
+       int ret;
+
+       ret = stmmac_pltfr_remove(pdev);
+       mediatek_dwmac_clks_config(priv_plat, false);
+
+       return ret;
 }
 
 static const struct of_device_id mediatek_dwmac_match[] = {
@@ -733,7 +726,7 @@ MODULE_DEVICE_TABLE(of, mediatek_dwmac_match);
 
 static struct platform_driver mediatek_dwmac_driver = {
        .probe  = mediatek_dwmac_probe,
-       .remove = stmmac_pltfr_remove,
+       .remove = mediatek_dwmac_remove,
        .driver = {
                .name           = "dwmac-mediatek",
                .pm             = &stmmac_pltfr_pm_ops,
index 462ca7ed095a2a8e8d4b5462191d02c756797098..71dad409f78b075eeaed6d2bacee3b47092aca84 100644 (file)
 #define        GMAC_PCS_IRQ_DEFAULT    (GMAC_INT_RGSMIIS | GMAC_INT_PCS_LINK | \
                                 GMAC_INT_PCS_ANE)
 
-#define        GMAC_INT_DEFAULT_ENABLE (GMAC_INT_PMT_EN | GMAC_INT_LPI_EN)
+#define        GMAC_INT_DEFAULT_ENABLE (GMAC_INT_PMT_EN | GMAC_INT_LPI_EN | \
+                                GMAC_INT_TSIE)
 
 enum dwmac4_irq_status {
        time_stamp_irq = 0x00001000,
index fd41db65fe1df41fe53d24f19d6a39f04173bf10..d8f1fbc25bdd3e7a7e66e9f7d983137492997e1a 100644 (file)
@@ -23,6 +23,7 @@
 static void dwmac4_core_init(struct mac_device_info *hw,
                             struct net_device *dev)
 {
+       struct stmmac_priv *priv = netdev_priv(dev);
        void __iomem *ioaddr = hw->pcsr;
        u32 value = readl(ioaddr + GMAC_CONFIG);
 
@@ -58,6 +59,9 @@ static void dwmac4_core_init(struct mac_device_info *hw,
                value |= GMAC_INT_FPE_EN;
 
        writel(value, ioaddr + GMAC_INT_EN);
+
+       if (GMAC_INT_DEFAULT_ENABLE & GMAC_INT_TSIE)
+               init_waitqueue_head(&priv->tstamp_busy_wait);
 }
 
 static void dwmac4_rx_queue_enable(struct mac_device_info *hw,
@@ -219,6 +223,9 @@ static void dwmac4_map_mtl_dma(struct mac_device_info *hw, u32 queue, u32 chan)
        if (queue == 0 || queue == 4) {
                value &= ~MTL_RXQ_DMA_Q04MDMACH_MASK;
                value |= MTL_RXQ_DMA_Q04MDMACH(chan);
+       } else if (queue > 4) {
+               value &= ~MTL_RXQ_DMA_QXMDMACH_MASK(queue - 4);
+               value |= MTL_RXQ_DMA_QXMDMACH(chan, queue - 4);
        } else {
                value &= ~MTL_RXQ_DMA_QXMDMACH_MASK(queue);
                value |= MTL_RXQ_DMA_QXMDMACH(chan, queue);
index 57970ae2178dab8a559a66e658443af91bb997bd..f9e83964aa7ea63beac580bf6fe906e9b252884a 100644 (file)
@@ -266,6 +266,7 @@ struct stmmac_priv {
        rwlock_t ptp_lock;
        /* Protects auxiliary snapshot registers from concurrent access. */
        struct mutex aux_ts_lock;
+       wait_queue_head_t tstamp_busy_wait;
 
        void __iomem *mmcaddr;
        void __iomem *ptpaddr;
index abfb3cd5958dfe353c184a98c07532c9ddb2753d..9c3055ee26085f645494fc708ef1f19739a892fa 100644 (file)
@@ -803,14 +803,6 @@ static int stmmac_ethtool_op_set_eee(struct net_device *dev,
                netdev_warn(priv->dev,
                            "Setting EEE tx-lpi is not supported\n");
 
-       if (priv->hw->xpcs) {
-               ret = xpcs_config_eee(priv->hw->xpcs,
-                                     priv->plat->mult_fact_100ns,
-                                     edata->eee_enabled);
-               if (ret)
-                       return ret;
-       }
-
        if (!edata->eee_enabled)
                stmmac_disable_eee_mode(priv);
 
index 92d32940aff00660663e709fd8b7196500e96e16..764832f4dae1a7b241e07d8f30e725eb6c83a870 100644 (file)
@@ -179,6 +179,11 @@ static void timestamp_interrupt(struct stmmac_priv *priv)
        u64 ptp_time;
        int i;
 
+       if (priv->plat->int_snapshot_en) {
+               wake_up(&priv->tstamp_busy_wait);
+               return;
+       }
+
        tsync_int = readl(priv->ioaddr + GMAC_INT_STATUS) & GMAC_INT_TSIE;
 
        if (!tsync_int)
index d1a7cf4567bc26bb34a605404b2303e1f87b9bb7..c5f33630e7718384fc0a0a63b36e5ca7dea5f549 100644 (file)
@@ -834,19 +834,10 @@ int stmmac_init_tstamp_counter(struct stmmac_priv *priv, u32 systime_flags)
        struct timespec64 now;
        u32 sec_inc = 0;
        u64 temp = 0;
-       int ret;
 
        if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp))
                return -EOPNOTSUPP;
 
-       ret = clk_prepare_enable(priv->plat->clk_ptp_ref);
-       if (ret < 0) {
-               netdev_warn(priv->dev,
-                           "failed to enable PTP reference clock: %pe\n",
-                           ERR_PTR(ret));
-               return ret;
-       }
-
        stmmac_config_hw_tstamping(priv, priv->ptpaddr, systime_flags);
        priv->systime_flags = systime_flags;
 
@@ -3270,6 +3261,14 @@ static int stmmac_hw_setup(struct net_device *dev, bool ptp_register)
 
        stmmac_mmc_setup(priv);
 
+       if (ptp_register) {
+               ret = clk_prepare_enable(priv->plat->clk_ptp_ref);
+               if (ret < 0)
+                       netdev_warn(priv->dev,
+                                   "failed to enable PTP reference clock: %pe\n",
+                                   ERR_PTR(ret));
+       }
+
        ret = stmmac_init_ptp(priv);
        if (ret == -EOPNOTSUPP)
                netdev_info(priv->dev, "PTP not supported by HW\n");
@@ -7213,8 +7212,6 @@ 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);
@@ -7241,6 +7238,9 @@ int stmmac_dvr_remove(struct device *dev)
        mutex_destroy(&priv->lock);
        bitmap_free(priv->af_xdp_zc_qps);
 
+       pm_runtime_disable(dev);
+       pm_runtime_put_noidle(dev);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(stmmac_dvr_remove);
index 11e1055e8260f49962ca88271337eb022b3fa3c5..9f5cac4000da680d061c37171817fb8642abee55 100644 (file)
@@ -815,7 +815,13 @@ static int __maybe_unused stmmac_pltfr_noirq_resume(struct device *dev)
                if (ret)
                        return ret;
 
-               stmmac_init_tstamp_counter(priv, priv->systime_flags);
+               ret = clk_prepare_enable(priv->plat->clk_ptp_ref);
+               if (ret < 0) {
+                       netdev_warn(priv->dev,
+                                   "failed to enable PTP reference clock: %pe\n",
+                                   ERR_PTR(ret));
+                       return ret;
+               }
        }
 
        return 0;
index e45fb191d8e6ef86317b40f4743172204a191773..4d11980dcd64dc063b5cf3fda361f84560f01ef7 100644 (file)
@@ -175,11 +175,10 @@ static int stmmac_enable(struct ptp_clock_info *ptp,
        struct stmmac_priv *priv =
            container_of(ptp, struct stmmac_priv, ptp_clock_ops);
        void __iomem *ptpaddr = priv->ptpaddr;
-       void __iomem *ioaddr = priv->hw->pcsr;
        struct stmmac_pps_cfg *cfg;
-       u32 intr_value, acr_value;
        int ret = -EOPNOTSUPP;
        unsigned long flags;
+       u32 acr_value;
 
        switch (rq->type) {
        case PTP_CLK_REQ_PEROUT:
@@ -213,19 +212,10 @@ static int stmmac_enable(struct ptp_clock_info *ptp,
                        netdev_dbg(priv->dev, "Auxiliary Snapshot %d enabled.\n",
                                   priv->plat->ext_snapshot_num >>
                                   PTP_ACR_ATSEN_SHIFT);
-                       /* Enable Timestamp Interrupt */
-                       intr_value = readl(ioaddr + GMAC_INT_EN);
-                       intr_value |= GMAC_INT_TSIE;
-                       writel(intr_value, ioaddr + GMAC_INT_EN);
-
                } else {
                        netdev_dbg(priv->dev, "Auxiliary Snapshot %d disabled.\n",
                                   priv->plat->ext_snapshot_num >>
                                   PTP_ACR_ATSEN_SHIFT);
-                       /* Disable Timestamp Interrupt */
-                       intr_value = readl(ioaddr + GMAC_INT_EN);
-                       intr_value &= ~GMAC_INT_TSIE;
-                       writel(intr_value, ioaddr + GMAC_INT_EN);
                }
                writel(acr_value, ptpaddr + PTP_ACR);
                mutex_unlock(&priv->aux_ts_lock);
index 77e5dffb558f4a15ee78cb34e45959bd3bbf472a..8594ee839628bd9fa80f1d8a4f8476ba2eab6ef2 100644 (file)
@@ -545,43 +545,24 @@ static int try_next_permutation(struct happy_meal *hp, void __iomem *tregs)
 
 static void display_link_mode(struct happy_meal *hp, void __iomem *tregs)
 {
-       printk(KERN_INFO "%s: Link is up using ", hp->dev->name);
-       if (hp->tcvr_type == external)
-               printk("external ");
-       else
-               printk("internal ");
-       printk("transceiver at ");
        hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, MII_LPA);
-       if (hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) {
-               if (hp->sw_lpa & LPA_100FULL)
-                       printk("100Mb/s, Full Duplex.\n");
-               else
-                       printk("100Mb/s, Half Duplex.\n");
-       } else {
-               if (hp->sw_lpa & LPA_10FULL)
-                       printk("10Mb/s, Full Duplex.\n");
-               else
-                       printk("10Mb/s, Half Duplex.\n");
-       }
+
+       netdev_info(hp->dev,
+                   "Link is up using %s transceiver at %dMb/s, %s Duplex.\n",
+                   hp->tcvr_type == external ? "external" : "internal",
+                   hp->sw_lpa & (LPA_100HALF | LPA_100FULL) ? 100 : 10,
+                   hp->sw_lpa & (LPA_100FULL | LPA_10FULL) ? "Full" : "Half");
 }
 
 static void display_forced_link_mode(struct happy_meal *hp, void __iomem *tregs)
 {
-       printk(KERN_INFO "%s: Link has been forced up using ", hp->dev->name);
-       if (hp->tcvr_type == external)
-               printk("external ");
-       else
-               printk("internal ");
-       printk("transceiver at ");
        hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
-       if (hp->sw_bmcr & BMCR_SPEED100)
-               printk("100Mb/s, ");
-       else
-               printk("10Mb/s, ");
-       if (hp->sw_bmcr & BMCR_FULLDPLX)
-               printk("Full Duplex.\n");
-       else
-               printk("Half Duplex.\n");
+
+       netdev_info(hp->dev,
+                   "Link has been forced up using %s transceiver at %dMb/s, %s Duplex.\n",
+                   hp->tcvr_type == external ? "external" : "internal",
+                   hp->sw_bmcr & BMCR_SPEED100 ? 100 : 10,
+                   hp->sw_bmcr & BMCR_FULLDPLX ? "Full" : "Half");
 }
 
 static int set_happy_link_modes(struct happy_meal *hp, void __iomem *tregs)
index fb92d4c1547db4eddb348badbb647af37f482c18..f4a6b590a1e3995a6eb51ba2c8d0c27b9b9af641 100644 (file)
@@ -2467,7 +2467,6 @@ static int am65_cpsw_nuss_register_devlink(struct am65_cpsw_common *common)
                                port->port_id, ret);
                        goto dl_port_unreg;
                }
-               devlink_port_type_eth_set(dl_port, port->ndev);
        }
        devlink_register(common->devlink);
        return ret;
@@ -2511,6 +2510,7 @@ static void am65_cpsw_unregister_devlink(struct am65_cpsw_common *common)
 static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
 {
        struct device *dev = common->dev;
+       struct devlink_port *dl_port;
        struct am65_cpsw_port *port;
        int ret = 0, i;
 
@@ -2527,6 +2527,10 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
                return ret;
        }
 
+       ret = am65_cpsw_nuss_register_devlink(common);
+       if (ret)
+               return ret;
+
        for (i = 0; i < common->port_num; i++) {
                port = &common->ports[i];
 
@@ -2539,25 +2543,24 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
                                i, ret);
                        goto err_cleanup_ndev;
                }
+
+               dl_port = &port->devlink_port;
+               devlink_port_type_eth_set(dl_port, port->ndev);
        }
 
        ret = am65_cpsw_register_notifiers(common);
        if (ret)
                goto err_cleanup_ndev;
 
-       ret = am65_cpsw_nuss_register_devlink(common);
-       if (ret)
-               goto clean_unregister_notifiers;
-
        /* can't auto unregister ndev using devm_add_action() due to
         * devres release sequence in DD core for DMA
         */
 
        return 0;
-clean_unregister_notifiers:
-       am65_cpsw_unregister_notifiers(common);
+
 err_cleanup_ndev:
        am65_cpsw_nuss_cleanup_ndev(common);
+       am65_cpsw_unregister_devlink(common);
 
        return ret;
 }
index e7fe9c0f63a9f078ccd0b5a5eed7151b5190fbaf..1a376ed45d7acc3948ef9e300955368d8ae8e7d6 100644 (file)
@@ -781,7 +781,7 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
                        intf->altsetting->desc.bInterfaceNumber, 1)) {
                dev_err(dev, "Can't set altsetting 1.\n");
                ret = -EIO;
-               goto fail_mem;;
+               goto fail_mem;
        }
 
        netdev = alloc_etherdev(sizeof(struct catc));
index 7389d6ef85697c083068d417befeee14be7a3877..0f6efaabaa32b892ccb57355bb9db3941ec216ec 100644 (file)
@@ -32,7 +32,7 @@
 #define NETNEXT_VERSION                "12"
 
 /* Information for net */
-#define NET_VERSION            "12"
+#define NET_VERSION            "13"
 
 #define DRIVER_VERSION         "v1." NETNEXT_VERSION "." NET_VERSION
 #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
@@ -2156,7 +2156,7 @@ static inline void rtl_rx_vlan_tag(struct rx_desc *desc, struct sk_buff *skb)
 }
 
 static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc,
-                        struct sk_buff *skb, u32 len, u32 transport_offset)
+                        struct sk_buff *skb, u32 len)
 {
        u32 mss = skb_shinfo(skb)->gso_size;
        u32 opts1, opts2 = 0;
@@ -2167,6 +2167,8 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc,
        opts1 = len | TX_FS | TX_LS;
 
        if (mss) {
+               u32 transport_offset = (u32)skb_transport_offset(skb);
+
                if (transport_offset > GTTCPHO_MAX) {
                        netif_warn(tp, tx_err, tp->netdev,
                                   "Invalid transport offset 0x%x for TSO\n",
@@ -2197,6 +2199,7 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc,
                opts1 |= transport_offset << GTTCPHO_SHIFT;
                opts2 |= min(mss, MSS_MAX) << MSS_SHIFT;
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               u32 transport_offset = (u32)skb_transport_offset(skb);
                u8 ip_protocol;
 
                if (transport_offset > TCPHO_MAX) {
@@ -2260,7 +2263,6 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
                struct tx_desc *tx_desc;
                struct sk_buff *skb;
                unsigned int len;
-               u32 offset;
 
                skb = __skb_dequeue(&skb_head);
                if (!skb)
@@ -2276,9 +2278,7 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
                tx_data = tx_agg_align(tx_data);
                tx_desc = (struct tx_desc *)tx_data;
 
-               offset = (u32)skb_transport_offset(skb);
-
-               if (r8152_tx_csum(tp, tx_desc, skb, skb->len, offset)) {
+               if (r8152_tx_csum(tp, tx_desc, skb, skb->len)) {
                        r8152_csum_workaround(tp, skb, &skb_head);
                        continue;
                }
@@ -2759,9 +2759,9 @@ rtl8152_features_check(struct sk_buff *skb, struct net_device *dev,
 {
        u32 mss = skb_shinfo(skb)->gso_size;
        int max_offset = mss ? GTTCPHO_MAX : TCPHO_MAX;
-       int offset = skb_transport_offset(skb);
 
-       if ((mss || skb->ip_summed == CHECKSUM_PARTIAL) && offset > max_offset)
+       if ((mss || skb->ip_summed == CHECKSUM_PARTIAL) &&
+           skb_transport_offset(skb) > max_offset)
                features &= ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
        else if ((skb->len + sizeof(struct tx_desc)) > agg_buf_sz)
                features &= ~NETIF_F_GSO_MASK;
@@ -5917,7 +5917,8 @@ static void r8153_enter_oob(struct r8152 *tp)
 
        wait_oob_link_list_ready(tp);
 
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, mtu_to_size(tp->netdev->mtu));
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, 1522);
+       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_DEFAULT);
 
        switch (tp->version) {
        case RTL_VER_03:
@@ -5953,6 +5954,10 @@ static void r8153_enter_oob(struct r8152 *tp)
        ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
        ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
 
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
+       ocp_data |= MCU_BORW_EN;
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
        rxdy_gated_en(tp, false);
 
        ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
@@ -6555,6 +6560,9 @@ static void rtl8156_down(struct r8152 *tp)
        rtl_disable(tp);
        rtl_reset_bmu(tp);
 
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, 1522);
+       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_DEFAULT);
+
        /* Clear teredo wake event. bit[15:8] is the teredo wakeup
         * type. Set it to zero. bits[7:0] are the W1C bits about
         * the events. Set them to all 1 to clear them.
@@ -6565,6 +6573,10 @@ static void rtl8156_down(struct r8152 *tp)
        ocp_data |= NOW_IS_OOB;
        ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
 
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
+       ocp_data |= MCU_BORW_EN;
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
        rtl_rx_vlan_en(tp, true);
        rxdy_gated_en(tp, false);
 
index e2135ab87a6ed66be181c77e0cdd363d5347c74e..78a92751ce4c26c3602093fe255120e7be77f2e9 100644 (file)
@@ -2137,7 +2137,7 @@ static void usbnet_async_cmd_cb(struct urb *urb)
 int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype,
                           u16 value, u16 index, const void *data, u16 size)
 {
-       struct usb_ctrlrequest *req = NULL;
+       struct usb_ctrlrequest *req;
        struct urb *urb;
        int err = -ENOMEM;
        void *buf = NULL;
@@ -2155,7 +2155,7 @@ int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype,
                if (!buf) {
                        netdev_err(dev->net, "Error allocating buffer"
                                   " in %s!\n", __func__);
-                       goto fail_free;
+                       goto fail_free_urb;
                }
        }
 
@@ -2179,14 +2179,21 @@ int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype,
        if (err < 0) {
                netdev_err(dev->net, "Error submitting the control"
                           " message: status=%d\n", err);
-               goto fail_free;
+               goto fail_free_all;
        }
        return 0;
 
+fail_free_all:
+       kfree(req);
 fail_free_buf:
        kfree(buf);
-fail_free:
-       kfree(req);
+       /*
+        * avoid a double free
+        * needed because the flag can be set only
+        * after filling the URB
+        */
+       urb->transfer_flags = 0;
+fail_free_urb:
        usb_free_urb(urb);
 fail:
        return err;
index 84d1c705401324620582d1139b4b45016f5b7a2d..7b1dc19c565eff33bfcde7ed86c6dfeaf3f1a4e7 100644 (file)
@@ -3822,7 +3822,8 @@ ath11k_wmi_obss_color_collision_event(struct ath11k_base *ab, struct sk_buff *sk
 
        switch (ev->evt_type) {
        case WMI_BSS_COLOR_COLLISION_DETECTION:
-               ieeee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap);
+               ieeee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap,
+                                                      GFP_KERNEL);
                ath11k_dbg(ab, ATH11K_DBG_WMI,
                           "OBSS color collision detected vdev:%d, event:%d, bitmap:%08llx\n",
                           ev->vdev_id, ev->evt_type, ev->obss_color_bitmap);
index 2f746eb645076070c17a05543069ea877a9afec1..6f83af849f2e0f147f1858ab93cb1c272a11b131 100644 (file)
@@ -4912,6 +4912,8 @@ static int hwsim_virtio_probe(struct virtio_device *vdev)
        if (err)
                return err;
 
+       virtio_device_ready(vdev);
+
        err = fill_vq(hwsim_vqs[HWSIM_VQ_RX]);
        if (err)
                goto out_remove;
index c02be4ac159e3a197b9b10aed6a8a74e1d7b3350..7db627fc26be9e9a358bb349b52277e413f5424d 100644 (file)
@@ -1233,9 +1233,6 @@ struct rtw_chip_info {
        const struct wiphy_wowlan_support *wowlan_stub;
        const u8 max_sched_scan_ssids;
 
-       /* for 8821c set channel */
-       u32 ch_param[3];
-
        /* coex paras */
        u32 coex_para_ver;
        u8 bt_desired_ver;
@@ -1937,6 +1934,9 @@ struct rtw_hal {
 
        enum rtw_sar_bands sar_band;
        struct rtw_sar sar;
+
+       /* for 8821c set channel */
+       u32 ch_param[3];
 };
 
 struct rtw_path_div {
index ffee39ea5df69945f45f4405d3438e99fafbea29..488a7ddd507c0a03699d9ee4dfde80eceb68254a 100644 (file)
@@ -125,6 +125,7 @@ static void rtw8821c_phy_bf_init(struct rtw_dev *rtwdev)
 
 static void rtw8821c_phy_set_param(struct rtw_dev *rtwdev)
 {
+       struct rtw_hal *hal = &rtwdev->hal;
        u8 crystal_cap, val;
 
        /* power on BB/RF domain */
@@ -159,9 +160,9 @@ static void rtw8821c_phy_set_param(struct rtw_dev *rtwdev)
 
        /* post init after header files config */
        rtw_write32_set(rtwdev, REG_RXPSEL, BIT_RX_PSEL_RST);
-       rtwdev->chip->ch_param[0] = rtw_read32_mask(rtwdev, REG_TXSF2, MASKDWORD);
-       rtwdev->chip->ch_param[1] = rtw_read32_mask(rtwdev, REG_TXSF6, MASKDWORD);
-       rtwdev->chip->ch_param[2] = rtw_read32_mask(rtwdev, REG_TXFILTER, MASKDWORD);
+       hal->ch_param[0] = rtw_read32_mask(rtwdev, REG_TXSF2, MASKDWORD);
+       hal->ch_param[1] = rtw_read32_mask(rtwdev, REG_TXSF6, MASKDWORD);
+       hal->ch_param[2] = rtw_read32_mask(rtwdev, REG_TXFILTER, MASKDWORD);
 
        rtw_phy_init(rtwdev);
        rtwdev->dm_info.cck_pd_default = rtw_read8(rtwdev, REG_CSRATIO) & 0x1f;
@@ -351,6 +352,7 @@ static void rtw8821c_set_channel_rxdfir(struct rtw_dev *rtwdev, u8 bw)
 static void rtw8821c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
                                    u8 primary_ch_idx)
 {
+       struct rtw_hal *hal = &rtwdev->hal;
        u32 val32;
 
        if (channel <= 14) {
@@ -367,11 +369,11 @@ static void rtw8821c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
                        rtw_write32_mask(rtwdev, REG_TXFILTER, MASKDWORD, 0x00003667);
                } else {
                        rtw_write32_mask(rtwdev, REG_TXSF2, MASKDWORD,
-                                        rtwdev->chip->ch_param[0]);
+                                        hal->ch_param[0]);
                        rtw_write32_mask(rtwdev, REG_TXSF6, MASKLWORD,
-                                        rtwdev->chip->ch_param[1] & MASKLWORD);
+                                        hal->ch_param[1] & MASKLWORD);
                        rtw_write32_mask(rtwdev, REG_TXFILTER, MASKDWORD,
-                                        rtwdev->chip->ch_param[2]);
+                                        hal->ch_param[2]);
                }
        } else if (channel > 35) {
                rtw_write32_mask(rtwdev, REG_ENTXCCK, BIT(18), 0x1);
index dbac4c03d21a14d12a2eee9e7b3418c9cc184d88..a0335407be423111d738358835282b143f8afafb 100644 (file)
@@ -495,6 +495,7 @@ void xenvif_rx_action(struct xenvif_queue *queue)
        queue->rx_copy.completed = &completed_skbs;
 
        while (xenvif_rx_ring_slots_available(queue) &&
+              !skb_queue_empty(&queue->rx_queue) &&
               work_done < RX_BATCH_SIZE) {
                xenvif_rx_skb(queue);
                work_done++;
index 8c0b9546d5a2d6e7620ffcf9f1f9385f08842187..2409007f1fd96e9fccdcb16ee8333d615f45b409 100644 (file)
@@ -66,6 +66,10 @@ module_param_named(max_queues, xennet_max_queues, uint, 0644);
 MODULE_PARM_DESC(max_queues,
                 "Maximum number of queues per virtual interface");
 
+static bool __read_mostly xennet_trusted = true;
+module_param_named(trusted, xennet_trusted, bool, 0644);
+MODULE_PARM_DESC(trusted, "Is the backend trusted");
+
 #define XENNET_TIMEOUT  (5 * HZ)
 
 static const struct ethtool_ops xennet_ethtool_ops;
@@ -173,6 +177,9 @@ struct netfront_info {
        /* Is device behaving sane? */
        bool broken;
 
+       /* Should skbs be bounced into a zeroed buffer? */
+       bool bounce;
+
        atomic_t rx_gso_checksum_fixup;
 };
 
@@ -271,7 +278,8 @@ static struct sk_buff *xennet_alloc_one_rx_buffer(struct netfront_queue *queue)
        if (unlikely(!skb))
                return NULL;
 
-       page = page_pool_dev_alloc_pages(queue->page_pool);
+       page = page_pool_alloc_pages(queue->page_pool,
+                                    GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO);
        if (unlikely(!page)) {
                kfree_skb(skb);
                return NULL;
@@ -665,6 +673,33 @@ static int xennet_xdp_xmit(struct net_device *dev, int n,
        return nxmit;
 }
 
+struct sk_buff *bounce_skb(const struct sk_buff *skb)
+{
+       unsigned int headerlen = skb_headroom(skb);
+       /* Align size to allocate full pages and avoid contiguous data leaks */
+       unsigned int size = ALIGN(skb_end_offset(skb) + skb->data_len,
+                                 XEN_PAGE_SIZE);
+       struct sk_buff *n = alloc_skb(size, GFP_ATOMIC | __GFP_ZERO);
+
+       if (!n)
+               return NULL;
+
+       if (!IS_ALIGNED((uintptr_t)n->head, XEN_PAGE_SIZE)) {
+               WARN_ONCE(1, "misaligned skb allocated\n");
+               kfree_skb(n);
+               return NULL;
+       }
+
+       /* Set the data pointer */
+       skb_reserve(n, headerlen);
+       /* Set the tail pointer and length */
+       skb_put(n, skb->len);
+
+       BUG_ON(skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len));
+
+       skb_copy_header(n, skb);
+       return n;
+}
 
 #define MAX_XEN_SKB_FRAGS (65536 / XEN_PAGE_SIZE + 1)
 
@@ -718,9 +753,13 @@ static netdev_tx_t xennet_start_xmit(struct sk_buff *skb, struct net_device *dev
 
        /* The first req should be at least ETH_HLEN size or the packet will be
         * dropped by netback.
+        *
+        * If the backend is not trusted bounce all data to zeroed pages to
+        * avoid exposing contiguous data on the granted page not belonging to
+        * the skb.
         */
-       if (unlikely(PAGE_SIZE - offset < ETH_HLEN)) {
-               nskb = skb_copy(skb, GFP_ATOMIC);
+       if (np->bounce || unlikely(PAGE_SIZE - offset < ETH_HLEN)) {
+               nskb = bounce_skb(skb);
                if (!nskb)
                        goto drop;
                dev_consume_skb_any(skb);
@@ -1053,8 +1092,10 @@ static int xennet_get_responses(struct netfront_queue *queue,
                        }
                }
                rcu_read_unlock();
-next:
+
                __skb_queue_tail(list, skb);
+
+next:
                if (!(rx->flags & XEN_NETRXF_more_data))
                        break;
 
@@ -2214,6 +2255,10 @@ static int talk_to_netback(struct xenbus_device *dev,
 
        info->netdev->irq = 0;
 
+       /* Check if backend is trusted. */
+       info->bounce = !xennet_trusted ||
+                      !xenbus_read_unsigned(dev->nodename, "trusted", 1);
+
        /* Check if backend supports multiple queues */
        max_queues = xenbus_read_unsigned(info->xbdev->otherend,
                                          "multi-queue-max-queues", 1);
@@ -2381,6 +2426,9 @@ static int xennet_connect(struct net_device *dev)
                return err;
        if (np->netback_has_xdp_headroom)
                pr_info("backend supports XDP headroom\n");
+       if (np->bounce)
+               dev_info(&np->xbdev->dev,
+                        "bouncing transmitted data to zeroed pages\n");
 
        /* talk_to_netback() sets the correct number of queues */
        num_queues = dev->real_num_tx_queues;
index ec6ac298d8de2b707ec6e079b46c9df48d15f9c4..6a12a906a11e45c35b37c30f86db10673ca408f6 100644 (file)
@@ -3786,7 +3786,7 @@ static int nvme_add_ns_cdev(struct nvme_ns *ns)
 }
 
 static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
-               unsigned nsid, struct nvme_ns_ids *ids)
+               unsigned nsid, struct nvme_ns_ids *ids, bool is_shared)
 {
        struct nvme_ns_head *head;
        size_t size = sizeof(*head);
@@ -3810,6 +3810,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
        head->subsys = ctrl->subsys;
        head->ns_id = nsid;
        head->ids = *ids;
+       head->shared = is_shared;
        kref_init(&head->ref);
 
        if (head->ids.csi) {
@@ -3891,12 +3892,11 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid,
                                nsid);
                        goto out_unlock;
                }
-               head = nvme_alloc_ns_head(ctrl, nsid, ids);
+               head = nvme_alloc_ns_head(ctrl, nsid, ids, is_shared);
                if (IS_ERR(head)) {
                        ret = PTR_ERR(head);
                        goto out_unlock;
                }
-               head->shared = is_shared;
        } else {
                ret = -EINVAL;
                if (!is_shared || !head->shared) {
index e7af2234e53b930e377b96e5a5fbffd4229be274..58c72d55769a1fc52b2033d567ea96a51454b638 100644 (file)
@@ -2690,8 +2690,13 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
        struct pci_dev *pdev = to_pci_dev(dev->dev);
 
        mutex_lock(&dev->shutdown_lock);
-       if (pci_device_is_present(pdev) && pci_is_enabled(pdev)) {
-               u32 csts = readl(dev->bar + NVME_REG_CSTS);
+       if (pci_is_enabled(pdev)) {
+               u32 csts;
+
+               if (pci_device_is_present(pdev))
+                       csts = readl(dev->bar + NVME_REG_CSTS);
+               else
+                       csts = ~0;
 
                if (dev->ctrl.state == NVME_CTRL_LIVE ||
                    dev->ctrl.state == NVME_CTRL_RESETTING) {
@@ -3465,7 +3470,8 @@ static const struct pci_device_id nvme_id_table[] = {
        { PCI_DEVICE(0x1987, 0x5012),   /* Phison E12 */
                .driver_data = NVME_QUIRK_BOGUS_NID, },
        { PCI_DEVICE(0x1987, 0x5016),   /* Phison E16 */
-               .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, },
+               .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN |
+                               NVME_QUIRK_BOGUS_NID, },
        { PCI_DEVICE(0x1b4b, 0x1092),   /* Lexar 256 GB SSD */
                .driver_data = NVME_QUIRK_NO_NS_DESC_LIST |
                                NVME_QUIRK_IGNORE_DEV_SUBNQN, },
index b5f85259461a62c81395b7fdee1f357fa936c77d..37c7f4c89f92e4caf386f422d6bdd0e8c09201d4 100644 (file)
@@ -69,7 +69,7 @@ TRACE_EVENT(nvme_setup_cmd,
                __entry->metadata = !!blk_integrity_rq(req);
                __entry->fctype = cmd->fabrics.fctype;
                __assign_disk_name(__entry->disk, req->q->disk);
-               memcpy(__entry->cdw10, &cmd->common.cdw10,
+               memcpy(__entry->cdw10, &cmd->common.cdws,
                        sizeof(__entry->cdw10));
            ),
            TP_printk("nvme%d: %sqid=%d, cmdid=%u, nsid=%u, flags=0x%x, meta=0x%x, cmd=(%s %s)",
index 30394929d700e0abde673178ba890885ac7f7424..eb89c9a75985985b3541c6281651e0d6735453bd 100644 (file)
@@ -1443,12 +1443,12 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node);
  * It provides the power used by @dev at @kHz if it is the frequency of an
  * existing OPP, or at the frequency of the first OPP above @kHz otherwise
  * (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled
- * frequency and @mW to the associated power.
+ * frequency and @uW to the associated power.
  *
  * Returns 0 on success or a proper -EINVAL value in case of error.
  */
 static int __maybe_unused
-_get_dt_power(struct device *dev, unsigned long *mW, unsigned long *kHz)
+_get_dt_power(struct device *dev, unsigned long *uW, unsigned long *kHz)
 {
        struct dev_pm_opp *opp;
        unsigned long opp_freq, opp_power;
@@ -1465,7 +1465,7 @@ _get_dt_power(struct device *dev, unsigned long *mW, unsigned long *kHz)
                return -EINVAL;
 
        *kHz = opp_freq / 1000;
-       *mW = opp_power / 1000;
+       *uW = opp_power;
 
        return 0;
 }
@@ -1475,14 +1475,14 @@ _get_dt_power(struct device *dev, unsigned long *mW, unsigned long *kHz)
  * This computes the power estimated by @dev at @kHz if it is the frequency
  * of an existing OPP, or at the frequency of the first OPP above @kHz otherwise
  * (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled
- * frequency and @mW to the associated power. The power is estimated as
+ * frequency and @uW to the associated power. The power is estimated as
  * P = C * V^2 * f with C being the device's capacitance and V and f
  * respectively the voltage and frequency of the OPP.
  *
  * Returns -EINVAL if the power calculation failed because of missing
  * parameters, 0 otherwise.
  */
-static int __maybe_unused _get_power(struct device *dev, unsigned long *mW,
+static int __maybe_unused _get_power(struct device *dev, unsigned long *uW,
                                     unsigned long *kHz)
 {
        struct dev_pm_opp *opp;
@@ -1512,9 +1512,10 @@ static int __maybe_unused _get_power(struct device *dev, unsigned long *mW,
                return -EINVAL;
 
        tmp = (u64)cap * mV * mV * (Hz / 1000000);
-       do_div(tmp, 1000000000);
+       /* Provide power in micro-Watts */
+       do_div(tmp, 1000000);
 
-       *mW = (unsigned long)tmp;
+       *uW = (unsigned long)tmp;
        *kHz = Hz / 1000;
 
        return 0;
index f52960d2dfbe8e060468ea79bd8b709b2570991f..bff144c97e66ec9556a2565745560bbdb09853b4 100644 (file)
@@ -32,7 +32,7 @@ config DEBUG_PINCTRL
          Say Y here to add some extra checks and diagnostics to PINCTRL calls.
 
 config PINCTRL_AMD
-       tristate "AMD GPIO pin control"
+       bool "AMD GPIO pin control"
        depends on HAS_IOMEM
        depends on ACPI || COMPILE_TEST
        select GPIOLIB
index c94e24aadf922d2a3b68537df445bf24934c5a98..83d47ff1cea8f2b1dd8f970a7f1e715b3db5d6cb 100644 (file)
@@ -236,11 +236,11 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
                const struct aspeed_sig_expr **funcs;
                const struct aspeed_sig_expr ***prios;
 
-               pr_debug("Muxing pin %s for %s\n", pdesc->name, pfunc->name);
-
                if (!pdesc)
                        return -EINVAL;
 
+               pr_debug("Muxing pin %s for %s\n", pdesc->name, pfunc->name);
+
                prios = pdesc->prios;
 
                if (!prios)
index c0630f69e995400834a347291a864133649625d8..417e41b37a6fd7ed078d506faed55194ac0ffc45 100644 (file)
@@ -239,6 +239,7 @@ static const struct pinctrl_pin_desc imx93_pinctrl_pads[] = {
 static const struct imx_pinctrl_soc_info imx93_pinctrl_info = {
        .pins = imx93_pinctrl_pads,
        .npins = ARRAY_SIZE(imx93_pinctrl_pads),
+       .flags = ZERO_OFFSET_VALID,
        .gpr_compatible = "fsl,imx93-iomuxc-gpr",
 };
 
index a140b6bfbfaa675c7eee4ac0b775f2bb862be9f6..bcde042d29dc3b6811a41b8d6b7c8676a4199cf1 100644 (file)
@@ -102,7 +102,7 @@ struct armada_37xx_pinctrl {
        struct device                   *dev;
        struct gpio_chip                gpio_chip;
        struct irq_chip                 irq_chip;
-       spinlock_t                      irq_lock;
+       raw_spinlock_t                  irq_lock;
        struct pinctrl_desc             pctl;
        struct pinctrl_dev              *pctl_dev;
        struct armada_37xx_pin_group    *groups;
@@ -523,9 +523,9 @@ static void armada_37xx_irq_ack(struct irq_data *d)
        unsigned long flags;
 
        armada_37xx_irq_update_reg(&reg, d);
-       spin_lock_irqsave(&info->irq_lock, flags);
+       raw_spin_lock_irqsave(&info->irq_lock, flags);
        writel(d->mask, info->base + reg);
-       spin_unlock_irqrestore(&info->irq_lock, flags);
+       raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 }
 
 static void armada_37xx_irq_mask(struct irq_data *d)
@@ -536,10 +536,10 @@ static void armada_37xx_irq_mask(struct irq_data *d)
        unsigned long flags;
 
        armada_37xx_irq_update_reg(&reg, d);
-       spin_lock_irqsave(&info->irq_lock, flags);
+       raw_spin_lock_irqsave(&info->irq_lock, flags);
        val = readl(info->base + reg);
        writel(val & ~d->mask, info->base + reg);
-       spin_unlock_irqrestore(&info->irq_lock, flags);
+       raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 }
 
 static void armada_37xx_irq_unmask(struct irq_data *d)
@@ -550,10 +550,10 @@ static void armada_37xx_irq_unmask(struct irq_data *d)
        unsigned long flags;
 
        armada_37xx_irq_update_reg(&reg, d);
-       spin_lock_irqsave(&info->irq_lock, flags);
+       raw_spin_lock_irqsave(&info->irq_lock, flags);
        val = readl(info->base + reg);
        writel(val | d->mask, info->base + reg);
-       spin_unlock_irqrestore(&info->irq_lock, flags);
+       raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 }
 
 static int armada_37xx_irq_set_wake(struct irq_data *d, unsigned int on)
@@ -564,14 +564,14 @@ static int armada_37xx_irq_set_wake(struct irq_data *d, unsigned int on)
        unsigned long flags;
 
        armada_37xx_irq_update_reg(&reg, d);
-       spin_lock_irqsave(&info->irq_lock, flags);
+       raw_spin_lock_irqsave(&info->irq_lock, flags);
        val = readl(info->base + reg);
        if (on)
                val |= (BIT(d->hwirq % GPIO_PER_REG));
        else
                val &= ~(BIT(d->hwirq % GPIO_PER_REG));
        writel(val, info->base + reg);
-       spin_unlock_irqrestore(&info->irq_lock, flags);
+       raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 
        return 0;
 }
@@ -583,7 +583,7 @@ static int armada_37xx_irq_set_type(struct irq_data *d, unsigned int type)
        u32 val, reg = IRQ_POL;
        unsigned long flags;
 
-       spin_lock_irqsave(&info->irq_lock, flags);
+       raw_spin_lock_irqsave(&info->irq_lock, flags);
        armada_37xx_irq_update_reg(&reg, d);
        val = readl(info->base + reg);
        switch (type) {
@@ -607,11 +607,11 @@ static int armada_37xx_irq_set_type(struct irq_data *d, unsigned int type)
                break;
        }
        default:
-               spin_unlock_irqrestore(&info->irq_lock, flags);
+               raw_spin_unlock_irqrestore(&info->irq_lock, flags);
                return -EINVAL;
        }
        writel(val, info->base + reg);
-       spin_unlock_irqrestore(&info->irq_lock, flags);
+       raw_spin_unlock_irqrestore(&info->irq_lock, flags);
 
        return 0;
 }
@@ -626,7 +626,7 @@ static int armada_37xx_edge_both_irq_swap_pol(struct armada_37xx_pinctrl *info,
 
        regmap_read(info->regmap, INPUT_VAL + 4*reg_idx, &l);
 
-       spin_lock_irqsave(&info->irq_lock, flags);
+       raw_spin_lock_irqsave(&info->irq_lock, flags);
        p = readl(info->base + IRQ_POL + 4 * reg_idx);
        if ((p ^ l) & (1 << bit_num)) {
                /*
@@ -647,7 +647,7 @@ static int armada_37xx_edge_both_irq_swap_pol(struct armada_37xx_pinctrl *info,
                ret = -1;
        }
 
-       spin_unlock_irqrestore(&info->irq_lock, flags);
+       raw_spin_unlock_irqrestore(&info->irq_lock, flags);
        return ret;
 }
 
@@ -664,11 +664,11 @@ static void armada_37xx_irq_handler(struct irq_desc *desc)
                u32 status;
                unsigned long flags;
 
-               spin_lock_irqsave(&info->irq_lock, flags);
+               raw_spin_lock_irqsave(&info->irq_lock, flags);
                status = readl_relaxed(info->base + IRQ_STATUS + 4 * i);
                /* Manage only the interrupt that was enabled */
                status &= readl_relaxed(info->base + IRQ_EN + 4 * i);
-               spin_unlock_irqrestore(&info->irq_lock, flags);
+               raw_spin_unlock_irqrestore(&info->irq_lock, flags);
                while (status) {
                        u32 hwirq = ffs(status) - 1;
                        u32 virq = irq_find_mapping(d, hwirq +
@@ -695,12 +695,12 @@ static void armada_37xx_irq_handler(struct irq_desc *desc)
 
 update_status:
                        /* Update status in case a new IRQ appears */
-                       spin_lock_irqsave(&info->irq_lock, flags);
+                       raw_spin_lock_irqsave(&info->irq_lock, flags);
                        status = readl_relaxed(info->base +
                                               IRQ_STATUS + 4 * i);
                        /* Manage only the interrupt that was enabled */
                        status &= readl_relaxed(info->base + IRQ_EN + 4 * i);
-                       spin_unlock_irqrestore(&info->irq_lock, flags);
+                       raw_spin_unlock_irqrestore(&info->irq_lock, flags);
                }
        }
        chained_irq_exit(chip, desc);
@@ -731,7 +731,7 @@ static int armada_37xx_irqchip_register(struct platform_device *pdev,
        struct device *dev = &pdev->dev;
        unsigned int i, nr_irq_parent;
 
-       spin_lock_init(&info->irq_lock);
+       raw_spin_lock_init(&info->irq_lock);
 
        nr_irq_parent = of_irq_count(np);
        if (!nr_irq_parent) {
@@ -1107,25 +1107,40 @@ static const struct of_device_id armada_37xx_pinctrl_of_match[] = {
        { },
 };
 
+static const struct regmap_config armada_37xx_pinctrl_regmap_config = {
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .use_raw_spinlock = true,
+};
+
 static int __init armada_37xx_pinctrl_probe(struct platform_device *pdev)
 {
        struct armada_37xx_pinctrl *info;
        struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node;
        struct regmap *regmap;
+       void __iomem *base;
        int ret;
 
+       base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+       if (IS_ERR(base)) {
+               dev_err(dev, "failed to ioremap base address: %pe\n", base);
+               return PTR_ERR(base);
+       }
+
+       regmap = devm_regmap_init_mmio(dev, base,
+                                      &armada_37xx_pinctrl_regmap_config);
+       if (IS_ERR(regmap)) {
+               dev_err(dev, "failed to create regmap: %pe\n", regmap);
+               return PTR_ERR(regmap);
+       }
+
        info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
        info->dev = dev;
-
-       regmap = syscon_node_to_regmap(np);
-       if (IS_ERR(regmap))
-               return dev_err_probe(dev, PTR_ERR(regmap), "cannot get regmap\n");
        info->regmap = regmap;
-
        info->data = of_device_get_match_data(dev);
 
        ret = armada_37xx_pinctrl_register(pdev, info);
index 5f4a8c5c66508ac6bf96789403e7dd1f061a2cf3..dfc8ea9f3843cfcf57d45fa920871b15a7341b9b 100644 (file)
 #define ocelot_clrsetbits(addr, clear, set) \
        writel((readl(addr) & ~(clear)) | (set), (addr))
 
-/* PINCONFIG bits (sparx5 only) */
 enum {
        PINCONF_BIAS,
        PINCONF_SCHMITT,
        PINCONF_DRIVE_STRENGTH,
 };
 
-#define BIAS_PD_BIT BIT(4)
-#define BIAS_PU_BIT BIT(3)
-#define BIAS_BITS   (BIAS_PD_BIT|BIAS_PU_BIT)
-#define SCHMITT_BIT BIT(2)
-#define DRIVE_BITS  GENMASK(1, 0)
-
 /* GPIO standard registers */
 #define OCELOT_GPIO_OUT_SET    0x0
 #define OCELOT_GPIO_OUT_CLR    0x4
@@ -321,6 +314,13 @@ struct ocelot_pin_caps {
        unsigned char a_functions[OCELOT_FUNC_PER_PIN]; /* Additional functions */
 };
 
+struct ocelot_pincfg_data {
+       u8 pd_bit;
+       u8 pu_bit;
+       u8 drive_bits;
+       u8 schmitt_bit;
+};
+
 struct ocelot_pinctrl {
        struct device *dev;
        struct pinctrl_dev *pctl;
@@ -328,10 +328,16 @@ struct ocelot_pinctrl {
        struct regmap *map;
        struct regmap *pincfg;
        struct pinctrl_desc *desc;
+       const struct ocelot_pincfg_data *pincfg_data;
        struct ocelot_pmx_func func[FUNC_MAX];
        u8 stride;
 };
 
+struct ocelot_match_data {
+       struct pinctrl_desc desc;
+       struct ocelot_pincfg_data pincfg_data;
+};
+
 #define LUTON_P(p, f0, f1)                                             \
 static struct ocelot_pin_caps luton_pin_##p = {                                \
        .pin = p,                                                       \
@@ -1325,24 +1331,27 @@ static int ocelot_hw_get_value(struct ocelot_pinctrl *info,
        int ret = -EOPNOTSUPP;
 
        if (info->pincfg) {
+               const struct ocelot_pincfg_data *opd = info->pincfg_data;
                u32 regcfg;
 
-               ret = regmap_read(info->pincfg, pin, &regcfg);
+               ret = regmap_read(info->pincfg,
+                                 pin * regmap_get_reg_stride(info->pincfg),
+                                 &regcfg);
                if (ret)
                        return ret;
 
                ret = 0;
                switch (reg) {
                case PINCONF_BIAS:
-                       *val = regcfg & BIAS_BITS;
+                       *val = regcfg & (opd->pd_bit | opd->pu_bit);
                        break;
 
                case PINCONF_SCHMITT:
-                       *val = regcfg & SCHMITT_BIT;
+                       *val = regcfg & opd->schmitt_bit;
                        break;
 
                case PINCONF_DRIVE_STRENGTH:
-                       *val = regcfg & DRIVE_BITS;
+                       *val = regcfg & opd->drive_bits;
                        break;
 
                default:
@@ -1359,14 +1368,18 @@ static int ocelot_pincfg_clrsetbits(struct ocelot_pinctrl *info, u32 regaddr,
        u32 val;
        int ret;
 
-       ret = regmap_read(info->pincfg, regaddr, &val);
+       ret = regmap_read(info->pincfg,
+                         regaddr * regmap_get_reg_stride(info->pincfg),
+                         &val);
        if (ret)
                return ret;
 
        val &= ~clrbits;
        val |= setbits;
 
-       ret = regmap_write(info->pincfg, regaddr, val);
+       ret = regmap_write(info->pincfg,
+                          regaddr * regmap_get_reg_stride(info->pincfg),
+                          val);
 
        return ret;
 }
@@ -1379,23 +1392,27 @@ static int ocelot_hw_set_value(struct ocelot_pinctrl *info,
        int ret = -EOPNOTSUPP;
 
        if (info->pincfg) {
+               const struct ocelot_pincfg_data *opd = info->pincfg_data;
 
                ret = 0;
                switch (reg) {
                case PINCONF_BIAS:
-                       ret = ocelot_pincfg_clrsetbits(info, pin, BIAS_BITS,
+                       ret = ocelot_pincfg_clrsetbits(info, pin,
+                                                      opd->pd_bit | opd->pu_bit,
                                                       val);
                        break;
 
                case PINCONF_SCHMITT:
-                       ret = ocelot_pincfg_clrsetbits(info, pin, SCHMITT_BIT,
+                       ret = ocelot_pincfg_clrsetbits(info, pin,
+                                                      opd->schmitt_bit,
                                                       val);
                        break;
 
                case PINCONF_DRIVE_STRENGTH:
                        if (val <= 3)
                                ret = ocelot_pincfg_clrsetbits(info, pin,
-                                                              DRIVE_BITS, val);
+                                                              opd->drive_bits,
+                                                              val);
                        else
                                ret = -EINVAL;
                        break;
@@ -1425,17 +1442,20 @@ static int ocelot_pinconf_get(struct pinctrl_dev *pctldev,
                if (param == PIN_CONFIG_BIAS_DISABLE)
                        val = (val == 0);
                else if (param == PIN_CONFIG_BIAS_PULL_DOWN)
-                       val = (val & BIAS_PD_BIT ? true : false);
+                       val = !!(val & info->pincfg_data->pd_bit);
                else    /* PIN_CONFIG_BIAS_PULL_UP */
-                       val = (val & BIAS_PU_BIT ? true : false);
+                       val = !!(val & info->pincfg_data->pu_bit);
                break;
 
        case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+               if (!info->pincfg_data->schmitt_bit)
+                       return -EOPNOTSUPP;
+
                err = ocelot_hw_get_value(info, pin, PINCONF_SCHMITT, &val);
                if (err)
                        return err;
 
-               val = (val & SCHMITT_BIT ? true : false);
+               val = !!(val & info->pincfg_data->schmitt_bit);
                break;
 
        case PIN_CONFIG_DRIVE_STRENGTH:
@@ -1479,6 +1499,7 @@ static int ocelot_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
                              unsigned long *configs, unsigned int num_configs)
 {
        struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       const struct ocelot_pincfg_data *opd = info->pincfg_data;
        u32 param, arg, p;
        int cfg, err = 0;
 
@@ -1491,8 +1512,8 @@ static int ocelot_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
                case PIN_CONFIG_BIAS_PULL_UP:
                case PIN_CONFIG_BIAS_PULL_DOWN:
                        arg = (param == PIN_CONFIG_BIAS_DISABLE) ? 0 :
-                       (param == PIN_CONFIG_BIAS_PULL_UP) ? BIAS_PU_BIT :
-                       BIAS_PD_BIT;
+                             (param == PIN_CONFIG_BIAS_PULL_UP) ?
+                               opd->pu_bit : opd->pd_bit;
 
                        err = ocelot_hw_set_value(info, pin, PINCONF_BIAS, arg);
                        if (err)
@@ -1501,7 +1522,10 @@ static int ocelot_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
                        break;
 
                case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
-                       arg = arg ? SCHMITT_BIT : 0;
+                       if (!opd->schmitt_bit)
+                               return -EOPNOTSUPP;
+
+                       arg = arg ? opd->schmitt_bit : 0;
                        err = ocelot_hw_set_value(info, pin, PINCONF_SCHMITT,
                                                  arg);
                        if (err)
@@ -1562,69 +1586,94 @@ static const struct pinctrl_ops ocelot_pctl_ops = {
        .dt_free_map = pinconf_generic_dt_free_map,
 };
 
-static struct pinctrl_desc luton_desc = {
-       .name = "luton-pinctrl",
-       .pins = luton_pins,
-       .npins = ARRAY_SIZE(luton_pins),
-       .pctlops = &ocelot_pctl_ops,
-       .pmxops = &ocelot_pmx_ops,
-       .owner = THIS_MODULE,
+static struct ocelot_match_data luton_desc = {
+       .desc = {
+               .name = "luton-pinctrl",
+               .pins = luton_pins,
+               .npins = ARRAY_SIZE(luton_pins),
+               .pctlops = &ocelot_pctl_ops,
+               .pmxops = &ocelot_pmx_ops,
+               .owner = THIS_MODULE,
+       },
 };
 
-static struct pinctrl_desc serval_desc = {
-       .name = "serval-pinctrl",
-       .pins = serval_pins,
-       .npins = ARRAY_SIZE(serval_pins),
-       .pctlops = &ocelot_pctl_ops,
-       .pmxops = &ocelot_pmx_ops,
-       .owner = THIS_MODULE,
+static struct ocelot_match_data serval_desc = {
+       .desc = {
+               .name = "serval-pinctrl",
+               .pins = serval_pins,
+               .npins = ARRAY_SIZE(serval_pins),
+               .pctlops = &ocelot_pctl_ops,
+               .pmxops = &ocelot_pmx_ops,
+               .owner = THIS_MODULE,
+       },
 };
 
-static struct pinctrl_desc ocelot_desc = {
-       .name = "ocelot-pinctrl",
-       .pins = ocelot_pins,
-       .npins = ARRAY_SIZE(ocelot_pins),
-       .pctlops = &ocelot_pctl_ops,
-       .pmxops = &ocelot_pmx_ops,
-       .owner = THIS_MODULE,
+static struct ocelot_match_data ocelot_desc = {
+       .desc = {
+               .name = "ocelot-pinctrl",
+               .pins = ocelot_pins,
+               .npins = ARRAY_SIZE(ocelot_pins),
+               .pctlops = &ocelot_pctl_ops,
+               .pmxops = &ocelot_pmx_ops,
+               .owner = THIS_MODULE,
+       },
 };
 
-static struct pinctrl_desc jaguar2_desc = {
-       .name = "jaguar2-pinctrl",
-       .pins = jaguar2_pins,
-       .npins = ARRAY_SIZE(jaguar2_pins),
-       .pctlops = &ocelot_pctl_ops,
-       .pmxops = &ocelot_pmx_ops,
-       .owner = THIS_MODULE,
+static struct ocelot_match_data jaguar2_desc = {
+       .desc = {
+               .name = "jaguar2-pinctrl",
+               .pins = jaguar2_pins,
+               .npins = ARRAY_SIZE(jaguar2_pins),
+               .pctlops = &ocelot_pctl_ops,
+               .pmxops = &ocelot_pmx_ops,
+               .owner = THIS_MODULE,
+       },
 };
 
-static struct pinctrl_desc servalt_desc = {
-       .name = "servalt-pinctrl",
-       .pins = servalt_pins,
-       .npins = ARRAY_SIZE(servalt_pins),
-       .pctlops = &ocelot_pctl_ops,
-       .pmxops = &ocelot_pmx_ops,
-       .owner = THIS_MODULE,
+static struct ocelot_match_data servalt_desc = {
+       .desc = {
+               .name = "servalt-pinctrl",
+               .pins = servalt_pins,
+               .npins = ARRAY_SIZE(servalt_pins),
+               .pctlops = &ocelot_pctl_ops,
+               .pmxops = &ocelot_pmx_ops,
+               .owner = THIS_MODULE,
+       },
 };
 
-static struct pinctrl_desc sparx5_desc = {
-       .name = "sparx5-pinctrl",
-       .pins = sparx5_pins,
-       .npins = ARRAY_SIZE(sparx5_pins),
-       .pctlops = &ocelot_pctl_ops,
-       .pmxops = &ocelot_pmx_ops,
-       .confops = &ocelot_confops,
-       .owner = THIS_MODULE,
+static struct ocelot_match_data sparx5_desc = {
+       .desc = {
+               .name = "sparx5-pinctrl",
+               .pins = sparx5_pins,
+               .npins = ARRAY_SIZE(sparx5_pins),
+               .pctlops = &ocelot_pctl_ops,
+               .pmxops = &ocelot_pmx_ops,
+               .confops = &ocelot_confops,
+               .owner = THIS_MODULE,
+       },
+       .pincfg_data = {
+               .pd_bit = BIT(4),
+               .pu_bit = BIT(3),
+               .drive_bits = GENMASK(1, 0),
+               .schmitt_bit = BIT(2),
+       },
 };
 
-static struct pinctrl_desc lan966x_desc = {
-       .name = "lan966x-pinctrl",
-       .pins = lan966x_pins,
-       .npins = ARRAY_SIZE(lan966x_pins),
-       .pctlops = &ocelot_pctl_ops,
-       .pmxops = &lan966x_pmx_ops,
-       .confops = &ocelot_confops,
-       .owner = THIS_MODULE,
+static struct ocelot_match_data lan966x_desc = {
+       .desc = {
+               .name = "lan966x-pinctrl",
+               .pins = lan966x_pins,
+               .npins = ARRAY_SIZE(lan966x_pins),
+               .pctlops = &ocelot_pctl_ops,
+               .pmxops = &lan966x_pmx_ops,
+               .confops = &ocelot_confops,
+               .owner = THIS_MODULE,
+       },
+       .pincfg_data = {
+               .pd_bit = BIT(3),
+               .pu_bit = BIT(2),
+               .drive_bits = GENMASK(1, 0),
+       },
 };
 
 static int ocelot_create_group_func_map(struct device *dev,
@@ -1890,7 +1939,8 @@ static const struct of_device_id ocelot_pinctrl_of_match[] = {
        {},
 };
 
-static struct regmap *ocelot_pinctrl_create_pincfg(struct platform_device *pdev)
+static struct regmap *ocelot_pinctrl_create_pincfg(struct platform_device *pdev,
+                                                  const struct ocelot_pinctrl *info)
 {
        void __iomem *base;
 
@@ -1898,7 +1948,7 @@ static struct regmap *ocelot_pinctrl_create_pincfg(struct platform_device *pdev)
                .reg_bits = 32,
                .val_bits = 32,
                .reg_stride = 4,
-               .max_register = 32,
+               .max_register = info->desc->npins * 4,
                .name = "pincfg",
        };
 
@@ -1913,6 +1963,7 @@ static struct regmap *ocelot_pinctrl_create_pincfg(struct platform_device *pdev)
 
 static int ocelot_pinctrl_probe(struct platform_device *pdev)
 {
+       const struct ocelot_match_data *data;
        struct device *dev = &pdev->dev;
        struct ocelot_pinctrl *info;
        struct reset_control *reset;
@@ -1929,7 +1980,16 @@ static int ocelot_pinctrl_probe(struct platform_device *pdev)
        if (!info)
                return -ENOMEM;
 
-       info->desc = (struct pinctrl_desc *)device_get_match_data(dev);
+       data = device_get_match_data(dev);
+       if (!data)
+               return -EINVAL;
+
+       info->desc = devm_kmemdup(dev, &data->desc, sizeof(*info->desc),
+                                 GFP_KERNEL);
+       if (!info->desc)
+               return -ENOMEM;
+
+       info->pincfg_data = &data->pincfg_data;
 
        reset = devm_reset_control_get_optional_shared(dev, "switch");
        if (IS_ERR(reset))
@@ -1956,7 +2016,7 @@ static int ocelot_pinctrl_probe(struct platform_device *pdev)
 
        /* Pinconf registers */
        if (info->desc->confops) {
-               pincfg = ocelot_pinctrl_create_pincfg(pdev);
+               pincfg = ocelot_pinctrl_create_pincfg(pdev, info);
                if (IS_ERR(pincfg))
                        dev_dbg(dev, "Failed to create pincfg regmap\n");
                else
index 63429a2874343a984966925261a4608f00a9f6d0..770862f45b3fe1c53fcf047bc92da02f09a2195f 100644 (file)
@@ -266,6 +266,8 @@ static int ralink_pinctrl_pins(struct ralink_priv *p)
                                                p->func[i]->pin_count,
                                                sizeof(int),
                                                GFP_KERNEL);
+               if (!p->func[i]->pins)
+                       return -ENOMEM;
                for (j = 0; j < p->func[i]->pin_count; j++)
                        p->func[i]->pins[j] = p->func[i]->pin_first + j;
 
index 57a33fb0f2d7d6955dcf812f4ba9cf9a932825db..14bcca73238aee98f42606bc84042e34aab8ea1e 100644 (file)
@@ -1338,16 +1338,18 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, struct fwnode
        bank->secure_control = pctl->match_data->secure_control;
        spin_lock_init(&bank->lock);
 
-       /* create irq hierarchical domain */
-       bank->fwnode = fwnode;
+       if (pctl->domain) {
+               /* create irq hierarchical domain */
+               bank->fwnode = fwnode;
 
-       bank->domain = irq_domain_create_hierarchy(pctl->domain, 0,
-                                       STM32_GPIO_IRQ_LINE, bank->fwnode,
-                                       &stm32_gpio_domain_ops, bank);
+               bank->domain = irq_domain_create_hierarchy(pctl->domain, 0, STM32_GPIO_IRQ_LINE,
+                                                          bank->fwnode, &stm32_gpio_domain_ops,
+                                                          bank);
 
-       if (!bank->domain) {
-               err = -ENODEV;
-               goto err_clk;
+               if (!bank->domain) {
+                       err = -ENODEV;
+                       goto err_clk;
+               }
        }
 
        err = gpiochip_add_data(&bank->gpio_chip, bank);
@@ -1510,6 +1512,8 @@ int stm32_pctl_probe(struct platform_device *pdev)
        pctl->domain = stm32_pctrl_get_irq_domain(pdev);
        if (IS_ERR(pctl->domain))
                return PTR_ERR(pctl->domain);
+       if (!pctl->domain)
+               dev_warn(dev, "pinctrl without interrupt support\n");
 
        /* hwspinlock is optional */
        hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0);
index 3ba47040ac423013f5aebddd8b047c26d4c495bc..2b3335ab56c66867b21c4c41d385acc4b001fa9d 100644 (file)
@@ -871,6 +871,9 @@ static int sppctl_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node
        }
 
        *map = kcalloc(*num_maps + nmG, sizeof(**map), GFP_KERNEL);
+       if (*map == NULL)
+               return -ENOMEM;
+
        for (i = 0; i < (*num_maps); i++) {
                dt_pin = be32_to_cpu(list[i]);
                pin_num = FIELD_GET(GENMASK(31, 24), dt_pin);
index 4ada80317a3bd56bab5627b7ae947d1d3a82c352..b5c1a8f363f32eebc965aeafee02c1ed61674e0d 100644 (file)
@@ -158,26 +158,26 @@ static const struct sunxi_desc_pin sun8i_a83t_pins[] = {
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ6 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ6 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D6 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ7 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ7 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D7 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQS */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQS */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* RST */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 17),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand")),         /* CE2 */
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* CE2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 18),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand")),         /* CE3 */
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* CE3 */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
index d9327d7d56eea8f4844980118448f6f8cd1b6593..dd928402af9978deb7159d6204dde1f605058c04 100644 (file)
@@ -544,6 +544,8 @@ static int sunxi_pconf_set(struct pinctrl_dev *pctldev, unsigned pin,
        struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
        int i;
 
+       pin -= pctl->desc->pin_base;
+
        for (i = 0; i < num_configs; i++) {
                enum pin_config_param param;
                unsigned long flags;
index f11d18beac1876343c85489d901373ad99dc8d1d..700eb19e84500ca729ae8d7eedcb6536c0cd75f6 100644 (file)
@@ -91,6 +91,8 @@
 #define AMD_CPU_ID_PCO                 AMD_CPU_ID_RV
 #define AMD_CPU_ID_CZN                 AMD_CPU_ID_RN
 #define AMD_CPU_ID_YC                  0x14B5
+#define AMD_CPU_ID_CB                  0x14D8
+#define AMD_CPU_ID_PS                  0x14E8
 
 #define PMC_MSG_DELAY_MIN_US           50
 #define RESPONSE_REGISTER_LOOP_MAX     20000
@@ -318,6 +320,8 @@ static int amd_pmc_idlemask_read(struct amd_pmc_dev *pdev, struct device *dev,
                val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_CZN);
                break;
        case AMD_CPU_ID_YC:
+       case AMD_CPU_ID_CB:
+       case AMD_CPU_ID_PS:
                val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_YC);
                break;
        default:
@@ -491,7 +495,8 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
                            &amd_pmc_idlemask_fops);
        /* Enable STB only when the module_param is set */
        if (enable_stb) {
-               if (dev->cpu_id == AMD_CPU_ID_YC)
+               if (dev->cpu_id == AMD_CPU_ID_YC || dev->cpu_id == AMD_CPU_ID_CB ||
+                   dev->cpu_id == AMD_CPU_ID_PS)
                        debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev,
                                            &amd_pmc_stb_debugfs_fops_v2);
                else
@@ -615,6 +620,8 @@ static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev)
                return MSG_OS_HINT_PCO;
        case AMD_CPU_ID_RN:
        case AMD_CPU_ID_YC:
+       case AMD_CPU_ID_CB:
+       case AMD_CPU_ID_PS:
                return MSG_OS_HINT_RN;
        }
        return -EINVAL;
@@ -735,6 +742,8 @@ static struct acpi_s2idle_dev_ops amd_pmc_s2idle_dev_ops = {
 #endif
 
 static const struct pci_device_id pmc_pci_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CB) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_YC) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CZN) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RN) },
@@ -877,7 +886,7 @@ static int amd_pmc_probe(struct platform_device *pdev)
 
        mutex_init(&dev->lock);
 
-       if (enable_stb && dev->cpu_id == AMD_CPU_ID_YC) {
+       if (enable_stb && (dev->cpu_id == AMD_CPU_ID_YC || dev->cpu_id == AMD_CPU_ID_CB)) {
                err = amd_pmc_s2d_init(dev);
                if (err)
                        return err;
@@ -915,6 +924,7 @@ static const struct acpi_device_id amd_pmc_acpi_ids[] = {
        {"AMDI0005", 0},
        {"AMDI0006", 0},
        {"AMDI0007", 0},
+       {"AMDI0008", 0},
        {"AMD0004", 0},
        {"AMD0005", 0},
        { }
index 57a07db659cbaaf154d16c857809492b6c38fa7b..478dd300b9c9a77e2564895955031e237eec9eb1 100644 (file)
@@ -522,6 +522,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
        { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
        { KE_KEY, 0x32, { KEY_MUTE } },
        { KE_KEY, 0x35, { KEY_SCREENLOCK } },
+       { KE_KEY, 0x38, { KEY_PROG3 } }, /* Armoury Crate */
        { KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
        { KE_KEY, 0x41, { KEY_NEXTSONG } },
        { KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */
@@ -574,6 +575,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
        { KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */
        { KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */
        { KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */
+       { KE_KEY, 0xB3, { KEY_PROG4 } }, /* AURA */
        { KE_KEY, 0xB5, { KEY_CALC } },
        { KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
        { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
index 497ad2f64a51c0400e9062c0acf1f08464b546a4..5e7e6659a84971e7cd5227470848659e5ed533d6 100644 (file)
@@ -150,6 +150,7 @@ static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = {
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M AORUS PRO-P"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M DS3H"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B660 GAMING X DDR4"),
+       DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B660I AORUS PRO DDR4"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("Z390 I AORUS PRO WIFI-CF"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("Z490 AORUS ELITE AC"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 AORUS ELITE"),
index 5935dfca166f0f14a3a3dbf64af1efae6bceae34..10077a61d8c5a91b9b720888a1c76b94eb1ea357 100644 (file)
@@ -50,7 +50,8 @@ static const struct dmi_system_id atomisp2_led_systems[] __initconst = {
        {
                .matches = {
                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
+                       /* Non exact match to also match T100TAF */
+                       DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
                },
                .driver_data = &asus_t100ta_lookup,
        },
index 7ce896434b8f8330793b9c8af80a518acb70376a..c341a27cc1a39b2f2d9b2722c5f891e66e3e404c 100644 (file)
@@ -1,6 +1,9 @@
 config INTEL_IFS
        tristate "Intel In Field Scan"
        depends on X86 && CPU_SUP_INTEL && 64BIT && SMP
+       # Discussion on the list has shown that the sysfs API needs a bit
+       # more work, mark this as broken for now
+       depends on BROKEN
        select INTEL_IFS_DEVICE
        help
          Enable support for the In Field Scan capability in select
index f446be72e53944852db9bbdd4e691447c0d8fed4..4803759774358b6d10e4db3fc5ce96d57ce95292 100644 (file)
@@ -27,8 +27,8 @@
 #include <linux/pinctrl/machine.h>
 #include <linux/platform_data/lp855x.h>
 #include <linux/platform_device.h>
-#include <linux/pm.h>
 #include <linux/power/bq24190_charger.h>
+#include <linux/reboot.h>
 #include <linux/rmi.h>
 #include <linux/serdev.h>
 #include <linux/spi/spi.h>
@@ -889,6 +889,7 @@ static const struct pinctrl_map lenovo_yoga_tab2_830_1050_codec_pinctrl_map =
                          "INT33FC:02", "pmu_clk2_grp", "pmu_clk");
 
 static struct pinctrl *lenovo_yoga_tab2_830_1050_codec_pinctrl;
+static struct sys_off_handler *lenovo_yoga_tab2_830_1050_sys_off_handler;
 
 static int __init lenovo_yoga_tab2_830_1050_init_codec(void)
 {
@@ -933,9 +934,11 @@ err_put_device:
  * followed by a normal 3 second press to recover. Avoid this by doing an EFI
  * poweroff instead.
  */
-static void lenovo_yoga_tab2_830_1050_power_off(void)
+static int lenovo_yoga_tab2_830_1050_power_off(struct sys_off_data *data)
 {
        efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
+
+       return NOTIFY_DONE;
 }
 
 static int __init lenovo_yoga_tab2_830_1050_init(void)
@@ -950,13 +953,19 @@ static int __init lenovo_yoga_tab2_830_1050_init(void)
        if (ret)
                return ret;
 
-       pm_power_off = lenovo_yoga_tab2_830_1050_power_off;
+       /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */
+       lenovo_yoga_tab2_830_1050_sys_off_handler =
+               register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_FIRMWARE + 1,
+                                        lenovo_yoga_tab2_830_1050_power_off, NULL);
+       if (IS_ERR(lenovo_yoga_tab2_830_1050_sys_off_handler))
+               return PTR_ERR(lenovo_yoga_tab2_830_1050_sys_off_handler);
+
        return 0;
 }
 
 static void lenovo_yoga_tab2_830_1050_exit(void)
 {
-       pm_power_off = NULL; /* Just turn poweroff into halt on module unload */
+       unregister_sys_off_handler(lenovo_yoga_tab2_830_1050_sys_off_handler);
 
        if (lenovo_yoga_tab2_830_1050_codec_pinctrl) {
                pinctrl_put(lenovo_yoga_tab2_830_1050_codec_pinctrl);
index 08d0a07b58ef284a6b9df6c9d54ad5bdf2ef8988..c7624d7611a7ede805e6fef8f79301b0a58dadfd 100644 (file)
@@ -146,6 +146,7 @@ static int __init versatile_reboot_probe(void)
        versatile_reboot_type = (enum versatile_reboot)reboot_id->data;
 
        syscon_regmap = syscon_node_to_regmap(np);
+       of_node_put(np);
        if (IS_ERR(syscon_regmap))
                return PTR_ERR(syscon_regmap);
 
index ec8a404d71b44b02985f7075aa3379bbea7de250..4339fa9ff0099185ca9c9c08893cd025d30b28b4 100644 (file)
@@ -3148,6 +3148,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        ret = ab8500_fg_init_hw_registers(di);
        if (ret) {
                dev_err(dev, "failed to initialize registers\n");
+               destroy_workqueue(di->fg_wq);
                return ret;
        }
 
@@ -3159,6 +3160,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        di->fg_psy = devm_power_supply_register(dev, &ab8500_fg_desc, &psy_cfg);
        if (IS_ERR(di->fg_psy)) {
                dev_err(dev, "failed to register FG psy\n");
+               destroy_workqueue(di->fg_wq);
                return PTR_ERR(di->fg_psy);
        }
 
@@ -3174,8 +3176,10 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        /* Register primary interrupt handlers */
        for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq); i++) {
                irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name);
-               if (irq < 0)
+               if (irq < 0) {
+                       destroy_workqueue(di->fg_wq);
                        return irq;
+               }
 
                ret = devm_request_threaded_irq(dev, irq, NULL,
                                  ab8500_fg_irq[i].isr,
@@ -3185,6 +3189,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
                if (ret != 0) {
                        dev_err(dev, "failed to request %s IRQ %d: %d\n",
                                ab8500_fg_irq[i].name, irq, ret);
+                       destroy_workqueue(di->fg_wq);
                        return ret;
                }
                dev_dbg(dev, "Requested %s IRQ %d: %d\n",
@@ -3200,6 +3205,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        ret = ab8500_fg_sysfs_init(di);
        if (ret) {
                dev_err(dev, "failed to create sysfs entry\n");
+               destroy_workqueue(di->fg_wq);
                return ret;
        }
 
@@ -3207,6 +3213,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(dev, "failed to create FG psy\n");
                ab8500_fg_sysfs_exit(di);
+               destroy_workqueue(di->fg_wq);
                return ret;
        }
 
index fad5890c899e2d976dd68383c8fcae66e43da2f8..470253c337c7306c0e8b430df2cd28b580247d26 100644 (file)
@@ -846,17 +846,17 @@ int power_supply_temp2resist_simple(struct power_supply_resistance_temp_table *t
 {
        int i, high, low;
 
-       /* Break loop at table_len - 1 because that is the highest index */
-       for (i = 0; i < table_len - 1; i++)
+       for (i = 0; i < table_len; i++)
                if (temp > table[i].temp)
                        break;
 
        /* The library function will deal with high == low */
-       if ((i == 0) || (i == (table_len - 1)))
-               high = i;
+       if (i == 0)
+               high = low = i;
+       else if (i == table_len)
+               high = low = i - 1;
        else
-               high = i - 1;
-       low = i;
+               high = (low = i) - 1;
 
        return fixp_linear_interpolate(table[low].temp,
                                       table[low].resistance,
@@ -958,17 +958,17 @@ int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table,
 {
        int i, high, low;
 
-       /* Break loop at table_len - 1 because that is the highest index */
-       for (i = 0; i < table_len - 1; i++)
+       for (i = 0; i < table_len; i++)
                if (ocv > table[i].ocv)
                        break;
 
        /* The library function will deal with high == low */
-       if ((i == 0) || (i == (table_len - 1)))
-               high = i - 1;
+       if (i == 0)
+               high = low = i;
+       else if (i == table_len)
+               high = low = i - 1;
        else
-               high = i; /* i.e. i == 0 */
-       low = i;
+               high = (low = i) - 1;
 
        return fixp_linear_interpolate(table[low].ocv,
                                       table[low].capacity,
index f5eced0842b36d158cf18a2c648482513a4496cc..61c5ff80bd30369a2e2c301053eb9a3b2db54ef8 100644 (file)
@@ -53,7 +53,7 @@ static u64 set_pd_power_limit(struct dtpm *dtpm, u64 power_limit)
 
        for (i = 0; i < pd->nr_perf_states; i++) {
 
-               power = pd->table[i].power * MICROWATT_PER_MILLIWATT * nr_cpus;
+               power = pd->table[i].power * nr_cpus;
 
                if (power > power_limit)
                        break;
@@ -63,8 +63,7 @@ static u64 set_pd_power_limit(struct dtpm *dtpm, u64 power_limit)
 
        freq_qos_update_request(&dtpm_cpu->qos_req, freq);
 
-       power_limit = pd->table[i - 1].power *
-               MICROWATT_PER_MILLIWATT * nr_cpus;
+       power_limit = pd->table[i - 1].power * nr_cpus;
 
        return power_limit;
 }
index a9c99d9e8b4285e77fbe7d037dff89c79d209370..21d624f9f5fb2028d780f0072fe93702751a0eb7 100644 (file)
@@ -1109,6 +1109,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = {
        X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L,         &rapl_defaults_core),
        X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N,         &rapl_defaults_core),
        X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE,          &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P,        &rapl_defaults_core),
        X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X,    &rapl_defaults_spr_server),
        X86_MATCH_INTEL_FAM6_MODEL(LAKEFIELD,           &rapl_defaults_core),
 
index 9d23984d89311b62524f8607bfc42312d4c6f9ec..bc6adda588835849c6c98cbdb2216fd656b8f2e2 100644 (file)
@@ -140,7 +140,9 @@ static const struct x86_cpu_id pl4_support_ids[] = {
        { X86_VENDOR_INTEL, 6, INTEL_FAM6_TIGERLAKE_L, X86_FEATURE_ANY },
        { X86_VENDOR_INTEL, 6, INTEL_FAM6_ALDERLAKE, X86_FEATURE_ANY },
        { X86_VENDOR_INTEL, 6, INTEL_FAM6_ALDERLAKE_L, X86_FEATURE_ANY },
+       { X86_VENDOR_INTEL, 6, INTEL_FAM6_ALDERLAKE_N, X86_FEATURE_ANY },
        { X86_VENDOR_INTEL, 6, INTEL_FAM6_RAPTORLAKE, X86_FEATURE_ANY },
+       { X86_VENDOR_INTEL, 6, INTEL_FAM6_RAPTORLAKE_P, X86_FEATURE_ANY },
        {}
 };
 
index 5c13d2079d96f32e8d85f208d09d74c48f94516a..0a9045b49c508192eea8eaf9c66c50a396f20c3f 100644 (file)
@@ -1435,7 +1435,7 @@ static int __verify_queue_reservations(struct device_driver *drv, void *data)
        if (ap_drv->in_use) {
                rc = ap_drv->in_use(ap_perms.apm, newaqm);
                if (rc)
-                       return -EBUSY;
+                       rc = -EBUSY;
        }
 
        /* release the driver's module */
index c95360a3c186f24cb11a2843ae4ed908dde71496..0917b05059b4e2ae15a81f6df54de0d9cd3b142c 100644 (file)
@@ -3195,6 +3195,9 @@ static int megasas_map_queues(struct Scsi_Host *shost)
        qoff += map->nr_queues;
        offset += map->nr_queues;
 
+       /* we never use READ queue, so can't cheat blk-mq */
+       shost->tag_set.map[HCTX_TYPE_READ].nr_queues = 0;
+
        /* Setup Poll hctx */
        map = &shost->tag_set.map[HCTX_TYPE_POLL];
        map->nr_queues = instance->iopoll_q_count;
index f7466a895d3b1fa2edc0620d66c80e4a0c689bf9..991eb01bb1e08409f822aac776c0c936c09cd59a 100644 (file)
@@ -3145,15 +3145,6 @@ void pm8001_bytes_dmaed(struct pm8001_hba_info *pm8001_ha, int i)
        if (!phy->phy_attached)
                return;
 
-       if (sas_phy->phy) {
-               struct sas_phy *sphy = sas_phy->phy;
-               sphy->negotiated_linkrate = sas_phy->linkrate;
-               sphy->minimum_linkrate = phy->minimum_linkrate;
-               sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
-               sphy->maximum_linkrate = phy->maximum_linkrate;
-               sphy->maximum_linkrate_hw = phy->maximum_linkrate;
-       }
-
        if (phy->phy_type & PORT_TYPE_SAS) {
                struct sas_identify_frame *id;
                id = (struct sas_identify_frame *)phy->frame_rcvd;
@@ -3177,26 +3168,22 @@ void pm8001_get_lrate_mode(struct pm8001_phy *phy, u8 link_rate)
        switch (link_rate) {
        case PHY_SPEED_120:
                phy->sas_phy.linkrate = SAS_LINK_RATE_12_0_GBPS;
-               phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_12_0_GBPS;
                break;
        case PHY_SPEED_60:
                phy->sas_phy.linkrate = SAS_LINK_RATE_6_0_GBPS;
-               phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS;
                break;
        case PHY_SPEED_30:
                phy->sas_phy.linkrate = SAS_LINK_RATE_3_0_GBPS;
-               phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
                break;
        case PHY_SPEED_15:
                phy->sas_phy.linkrate = SAS_LINK_RATE_1_5_GBPS;
-               phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
                break;
        }
        sas_phy->negotiated_linkrate = phy->sas_phy.linkrate;
-       sas_phy->maximum_linkrate_hw = SAS_LINK_RATE_6_0_GBPS;
+       sas_phy->maximum_linkrate_hw = phy->maximum_linkrate;
        sas_phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
-       sas_phy->maximum_linkrate = SAS_LINK_RATE_6_0_GBPS;
-       sas_phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+       sas_phy->maximum_linkrate = phy->maximum_linkrate;
+       sas_phy->minimum_linkrate = phy->minimum_linkrate;
 }
 
 /**
index 9b04f1a6a67d7c807b886c2da899db459b1afcaa..01f2f41928ebecb9c85da49d33a4d4b6b4f117ab 100644 (file)
@@ -143,6 +143,8 @@ static void pm8001_phy_init(struct pm8001_hba_info *pm8001_ha, int phy_id)
        struct asd_sas_phy *sas_phy = &phy->sas_phy;
        phy->phy_state = PHY_LINK_DISABLE;
        phy->pm8001_ha = pm8001_ha;
+       phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+       phy->maximum_linkrate = SAS_LINK_RATE_6_0_GBPS;
        sas_phy->enabled = (phy_id < pm8001_ha->chip->n_phy) ? 1 : 0;
        sas_phy->class = SAS;
        sas_phy->iproto = SAS_PROTOCOL_ALL;
index 01c5e8ff4cc5fbe41525fe64bcafa47a060e94ed..303cd05fec5064c4d34bc6b9f8829f8ff61955c7 100644 (file)
@@ -3723,8 +3723,12 @@ static int mpi_phy_stop_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
        pm8001_dbg(pm8001_ha, MSG, "phy:0x%x status:0x%x\n",
                   phyid, status);
        if (status == PHY_STOP_SUCCESS ||
-               status == PHY_STOP_ERR_DEVICE_ATTACHED)
+               status == PHY_STOP_ERR_DEVICE_ATTACHED) {
                phy->phy_state = PHY_LINK_DISABLE;
+               phy->sas_phy.phy->negotiated_linkrate = SAS_PHY_DISABLED;
+               phy->sas_phy.linkrate = SAS_PHY_DISABLED;
+       }
+
        return 0;
 }
 
index b2d365ae02823fe4ab48232dedec4e455434c985..dae8a2e0f7455d828ee2e19b23293dd8f2676e68 100644 (file)
@@ -91,14 +91,14 @@ static const struct at91_soc socs[] __initconst = {
        AT91_SOC(SAM9X60_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
                 AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH,
                 "sam9x60", "sam9x60"),
-       AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D5M_EXID_MATCH,
-                AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH,
+       AT91_SOC(SAM9X60_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
+                AT91_CIDR_VERSION_MASK, SAM9X60_D5M_EXID_MATCH,
                 "sam9x60 64MiB DDR2 SiP", "sam9x60"),
-       AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D1G_EXID_MATCH,
-                AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH,
+       AT91_SOC(SAM9X60_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
+                AT91_CIDR_VERSION_MASK, SAM9X60_D1G_EXID_MATCH,
                 "sam9x60 128MiB DDR2 SiP", "sam9x60"),
-       AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D6K_EXID_MATCH,
-                AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH,
+       AT91_SOC(SAM9X60_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
+                AT91_CIDR_VERSION_MASK, SAM9X60_D6K_EXID_MATCH,
                 "sam9x60 8MiB SDRAM SiP", "sam9x60"),
 #endif
 #ifdef CONFIG_SOC_SAMA5
index 613935cb6a488fbdeb1a7e38d22b4aecc6517f48..58240e320c132fed982da17d62094ab7b1e896f2 100644 (file)
@@ -758,7 +758,7 @@ static const struct of_device_id ixp4xx_npe_of_match[] = {
 static struct platform_driver ixp4xx_npe_driver = {
        .driver = {
                .name           = "ixp4xx-npe",
-               .of_match_table = of_match_ptr(ixp4xx_npe_of_match),
+               .of_match_table = ixp4xx_npe_of_match,
        },
        .probe = ixp4xx_npe_probe,
        .remove = ixp4xx_npe_remove,
index 3e95835653eaa8d7ccdfd1f864e625bca51c873c..4f163d62942c1aa580bb54786a6430aa55f6b3f6 100644 (file)
@@ -926,7 +926,7 @@ qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
        struct smem_partition_header *header;
        struct smem_ptable_entry *entry;
        struct smem_ptable *ptable;
-       unsigned int remote_host;
+       u16 remote_host;
        u16 host0, host1;
        int i;
 
@@ -951,12 +951,12 @@ qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
                        continue;
 
                if (remote_host >= SMEM_HOST_COUNT) {
-                       dev_err(smem->dev, "bad host %hu\n", remote_host);
+                       dev_err(smem->dev, "bad host %u\n", remote_host);
                        return -EINVAL;
                }
 
                if (smem->partitions[remote_host].virt_base) {
-                       dev_err(smem->dev, "duplicate host %hu\n", remote_host);
+                       dev_err(smem->dev, "duplicate host %u\n", remote_host);
                        return -EINVAL;
                }
 
index cba6a4486c24c408d9bed3d44cf7a098c5728609..efdcbe6c4c2665c5a3d350b9e95f6d7af7ef53b0 100644 (file)
@@ -33,6 +33,7 @@
 #define AMD_SPI_RX_COUNT_REG   0x4B
 #define AMD_SPI_STATUS_REG     0x4C
 
+#define AMD_SPI_FIFO_SIZE      70
 #define AMD_SPI_MEM_SIZE       200
 
 /* M_CMD OP codes for SPI */
@@ -270,6 +271,11 @@ static int amd_spi_master_transfer(struct spi_master *master,
        return 0;
 }
 
+static size_t amd_spi_max_transfer_size(struct spi_device *spi)
+{
+       return AMD_SPI_FIFO_SIZE;
+}
+
 static int amd_spi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -302,6 +308,8 @@ static int amd_spi_probe(struct platform_device *pdev)
        master->flags = SPI_MASTER_HALF_DUPLEX;
        master->setup = amd_spi_master_setup;
        master->transfer_one_message = amd_spi_master_transfer;
+       master->max_transfer_size = amd_spi_max_transfer_size;
+       master->max_message_size = amd_spi_max_transfer_size;
 
        /* Register the controller with SPI framework */
        err = devm_spi_register_master(dev, master);
index 496f3e1e9079b0886865b48a319df507e727a7e0..3e891bf22470e0610c64c5e15bf0a2f3f1e956eb 100644 (file)
@@ -558,6 +558,14 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
        u32 ctl_val;
        int ret = 0;
 
+       dev_dbg(aspi->dev,
+               "CE%d %s dirmap [ 0x%.8llx - 0x%.8llx ] OP %#x mode:%d.%d.%d.%d naddr:%#x ndummies:%#x\n",
+               chip->cs, op->data.dir == SPI_MEM_DATA_IN ? "read" : "write",
+               desc->info.offset, desc->info.offset + desc->info.length,
+               op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
+               op->dummy.buswidth, op->data.buswidth,
+               op->addr.nbytes, op->dummy.nbytes);
+
        chip->clk_freq = desc->mem->spi->max_speed_hz;
 
        /* Only for reads */
@@ -574,9 +582,11 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
        ctl_val = readl(chip->ctl) & ~CTRL_IO_CMD_MASK;
        ctl_val |= aspeed_spi_get_io_mode(op) |
                op->cmd.opcode << CTRL_COMMAND_SHIFT |
-               CTRL_IO_DUMMY_SET(op->dummy.nbytes / op->dummy.buswidth) |
                CTRL_IO_MODE_READ;
 
+       if (op->dummy.nbytes)
+               ctl_val |= CTRL_IO_DUMMY_SET(op->dummy.nbytes / op->dummy.buswidth);
+
        /* Tune 4BYTE address mode */
        if (op->addr.nbytes) {
                u32 addr_mode = readl(aspi->regs + CE_CTRL_REG);
index 775c0bf2f923d4818fc940e9b0eb11555862d7d4..0933948d7df3d85c489395e84931f7f346dc61c8 100644 (file)
@@ -1138,10 +1138,14 @@ static void bcm2835_spi_handle_err(struct spi_controller *ctlr,
        struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
 
        /* if an error occurred and we have an active dma, then terminate */
-       dmaengine_terminate_sync(ctlr->dma_tx);
-       bs->tx_dma_active = false;
-       dmaengine_terminate_sync(ctlr->dma_rx);
-       bs->rx_dma_active = false;
+       if (ctlr->dma_tx) {
+               dmaengine_terminate_sync(ctlr->dma_tx);
+               bs->tx_dma_active = false;
+       }
+       if (ctlr->dma_rx) {
+               dmaengine_terminate_sync(ctlr->dma_rx);
+               bs->rx_dma_active = false;
+       }
        bcm2835_spi_undo_prologue(bs);
 
        /* and reset */
index 2b9fc8449a622ef260d5159fc637ad4058be00bf..72b1a5a2298c551c34a80aefd56af16d98949f40 100644 (file)
@@ -1578,8 +1578,7 @@ static int cqspi_probe(struct platform_device *pdev)
        ret = cqspi_of_get_pdata(cqspi);
        if (ret) {
                dev_err(dev, "Cannot get mandatory OF data.\n");
-               ret = -ENODEV;
-               goto probe_master_put;
+               return -ENODEV;
        }
 
        /* Obtain QSPI clock. */
@@ -1587,7 +1586,7 @@ static int cqspi_probe(struct platform_device *pdev)
        if (IS_ERR(cqspi->clk)) {
                dev_err(dev, "Cannot claim QSPI clock.\n");
                ret = PTR_ERR(cqspi->clk);
-               goto probe_master_put;
+               return ret;
        }
 
        /* Obtain and remap controller address. */
@@ -1596,7 +1595,7 @@ static int cqspi_probe(struct platform_device *pdev)
        if (IS_ERR(cqspi->iobase)) {
                dev_err(dev, "Cannot remap controller address.\n");
                ret = PTR_ERR(cqspi->iobase);
-               goto probe_master_put;
+               return ret;
        }
 
        /* Obtain and remap AHB address. */
@@ -1605,7 +1604,7 @@ static int cqspi_probe(struct platform_device *pdev)
        if (IS_ERR(cqspi->ahb_base)) {
                dev_err(dev, "Cannot remap AHB address.\n");
                ret = PTR_ERR(cqspi->ahb_base);
-               goto probe_master_put;
+               return ret;
        }
        cqspi->mmap_phys_base = (dma_addr_t)res_ahb->start;
        cqspi->ahb_size = resource_size(res_ahb);
@@ -1614,15 +1613,13 @@ static int cqspi_probe(struct platform_device *pdev)
 
        /* Obtain IRQ line. */
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               ret = -ENXIO;
-               goto probe_master_put;
-       }
+       if (irq < 0)
+               return -ENXIO;
 
        pm_runtime_enable(dev);
        ret = pm_runtime_resume_and_get(dev);
        if (ret < 0)
-               goto probe_master_put;
+               return ret;
 
        ret = clk_prepare_enable(cqspi->clk);
        if (ret) {
@@ -1716,8 +1713,6 @@ probe_reset_failed:
 probe_clk_failed:
        pm_runtime_put_sync(dev);
        pm_runtime_disable(dev);
-probe_master_put:
-       spi_master_put(master);
        return ret;
 }
 
index 31d778e9d255b9ceb8848188d3a26c6a8540384e..6a7f7df1e7764f297788c01aad46c0b8fcc0bdeb 100644 (file)
@@ -69,7 +69,7 @@
 #define CDNS_SPI_BAUD_DIV_SHIFT                3 /* Baud rate divisor shift in CR */
 #define CDNS_SPI_SS_SHIFT              10 /* Slave Select field shift in CR */
 #define CDNS_SPI_SS0                   0x1 /* Slave Select zero */
-#define CDNS_SPI_NOSS                  0x3C /* No Slave select */
+#define CDNS_SPI_NOSS                  0xF /* No Slave select */
 
 /*
  * SPI Interrupt Registers bit Masks
index 7a014eeec2d0d9a2072a4190042d14ffe14bf454..411b1307b7fd82679ecd17678bf5d7b64ba3e906 100644 (file)
@@ -613,6 +613,10 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
                                               rspi->dma_callbacked, HZ);
        if (ret > 0 && rspi->dma_callbacked) {
                ret = 0;
+               if (tx)
+                       dmaengine_synchronize(rspi->ctlr->dma_tx);
+               if (rx)
+                       dmaengine_synchronize(rspi->ctlr->dma_rx);
        } else {
                if (!ret) {
                        dev_err(&rspi->ctlr->dev, "DMA timeout\n");
index 33844526c7977df9ac9fc69537b538dc848b6bf7..02fdef7a16c872dab6fb3694550d7b3f5adab549 100644 (file)
@@ -2632,7 +2632,7 @@ static void hfa384x_usbctlx_reaper_task(struct work_struct *work)
  */
 static void hfa384x_usbctlx_completion_task(struct work_struct *work)
 {
-       struct hfa384x *hw = container_of(work, struct hfa384x, reaper_bh);
+       struct hfa384x *hw = container_of(work, struct hfa384x, completion_bh);
        struct hfa384x_usbctlx *ctlx, *temp;
        unsigned long flags;
 
index e68f1cc8ef98bd56098bdad6680576a4e6167b5b..6c8d8b051bfd5dcf0bd470207cd430de46344974 100644 (file)
@@ -448,6 +448,9 @@ fd_execute_write_same(struct se_cmd *cmd)
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
        }
 
+       if (!cmd->t_data_nents)
+               return TCM_INVALID_CDB_FIELD;
+
        if (cmd->t_data_nents > 1 ||
            cmd->t_data_sg[0].length != cmd->se_dev->dev_attrib.block_size) {
                pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u"
index 378c80313a0f27a4aef7ece5f6215bcb30c237e1..1ed9381751e6488964b4209a2951737375db6575 100644 (file)
@@ -494,6 +494,10 @@ iblock_execute_write_same(struct se_cmd *cmd)
                       " backends not supported\n");
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
        }
+
+       if (!cmd->t_data_nents)
+               return TCM_INVALID_CDB_FIELD;
+
        sg = &cmd->t_data_sg[0];
 
        if (cmd->t_data_nents > 1 ||
index ca1b2312d6e7b2b75cfa50f9763d143922e7064b..f6132836eb387ac419cccaa2762b7d35ca45a9e4 100644 (file)
@@ -312,6 +312,12 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char flags, struct sbc_ops *op
                pr_warn("WRITE SAME with ANCHOR not supported\n");
                return TCM_INVALID_CDB_FIELD;
        }
+
+       if (flags & 0x01) {
+               pr_warn("WRITE SAME with NDOB not supported\n");
+               return TCM_INVALID_CDB_FIELD;
+       }
+
        /*
         * Special case for WRITE_SAME w/ UNMAP=1 that ends up getting
         * translated into block discard requests within backend code.
index c60896cf71cb21f22b3e89d361b60cc72ccc3cc4..73b5e7760d102d9e1424dbcece28557c0281c6f0 100644 (file)
@@ -189,7 +189,7 @@ struct optee_smc_call_get_os_revision_result {
  * Have config return register usage:
  * a0  OPTEE_SMC_RETURN_OK
  * a1  Physical address of start of SHM
- * a2  Size of of SHM
+ * a2  Size of SHM
  * a3  Cache settings of memory, as defined by the
  *     OPTEE_SMC_SHM_* values above
  * a4-7        Preserved
index 385cb0aee61013b53c9dc55b9cb9b44695d7a179..a1c1fa1a9c28a7374337dc571a5a28db575f2317 100644 (file)
@@ -884,8 +884,8 @@ static int optee_smc_do_call_with_arg(struct tee_context *ctx,
 
                rpc_arg_offs = OPTEE_MSG_GET_ARG_SIZE(arg->num_params);
                rpc_arg = tee_shm_get_va(shm, offs + rpc_arg_offs);
-               if (IS_ERR(arg))
-                       return PTR_ERR(arg);
+               if (IS_ERR(rpc_arg))
+                       return PTR_ERR(rpc_arg);
        }
 
        if  (rpc_arg && tee_shm_is_dynamic(shm)) {
index af0f7c603fa46045fd1b4a9ba62ed38a82f1419f..98da206cd7615ba8a9269e2e31420ce9a1542b7d 100644 (file)
@@ -1073,7 +1073,7 @@ EXPORT_SYMBOL_GPL(tee_device_unregister);
 /**
  * tee_get_drvdata() - Return driver_data pointer
  * @teedev:    Device containing the driver_data pointer
- * @returns the driver_data pointer supplied to tee_register().
+ * @returns the driver_data pointer supplied to tee_device_alloc().
  */
 void *tee_get_drvdata(struct tee_device *teedev)
 {
index b8151d95a8068b83fb6d1ce8788dd7d3f8ee671d..dc19e7c80751af4159a3f263f5fba806614d189a 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/pm_qos.h>
 #include <linux/slab.h>
 #include <linux/thermal.h>
+#include <linux/units.h>
 
 #include <trace/events/thermal.h>
 
@@ -101,6 +102,7 @@ static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_cdev,
 static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_cdev,
                             u32 freq)
 {
+       unsigned long power_mw;
        int i;
 
        for (i = cpufreq_cdev->max_level - 1; i >= 0; i--) {
@@ -108,16 +110,23 @@ static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_cdev,
                        break;
        }
 
-       return cpufreq_cdev->em->table[i + 1].power;
+       power_mw = cpufreq_cdev->em->table[i + 1].power;
+       power_mw /= MICROWATT_PER_MILLIWATT;
+
+       return power_mw;
 }
 
 static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev,
                             u32 power)
 {
+       unsigned long em_power_mw;
        int i;
 
        for (i = cpufreq_cdev->max_level; i > 0; i--) {
-               if (power >= cpufreq_cdev->em->table[i].power)
+               /* Convert EM power to milli-Watts to make safe comparison */
+               em_power_mw = cpufreq_cdev->em->table[i].power;
+               em_power_mw /= MICROWATT_PER_MILLIWATT;
+               if (power >= em_power_mw)
                        break;
        }
 
index 8c76f9655e5774446fbef0d0e16be75b63f1a015..8d1260f65061e9c4f5a48e88b8e3e98fcb2199f5 100644 (file)
@@ -200,7 +200,11 @@ static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cd
                res = dfc->power_ops->get_real_power(df, power, freq, voltage);
                if (!res) {
                        state = dfc->capped_state;
+
+                       /* Convert EM power into milli-Watts first */
                        dfc->res_util = dfc->em_pd->table[state].power;
+                       dfc->res_util /= MICROWATT_PER_MILLIWATT;
+
                        dfc->res_util *= SCALE_ERROR_MITIGATION;
 
                        if (*power > 1)
@@ -218,8 +222,10 @@ static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cd
 
                _normalize_load(&status);
 
-               /* Scale power for utilization */
+               /* Convert EM power into milli-Watts first */
                *power = dfc->em_pd->table[perf_idx].power;
+               *power /= MICROWATT_PER_MILLIWATT;
+               /* Scale power for utilization */
                *power *= status.busy_time;
                *power >>= 10;
        }
@@ -244,6 +250,7 @@ static int devfreq_cooling_state2power(struct thermal_cooling_device *cdev,
 
        perf_idx = dfc->max_state - state;
        *power = dfc->em_pd->table[perf_idx].power;
+       *power /= MICROWATT_PER_MILLIWATT;
 
        return 0;
 }
@@ -254,7 +261,7 @@ static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev,
        struct devfreq_cooling_device *dfc = cdev->devdata;
        struct devfreq *df = dfc->devfreq;
        struct devfreq_dev_status status;
-       unsigned long freq;
+       unsigned long freq, em_power_mw;
        s32 est_power;
        int i;
 
@@ -279,9 +286,13 @@ static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev,
         * Find the first cooling state that is within the power
         * budget. The EM power table is sorted ascending.
         */
-       for (i = dfc->max_state; i > 0; i--)
-               if (est_power >= dfc->em_pd->table[i].power)
+       for (i = dfc->max_state; i > 0; i--) {
+               /* Convert EM power to milli-Watts to make safe comparison */
+               em_power_mw = dfc->em_pd->table[i].power;
+               em_power_mw /= MICROWATT_PER_MILLIWATT;
+               if (est_power >= em_power_mw)
                        break;
+       }
 
        *state = dfc->max_state - i;
        dfc->capped_state = *state;
index 74bfabe5b45381e62214c353d7461ed5a08f2179..752dab3356d72b6e9c7f3d25ad91eae31ae8fc83 100644 (file)
@@ -111,21 +111,11 @@ static void pty_unthrottle(struct tty_struct *tty)
 static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
 {
        struct tty_struct *to = tty->link;
-       unsigned long flags;
 
-       if (tty->flow.stopped)
+       if (tty->flow.stopped || !c)
                return 0;
 
-       if (c > 0) {
-               spin_lock_irqsave(&to->port->lock, flags);
-               /* Stuff the data into the input queue of the other end */
-               c = tty_insert_flip_string(to->port, buf, c);
-               spin_unlock_irqrestore(&to->port->lock, flags);
-               /* And shovel */
-               if (c)
-                       tty_flip_buffer_push(to->port);
-       }
-       return c;
+       return tty_insert_flip_string_and_push_buffer(to->port, buf, c);
 }
 
 /**
index cfbd2de0ca6e4bcde9c72d4e742330880cb8ee5c..3f56dbc9432b3317bcc2cc6788d8d0061cf8ac43 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/sysrq.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/tty.h>
 #include <linux/ratelimit.h>
 #include <linux/tty_flip.h>
@@ -559,6 +560,9 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
 
                up->port.dev = dev;
 
+               if (uart_console_enabled(&up->port))
+                       pm_runtime_get_sync(up->port.dev);
+
                serial8250_apply_quirks(up);
                uart_add_one_port(drv, &up->port);
        }
index 7133fceed35e35100398f0994038c36cf4ce4e30..a8dba4a0a8fb70b823abd89cbeed677f84079429 100644 (file)
@@ -106,10 +106,10 @@ int serial8250_tx_dma(struct uart_8250_port *p)
                                   UART_XMIT_SIZE, DMA_TO_DEVICE);
 
        dma_async_issue_pending(dma->txchan);
-       if (dma->tx_err) {
+       serial8250_clear_THRI(p);
+       if (dma->tx_err)
                dma->tx_err = 0;
-               serial8250_clear_THRI(p);
-       }
+
        return 0;
 err:
        dma->tx_err = 1;
index f57bbd32ef11aaaa24ca946cf0233fce5b933f75..bb6aca07ab563bb461ce9dfa41df4f7e06640a28 100644 (file)
@@ -47,7 +47,7 @@
 #define RZN1_UART_xDMACR_DMA_EN                BIT(0)
 #define RZN1_UART_xDMACR_1_WORD_BURST  (0 << 1)
 #define RZN1_UART_xDMACR_4_WORD_BURST  (1 << 1)
-#define RZN1_UART_xDMACR_8_WORD_BURST  (3 << 1)
+#define RZN1_UART_xDMACR_8_WORD_BURST  (2 << 1)
 #define RZN1_UART_xDMACR_BLK_SZ(x)     ((x) << 3)
 
 /* Quirks */
@@ -773,18 +773,18 @@ static const struct of_device_id dw8250_of_match[] = {
 MODULE_DEVICE_TABLE(of, dw8250_of_match);
 
 static const struct acpi_device_id dw8250_acpi_match[] = {
-       { "INT33C4", 0 },
-       { "INT33C5", 0 },
-       { "INT3434", 0 },
-       { "INT3435", 0 },
-       { "80860F0A", 0 },
-       { "8086228A", 0 },
-       { "APMC0D08", 0},
-       { "AMD0020", 0 },
-       { "AMDI0020", 0 },
-       { "AMDI0022", 0 },
-       { "BRCM2032", 0 },
-       { "HISI0031", 0 },
+       { "80860F0A", (kernel_ulong_t)&dw8250_dw_apb },
+       { "8086228A", (kernel_ulong_t)&dw8250_dw_apb },
+       { "AMD0020", (kernel_ulong_t)&dw8250_dw_apb },
+       { "AMDI0020", (kernel_ulong_t)&dw8250_dw_apb },
+       { "AMDI0022", (kernel_ulong_t)&dw8250_dw_apb },
+       { "APMC0D08", (kernel_ulong_t)&dw8250_dw_apb},
+       { "BRCM2032", (kernel_ulong_t)&dw8250_dw_apb },
+       { "HISI0031", (kernel_ulong_t)&dw8250_dw_apb },
+       { "INT33C4", (kernel_ulong_t)&dw8250_dw_apb },
+       { "INT33C5", (kernel_ulong_t)&dw8250_dw_apb },
+       { "INT3434", (kernel_ulong_t)&dw8250_dw_apb },
+       { "INT3435", (kernel_ulong_t)&dw8250_dw_apb },
        { },
 };
 MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
index 8f32fe9e149e913081d49758f168feb79c87323f..3c36a06a20b048a941b6cfa00ba2b3b01d7b3856 100644 (file)
@@ -1949,7 +1949,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
        if ((status & UART_LSR_THRE) && (up->ier & UART_IER_THRI)) {
                if (!up->dma || up->dma->tx_err)
                        serial8250_tx_chars(up);
-               else
+               else if (!up->dma->tx_running)
                        __stop_tx(up);
        }
 
@@ -2975,8 +2975,10 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
        case UPIO_MEM32BE:
        case UPIO_MEM16:
        case UPIO_MEM:
-               if (!port->mapbase)
+               if (!port->mapbase) {
+                       ret = -EINVAL;
                        break;
+               }
 
                if (!request_mem_region(port->mapbase, size, "serial")) {
                        ret = -EBUSY;
index 97ef41cb2721d24248a75dec91696ddf915d5168..16a21422ddce3fd06ba577fc51794d421211f609 100644 (file)
@@ -1367,6 +1367,15 @@ static void pl011_stop_rx(struct uart_port *port)
        pl011_dma_rx_stop(uap);
 }
 
+static void pl011_throttle_rx(struct uart_port *port)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       pl011_stop_rx(port);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
 static void pl011_enable_ms(struct uart_port *port)
 {
        struct uart_amba_port *uap =
@@ -1788,9 +1797,10 @@ static int pl011_allocate_irq(struct uart_amba_port *uap)
  */
 static void pl011_enable_interrupts(struct uart_amba_port *uap)
 {
+       unsigned long flags;
        unsigned int i;
 
-       spin_lock_irq(&uap->port.lock);
+       spin_lock_irqsave(&uap->port.lock, flags);
 
        /* Clear out any spuriously appearing RX interrupts */
        pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR);
@@ -1812,7 +1822,14 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap)
        if (!pl011_dma_rx_running(uap))
                uap->im |= UART011_RXIM;
        pl011_write(uap->im, uap, REG_IMSC);
-       spin_unlock_irq(&uap->port.lock);
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+}
+
+static void pl011_unthrottle_rx(struct uart_port *port)
+{
+       struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port);
+
+       pl011_enable_interrupts(uap);
 }
 
 static int pl011_startup(struct uart_port *port)
@@ -2225,6 +2242,8 @@ static const struct uart_ops amba_pl011_pops = {
        .stop_tx        = pl011_stop_tx,
        .start_tx       = pl011_start_tx,
        .stop_rx        = pl011_stop_rx,
+       .throttle       = pl011_throttle_rx,
+       .unthrottle     = pl011_unthrottle_rx,
        .enable_ms      = pl011_enable_ms,
        .break_ctl      = pl011_break_ctl,
        .startup        = pl011_startup,
index 0429c2a5429024bc964703de1592a557460bd202..93489fe334d0fa39fc7f846302ce26e0793faaa0 100644 (file)
@@ -470,14 +470,14 @@ static void mvebu_uart_shutdown(struct uart_port *port)
        }
 }
 
-static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
+static unsigned int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
 {
        unsigned int d_divisor, m_divisor;
        unsigned long flags;
        u32 brdv, osamp;
 
        if (!port->uartclk)
-               return -EOPNOTSUPP;
+               return 0;
 
        /*
         * The baudrate is derived from the UART clock thanks to divisors:
@@ -548,7 +548,7 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
                        (m_divisor << 16) | (m_divisor << 24);
        writel(osamp, port->membase + UART_OSAMP);
 
-       return 0;
+       return DIV_ROUND_CLOSEST(port->uartclk, d_divisor * m_divisor);
 }
 
 static void mvebu_uart_set_termios(struct uart_port *port,
@@ -587,15 +587,11 @@ static void mvebu_uart_set_termios(struct uart_port *port,
        max_baud = port->uartclk / 80;
 
        baud = uart_get_baud_rate(port, termios, old, min_baud, max_baud);
-       if (mvebu_uart_baud_rate_set(port, baud)) {
-               /* No clock available, baudrate cannot be changed */
-               if (old)
-                       baud = uart_get_baud_rate(port, old, NULL,
-                                                 min_baud, max_baud);
-       } else {
-               tty_termios_encode_baud_rate(termios, baud, baud);
-               uart_update_timeout(port, termios->c_cflag, baud);
-       }
+       baud = mvebu_uart_baud_rate_set(port, baud);
+
+       /* In case baudrate cannot be changed, report previous old value */
+       if (baud == 0 && old)
+               baud = tty_termios_baud_rate(old);
 
        /* Only the following flag changes are supported */
        if (old) {
@@ -606,6 +602,11 @@ static void mvebu_uart_set_termios(struct uart_port *port,
                termios->c_cflag |= CS8;
        }
 
+       if (baud != 0) {
+               tty_termios_encode_baud_rate(termios, baud, baud);
+               uart_update_timeout(port, termios->c_cflag, baud);
+       }
+
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
index d5ca904def345df46e3483b296fcb52d67583708..1afe47b62ad567ac51d762986a7aeb7a8e3c7352 100644 (file)
@@ -377,8 +377,7 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
        /* Enable tx dma mode */
        ucon = rd_regl(port, S3C2410_UCON);
        ucon &= ~(S3C64XX_UCON_TXBURST_MASK | S3C64XX_UCON_TXMODE_MASK);
-       ucon |= (dma_get_cache_alignment() >= 16) ?
-               S3C64XX_UCON_TXBURST_16 : S3C64XX_UCON_TXBURST_1;
+       ucon |= S3C64XX_UCON_TXBURST_1;
        ucon |= S3C64XX_UCON_TXMODE_DMA;
        wr_regl(port,  S3C2410_UCON, ucon);
 
@@ -674,7 +673,7 @@ static void enable_rx_dma(struct s3c24xx_uart_port *ourport)
                        S3C64XX_UCON_DMASUS_EN |
                        S3C64XX_UCON_TIMEOUT_EN |
                        S3C64XX_UCON_RXMODE_MASK);
-       ucon |= S3C64XX_UCON_RXBURST_16 |
+       ucon |= S3C64XX_UCON_RXBURST_1 |
                        0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
                        S3C64XX_UCON_EMPTYINT_EN |
                        S3C64XX_UCON_TIMEOUT_EN |
index 338ebadfd44b8cff7fc00ef7bef0a73fbfef188c..3dc926d6c00ab804940c51dfaf2242dff0010222 100644 (file)
@@ -1941,11 +1941,6 @@ static int uart_proc_show(struct seq_file *m, void *v)
 }
 #endif
 
-static inline bool uart_console_enabled(struct uart_port *port)
-{
-       return uart_console(port) && (port->cons->flags & CON_ENABLED);
-}
-
 static void uart_port_spin_lock_init(struct uart_port *port)
 {
        spin_lock_init(&port->lock);
index b7b44f4050d49acace4a4ac48fa7a1b01ec8d561..0973b03eeeaa4f6d2e42ccba5c36c7a2be04eeef 100644 (file)
@@ -72,6 +72,8 @@ static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE,
        *cr3 |= USART_CR3_DEM;
        over8 = *cr1 & USART_CR1_OVER8;
 
+       *cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK);
+
        if (over8)
                rs485_deat_dedt = delay_ADE * baud * 8;
        else
index b710c5ef89ab2f5939869dacaa73f383628d60e1..f310a8274df1539a9a71c2220fbd7fe2b9067f17 100644 (file)
@@ -111,4 +111,7 @@ static inline void tty_audit_tiocsti(struct tty_struct *tty, char ch)
 
 ssize_t redirected_tty_write(struct kiocb *, struct iov_iter *);
 
+int tty_insert_flip_string_and_push_buffer(struct tty_port *port,
+               const unsigned char *chars, size_t cnt);
+
 #endif
index bfa431a8e6902a68148a0f56a0c4e6f7d9e8e088..595d8b49c745dc8f2ced5672fc849a95476e8f00 100644 (file)
@@ -532,6 +532,15 @@ static void flush_to_ldisc(struct work_struct *work)
 
 }
 
+static inline void tty_flip_buffer_commit(struct tty_buffer *tail)
+{
+       /*
+        * Paired w/ acquire in flush_to_ldisc(); ensures flush_to_ldisc() sees
+        * buffer data.
+        */
+       smp_store_release(&tail->commit, tail->used);
+}
+
 /**
  * tty_flip_buffer_push                -       push terminal buffers
  * @port: tty port to push
@@ -546,15 +555,42 @@ void tty_flip_buffer_push(struct tty_port *port)
 {
        struct tty_bufhead *buf = &port->buf;
 
-       /*
-        * Paired w/ acquire in flush_to_ldisc(); ensures flush_to_ldisc() sees
-        * buffer data.
-        */
-       smp_store_release(&buf->tail->commit, buf->tail->used);
+       tty_flip_buffer_commit(buf->tail);
        queue_work(system_unbound_wq, &buf->work);
 }
 EXPORT_SYMBOL(tty_flip_buffer_push);
 
+/**
+ * tty_insert_flip_string_and_push_buffer - add characters to the tty buffer and
+ *     push
+ * @port: tty port
+ * @chars: characters
+ * @size: size
+ *
+ * The function combines tty_insert_flip_string() and tty_flip_buffer_push()
+ * with the exception of properly holding the @port->lock.
+ *
+ * To be used only internally (by pty currently).
+ *
+ * Returns: the number added.
+ */
+int tty_insert_flip_string_and_push_buffer(struct tty_port *port,
+               const unsigned char *chars, size_t size)
+{
+       struct tty_bufhead *buf = &port->buf;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       size = tty_insert_flip_string(port, chars, size);
+       if (size)
+               tty_flip_buffer_commit(buf->tail);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       queue_work(system_unbound_wq, &buf->work);
+
+       return size;
+}
+
 /**
  * tty_buffer_init             -       prepare a tty buffer structure
  * @port: tty port to initialise
index f8c87c4d739955a19a82db355322e395f9268e37..dfc1f4b445f3bfaca012ae801c087e553e47da7c 100644 (file)
@@ -855,7 +855,7 @@ static void delete_char(struct vc_data *vc, unsigned int nr)
        unsigned short *p = (unsigned short *) vc->vc_pos;
 
        vc_uniscr_delete(vc, nr);
-       scr_memcpyw(p, p + nr, (vc->vc_cols - vc->state.x - nr) * 2);
+       scr_memmovew(p, p + nr, (vc->vc_cols - vc->state.x - nr) * 2);
        scr_memsetw(p + vc->vc_cols - vc->state.x - nr, vc->vc_video_erase_char,
                        nr * 2);
        vc->vc_need_wrap = 0;
index ce86d1b790c058ba6ac579d14e69258bf4b51a16..c7b337480e3e7d0317fd4a2735c8af6ed593584b 100644 (file)
@@ -5738,7 +5738,7 @@ int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable)
        }
 
        hba->dev_info.wb_enabled = enable;
-       dev_info(hba->dev, "%s Write Booster %s\n",
+       dev_dbg(hba->dev, "%s Write Booster %s\n",
                        __func__, enable ? "enabled" : "disabled");
 
        return ret;
@@ -7253,7 +7253,7 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
        hba->silence_err_logs = false;
 
        /* scale up clocks to max frequency before full reinitialization */
-       ufshcd_set_clk_freq(hba, true);
+       ufshcd_scale_clks(hba, true);
 
        err = ufshcd_hba_enable(hba);
 
index fea7aca35dc88a8fd91909297b658bf7e9ae5fa8..173cf3579c55d8098f89f1c5a1615cdc5eb98611 100644 (file)
@@ -195,8 +195,7 @@ static int dwc3_ti_probe(struct platform_device *pdev)
 
        if (i == ARRAY_SIZE(dwc3_ti_rate_table)) {
                dev_err(dev, "unsupported usb2_refclk rate: %lu KHz\n", rate);
-               ret = -EINVAL;
-               goto err_clk_disable;
+               return -EINVAL;
        }
 
        data->rate_code = i;
@@ -204,7 +203,7 @@ static int dwc3_ti_probe(struct platform_device *pdev)
        /* Read the syscon property and set the rate code */
        ret = phy_syscon_pll_refclk(data);
        if (ret)
-               goto err_clk_disable;
+               return ret;
 
        /* VBUS divider select */
        data->vbus_divider = device_property_read_bool(dev, "ti,vbus-divider");
@@ -245,8 +244,6 @@ err_pm_disable:
        clk_disable_unprepare(data->usb2_refclk);
        pm_runtime_disable(dev);
        pm_runtime_set_suspended(dev);
-err_clk_disable:
-       clk_put(data->usb2_refclk);
        return ret;
 }
 
@@ -276,7 +273,6 @@ static int dwc3_ti_remove(struct platform_device *pdev)
        pm_runtime_disable(dev);
        pm_runtime_set_suspended(dev);
 
-       clk_put(data->usb2_refclk);
        platform_set_drvdata(pdev, NULL);
        return 0;
 }
index 8716bece107208289dc479bf4ee0da226688c115..0d89dfa6eef57064474566026009f8df70ac7c64 100644 (file)
@@ -4249,7 +4249,6 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt)
        }
 
        evt->count = 0;
-       evt->flags &= ~DWC3_EVENT_PENDING;
        ret = IRQ_HANDLED;
 
        /* Unmask interrupt */
@@ -4261,6 +4260,9 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt)
                dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
        }
 
+       /* Keep the clearing of DWC3_EVENT_PENDING at the end */
+       evt->flags &= ~DWC3_EVENT_PENDING;
+
        return ret;
 }
 
index e5a6b6e36b3dd85cc72565cc2ad6e4076f719576..4303a3283ba0a3a3b9927391553546fe2fbb3ccf 100644 (file)
@@ -2371,6 +2371,7 @@ static ssize_t f_uvc_opts_string_##cname##_store(struct config_item *item,\
                                          const char *page, size_t len) \
 {                                                                      \
        struct f_uvc_opts *opts = to_f_uvc_opts(item);                  \
+       int size = min(sizeof(opts->aname), len + 1);                   \
        int ret = 0;                                                    \
                                                                        \
        mutex_lock(&opts->lock);                                        \
@@ -2379,8 +2380,9 @@ static ssize_t f_uvc_opts_string_##cname##_store(struct config_item *item,\
                goto end;                                               \
        }                                                               \
                                                                        \
-       ret = snprintf(opts->aname, min(sizeof(opts->aname), len),      \
-                       "%s", page);                                    \
+       ret = strscpy(opts->aname, page, size);                         \
+       if (ret == -E2BIG)                                              \
+               ret = size - 1;                                         \
                                                                        \
 end:                                                                   \
        mutex_unlock(&opts->lock);                                      \
index 385be30baad360ae911d678053575be9dce33d85..896c0d107f725d8ecd5d2d525b2b643d1c192a44 100644 (file)
@@ -76,14 +76,9 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res) {
-               dev_err(&pdev->dev,
-                       "Found HC with no IRQ. Check %s setup!\n",
-                       dev_name(&pdev->dev));
-               return -ENODEV;
-       }
-       irq = res->start;
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
 
        hcd = __usb_create_hcd(&fsl_ehci_hc_driver, pdev->dev.parent,
                               &pdev->dev, dev_name(&pdev->dev), NULL);
index 44a7e58a26e3ddc0edbf1a345254c1c4472a2dd5..e5df175228928ccf1f4fa3d1340eb9ef6df2d891 100644 (file)
@@ -112,6 +112,9 @@ static struct platform_device *fsl_usb2_device_register(
                        goto error;
        }
 
+       pdev->dev.of_node = ofdev->dev.of_node;
+       pdev->dev.of_node_reused = true;
+
        retval = platform_device_add(pdev);
        if (retval)
                goto error;
index b440d338a895da8fd1136274d7e9c85ae25864ea..d5a3986dfee755bc7418e2c998403dad96977e41 100644 (file)
@@ -1023,6 +1023,9 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_DISPLAY_PID) },
        { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_LITE_PID) },
        { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_ANALOG_PID) },
+       /* Belimo Automation devices */
+       { USB_DEVICE(FTDI_VID, BELIMO_ZTH_PID) },
+       { USB_DEVICE(FTDI_VID, BELIMO_ZIP_PID) },
        /* ICP DAS I-756xU devices */
        { USB_DEVICE(ICPDAS_VID, ICPDAS_I7560U_PID) },
        { USB_DEVICE(ICPDAS_VID, ICPDAS_I7561U_PID) },
index d1a9564697a4becf6f32b52461eef0fe36c1bbc0..4e92c165c86bf0aa199e00bee12e7f8a226ae865 100644 (file)
 #define CHETCO_SEASMART_LITE_PID       0xA5AE /* SeaSmart Lite USB Adapter */
 #define CHETCO_SEASMART_ANALOG_PID     0xA5AF /* SeaSmart Analog Adapter */
 
+/*
+ * Belimo Automation
+ */
+#define BELIMO_ZTH_PID                 0x8050
+#define BELIMO_ZIP_PID                 0xC811
+
 /*
  * Unjo AB
  */
index ee0e520707dd7eea2bec3edd9e03cd7258472fe4..c4724750c81a5a3b14f1c089fcb7d2bef18fb51e 100644 (file)
@@ -1718,6 +1718,7 @@ void typec_set_pwr_opmode(struct typec_port *port,
                        partner->usb_pd = 1;
                        sysfs_notify(&partner_dev->kobj, NULL,
                                     "supports_usb_power_delivery");
+                       kobject_uevent(&partner_dev->kobj, KOBJ_CHANGE);
                }
                put_device(partner_dev);
        }
index 61e71c1154be673e9c40989958ff0c6a86600161..e60b06f2ac22393ae4f3deaf02e680d506368eab 100644 (file)
@@ -549,6 +549,16 @@ static struct vfio_group *vfio_group_find_or_alloc(struct device *dev)
        if (!iommu_group)
                return ERR_PTR(-EINVAL);
 
+       /*
+        * VFIO always sets IOMMU_CACHE because we offer no way for userspace to
+        * restore cache coherency. It has to be checked here because it is only
+        * valid for cases where we are using iommu groups.
+        */
+       if (!iommu_capable(dev->bus, IOMMU_CAP_CACHE_COHERENCY)) {
+               iommu_group_put(iommu_group);
+               return ERR_PTR(-EINVAL);
+       }
+
        group = vfio_group_get_from_iommu(iommu_group);
        if (!group)
                group = vfio_create_group(iommu_group, VFIO_IOMMU);
@@ -601,13 +611,6 @@ static int __vfio_register_dev(struct vfio_device *device,
 
 int vfio_register_group_dev(struct vfio_device *device)
 {
-       /*
-        * VFIO always sets IOMMU_CACHE because we offer no way for userspace to
-        * restore cache coherency.
-        */
-       if (!iommu_capable(device->dev->bus, IOMMU_CAP_CACHE_COHERENCY))
-               return -EINVAL;
-
        return __vfio_register_dev(device,
                vfio_group_find_or_alloc(device->dev));
 }
index c4e91715ef0063570381b1cac8366f47c9e160f0..1a9aa12cf8860849b32c617da82a43946b5fa2b1 100644 (file)
@@ -2469,6 +2469,11 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
        if (charcount != 256 && charcount != 512)
                return -EINVAL;
 
+       /* font bigger than screen resolution ? */
+       if (w > FBCON_SWAP(info->var.rotate, info->var.xres, info->var.yres) ||
+           h > FBCON_SWAP(info->var.rotate, info->var.yres, info->var.xres))
+               return -EINVAL;
+
        /* Make sure drawing engine can handle the font */
        if (!(info->pixmap.blit_x & (1 << (font->width - 1))) ||
            !(info->pixmap.blit_y & (1 << (font->height - 1))))
@@ -2731,6 +2736,34 @@ void fbcon_update_vcs(struct fb_info *info, bool all)
 }
 EXPORT_SYMBOL(fbcon_update_vcs);
 
+/* let fbcon check if it supports a new screen resolution */
+int fbcon_modechange_possible(struct fb_info *info, struct fb_var_screeninfo *var)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct vc_data *vc;
+       unsigned int i;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       if (!ops)
+               return 0;
+
+       /* prevent setting a screen size which is smaller than font size */
+       for (i = first_fb_vc; i <= last_fb_vc; i++) {
+               vc = vc_cons[i].d;
+               if (!vc || vc->vc_mode != KD_TEXT ||
+                          fbcon_info_from_console(i) != info)
+                       continue;
+
+               if (vc->vc_font.width  > FBCON_SWAP(var->rotate, var->xres, var->yres) ||
+                   vc->vc_font.height > FBCON_SWAP(var->rotate, var->yres, var->xres))
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(fbcon_modechange_possible);
+
 int fbcon_mode_deleted(struct fb_info *info,
                       struct fb_videomode *mode)
 {
index 8afc4538558cd74d9f77bbc0c1a5a1e5922f76bc..7ee6eb2fa715179b4548316ac6c680e795094cb0 100644 (file)
@@ -511,7 +511,7 @@ static int fb_show_logo_line(struct fb_info *info, int rotate,
 
                while (n && (n * (logo->width + 8) - 8 > xres))
                        --n;
-               image.dx = (xres - n * (logo->width + 8) - 8) / 2;
+               image.dx = (xres - (n * (logo->width + 8) - 8)) / 2;
                image.dy = y ?: (yres - logo->height) / 2;
        } else {
                image.dx = 0;
@@ -1017,6 +1017,16 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
        if (ret)
                return ret;
 
+       /* verify that virtual resolution >= physical resolution */
+       if (var->xres_virtual < var->xres ||
+           var->yres_virtual < var->yres) {
+               pr_warn("WARNING: fbcon: Driver '%s' missed to adjust virtual screen size (%ux%u vs. %ux%u)\n",
+                       info->fix.id,
+                       var->xres_virtual, var->yres_virtual,
+                       var->xres, var->yres);
+               return -EINVAL;
+       }
+
        if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
                return 0;
 
@@ -1107,7 +1117,9 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
                        return -EFAULT;
                console_lock();
                lock_fb_info(info);
-               ret = fb_set_var(info, &var);
+               ret = fbcon_modechange_possible(info, &var);
+               if (!ret)
+                       ret = fb_set_var(info, &var);
                if (!ret)
                        fbcon_update_vcs(info, var.activate & FB_ACTIVATE_ALL);
                unlock_fb_info(info);
index 90ce16b6e05f91e9f29173d9def568ab4075f863..f422f9c58ba790c94957f4c38da4f8599fbc1e44 100644 (file)
@@ -632,16 +632,19 @@ static int __init sev_guest_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct snp_guest_dev *snp_dev;
        struct miscdevice *misc;
+       void __iomem *mapping;
        int ret;
 
        if (!dev->platform_data)
                return -ENODEV;
 
        data = (struct sev_guest_platform_data *)dev->platform_data;
-       layout = (__force void *)ioremap_encrypted(data->secrets_gpa, PAGE_SIZE);
-       if (!layout)
+       mapping = ioremap_encrypted(data->secrets_gpa, PAGE_SIZE);
+       if (!mapping)
                return -ENODEV;
 
+       layout = (__force void *)mapping;
+
        ret = -ENOMEM;
        snp_dev = devm_kzalloc(&pdev->dev, sizeof(struct snp_guest_dev), GFP_KERNEL);
        if (!snp_dev)
@@ -706,7 +709,7 @@ e_free_response:
 e_free_request:
        free_shared_pages(snp_dev->request, sizeof(struct snp_guest_msg));
 e_unmap:
-       iounmap(layout);
+       iounmap(mapping);
        return ret;
 }
 
index 4b56c39f766d4da68570d08d963f6ef40c8d9c37..84b143eef395b1585f3a8c0fdcb301ce9fbc52ec 100644 (file)
@@ -396,13 +396,15 @@ static void __unmap_grant_pages_done(int result,
        unsigned int offset = data->unmap_ops - map->unmap_ops;
 
        for (i = 0; i < data->count; i++) {
-               WARN_ON(map->unmap_ops[offset+i].status);
+               WARN_ON(map->unmap_ops[offset + i].status != GNTST_okay &&
+                       map->unmap_ops[offset + i].handle != INVALID_GRANT_HANDLE);
                pr_debug("unmap handle=%d st=%d\n",
                        map->unmap_ops[offset+i].handle,
                        map->unmap_ops[offset+i].status);
                map->unmap_ops[offset+i].handle = INVALID_GRANT_HANDLE;
                if (use_ptemod) {
-                       WARN_ON(map->kunmap_ops[offset+i].status);
+                       WARN_ON(map->kunmap_ops[offset + i].status != GNTST_okay &&
+                               map->kunmap_ops[offset + i].handle != INVALID_GRANT_HANDLE);
                        pr_debug("kunmap handle=%u st=%d\n",
                                 map->kunmap_ops[offset+i].handle,
                                 map->kunmap_ops[offset+i].status);
index 42118a4f338331433af660cd9464c43e1cc8b03b..d1cfb235c4b9b7be2226fd8129ea79326c933ef9 100644 (file)
@@ -375,7 +375,7 @@ static int afs_begin_cache_operation(struct netfs_io_request *rreq)
 }
 
 static int afs_check_write_begin(struct file *file, loff_t pos, unsigned len,
-                                struct folio *folio, void **_fsdata)
+                                struct folio **foliop, void **_fsdata)
 {
        struct afs_vnode *vnode = AFS_FS_I(file_inode(file));
 
index 415bf1823fb3a39c88799603b807a464ed48c272..9c21e214d29e410883fc82f2297e80e021144321 100644 (file)
@@ -675,9 +675,8 @@ struct btrfs_fs_info {
        rwlock_t global_root_lock;
        struct rb_root global_root_tree;
 
-       /* The xarray that holds all the FS roots */
-       spinlock_t fs_roots_lock;
-       struct xarray fs_roots;
+       spinlock_t fs_roots_radix_lock;
+       struct radix_tree_root fs_roots_radix;
 
        /* block group cache stuff */
        rwlock_t block_group_cache_lock;
@@ -995,10 +994,10 @@ struct btrfs_fs_info {
 
        struct btrfs_delayed_root *delayed_root;
 
-       /* Extent buffer xarray */
+       /* Extent buffer radix tree */
        spinlock_t buffer_lock;
        /* Entries are eb->start / sectorsize */
-       struct xarray extent_buffers;
+       struct radix_tree_root buffer_radix;
 
        /* next backup root to be overwritten */
        int backup_root_index;
@@ -1119,8 +1118,7 @@ enum {
         */
        BTRFS_ROOT_SHAREABLE,
        BTRFS_ROOT_TRACK_DIRTY,
-       /* The root is tracked in fs_info::fs_roots */
-       BTRFS_ROOT_REGISTERED,
+       BTRFS_ROOT_IN_RADIX,
        BTRFS_ROOT_ORPHAN_ITEM_INSERTED,
        BTRFS_ROOT_DEFRAG_RUNNING,
        BTRFS_ROOT_FORCE_COW,
@@ -1224,10 +1222,10 @@ struct btrfs_root {
        struct rb_root inode_tree;
 
        /*
-        * Xarray that keeps track of delayed nodes of every inode, protected
-        * by inode_lock
+        * radix tree that keeps track of delayed nodes of every inode,
+        * protected by inode_lock
         */
-       struct xarray delayed_nodes;
+       struct radix_tree_root delayed_nodes_tree;
        /*
         * right now this just gets used so that a root has its own devid
         * for stat.  It may be used for more later
index 66779ab3ed4a3f457bdd5617bce91b43c487af67..748bf6b0d8600fcd380e38b91a973c0255c17c76 100644 (file)
@@ -78,7 +78,7 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node(
        }
 
        spin_lock(&root->inode_lock);
-       node = xa_load(&root->delayed_nodes, ino);
+       node = radix_tree_lookup(&root->delayed_nodes_tree, ino);
 
        if (node) {
                if (btrfs_inode->delayed_node) {
@@ -90,9 +90,9 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node(
 
                /*
                 * It's possible that we're racing into the middle of removing
-                * this node from the xarray.  In this case, the refcount
+                * this node from the radix tree.  In this case, the refcount
                 * was zero and it should never go back to one.  Just return
-                * NULL like it was never in the xarray at all; our release
+                * NULL like it was never in the radix at all; our release
                 * function is in the process of removing it.
                 *
                 * Some implementations of refcount_inc refuse to bump the
@@ -100,7 +100,7 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node(
                 * here, refcount_inc() may decide to just WARN_ONCE() instead
                 * of actually bumping the refcount.
                 *
-                * If this node is properly in the xarray, we want to bump the
+                * If this node is properly in the radix, we want to bump the
                 * refcount twice, once for the inode and once for this get
                 * operation.
                 */
@@ -128,30 +128,36 @@ static struct btrfs_delayed_node *btrfs_get_or_create_delayed_node(
        u64 ino = btrfs_ino(btrfs_inode);
        int ret;
 
-       do {
-               node = btrfs_get_delayed_node(btrfs_inode);
-               if (node)
-                       return node;
+again:
+       node = btrfs_get_delayed_node(btrfs_inode);
+       if (node)
+               return node;
 
-               node = kmem_cache_zalloc(delayed_node_cache, GFP_NOFS);
-               if (!node)
-                       return ERR_PTR(-ENOMEM);
-               btrfs_init_delayed_node(node, root, ino);
+       node = kmem_cache_zalloc(delayed_node_cache, GFP_NOFS);
+       if (!node)
+               return ERR_PTR(-ENOMEM);
+       btrfs_init_delayed_node(node, root, ino);
 
-               /* Cached in the inode and can be accessed */
-               refcount_set(&node->refs, 2);
+       /* cached in the btrfs inode and can be accessed */
+       refcount_set(&node->refs, 2);
 
-               spin_lock(&root->inode_lock);
-               ret = xa_insert(&root->delayed_nodes, ino, node, GFP_NOFS);
-               if (ret) {
-                       spin_unlock(&root->inode_lock);
-                       kmem_cache_free(delayed_node_cache, node);
-                       if (ret != -EBUSY)
-                               return ERR_PTR(ret);
-               }
-       } while (ret);
+       ret = radix_tree_preload(GFP_NOFS);
+       if (ret) {
+               kmem_cache_free(delayed_node_cache, node);
+               return ERR_PTR(ret);
+       }
+
+       spin_lock(&root->inode_lock);
+       ret = radix_tree_insert(&root->delayed_nodes_tree, ino, node);
+       if (ret == -EEXIST) {
+               spin_unlock(&root->inode_lock);
+               kmem_cache_free(delayed_node_cache, node);
+               radix_tree_preload_end();
+               goto again;
+       }
        btrfs_inode->delayed_node = node;
        spin_unlock(&root->inode_lock);
+       radix_tree_preload_end();
 
        return node;
 }
@@ -270,7 +276,8 @@ static void __btrfs_release_delayed_node(
                 * back up.  We can delete it now.
                 */
                ASSERT(refcount_read(&delayed_node->refs) == 0);
-               xa_erase(&root->delayed_nodes, delayed_node->inode_id);
+               radix_tree_delete(&root->delayed_nodes_tree,
+                                 delayed_node->inode_id);
                spin_unlock(&root->inode_lock);
                kmem_cache_free(delayed_node_cache, delayed_node);
        }
@@ -1863,35 +1870,34 @@ void btrfs_kill_delayed_inode_items(struct btrfs_inode *inode)
 
 void btrfs_kill_all_delayed_nodes(struct btrfs_root *root)
 {
-       unsigned long index = 0;
-       struct btrfs_delayed_node *delayed_node;
+       u64 inode_id = 0;
        struct btrfs_delayed_node *delayed_nodes[8];
+       int i, n;
 
        while (1) {
-               int n = 0;
-
                spin_lock(&root->inode_lock);
-               if (xa_empty(&root->delayed_nodes)) {
+               n = radix_tree_gang_lookup(&root->delayed_nodes_tree,
+                                          (void **)delayed_nodes, inode_id,
+                                          ARRAY_SIZE(delayed_nodes));
+               if (!n) {
                        spin_unlock(&root->inode_lock);
-                       return;
+                       break;
                }
 
-               xa_for_each_start(&root->delayed_nodes, index, delayed_node, index) {
+               inode_id = delayed_nodes[n - 1]->inode_id + 1;
+               for (i = 0; i < n; i++) {
                        /*
                         * Don't increase refs in case the node is dead and
                         * about to be removed from the tree in the loop below
                         */
-                       if (refcount_inc_not_zero(&delayed_node->refs)) {
-                               delayed_nodes[n] = delayed_node;
-                               n++;
-                       }
-                       if (n >= ARRAY_SIZE(delayed_nodes))
-                               break;
+                       if (!refcount_inc_not_zero(&delayed_nodes[i]->refs))
+                               delayed_nodes[i] = NULL;
                }
-               index++;
                spin_unlock(&root->inode_lock);
 
-               for (int i = 0; i < n; i++) {
+               for (i = 0; i < n; i++) {
+                       if (!delayed_nodes[i])
+                               continue;
                        __btrfs_kill_delayed_node(delayed_nodes[i]);
                        btrfs_release_delayed_node(delayed_nodes[i]);
                }
index 4ba005c4198368214fb4b055fd15d02af19e3b06..de440ebf5648b059ff3a63022b9015b2a99ed0bf 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/fs.h>
 #include <linux/blkdev.h>
+#include <linux/radix-tree.h>
 #include <linux/writeback.h>
 #include <linux/workqueue.h>
 #include <linux/kthread.h>
@@ -485,7 +486,7 @@ static int csum_dirty_subpage_buffers(struct btrfs_fs_info *fs_info,
                uptodate = btrfs_subpage_test_uptodate(fs_info, page, cur,
                                                       fs_info->nodesize);
 
-               /* A dirty eb shouldn't disappear from extent_buffers */
+               /* A dirty eb shouldn't disappear from buffer_radix */
                if (WARN_ON(!eb))
                        return -EUCLEAN;
 
@@ -1158,7 +1159,7 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
        root->nr_delalloc_inodes = 0;
        root->nr_ordered_extents = 0;
        root->inode_tree = RB_ROOT;
-       xa_init_flags(&root->delayed_nodes, GFP_ATOMIC);
+       INIT_RADIX_TREE(&root->delayed_nodes_tree, GFP_ATOMIC);
 
        btrfs_init_root_block_rsv(root);
 
@@ -1210,9 +1211,9 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
        btrfs_qgroup_init_swapped_blocks(&root->swapped_blocks);
 #ifdef CONFIG_BTRFS_DEBUG
        INIT_LIST_HEAD(&root->leak_list);
-       spin_lock(&fs_info->fs_roots_lock);
+       spin_lock(&fs_info->fs_roots_radix_lock);
        list_add_tail(&root->leak_list, &fs_info->allocated_roots);
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
 #endif
 }
 
@@ -1659,11 +1660,12 @@ static struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
 {
        struct btrfs_root *root;
 
-       spin_lock(&fs_info->fs_roots_lock);
-       root = xa_load(&fs_info->fs_roots, (unsigned long)root_id);
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       root = radix_tree_lookup(&fs_info->fs_roots_radix,
+                                (unsigned long)root_id);
        if (root)
                root = btrfs_grab_root(root);
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
        return root;
 }
 
@@ -1705,14 +1707,20 @@ int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,
 {
        int ret;
 
-       spin_lock(&fs_info->fs_roots_lock);
-       ret = xa_insert(&fs_info->fs_roots, (unsigned long)root->root_key.objectid,
-                       root, GFP_NOFS);
+       ret = radix_tree_preload(GFP_NOFS);
+       if (ret)
+               return ret;
+
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       ret = radix_tree_insert(&fs_info->fs_roots_radix,
+                               (unsigned long)root->root_key.objectid,
+                               root);
        if (ret == 0) {
                btrfs_grab_root(root);
-               set_bit(BTRFS_ROOT_REGISTERED, &root->state);
+               set_bit(BTRFS_ROOT_IN_RADIX, &root->state);
        }
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
+       radix_tree_preload_end();
 
        return ret;
 }
@@ -2342,9 +2350,9 @@ void btrfs_put_root(struct btrfs_root *root)
                btrfs_drew_lock_destroy(&root->snapshot_lock);
                free_root_extent_buffers(root);
 #ifdef CONFIG_BTRFS_DEBUG
-               spin_lock(&root->fs_info->fs_roots_lock);
+               spin_lock(&root->fs_info->fs_roots_radix_lock);
                list_del_init(&root->leak_list);
-               spin_unlock(&root->fs_info->fs_roots_lock);
+               spin_unlock(&root->fs_info->fs_roots_radix_lock);
 #endif
                kfree(root);
        }
@@ -2352,21 +2360,28 @@ void btrfs_put_root(struct btrfs_root *root)
 
 void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info)
 {
-       struct btrfs_root *root;
-       unsigned long index = 0;
+       int ret;
+       struct btrfs_root *gang[8];
+       int i;
 
        while (!list_empty(&fs_info->dead_roots)) {
-               root = list_entry(fs_info->dead_roots.next,
-                                 struct btrfs_root, root_list);
-               list_del(&root->root_list);
+               gang[0] = list_entry(fs_info->dead_roots.next,
+                                    struct btrfs_root, root_list);
+               list_del(&gang[0]->root_list);
 
-               if (test_bit(BTRFS_ROOT_REGISTERED, &root->state))
-                       btrfs_drop_and_free_fs_root(fs_info, root);
-               btrfs_put_root(root);
+               if (test_bit(BTRFS_ROOT_IN_RADIX, &gang[0]->state))
+                       btrfs_drop_and_free_fs_root(fs_info, gang[0]);
+               btrfs_put_root(gang[0]);
        }
 
-       xa_for_each(&fs_info->fs_roots, index, root) {
-               btrfs_drop_and_free_fs_root(fs_info, root);
+       while (1) {
+               ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
+                                            (void **)gang, 0,
+                                            ARRAY_SIZE(gang));
+               if (!ret)
+                       break;
+               for (i = 0; i < ret; i++)
+                       btrfs_drop_and_free_fs_root(fs_info, gang[i]);
        }
 }
 
@@ -3134,8 +3149,8 @@ static int __cold init_tree_roots(struct btrfs_fs_info *fs_info)
 
 void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
 {
-       xa_init_flags(&fs_info->fs_roots, GFP_ATOMIC);
-       xa_init_flags(&fs_info->extent_buffers, GFP_ATOMIC);
+       INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
+       INIT_RADIX_TREE(&fs_info->buffer_radix, GFP_ATOMIC);
        INIT_LIST_HEAD(&fs_info->trans_list);
        INIT_LIST_HEAD(&fs_info->dead_roots);
        INIT_LIST_HEAD(&fs_info->delayed_iputs);
@@ -3143,7 +3158,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
        INIT_LIST_HEAD(&fs_info->caching_block_groups);
        spin_lock_init(&fs_info->delalloc_root_lock);
        spin_lock_init(&fs_info->trans_lock);
-       spin_lock_init(&fs_info->fs_roots_lock);
+       spin_lock_init(&fs_info->fs_roots_radix_lock);
        spin_lock_init(&fs_info->delayed_iput_lock);
        spin_lock_init(&fs_info->defrag_inodes_lock);
        spin_lock_init(&fs_info->super_lock);
@@ -3374,7 +3389,7 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info)
        /*
         * btrfs_find_orphan_roots() is responsible for finding all the dead
         * roots (with 0 refs), flag them with BTRFS_ROOT_DEAD_TREE and load
-        * them into the fs_info->fs_roots. This must be done before
+        * them into the fs_info->fs_roots_radix tree. This must be done before
         * calling btrfs_orphan_cleanup() on the tree root. If we don't do it
         * first, then btrfs_orphan_cleanup() will delete a dead root's orphan
         * item before the root's tree is deleted - this means that if we unmount
@@ -4499,11 +4514,12 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
 {
        bool drop_ref = false;
 
-       spin_lock(&fs_info->fs_roots_lock);
-       xa_erase(&fs_info->fs_roots, (unsigned long)root->root_key.objectid);
-       if (test_and_clear_bit(BTRFS_ROOT_REGISTERED, &root->state))
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       radix_tree_delete(&fs_info->fs_roots_radix,
+                         (unsigned long)root->root_key.objectid);
+       if (test_and_clear_bit(BTRFS_ROOT_IN_RADIX, &root->state))
                drop_ref = true;
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
 
        if (BTRFS_FS_ERROR(fs_info)) {
                ASSERT(root->log_root == NULL);
@@ -4519,48 +4535,50 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
 
 int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)
 {
-       struct btrfs_root *roots[8];
-       unsigned long index = 0;
-       int i;
+       u64 root_objectid = 0;
+       struct btrfs_root *gang[8];
+       int i = 0;
        int err = 0;
-       int grabbed;
+       unsigned int ret = 0;
 
        while (1) {
-               struct btrfs_root *root;
-
-               spin_lock(&fs_info->fs_roots_lock);
-               if (!xa_find(&fs_info->fs_roots, &index, ULONG_MAX, XA_PRESENT)) {
-                       spin_unlock(&fs_info->fs_roots_lock);
-                       return err;
+               spin_lock(&fs_info->fs_roots_radix_lock);
+               ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
+                                            (void **)gang, root_objectid,
+                                            ARRAY_SIZE(gang));
+               if (!ret) {
+                       spin_unlock(&fs_info->fs_roots_radix_lock);
+                       break;
                }
+               root_objectid = gang[ret - 1]->root_key.objectid + 1;
 
-               grabbed = 0;
-               xa_for_each_start(&fs_info->fs_roots, index, root, index) {
-                       /* Avoid grabbing roots in dead_roots */
-                       if (btrfs_root_refs(&root->root_item) > 0)
-                               roots[grabbed++] = btrfs_grab_root(root);
-                       if (grabbed >= ARRAY_SIZE(roots))
-                               break;
+               for (i = 0; i < ret; i++) {
+                       /* Avoid to grab roots in dead_roots */
+                       if (btrfs_root_refs(&gang[i]->root_item) == 0) {
+                               gang[i] = NULL;
+                               continue;
+                       }
+                       /* grab all the search result for later use */
+                       gang[i] = btrfs_grab_root(gang[i]);
                }
-               spin_unlock(&fs_info->fs_roots_lock);
+               spin_unlock(&fs_info->fs_roots_radix_lock);
 
-               for (i = 0; i < grabbed; i++) {
-                       if (!roots[i])
+               for (i = 0; i < ret; i++) {
+                       if (!gang[i])
                                continue;
-                       index = roots[i]->root_key.objectid;
-                       err = btrfs_orphan_cleanup(roots[i]);
+                       root_objectid = gang[i]->root_key.objectid;
+                       err = btrfs_orphan_cleanup(gang[i]);
                        if (err)
-                               goto out;
-                       btrfs_put_root(roots[i]);
+                               break;
+                       btrfs_put_root(gang[i]);
                }
-               index++;
+               root_objectid++;
        }
 
-out:
-       /* Release the roots that remain uncleaned due to error */
-       for (; i < grabbed; i++) {
-               if (roots[i])
-                       btrfs_put_root(roots[i]);
+       /* release the uncleaned roots due to error */
+       for (; i < ret; i++) {
+               if (gang[i])
+                       btrfs_put_root(gang[i]);
        }
        return err;
 }
@@ -4879,28 +4897,31 @@ static void btrfs_error_commit_super(struct btrfs_fs_info *fs_info)
 
 static void btrfs_drop_all_logs(struct btrfs_fs_info *fs_info)
 {
-       unsigned long index = 0;
-       int grabbed = 0;
-       struct btrfs_root *roots[8];
+       struct btrfs_root *gang[8];
+       u64 root_objectid = 0;
+       int ret;
+
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       while ((ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
+                                            (void **)gang, root_objectid,
+                                            ARRAY_SIZE(gang))) != 0) {
+               int i;
 
-       spin_lock(&fs_info->fs_roots_lock);
-       while ((grabbed = xa_extract(&fs_info->fs_roots, (void **)roots, index,
-                                    ULONG_MAX, 8, XA_PRESENT))) {
-               for (int i = 0; i < grabbed; i++)
-                       roots[i] = btrfs_grab_root(roots[i]);
-               spin_unlock(&fs_info->fs_roots_lock);
+               for (i = 0; i < ret; i++)
+                       gang[i] = btrfs_grab_root(gang[i]);
+               spin_unlock(&fs_info->fs_roots_radix_lock);
 
-               for (int i = 0; i < grabbed; i++) {
-                       if (!roots[i])
+               for (i = 0; i < ret; i++) {
+                       if (!gang[i])
                                continue;
-                       index = roots[i]->root_key.objectid;
-                       btrfs_free_log(NULL, roots[i]);
-                       btrfs_put_root(roots[i]);
+                       root_objectid = gang[i]->root_key.objectid;
+                       btrfs_free_log(NULL, gang[i]);
+                       btrfs_put_root(gang[i]);
                }
-               index++;
-               spin_lock(&fs_info->fs_roots_lock);
+               root_objectid++;
+               spin_lock(&fs_info->fs_roots_radix_lock);
        }
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
        btrfs_free_log_root_tree(NULL, fs_info);
 }
 
index 4157ecc27d4b6aeca1c290064b6c8baf0e69c580..a3afc15430cead41e1d49b7606cb6539a0aed1d7 100644 (file)
@@ -5829,7 +5829,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc)
        btrfs_qgroup_convert_reserved_meta(root, INT_MAX);
        btrfs_qgroup_free_meta_all_pertrans(root);
 
-       if (test_bit(BTRFS_ROOT_REGISTERED, &root->state))
+       if (test_bit(BTRFS_ROOT_IN_RADIX, &root->state))
                btrfs_add_dropped_root(trans, root);
        else
                btrfs_put_root(root);
index 04e36343da3a160c455e26f475c5696357f08401..f03ab5dbda7ae2693bdd4f7c493e90b9a157b8ca 100644 (file)
@@ -2966,7 +2966,7 @@ static void begin_page_read(struct btrfs_fs_info *fs_info, struct page *page)
 }
 
 /*
- * Find extent buffer for a given bytenr.
+ * Find extent buffer for a givne bytenr.
  *
  * This is for end_bio_extent_readpage(), thus we can't do any unsafe locking
  * in endio context.
@@ -2985,9 +2985,11 @@ static struct extent_buffer *find_extent_buffer_readpage(
                return (struct extent_buffer *)page->private;
        }
 
-       /* For subpage case, we need to lookup extent buffer xarray */
-       eb = xa_load(&fs_info->extent_buffers,
-                    bytenr >> fs_info->sectorsize_bits);
+       /* For subpage case, we need to lookup buffer radix tree */
+       rcu_read_lock();
+       eb = radix_tree_lookup(&fs_info->buffer_radix,
+                              bytenr >> fs_info->sectorsize_bits);
+       rcu_read_unlock();
        ASSERT(eb);
        return eb;
 }
@@ -4435,8 +4437,8 @@ static struct extent_buffer *find_extent_buffer_nolock(
        struct extent_buffer *eb;
 
        rcu_read_lock();
-       eb = xa_load(&fs_info->extent_buffers,
-                    start >> fs_info->sectorsize_bits);
+       eb = radix_tree_lookup(&fs_info->buffer_radix,
+                              start >> fs_info->sectorsize_bits);
        if (eb && atomic_inc_not_zero(&eb->refs)) {
                rcu_read_unlock();
                return eb;
@@ -6129,22 +6131,24 @@ struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info,
        if (!eb)
                return ERR_PTR(-ENOMEM);
        eb->fs_info = fs_info;
-
-       do {
-               ret = xa_insert(&fs_info->extent_buffers,
-                               start >> fs_info->sectorsize_bits,
-                               eb, GFP_NOFS);
-               if (ret == -ENOMEM) {
-                       exists = ERR_PTR(ret);
+again:
+       ret = radix_tree_preload(GFP_NOFS);
+       if (ret) {
+               exists = ERR_PTR(ret);
+               goto free_eb;
+       }
+       spin_lock(&fs_info->buffer_lock);
+       ret = radix_tree_insert(&fs_info->buffer_radix,
+                               start >> fs_info->sectorsize_bits, eb);
+       spin_unlock(&fs_info->buffer_lock);
+       radix_tree_preload_end();
+       if (ret == -EEXIST) {
+               exists = find_extent_buffer(fs_info, start);
+               if (exists)
                        goto free_eb;
-               }
-               if (ret == -EBUSY) {
-                       exists = find_extent_buffer(fs_info, start);
-                       if (exists)
-                               goto free_eb;
-               }
-       } while (ret);
-
+               else
+                       goto again;
+       }
        check_buffer_tree_ref(eb);
        set_bit(EXTENT_BUFFER_IN_TREE, &eb->bflags);
 
@@ -6319,22 +6323,25 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
        }
        if (uptodate)
                set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
-
-       do {
-               ret = xa_insert(&fs_info->extent_buffers,
-                               start >> fs_info->sectorsize_bits,
-                               eb, GFP_NOFS);
-               if (ret == -ENOMEM) {
-                       exists = ERR_PTR(ret);
+again:
+       ret = radix_tree_preload(GFP_NOFS);
+       if (ret) {
+               exists = ERR_PTR(ret);
+               goto free_eb;
+       }
+
+       spin_lock(&fs_info->buffer_lock);
+       ret = radix_tree_insert(&fs_info->buffer_radix,
+                               start >> fs_info->sectorsize_bits, eb);
+       spin_unlock(&fs_info->buffer_lock);
+       radix_tree_preload_end();
+       if (ret == -EEXIST) {
+               exists = find_extent_buffer(fs_info, start);
+               if (exists)
                        goto free_eb;
-               }
-               if (ret == -EBUSY) {
-                       exists = find_extent_buffer(fs_info, start);
-                       if (exists)
-                               goto free_eb;
-               }
-       } while (ret);
-
+               else
+                       goto again;
+       }
        /* add one reference for the tree */
        check_buffer_tree_ref(eb);
        set_bit(EXTENT_BUFFER_IN_TREE, &eb->bflags);
@@ -6379,8 +6386,10 @@ static int release_extent_buffer(struct extent_buffer *eb)
 
                        spin_unlock(&eb->refs_lock);
 
-                       xa_erase(&fs_info->extent_buffers,
-                                eb->start >> fs_info->sectorsize_bits);
+                       spin_lock(&fs_info->buffer_lock);
+                       radix_tree_delete(&fs_info->buffer_radix,
+                                         eb->start >> fs_info->sectorsize_bits);
+                       spin_unlock(&fs_info->buffer_lock);
                } else {
                        spin_unlock(&eb->refs_lock);
                }
@@ -7325,25 +7334,42 @@ void memmove_extent_buffer(const struct extent_buffer *dst,
        }
 }
 
+#define GANG_LOOKUP_SIZE       16
 static struct extent_buffer *get_next_extent_buffer(
                struct btrfs_fs_info *fs_info, struct page *page, u64 bytenr)
 {
-       struct extent_buffer *eb;
-       unsigned long index;
+       struct extent_buffer *gang[GANG_LOOKUP_SIZE];
+       struct extent_buffer *found = NULL;
        u64 page_start = page_offset(page);
+       u64 cur = page_start;
 
        ASSERT(in_range(bytenr, page_start, PAGE_SIZE));
        lockdep_assert_held(&fs_info->buffer_lock);
 
-       xa_for_each_start(&fs_info->extent_buffers, index, eb,
-                         page_start >> fs_info->sectorsize_bits) {
-               if (in_range(eb->start, page_start, PAGE_SIZE))
-                       return eb;
-               else if (eb->start >= page_start + PAGE_SIZE)
-                       /* Already beyond page end */
-                       return NULL;
+       while (cur < page_start + PAGE_SIZE) {
+               int ret;
+               int i;
+
+               ret = radix_tree_gang_lookup(&fs_info->buffer_radix,
+                               (void **)gang, cur >> fs_info->sectorsize_bits,
+                               min_t(unsigned int, GANG_LOOKUP_SIZE,
+                                     PAGE_SIZE / fs_info->nodesize));
+               if (ret == 0)
+                       goto out;
+               for (i = 0; i < ret; i++) {
+                       /* Already beyond page end */
+                       if (gang[i]->start >= page_start + PAGE_SIZE)
+                               goto out;
+                       /* Found one */
+                       if (gang[i]->start >= bytenr) {
+                               found = gang[i];
+                               goto out;
+                       }
+               }
+               cur = gang[ret - 1]->start + gang[ret - 1]->len;
        }
-       return NULL;
+out:
+       return found;
 }
 
 static int try_release_subpage_extent_buffer(struct page *page)
index 05e0c4a5affda0268cbce2260ff84998d862266e..d50448bf8eedd951890d6e6f0a64ef131b90c70a 100644 (file)
@@ -3578,7 +3578,6 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
        u64 last_objectid = 0;
        int ret = 0, nr_unlink = 0;
 
-       /* Bail out if the cleanup is already running. */
        if (test_and_set_bit(BTRFS_ROOT_ORPHAN_CLEANUP, &root->state))
                return 0;
 
@@ -3661,17 +3660,17 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
                         *
                         * btrfs_find_orphan_roots() ran before us, which has
                         * found all deleted roots and loaded them into
-                        * fs_info->fs_roots. So here we can find if an
+                        * fs_info->fs_roots_radix. So here we can find if an
                         * orphan item corresponds to a deleted root by looking
-                        * up the root from that xarray.
+                        * up the root from that radix tree.
                         */
 
-                       spin_lock(&fs_info->fs_roots_lock);
-                       dead_root = xa_load(&fs_info->fs_roots,
-                                           (unsigned long)found_key.objectid);
+                       spin_lock(&fs_info->fs_roots_radix_lock);
+                       dead_root = radix_tree_lookup(&fs_info->fs_roots_radix,
+                                                        (unsigned long)found_key.objectid);
                        if (dead_root && btrfs_root_refs(&dead_root->root_item) == 0)
                                is_dead_root = 1;
-                       spin_unlock(&fs_info->fs_roots_lock);
+                       spin_unlock(&fs_info->fs_roots_radix_lock);
 
                        if (is_dead_root) {
                                /* prevent this orphan from being found again */
@@ -3911,7 +3910,7 @@ cache_index:
         * cache.
         *
         * This is required for both inode re-read from disk and delayed inode
-        * in the delayed_nodes xarray.
+        * in delayed_nodes_tree.
         */
        if (BTRFS_I(inode)->last_trans == fs_info->generation)
                set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
@@ -7681,7 +7680,19 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
        if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags) ||
            em->block_start == EXTENT_MAP_INLINE) {
                free_extent_map(em);
-               ret = -ENOTBLK;
+               /*
+                * If we are in a NOWAIT context, return -EAGAIN in order to
+                * fallback to buffered IO. This is not only because we can
+                * block with buffered IO (no support for NOWAIT semantics at
+                * the moment) but also to avoid returning short reads to user
+                * space - this happens if we were able to read some data from
+                * previous non-compressed extents and then when we fallback to
+                * buffered IO, at btrfs_file_read_iter() by calling
+                * filemap_read(), we fail to fault in pages for the read buffer,
+                * in which case filemap_read() returns a short read (the number
+                * of bytes previously read is > 0, so it does not return -EFAULT).
+                */
+               ret = (flags & IOMAP_NOWAIT) ? -EAGAIN : -ENOTBLK;
                goto unlock_err;
        }
 
index fa56890ff81fc0adf2bd63e9c5cd69f0bdf2d159..c7dea639a56f9dd2faa756af3d8cf61c31c2c992 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/mount.h>
 #include <linux/xattr.h>
 #include <linux/posix_acl_xattr.h>
+#include <linux/radix-tree.h>
 #include <linux/vmalloc.h>
 #include <linux/string.h>
 #include <linux/compat.h>
@@ -127,7 +128,7 @@ struct send_ctx {
        struct list_head new_refs;
        struct list_head deleted_refs;
 
-       struct xarray name_cache;
+       struct radix_tree_root name_cache;
        struct list_head name_cache_list;
        int name_cache_size;
 
@@ -268,13 +269,14 @@ struct orphan_dir_info {
 struct name_cache_entry {
        struct list_head list;
        /*
-        * On 32bit kernels, xarray has only 32bit indices, but we need to
-        * handle 64bit inums. We use the lower 32bit of the 64bit inum to store
-        * it in the tree. If more than one inum would fall into the same entry,
-        * we use inum_aliases to store the additional entries. inum_aliases is
-        * also used to store entries with the same inum but different generations.
+        * radix_tree has only 32bit entries but we need to handle 64bit inums.
+        * We use the lower 32bit of the 64bit inum to store it in the tree. If
+        * more then one inum would fall into the same entry, we use radix_list
+        * to store the additional entries. radix_list is also used to store
+        * entries where two entries have the same inum but different
+        * generations.
         */
-       struct list_head inum_aliases;
+       struct list_head radix_list;
        u64 ino;
        u64 gen;
        u64 parent_ino;
@@ -2024,9 +2026,9 @@ out:
 }
 
 /*
- * Insert a name cache entry. On 32bit kernels the xarray index is 32bit,
+ * Insert a name cache entry. On 32bit kernels the radix tree index is 32bit,
  * so we need to do some special handling in case we have clashes. This function
- * takes care of this with the help of name_cache_entry::inum_aliases.
+ * takes care of this with the help of name_cache_entry::radix_list.
  * In case of error, nce is kfreed.
  */
 static int name_cache_insert(struct send_ctx *sctx,
@@ -2035,7 +2037,8 @@ static int name_cache_insert(struct send_ctx *sctx,
        int ret = 0;
        struct list_head *nce_head;
 
-       nce_head = xa_load(&sctx->name_cache, (unsigned long)nce->ino);
+       nce_head = radix_tree_lookup(&sctx->name_cache,
+                       (unsigned long)nce->ino);
        if (!nce_head) {
                nce_head = kmalloc(sizeof(*nce_head), GFP_KERNEL);
                if (!nce_head) {
@@ -2044,14 +2047,14 @@ static int name_cache_insert(struct send_ctx *sctx,
                }
                INIT_LIST_HEAD(nce_head);
 
-               ret = xa_insert(&sctx->name_cache, nce->ino, nce_head, GFP_KERNEL);
+               ret = radix_tree_insert(&sctx->name_cache, nce->ino, nce_head);
                if (ret < 0) {
                        kfree(nce_head);
                        kfree(nce);
                        return ret;
                }
        }
-       list_add_tail(&nce->inum_aliases, nce_head);
+       list_add_tail(&nce->radix_list, nce_head);
        list_add_tail(&nce->list, &sctx->name_cache_list);
        sctx->name_cache_size++;
 
@@ -2063,14 +2066,15 @@ static void name_cache_delete(struct send_ctx *sctx,
 {
        struct list_head *nce_head;
 
-       nce_head = xa_load(&sctx->name_cache, (unsigned long)nce->ino);
+       nce_head = radix_tree_lookup(&sctx->name_cache,
+                       (unsigned long)nce->ino);
        if (!nce_head) {
                btrfs_err(sctx->send_root->fs_info,
              "name_cache_delete lookup failed ino %llu cache size %d, leaking memory",
                        nce->ino, sctx->name_cache_size);
        }
 
-       list_del(&nce->inum_aliases);
+       list_del(&nce->radix_list);
        list_del(&nce->list);
        sctx->name_cache_size--;
 
@@ -2078,7 +2082,7 @@ static void name_cache_delete(struct send_ctx *sctx,
         * We may not get to the final release of nce_head if the lookup fails
         */
        if (nce_head && list_empty(nce_head)) {
-               xa_erase(&sctx->name_cache, (unsigned long)nce->ino);
+               radix_tree_delete(&sctx->name_cache, (unsigned long)nce->ino);
                kfree(nce_head);
        }
 }
@@ -2089,11 +2093,11 @@ static struct name_cache_entry *name_cache_search(struct send_ctx *sctx,
        struct list_head *nce_head;
        struct name_cache_entry *cur;
 
-       nce_head = xa_load(&sctx->name_cache, (unsigned long)ino);
+       nce_head = radix_tree_lookup(&sctx->name_cache, (unsigned long)ino);
        if (!nce_head)
                return NULL;
 
-       list_for_each_entry(cur, nce_head, inum_aliases) {
+       list_for_each_entry(cur, nce_head, radix_list) {
                if (cur->ino == ino && cur->gen == gen)
                        return cur;
        }
@@ -7518,7 +7522,7 @@ long btrfs_ioctl_send(struct inode *inode, struct btrfs_ioctl_send_args *arg)
 
        INIT_LIST_HEAD(&sctx->new_refs);
        INIT_LIST_HEAD(&sctx->deleted_refs);
-       xa_init_flags(&sctx->name_cache, GFP_KERNEL);
+       INIT_RADIX_TREE(&sctx->name_cache, GFP_KERNEL);
        INIT_LIST_HEAD(&sctx->name_cache_list);
 
        sctx->flags = arg->flags;
index 1591bfa55bcc61112152903c4743590a4be81fe6..d8e56edd69910d66494b1113d5793ca557229f62 100644 (file)
@@ -150,8 +150,8 @@ struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(u32 nodesize, u32 sectorsize)
 
 void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info)
 {
-       unsigned long index;
-       struct extent_buffer *eb;
+       struct radix_tree_iter iter;
+       void **slot;
        struct btrfs_device *dev, *tmp;
 
        if (!fs_info)
@@ -163,9 +163,25 @@ void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info)
 
        test_mnt->mnt_sb->s_fs_info = NULL;
 
-       xa_for_each(&fs_info->extent_buffers, index, eb) {
+       spin_lock(&fs_info->buffer_lock);
+       radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter, 0) {
+               struct extent_buffer *eb;
+
+               eb = radix_tree_deref_slot_protected(slot, &fs_info->buffer_lock);
+               if (!eb)
+                       continue;
+               /* Shouldn't happen but that kind of thinking creates CVE's */
+               if (radix_tree_exception(eb)) {
+                       if (radix_tree_deref_retry(eb))
+                               slot = radix_tree_iter_retry(&iter);
+                       continue;
+               }
+               slot = radix_tree_iter_resume(slot, &iter);
+               spin_unlock(&fs_info->buffer_lock);
                free_extent_buffer_stale(eb);
+               spin_lock(&fs_info->buffer_lock);
        }
+       spin_unlock(&fs_info->buffer_lock);
 
        btrfs_mapping_tree_free(&fs_info->mapping_tree);
        list_for_each_entry_safe(dev, tmp, &fs_info->fs_devices->devices,
@@ -186,7 +202,7 @@ void btrfs_free_dummy_root(struct btrfs_root *root)
        if (!root)
                return;
        /* Will be freed by btrfs_free_fs_roots */
-       if (WARN_ON(test_bit(BTRFS_ROOT_REGISTERED, &root->state)))
+       if (WARN_ON(test_bit(BTRFS_ROOT_IN_RADIX, &root->state)))
                return;
        btrfs_global_root_delete(root);
        btrfs_put_root(root);
index 06c0a958d114b89954575a7137ae50f4c6b37962..875b801ab3d7c00ef665d8e84a041a81c8663d43 100644 (file)
@@ -23,7 +23,7 @@
 #include "space-info.h"
 #include "zoned.h"
 
-#define BTRFS_ROOT_TRANS_TAG                           XA_MARK_0
+#define BTRFS_ROOT_TRANS_TAG 0
 
 /*
  * Transaction states and transitions
@@ -437,15 +437,15 @@ static int record_root_in_trans(struct btrfs_trans_handle *trans,
                 */
                smp_wmb();
 
-               spin_lock(&fs_info->fs_roots_lock);
+               spin_lock(&fs_info->fs_roots_radix_lock);
                if (root->last_trans == trans->transid && !force) {
-                       spin_unlock(&fs_info->fs_roots_lock);
+                       spin_unlock(&fs_info->fs_roots_radix_lock);
                        return 0;
                }
-               xa_set_mark(&fs_info->fs_roots,
-                           (unsigned long)root->root_key.objectid,
-                           BTRFS_ROOT_TRANS_TAG);
-               spin_unlock(&fs_info->fs_roots_lock);
+               radix_tree_tag_set(&fs_info->fs_roots_radix,
+                                  (unsigned long)root->root_key.objectid,
+                                  BTRFS_ROOT_TRANS_TAG);
+               spin_unlock(&fs_info->fs_roots_radix_lock);
                root->last_trans = trans->transid;
 
                /* this is pretty tricky.  We don't want to
@@ -487,9 +487,11 @@ void btrfs_add_dropped_root(struct btrfs_trans_handle *trans,
        spin_unlock(&cur_trans->dropped_roots_lock);
 
        /* Make sure we don't try to update the root at commit time */
-       xa_clear_mark(&fs_info->fs_roots,
-                     (unsigned long)root->root_key.objectid,
-                     BTRFS_ROOT_TRANS_TAG);
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       radix_tree_tag_clear(&fs_info->fs_roots_radix,
+                            (unsigned long)root->root_key.objectid,
+                            BTRFS_ROOT_TRANS_TAG);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
 }
 
 int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans,
@@ -1402,8 +1404,9 @@ void btrfs_add_dead_root(struct btrfs_root *root)
 static noinline int commit_fs_roots(struct btrfs_trans_handle *trans)
 {
        struct btrfs_fs_info *fs_info = trans->fs_info;
-       struct btrfs_root *root;
-       unsigned long index;
+       struct btrfs_root *gang[8];
+       int i;
+       int ret;
 
        /*
         * At this point no one can be using this transaction to modify any tree
@@ -1411,46 +1414,57 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans)
         */
        ASSERT(trans->transaction->state == TRANS_STATE_COMMIT_DOING);
 
-       spin_lock(&fs_info->fs_roots_lock);
-       xa_for_each_marked(&fs_info->fs_roots, index, root, BTRFS_ROOT_TRANS_TAG) {
-               int ret;
-
-               /*
-                * At this point we can neither have tasks logging inodes
-                * from a root nor trying to commit a log tree.
-                */
-               ASSERT(atomic_read(&root->log_writers) == 0);
-               ASSERT(atomic_read(&root->log_commit[0]) == 0);
-               ASSERT(atomic_read(&root->log_commit[1]) == 0);
-
-               xa_clear_mark(&fs_info->fs_roots,
-                             (unsigned long)root->root_key.objectid,
-                             BTRFS_ROOT_TRANS_TAG);
-               spin_unlock(&fs_info->fs_roots_lock);
-
-               btrfs_free_log(trans, root);
-               ret = btrfs_update_reloc_root(trans, root);
-               if (ret)
-                       return ret;
-
-               /* See comments in should_cow_block() */
-               clear_bit(BTRFS_ROOT_FORCE_COW, &root->state);
-               smp_mb__after_atomic();
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       while (1) {
+               ret = radix_tree_gang_lookup_tag(&fs_info->fs_roots_radix,
+                                                (void **)gang, 0,
+                                                ARRAY_SIZE(gang),
+                                                BTRFS_ROOT_TRANS_TAG);
+               if (ret == 0)
+                       break;
+               for (i = 0; i < ret; i++) {
+                       struct btrfs_root *root = gang[i];
+                       int ret2;
+
+                       /*
+                        * At this point we can neither have tasks logging inodes
+                        * from a root nor trying to commit a log tree.
+                        */
+                       ASSERT(atomic_read(&root->log_writers) == 0);
+                       ASSERT(atomic_read(&root->log_commit[0]) == 0);
+                       ASSERT(atomic_read(&root->log_commit[1]) == 0);
+
+                       radix_tree_tag_clear(&fs_info->fs_roots_radix,
+                                       (unsigned long)root->root_key.objectid,
+                                       BTRFS_ROOT_TRANS_TAG);
+                       spin_unlock(&fs_info->fs_roots_radix_lock);
+
+                       btrfs_free_log(trans, root);
+                       ret2 = btrfs_update_reloc_root(trans, root);
+                       if (ret2)
+                               return ret2;
+
+                       /* see comments in should_cow_block() */
+                       clear_bit(BTRFS_ROOT_FORCE_COW, &root->state);
+                       smp_mb__after_atomic();
+
+                       if (root->commit_root != root->node) {
+                               list_add_tail(&root->dirty_list,
+                                       &trans->transaction->switch_commits);
+                               btrfs_set_root_node(&root->root_item,
+                                                   root->node);
+                       }
 
-               if (root->commit_root != root->node) {
-                       list_add_tail(&root->dirty_list,
-                                     &trans->transaction->switch_commits);
-                       btrfs_set_root_node(&root->root_item, root->node);
+                       ret2 = btrfs_update_root(trans, fs_info->tree_root,
+                                               &root->root_key,
+                                               &root->root_item);
+                       if (ret2)
+                               return ret2;
+                       spin_lock(&fs_info->fs_roots_radix_lock);
+                       btrfs_qgroup_free_meta_all_pertrans(root);
                }
-
-               ret = btrfs_update_root(trans, fs_info->tree_root,
-                                       &root->root_key, &root->root_item);
-               if (ret)
-                       return ret;
-               spin_lock(&fs_info->fs_roots_lock);
-               btrfs_qgroup_free_meta_all_pertrans(root);
        }
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
        return 0;
 }
 
index 79e8c8cd75edf11f77caa15e5b3764683d3a7c49..d99026df6f67957f4cef63fc33d65e4801c058c7 100644 (file)
@@ -1735,12 +1735,14 @@ static int read_zone_info(struct btrfs_fs_info *fs_info, u64 logical,
        ret = btrfs_map_sblock(fs_info, BTRFS_MAP_GET_READ_MIRRORS, logical,
                               &mapped_length, &bioc);
        if (ret || !bioc || mapped_length < PAGE_SIZE) {
-               btrfs_put_bioc(bioc);
-               return -EIO;
+               ret = -EIO;
+               goto out_put_bioc;
        }
 
-       if (bioc->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK)
-               return -EINVAL;
+       if (bioc->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
+               ret = -EINVAL;
+               goto out_put_bioc;
+       }
 
        nofs_flag = memalloc_nofs_save();
        nmirrors = (int)bioc->num_stripes;
@@ -1759,7 +1761,8 @@ static int read_zone_info(struct btrfs_fs_info *fs_info, u64 logical,
                break;
        }
        memalloc_nofs_restore(nofs_flag);
-
+out_put_bioc:
+       btrfs_put_bioc(bioc);
        return ret;
 }
 
@@ -1885,7 +1888,6 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
 {
        struct btrfs_fs_info *fs_info = block_group->fs_info;
        struct map_lookup *map;
-       bool need_zone_finish;
        int ret = 0;
        int i;
 
@@ -1942,12 +1944,6 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
                }
        }
 
-       /*
-        * The block group is not fully allocated, so not fully written yet. We
-        * need to send ZONE_FINISH command to free up an active zone.
-        */
-       need_zone_finish = !btrfs_zoned_bg_is_full(block_group);
-
        block_group->zone_is_active = 0;
        block_group->alloc_offset = block_group->zone_capacity;
        block_group->free_space_ctl->free_space = 0;
@@ -1963,15 +1959,13 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
                if (device->zone_info->max_active_zones == 0)
                        continue;
 
-               if (need_zone_finish) {
-                       ret = blkdev_zone_mgmt(device->bdev, REQ_OP_ZONE_FINISH,
-                                              physical >> SECTOR_SHIFT,
-                                              device->zone_info->zone_size >> SECTOR_SHIFT,
-                                              GFP_NOFS);
+               ret = blkdev_zone_mgmt(device->bdev, REQ_OP_ZONE_FINISH,
+                                      physical >> SECTOR_SHIFT,
+                                      device->zone_info->zone_size >> SECTOR_SHIFT,
+                                      GFP_NOFS);
 
-                       if (ret)
-                               return ret;
-               }
+               if (ret)
+                       return ret;
 
                btrfs_dev_clear_active_zone(device, physical);
        }
index a41ae6efc5454523f1e4775fa748da89c206dede..1fee702d55293e9a25b23fe83dc9bb07dbe96ddb 100644 (file)
@@ -21,7 +21,8 @@ static int cachefiles_ondemand_fd_release(struct inode *inode,
         * anon_fd.
         */
        xas_for_each(&xas, req, ULONG_MAX) {
-               if (req->msg.opcode == CACHEFILES_OP_READ) {
+               if (req->msg.object_id == object_id &&
+                   req->msg.opcode == CACHEFILES_OP_READ) {
                        req->error = -EIO;
                        complete(&req->done);
                        xas_store(&xas, NULL);
index 6dee88815491c869364ee223dcaed0a0f1ff7492..d6e5916138e4f3c3f89fe529933537a924fb6091 100644 (file)
@@ -63,7 +63,7 @@
         (CONGESTION_ON_THRESH(congestion_kb) >> 2))
 
 static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned int len,
-                                       struct folio *folio, void **_fsdata);
+                                       struct folio **foliop, void **_fsdata);
 
 static inline struct ceph_snap_context *page_snap_context(struct page *page)
 {
@@ -1288,18 +1288,19 @@ ceph_find_incompatible(struct page *page)
 }
 
 static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned int len,
-                                       struct folio *folio, void **_fsdata)
+                                       struct folio **foliop, void **_fsdata)
 {
        struct inode *inode = file_inode(file);
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_snap_context *snapc;
 
-       snapc = ceph_find_incompatible(folio_page(folio, 0));
+       snapc = ceph_find_incompatible(folio_page(*foliop, 0));
        if (snapc) {
                int r;
 
-               folio_unlock(folio);
-               folio_put(folio);
+               folio_unlock(*foliop);
+               folio_put(*foliop);
+               *foliop = NULL;
                if (IS_ERR(snapc))
                        return PTR_ERR(snapc);
 
index fa29c9aae24bc2c073b88704d87788256975d905..386bb523c69ea756e62c8cd9640bdb7b243ae706 100644 (file)
@@ -1918,7 +1918,6 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
        list_del_init(&ses->smb_ses_list);
        spin_unlock(&cifs_tcp_ses_lock);
 
-       spin_lock(&ses->chan_lock);
        chan_count = ses->chan_count;
 
        /* close any extra channels */
@@ -1934,7 +1933,6 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
                        ses->chans[i].server = NULL;
                }
        }
-       spin_unlock(&ses->chan_lock);
 
        sesInfoFree(ses);
        cifs_put_tcp_session(server, 0);
index b85718f32b531e66cf5bdc4ec01f294d366c1360..02c8b2906196dd1ae4db5e14bd675180188c9ed3 100644 (file)
@@ -474,6 +474,14 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
 
 out:
        if (rc && chan->server) {
+               /*
+                * we should avoid race with these delayed works before we
+                * remove this channel
+                */
+               cancel_delayed_work_sync(&chan->server->echo);
+               cancel_delayed_work_sync(&chan->server->resolve);
+               cancel_delayed_work_sync(&chan->server->reconnect);
+
                spin_lock(&ses->chan_lock);
                /* we rely on all bits beyond chan_count to be clear */
                cifs_chan_clear_need_reconnect(ses, chan->server);
@@ -484,10 +492,9 @@ out:
                 */
                WARN_ON(ses->chan_count < 1);
                spin_unlock(&ses->chan_lock);
-       }
 
-       if (rc && chan->server)
                cifs_put_tcp_session(chan->server, 0);
+       }
 
        return rc;
 }
index 12b4dddaedb020ed158d54b305aa43eeeadc8eb1..c705de32e22579b53dcc835dd3e938d658dcdd05 100644 (file)
@@ -571,10 +571,6 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
        *total_len += ctxt_len;
        pneg_ctxt += ctxt_len;
 
-       build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
-       *total_len += sizeof(struct smb2_posix_neg_context);
-       pneg_ctxt += sizeof(struct smb2_posix_neg_context);
-
        /*
         * secondary channels don't have the hostname field populated
         * use the hostname field in the primary channel instead
@@ -586,9 +582,14 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
                                              hostname);
                *total_len += ctxt_len;
                pneg_ctxt += ctxt_len;
-               neg_context_count = 4;
-       } else /* second channels do not have a hostname */
                neg_context_count = 3;
+       } else
+               neg_context_count = 2;
+
+       build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
+       *total_len += sizeof(struct smb2_posix_neg_context);
+       pneg_ctxt += sizeof(struct smb2_posix_neg_context);
+       neg_context_count++;
 
        if (server->compress_algorithm) {
                build_compression_ctxt((struct smb2_compression_capabilities_context *)
index 0989fb8472a18fa65214769692f3d30cc979f1a8..778123259e4249c6a428e24757ba4510eece301e 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1301,7 +1301,7 @@ int begin_new_exec(struct linux_binprm * bprm)
        bprm->mm = NULL;
 
 #ifdef CONFIG_POSIX_TIMERS
-       exit_itimers(me->signal);
+       exit_itimers(me);
        flush_itimer_signals();
 #endif
 
index 9d3cf01117093da9aa133bc83066b0338466e74a..74920826d8f67467dc6d633e1820bc920b727d15 100644 (file)
@@ -372,17 +372,22 @@ nomem:
        return NULL;
 }
 
+static inline bool fscache_cookie_is_dropped(struct fscache_cookie *cookie)
+{
+       return READ_ONCE(cookie->state) == FSCACHE_COOKIE_STATE_DROPPED;
+}
+
 static void fscache_wait_on_collision(struct fscache_cookie *candidate,
                                      struct fscache_cookie *wait_for)
 {
        enum fscache_cookie_state *statep = &wait_for->state;
 
-       wait_var_event_timeout(statep, READ_ONCE(*statep) == FSCACHE_COOKIE_STATE_DROPPED,
+       wait_var_event_timeout(statep, fscache_cookie_is_dropped(wait_for),
                               20 * HZ);
-       if (READ_ONCE(*statep) != FSCACHE_COOKIE_STATE_DROPPED) {
+       if (!fscache_cookie_is_dropped(wait_for)) {
                pr_notice("Potential collision c=%08x old: c=%08x",
                          candidate->debug_id, wait_for->debug_id);
-               wait_var_event(statep, READ_ONCE(*statep) == FSCACHE_COOKIE_STATE_DROPPED);
+               wait_var_event(statep, fscache_cookie_is_dropped(wait_for));
        }
 }
 
@@ -517,7 +522,14 @@ static void fscache_perform_lookup(struct fscache_cookie *cookie)
        }
 
        fscache_see_cookie(cookie, fscache_cookie_see_active);
-       fscache_set_cookie_state(cookie, FSCACHE_COOKIE_STATE_ACTIVE);
+       spin_lock(&cookie->lock);
+       if (test_and_clear_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags))
+               __fscache_set_cookie_state(cookie,
+                                          FSCACHE_COOKIE_STATE_INVALIDATING);
+       else
+               __fscache_set_cookie_state(cookie, FSCACHE_COOKIE_STATE_ACTIVE);
+       spin_unlock(&cookie->lock);
+       wake_up_cookie_state(cookie);
        trace = fscache_access_lookup_cookie_end;
 
 out:
@@ -752,6 +764,9 @@ again_locked:
                        spin_lock(&cookie->lock);
                }
 
+               if (test_and_clear_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags))
+                       fscache_end_cookie_access(cookie, fscache_access_invalidate_cookie_end);
+
                switch (state) {
                case FSCACHE_COOKIE_STATE_RELINQUISHING:
                        fscache_see_cookie(cookie, fscache_cookie_see_relinquish);
@@ -1048,6 +1063,9 @@ void __fscache_invalidate(struct fscache_cookie *cookie,
                return;
 
        case FSCACHE_COOKIE_STATE_LOOKING_UP:
+               __fscache_begin_cookie_access(cookie, fscache_access_invalidate_cookie);
+               set_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags);
+               fallthrough;
        case FSCACHE_COOKIE_STATE_CREATING:
                spin_unlock(&cookie->lock);
                _leave(" [look %x]", cookie->inval_counter);
index f2aa7dbad76674eab8dc2f12dec1cfee9c3e35af..a058e0136bfebfc8fb5771f3826c91a5cbe5e5cc 100644 (file)
@@ -143,7 +143,7 @@ static void fscache_wait_on_volume_collision(struct fscache_volume *candidate,
 {
        wait_var_event_timeout(&candidate->flags,
                               !fscache_is_acquire_pending(candidate), 20 * HZ);
-       if (!fscache_is_acquire_pending(candidate)) {
+       if (fscache_is_acquire_pending(candidate)) {
                pr_notice("Potential volume collision new=%08x old=%08x",
                          candidate->debug_id, collidee_debug_id);
                fscache_stat(&fscache_n_volumes_collision);
@@ -182,7 +182,7 @@ static bool fscache_hash_volume(struct fscache_volume *candidate)
        hlist_bl_add_head(&candidate->hash_link, h);
        hlist_bl_unlock(h);
 
-       if (test_bit(FSCACHE_VOLUME_ACQUIRE_PENDING, &candidate->flags))
+       if (fscache_is_acquire_pending(candidate))
                fscache_wait_on_volume_collision(candidate, collidee_debug_id);
        return true;
 
index 0d491ad15b66ad92eb12b480331b32e841675281..e8e769be9ed0581238efdbf223ff448922ba52c3 100644 (file)
@@ -1737,6 +1737,14 @@ static void io_kbuf_recycle(struct io_kiocb *req, unsigned issue_flags)
            (req->flags & REQ_F_PARTIAL_IO))
                return;
 
+       /*
+        * READV uses fields in `struct io_rw` (len/addr) to stash the selected
+        * buffer data. However if that buffer is recycled the original request
+        * data stored in addr is lost. Therefore forbid recycling for now.
+        */
+       if (req->opcode == IORING_OP_READV)
+               return;
+
        /*
         * We don't need to recycle for REQ_F_BUFFER_RING, we can just clear
         * the flag and hence ensure that bl->head doesn't get incremented.
@@ -5066,7 +5074,7 @@ static int io_uring_cmd_prep(struct io_kiocb *req,
 {
        struct io_uring_cmd *ioucmd = &req->uring_cmd;
 
-       if (sqe->rw_flags)
+       if (sqe->rw_flags || sqe->__pad1)
                return -EINVAL;
        ioucmd->cmd = sqe->cmd;
        ioucmd->cmd_op = READ_ONCE(sqe->cmd_op);
@@ -7973,6 +7981,9 @@ static int io_files_update_with_index_alloc(struct io_kiocb *req,
        struct file *file;
        int ret, fd;
 
+       if (!req->ctx->file_data)
+               return -ENXIO;
+
        for (done = 0; done < req->rsrc_update.nr_args; done++) {
                if (copy_from_user(&fd, &fds[done], sizeof(fd))) {
                        ret = -EFAULT;
@@ -12928,7 +12939,7 @@ static int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)
 {
        struct io_uring_buf_ring *br;
        struct io_uring_buf_reg reg;
-       struct io_buffer_list *bl;
+       struct io_buffer_list *bl, *free_bl = NULL;
        struct page **pages;
        int nr_pages;
 
@@ -12960,7 +12971,7 @@ static int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)
                if (bl->buf_nr_pages || !list_empty(&bl->buf_list))
                        return -EEXIST;
        } else {
-               bl = kzalloc(sizeof(*bl), GFP_KERNEL);
+               free_bl = bl = kzalloc(sizeof(*bl), GFP_KERNEL);
                if (!bl)
                        return -ENOMEM;
        }
@@ -12969,7 +12980,7 @@ static int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)
                             struct_size(br, bufs, reg.ring_entries),
                             &nr_pages);
        if (IS_ERR(pages)) {
-               kfree(bl);
+               kfree(free_bl);
                return PTR_ERR(pages);
        }
 
index 0a22a2faf552245716f88837ddd59e34bfea79a6..e1c4617de7714735302e5889aaf2cb80d045d5cf 100644 (file)
@@ -176,7 +176,7 @@ nlm_delete_file(struct nlm_file *file)
        }
 }
 
-static int nlm_unlock_files(struct nlm_file *file)
+static int nlm_unlock_files(struct nlm_file *file, fl_owner_t owner)
 {
        struct file_lock lock;
 
@@ -184,6 +184,7 @@ static int nlm_unlock_files(struct nlm_file *file)
        lock.fl_type  = F_UNLCK;
        lock.fl_start = 0;
        lock.fl_end   = OFFSET_MAX;
+       lock.fl_owner = owner;
        if (file->f_file[O_RDONLY] &&
            vfs_lock_file(file->f_file[O_RDONLY], F_SETLK, &lock, NULL))
                goto out_err;
@@ -225,7 +226,7 @@ again:
                if (match(lockhost, host)) {
 
                        spin_unlock(&flctx->flc_lock);
-                       if (nlm_unlock_files(file))
+                       if (nlm_unlock_files(file, fl->fl_owner))
                                return 1;
                        goto again;
                }
@@ -282,11 +283,10 @@ nlm_file_inuse(struct nlm_file *file)
 
 static void nlm_close_files(struct nlm_file *file)
 {
-       struct file *f;
-
-       for (f = file->f_file[0]; f <= file->f_file[1]; f++)
-               if (f)
-                       nlmsvc_ops->fclose(f);
+       if (file->f_file[O_RDONLY])
+               nlmsvc_ops->fclose(file->f_file[O_RDONLY]);
+       if (file->f_file[O_WRONLY])
+               nlmsvc_ops->fclose(file->f_file[O_WRONLY]);
 }
 
 /*
index 42f892c5712eae9daead74227a202ab8e5b4aa0e..0ce5358521510694f21b9dd1133081e182593be7 100644 (file)
@@ -319,8 +319,9 @@ zero_out:
  * conflicting writes once the folio is grabbed and locked.  It is passed a
  * pointer to the fsdata cookie that gets returned to the VM to be passed to
  * write_end.  It is permitted to sleep.  It should return 0 if the request
- * should go ahead; unlock the folio and return -EAGAIN to cause the folio to
- * be regot; or return an error.
+ * should go ahead or it may return an error.  It may also unlock and put the
+ * folio, provided it sets ``*foliop`` to NULL, in which case a return of 0
+ * will cause the folio to be re-got and the process to be retried.
  *
  * The calling netfs must initialise a netfs context contiguous to the vfs
  * inode before calling this.
@@ -348,13 +349,13 @@ retry:
 
        if (ctx->ops->check_write_begin) {
                /* Allow the netfs (eg. ceph) to flush conflicts. */
-               ret = ctx->ops->check_write_begin(file, pos, len, folio, _fsdata);
+               ret = ctx->ops->check_write_begin(file, pos, len, &folio, _fsdata);
                if (ret < 0) {
                        trace_netfs_failure(NULL, NULL, ret, netfs_fail_check_write_begin);
-                       if (ret == -EAGAIN)
-                               goto retry;
                        goto error;
                }
+               if (!folio)
+                       goto retry;
        }
 
        if (folio_test_uptodate(folio))
@@ -416,8 +417,10 @@ have_folio_no_wait:
 error_put:
        netfs_put_request(rreq, false, netfs_rreq_trace_put_failed);
 error:
-       folio_unlock(folio);
-       folio_put(folio);
+       if (folio) {
+               folio_unlock(folio);
+               folio_put(folio);
+       }
        _leave(" = %d", ret);
        return ret;
 }
index 61b2aae81abb750196299772d08d46e5daca021f..2acea7792bb26b1a1c3f1157649cebde0f310c68 100644 (file)
@@ -470,6 +470,15 @@ nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen,
                        return nfserr_bad_xdr;
                }
        }
+       if (bmval[1] & FATTR4_WORD1_TIME_CREATE) {
+               struct timespec64 ts;
+
+               /* No Linux filesystem supports setting this attribute. */
+               bmval[1] &= ~FATTR4_WORD1_TIME_CREATE;
+               status = nfsd4_decode_nfstime4(argp, &ts);
+               if (status)
+                       return status;
+       }
        if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
                u32 set_it;
 
index 847b482155ae97cfdaa5e7eaaccb3d87741c152d..9a8b09afc17333712e53843f82baa3d602a68f61 100644 (file)
@@ -465,7 +465,8 @@ static inline bool nfsd_attrs_supported(u32 minorversion, const u32 *bmval)
        (FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL)
 #define NFSD_WRITEABLE_ATTRS_WORD1 \
        (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
-       | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
+       | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_CREATE \
+       | FATTR4_WORD1_TIME_MODIFY_SET)
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
 #define MAYBE_FATTR4_WORD2_SECURITY_LABEL \
        FATTR4_WORD2_SECURITY_LABEL
index 1344f7d475d3c664dc18746ce489a3ae0fcae989..aecda4fc95f5faea7fa5d75643bfe514a3c71120 100644 (file)
@@ -198,6 +198,9 @@ static inline int nilfs_acl_chmod(struct inode *inode)
 
 static inline int nilfs_init_acl(struct inode *inode, struct inode *dir)
 {
+       if (S_ISLNK(inode->i_mode))
+               return 0;
+
        inode->i_mode &= ~current_umask();
        return 0;
 }
index e0a2e0468ee7f1e4bb668df4a9d13cea9d34082b..1ce5c9698393731229d0a083cc1d7b4bad51c1e5 100644 (file)
@@ -1003,6 +1003,9 @@ ovl_posix_acl_xattr_get(const struct xattr_handler *handler,
                        struct dentry *dentry, struct inode *inode,
                        const char *name, void *buffer, size_t size)
 {
+       if (!IS_POSIXACL(inode))
+               return -EOPNOTSUPP;
+
        return ovl_xattr_get(dentry, inode, handler->name, buffer, size);
 }
 
@@ -1018,6 +1021,9 @@ ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
        struct posix_acl *acl = NULL;
        int err;
 
+       if (!IS_POSIXACL(inode))
+               return -EOPNOTSUPP;
+
        /* Check that everything is OK before copy-up */
        if (value) {
                acl = posix_acl_from_xattr(&init_user_ns, value, size);
@@ -1960,6 +1966,20 @@ static struct dentry *ovl_get_root(struct super_block *sb,
        return root;
 }
 
+static bool ovl_has_idmapped_layers(struct ovl_fs *ofs)
+{
+
+       unsigned int i;
+       const struct vfsmount *mnt;
+
+       for (i = 0; i < ofs->numlayer; i++) {
+               mnt = ofs->layers[i].mnt;
+               if (mnt && is_idmapped_mnt(mnt))
+                       return true;
+       }
+       return false;
+}
+
 static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct path upperpath = { };
@@ -2129,7 +2149,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_xattr = ofs->config.userxattr ? ovl_user_xattr_handlers :
                ovl_trusted_xattr_handlers;
        sb->s_fs_info = ofs;
-       sb->s_flags |= SB_POSIXACL;
+       if (ovl_has_idmapped_layers(ofs))
+               pr_warn("POSIX ACLs are not yet supported with idmapped layers, mounting without ACL support.\n");
+       else
+               sb->s_flags |= SB_POSIXACL;
        sb->s_iflags |= SB_I_SKIP_SYNC;
 
        err = -ENOMEM;
index e112b5424cdb9fdfc843fbe8af336c229f786f18..881a306ee2473ddccde84367eadd7701b074403e 100644 (file)
@@ -71,7 +71,8 @@ static int generic_remap_checks(struct file *file_in, loff_t pos_in,
         * Otherwise, make sure the count is also block-aligned, having
         * already confirmed the starting offsets' block alignment.
         */
-       if (pos_in + count == size_in) {
+       if (pos_in + count == size_in &&
+           (!(remap_flags & REMAP_FILE_DEDUP) || pos_out + count == size_out)) {
                bcount = ALIGN(size_in, bs) - pos_in;
        } else {
                if (!IS_ALIGNED(count, bs))
index c6108581d97dc66dd5b3afc94460651d2b9dc510..d389bab54241d75d598940e9aa6a690c58926c5d 100644 (file)
@@ -145,6 +145,7 @@ extern bool cppc_allow_fast_switch(void);
 extern int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data);
 extern unsigned int cppc_get_transition_latency(int cpu);
 extern bool cpc_ffh_supported(void);
+extern bool cpc_supported_by_cpu(void);
 extern int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val);
 extern int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val);
 #else /* !CONFIG_ACPI_CPPC_LIB */
index ff3e82553a76c16baeaf25d00c849bfb5f90b2db..492dce43236eacd41b5f822a5a34ca56623be237 100644 (file)
  *  Useful if your architecture doesn't use IPIs for remote TLB invalidates
  *  and therefore doesn't naturally serialize with software page-table walkers.
  *
+ *  MMU_GATHER_NO_FLUSH_CACHE
+ *
+ *  Indicates the architecture has flush_cache_range() but it needs *NOT* be called
+ *  before unmapping a VMA.
+ *
+ *  NOTE: strictly speaking we shouldn't have this knob and instead rely on
+ *       flush_cache_range() being a NOP, except Sparc64 seems to be
+ *       different here.
+ *
+ *  MMU_GATHER_MERGE_VMAS
+ *
+ *  Indicates the architecture wants to merge ranges over VMAs; typical when
+ *  multiple range invalidates are more expensive than a full invalidate.
+ *
  *  MMU_GATHER_NO_RANGE
  *
- *  Use this if your architecture lacks an efficient flush_tlb_range().
+ *  Use this if your architecture lacks an efficient flush_tlb_range(). This
+ *  option implies MMU_GATHER_MERGE_VMAS above.
  *
  *  MMU_GATHER_NO_GATHER
  *
@@ -288,6 +303,7 @@ struct mmu_gather {
         */
        unsigned int            vma_exec : 1;
        unsigned int            vma_huge : 1;
+       unsigned int            vma_pfn  : 1;
 
        unsigned int            batch_count;
 
@@ -334,8 +350,8 @@ static inline void __tlb_reset_range(struct mmu_gather *tlb)
 
 #ifdef CONFIG_MMU_GATHER_NO_RANGE
 
-#if defined(tlb_flush) || defined(tlb_start_vma) || defined(tlb_end_vma)
-#error MMU_GATHER_NO_RANGE relies on default tlb_flush(), tlb_start_vma() and tlb_end_vma()
+#if defined(tlb_flush)
+#error MMU_GATHER_NO_RANGE relies on default tlb_flush()
 #endif
 
 /*
@@ -352,20 +368,9 @@ static inline void tlb_flush(struct mmu_gather *tlb)
                flush_tlb_mm(tlb->mm);
 }
 
-static inline void
-tlb_update_vma_flags(struct mmu_gather *tlb, struct vm_area_struct *vma) { }
-
-#define tlb_end_vma tlb_end_vma
-static inline void tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) { }
-
 #else /* CONFIG_MMU_GATHER_NO_RANGE */
 
 #ifndef tlb_flush
-
-#if defined(tlb_start_vma) || defined(tlb_end_vma)
-#error Default tlb_flush() relies on default tlb_start_vma() and tlb_end_vma()
-#endif
-
 /*
  * When an architecture does not provide its own tlb_flush() implementation
  * but does have a reasonably efficient flush_vma_range() implementation
@@ -385,6 +390,9 @@ static inline void tlb_flush(struct mmu_gather *tlb)
                flush_tlb_range(&vma, tlb->start, tlb->end);
        }
 }
+#endif
+
+#endif /* CONFIG_MMU_GATHER_NO_RANGE */
 
 static inline void
 tlb_update_vma_flags(struct mmu_gather *tlb, struct vm_area_struct *vma)
@@ -402,17 +410,9 @@ tlb_update_vma_flags(struct mmu_gather *tlb, struct vm_area_struct *vma)
         */
        tlb->vma_huge = is_vm_hugetlb_page(vma);
        tlb->vma_exec = !!(vma->vm_flags & VM_EXEC);
+       tlb->vma_pfn  = !!(vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP));
 }
 
-#else
-
-static inline void
-tlb_update_vma_flags(struct mmu_gather *tlb, struct vm_area_struct *vma) { }
-
-#endif
-
-#endif /* CONFIG_MMU_GATHER_NO_RANGE */
-
 static inline void tlb_flush_mmu_tlbonly(struct mmu_gather *tlb)
 {
        /*
@@ -486,32 +486,36 @@ static inline unsigned long tlb_get_unmap_size(struct mmu_gather *tlb)
  * case where we're doing a full MM flush.  When we're doing a munmap,
  * the vmas are adjusted to only cover the region to be torn down.
  */
-#ifndef tlb_start_vma
 static inline void tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
 {
        if (tlb->fullmm)
                return;
 
        tlb_update_vma_flags(tlb, vma);
+#ifndef CONFIG_MMU_GATHER_NO_FLUSH_CACHE
        flush_cache_range(vma, vma->vm_start, vma->vm_end);
-}
 #endif
+}
 
-#ifndef tlb_end_vma
 static inline void tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
 {
        if (tlb->fullmm)
                return;
 
        /*
-        * Do a TLB flush and reset the range at VMA boundaries; this avoids
-        * the ranges growing with the unused space between consecutive VMAs,
-        * but also the mmu_gather::vma_* flags from tlb_start_vma() rely on
-        * this.
+        * VM_PFNMAP is more fragile because the core mm will not track the
+        * page mapcount -- there might not be page-frames for these PFNs after
+        * all. Force flush TLBs for such ranges to avoid munmap() vs
+        * unmap_mapping_range() races.
         */
-       tlb_flush_mmu_tlbonly(tlb);
+       if (tlb->vma_pfn || !IS_ENABLED(CONFIG_MMU_GATHER_MERGE_VMAS)) {
+               /*
+                * Do a TLB flush and reset the range at VMA boundaries; this avoids
+                * the ranges growing with the unused space between consecutive VMAs.
+                */
+               tlb_flush_mmu_tlbonly(tlb);
+       }
 }
-#endif
 
 /*
  * tlb_flush_{pte|pmd|pud|p4d}_range() adjust the tlb->start and tlb->end,
index 0fca8f38bee4dd85481a4632cb74691e8f5a9610..addb135eeea6227459e5247dfe382f6df239a12e 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/dma-fence.h>
 #include <linux/completion.h>
 #include <linux/xarray.h>
-#include <linux/irq_work.h>
+#include <linux/workqueue.h>
 
 #define MAX_WAIT_SCHED_ENTITY_Q_EMPTY msecs_to_jiffies(1000)
 
@@ -295,7 +295,7 @@ struct drm_sched_job {
         */
        union {
                struct dma_fence_cb             finish_cb;
-               struct irq_work                 work;
+               struct work_struct              work;
        };
 
        uint64_t                        id;
index 4f82a5bc6d987fe9ef1f6ddfb253d9ba0e087fc2..44975c1bbe12f72a6ee579872b1b4bd723c2a738 100644 (file)
@@ -584,7 +584,7 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
 extern bool osc_sb_apei_support_acked;
 extern bool osc_pc_lpi_support_confirmed;
 extern bool osc_sb_native_usb4_support_confirmed;
-extern bool osc_sb_cppc_not_supported;
+extern bool osc_sb_cppc2_support_acked;
 extern bool osc_cpc_flexible_adr_space_confirmed;
 
 /* USB4 Capabilities */
index 1bfcfb1af3524f46388d240a4246218a6b042f6f..d4427d0a0e1872c8c0af741199547957e10397fb 100644 (file)
@@ -264,7 +264,8 @@ struct css_set {
         * List of csets participating in the on-going migration either as
         * source or destination.  Protected by cgroup_mutex.
         */
-       struct list_head mg_preload_node;
+       struct list_head mg_src_preload_node;
+       struct list_head mg_dst_preload_node;
        struct list_head mg_node;
 
        /*
index 2c74773547444e6ab4eb185d8eb62f5e06c6fe65..314802f98b9daadf3b0d7cf346fa0722b50a5b7a 100644 (file)
@@ -68,6 +68,8 @@ extern ssize_t cpu_show_srbds(struct device *dev, struct device_attribute *attr,
 extern ssize_t cpu_show_mmio_stale_data(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf);
+extern ssize_t cpu_show_retbleed(struct device *dev,
+                                struct device_attribute *attr, char *buf);
 
 extern __printf(4, 5)
 struct device *cpu_device_create(struct device *parent, void *drvdata,
index 8419bffb4398f8ce569bacf255fd343b3e02c8fc..b9caa01dfac48594e463e954a3bbd65a5b8ad96e 100644 (file)
@@ -62,7 +62,7 @@ struct em_perf_domain {
 /*
  *  em_perf_domain flags:
  *
- *  EM_PERF_DOMAIN_MILLIWATTS: The power values are in milli-Watts or some
+ *  EM_PERF_DOMAIN_MICROWATTS: The power values are in micro-Watts or some
  *  other scale.
  *
  *  EM_PERF_DOMAIN_SKIP_INEFFICIENCIES: Skip inefficient states when estimating
@@ -71,7 +71,7 @@ struct em_perf_domain {
  *  EM_PERF_DOMAIN_ARTIFICIAL: The power values are artificial and might be
  *  created by platform missing real power information
  */
-#define EM_PERF_DOMAIN_MILLIWATTS BIT(0)
+#define EM_PERF_DOMAIN_MICROWATTS BIT(0)
 #define EM_PERF_DOMAIN_SKIP_INEFFICIENCIES BIT(1)
 #define EM_PERF_DOMAIN_ARTIFICIAL BIT(2)
 
@@ -79,22 +79,44 @@ struct em_perf_domain {
 #define em_is_artificial(em) ((em)->flags & EM_PERF_DOMAIN_ARTIFICIAL)
 
 #ifdef CONFIG_ENERGY_MODEL
-#define EM_MAX_POWER 0xFFFF
+/*
+ * The max power value in micro-Watts. The limit of 64 Watts is set as
+ * a safety net to not overflow multiplications on 32bit platforms. The
+ * 32bit value limit for total Perf Domain power implies a limit of
+ * maximum CPUs in such domain to 64.
+ */
+#define EM_MAX_POWER (64000000) /* 64 Watts */
+
+/*
+ * To avoid possible energy estimation overflow on 32bit machines add
+ * limits to number of CPUs in the Perf. Domain.
+ * We are safe on 64bit machine, thus some big number.
+ */
+#ifdef CONFIG_64BIT
+#define EM_MAX_NUM_CPUS 4096
+#else
+#define EM_MAX_NUM_CPUS 16
+#endif
 
 /*
- * Increase resolution of energy estimation calculations for 64-bit
- * architectures. The extra resolution improves decision made by EAS for the
- * task placement when two Performance Domains might provide similar energy
- * estimation values (w/o better resolution the values could be equal).
+ * To avoid an overflow on 32bit machines while calculating the energy
+ * use a different order in the operation. First divide by the 'cpu_scale'
+ * which would reduce big value stored in the 'cost' field, then multiply by
+ * the 'sum_util'. This would allow to handle existing platforms, which have
+ * e.g. power ~1.3 Watt at max freq, so the 'cost' value > 1mln micro-Watts.
+ * In such scenario, where there are 4 CPUs in the Perf. Domain the 'sum_util'
+ * could be 4096, then multiplication: 'cost' * 'sum_util'  would overflow.
+ * This reordering of operations has some limitations, we lose small
+ * precision in the estimation (comparing to 64bit platform w/o reordering).
  *
- * We increase resolution only if we have enough bits to allow this increased
- * resolution (i.e. 64-bit). The costs for increasing resolution when 32-bit
- * are pretty high and the returns do not justify the increased costs.
+ * We are safe on 64bit machine.
  */
 #ifdef CONFIG_64BIT
-#define em_scale_power(p) ((p) * 1000)
+#define em_estimate_energy(cost, sum_util, scale_cpu) \
+       (((cost) * (sum_util)) / (scale_cpu))
 #else
-#define em_scale_power(p) (p)
+#define em_estimate_energy(cost, sum_util, scale_cpu) \
+       (((cost) / (scale_cpu)) * (sum_util))
 #endif
 
 struct em_data_callback {
@@ -112,7 +134,7 @@ struct em_data_callback {
         * and frequency.
         *
         * In case of CPUs, the power is the one of a single CPU in the domain,
-        * expressed in milli-Watts or an abstract scale. It is expected to
+        * expressed in micro-Watts or an abstract scale. It is expected to
         * fit in the [0, EM_MAX_POWER] range.
         *
         * Return 0 on success.
@@ -148,7 +170,7 @@ struct em_perf_domain *em_cpu_get(int cpu);
 struct em_perf_domain *em_pd_get(struct device *dev);
 int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
                                struct em_data_callback *cb, cpumask_t *span,
-                               bool milliwatts);
+                               bool microwatts);
 void em_dev_unregister_perf_domain(struct device *dev);
 
 /**
@@ -273,7 +295,7 @@ static inline unsigned long em_cpu_energy(struct em_perf_domain *pd,
         *   pd_nrg = ------------------------                       (4)
         *                  scale_cpu
         */
-       return ps->cost * sum_util / scale_cpu;
+       return em_estimate_energy(ps->cost, sum_util, scale_cpu);
 }
 
 /**
@@ -297,7 +319,7 @@ struct em_data_callback {};
 static inline
 int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
                                struct em_data_callback *cb, cpumask_t *span,
-                               bool milliwatts)
+                               bool microwatts)
 {
        return -EINVAL;
 }
index ff5596dd30f85575dc7f6dfcbd2212022e0ea25e..2382dec6d6ab8e0276e8e87489300fa33741dbf5 100644 (file)
@@ -15,6 +15,8 @@ void fbcon_new_modelist(struct fb_info *info);
 void fbcon_get_requirement(struct fb_info *info,
                           struct fb_blit_caps *caps);
 void fbcon_fb_blanked(struct fb_info *info, int blank);
+int  fbcon_modechange_possible(struct fb_info *info,
+                              struct fb_var_screeninfo *var);
 void fbcon_update_vcs(struct fb_info *info, bool all);
 void fbcon_remap_all(struct fb_info *info);
 int fbcon_set_con2fb_map_ioctl(void __user *argp);
@@ -33,6 +35,8 @@ static inline void fbcon_new_modelist(struct fb_info *info) {}
 static inline void fbcon_get_requirement(struct fb_info *info,
                                         struct fb_blit_caps *caps) {}
 static inline void fbcon_fb_blanked(struct fb_info *info, int blank) {}
+static inline int  fbcon_modechange_possible(struct fb_info *info,
+                               struct fb_var_screeninfo *var) { return 0; }
 static inline void fbcon_update_vcs(struct fb_info *info, bool all) {}
 static inline void fbcon_remap_all(struct fb_info *info) {}
 static inline int fbcon_set_con2fb_map_ioctl(void __user *argp) { return 0; }
index 72585c9729a2c4235a6fbcddd962dbd810ea7ea7..b86265664879e9b1c2273d464572d18ce4e8d01d 100644 (file)
@@ -130,6 +130,7 @@ struct fscache_cookie {
 #define FSCACHE_COOKIE_DO_PREP_TO_WRITE        12              /* T if cookie needs write preparation */
 #define FSCACHE_COOKIE_HAVE_DATA       13              /* T if this cookie has data stored */
 #define FSCACHE_COOKIE_IS_HASHED       14              /* T if this cookie is hashed */
+#define FSCACHE_COOKIE_DO_INVALIDATE   15              /* T if cookie needs invalidation */
 
        enum fscache_cookie_state       state;
        u8                              advice;         /* FSCACHE_ADV_* */
index 3af34de54330cbd7dea8747ff6335ff184fc5910..56d6a019653489068be01e9dc260c6606f992368 100644 (file)
@@ -149,19 +149,19 @@ static inline void *kmap_local_folio(struct folio *folio, size_t offset);
  * It is used in atomic context when code wants to access the contents of a
  * page that might be allocated from high memory (see __GFP_HIGHMEM), for
  * example a page in the pagecache.  The API has two functions, and they
- * can be used in a manner similar to the following:
+ * can be used in a manner similar to the following::
  *
- * -- Find the page of interest. --
- * struct page *page = find_get_page(mapping, offset);
+ *   // Find the page of interest.
+ *   struct page *page = find_get_page(mapping, offset);
  *
- * -- Gain access to the contents of that page. --
- * void *vaddr = kmap_atomic(page);
+ *   // Gain access to the contents of that page.
+ *   void *vaddr = kmap_atomic(page);
  *
- * -- Do something to the contents of that page. --
- * memset(vaddr, 0, PAGE_SIZE);
+ *   // Do something to the contents of that page.
+ *   memset(vaddr, 0, PAGE_SIZE);
  *
- * -- Unmap that page. --
- * kunmap_atomic(vaddr);
+ *   // Unmap that page.
+ *   kunmap_atomic(vaddr);
  *
  * Note that the kunmap_atomic() call takes the result of the kmap_atomic()
  * call, not the argument.
index 4f29139bbfc39866c49ed6e0d68532ecb692655e..5fcf89faa31ab4125919767a37cfd6ccc5efbb73 100644 (file)
@@ -612,7 +612,6 @@ struct intel_iommu {
 struct device_domain_info {
        struct list_head link;  /* link to domain siblings */
        struct list_head global; /* link to global list */
-       struct list_head table; /* link to pasid table */
        u32 segment;            /* PCI segment number */
        u8 bus;                 /* PCI bus number */
        u8 devfn;               /* PCI devfn number */
@@ -729,8 +728,6 @@ extern int dmar_ir_support(void);
 void *alloc_pgtable_page(int node);
 void free_pgtable_page(void *vaddr);
 struct intel_iommu *domain_get_iommu(struct dmar_domain *domain);
-int for_each_device_domain(int (*fn)(struct device_domain_info *info,
-                                    void *data), void *data);
 void iommu_flush_write_buffer(struct intel_iommu *iommu);
 int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct device *dev);
 struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn);
index ce6536f1d269970856ecabad52f7a7604f27e210..475683cd67f1620f27aa2d32acb892358e64e047 100644 (file)
@@ -452,6 +452,12 @@ static inline int kexec_crash_loaded(void) { return 0; }
 #define kexec_in_progress false
 #endif /* CONFIG_KEXEC_CORE */
 
+#ifdef CONFIG_KEXEC_SIG
+void set_kexec_sig_enforced(void);
+#else
+static inline void set_kexec_sig_enforced(void) {}
+#endif
+
 #endif /* !defined(__ASSEBMLY__) */
 
 #endif /* LINUX_KEXEC_H */
index c20f2d55840ca0477a0397058bcc954f672edc15..90a45ef7203bdb2a36862516853f8c6b9df3c265 100644 (file)
@@ -1513,7 +1513,7 @@ static inline void kvm_arch_end_assignment(struct kvm *kvm)
 {
 }
 
-static inline bool kvm_arch_has_assigned_device(struct kvm *kvm)
+static __always_inline bool kvm_arch_has_assigned_device(struct kvm *kvm)
 {
        return false;
 }
@@ -1822,6 +1822,15 @@ struct _kvm_stats_desc {
        STATS_DESC_PEAK(SCOPE, name, KVM_STATS_UNIT_NONE,                      \
                KVM_STATS_BASE_POW10, 0)
 
+/* Instantaneous boolean value, read only */
+#define STATS_DESC_IBOOLEAN(SCOPE, name)                                      \
+       STATS_DESC_INSTANT(SCOPE, name, KVM_STATS_UNIT_BOOLEAN,                \
+               KVM_STATS_BASE_POW10, 0)
+/* Peak (sticky) boolean value, read/write */
+#define STATS_DESC_PBOOLEAN(SCOPE, name)                                      \
+       STATS_DESC_PEAK(SCOPE, name, KVM_STATS_UNIT_BOOLEAN,                   \
+               KVM_STATS_BASE_POW10, 0)
+
 /* Cumulative time in nanosecond */
 #define STATS_DESC_TIME_NSEC(SCOPE, name)                                     \
        STATS_DESC_CUMULATIVE(SCOPE, name, KVM_STATS_UNIT_SECONDS,             \
@@ -1853,7 +1862,7 @@ struct _kvm_stats_desc {
                        HALT_POLL_HIST_COUNT),                                 \
        STATS_DESC_LOGHIST_TIME_NSEC(VCPU_GENERIC, halt_wait_hist,             \
                        HALT_POLL_HIST_COUNT),                                 \
-       STATS_DESC_ICOUNTER(VCPU_GENERIC, blocking)
+       STATS_DESC_IBOOLEAN(VCPU_GENERIC, blocking)
 
 extern struct dentry *kvm_debugfs_dir;
 
index e11595256cac006569bc4f0edbe74718667a2a00..c04c4fd2e20919a8e0fb11b753740b4ec4057b46 100644 (file)
@@ -16,7 +16,7 @@ static inline int memregion_alloc(gfp_t gfp)
 {
        return -ENOMEM;
 }
-void memregion_free(int id)
+static inline void memregion_free(int id)
 {
 }
 #endif
index 1773e5df8e65ba3c3e1cd563fc4f3e311ecacaf6..1b18dfa52e48e2c0d733bccc89cd91a13c01c43e 100644 (file)
@@ -214,7 +214,7 @@ struct netfs_request_ops {
        void (*issue_read)(struct netfs_io_subrequest *subreq);
        bool (*is_still_valid)(struct netfs_io_request *rreq);
        int (*check_write_begin)(struct file *file, loff_t pos, unsigned len,
-                                struct folio *folio, void **_fsdata);
+                                struct folio **foliop, void **_fsdata);
        void (*done)(struct netfs_io_request *rreq);
 };
 
index e3934003f2397e02003c42bb6173feb2575d0d42..07cfc922f8e48b8298fc9da04108962e06d2197b 100644 (file)
@@ -906,12 +906,14 @@ struct nvme_common_command {
        __le32                  cdw2[2];
        __le64                  metadata;
        union nvme_data_ptr     dptr;
+       struct_group(cdws,
        __le32                  cdw10;
        __le32                  cdw11;
        __le32                  cdw12;
        __le32                  cdw13;
        __le32                  cdw14;
        __le32                  cdw15;
+       );
 };
 
 struct nvme_rw_command {
index 15b940ec1eac9d72c0f35c34e52d368fe00a5219..10bc88cc3bf6b8bc4865baf006151a4a25383795 100644 (file)
@@ -32,11 +32,16 @@ struct unwind_hint {
  *
  * UNWIND_HINT_FUNC: Generate the unwind metadata of a callable function.
  * Useful for code which doesn't have an ELF function annotation.
+ *
+ * UNWIND_HINT_ENTRY: machine entry without stack, SYSCALL/SYSENTER etc.
  */
 #define UNWIND_HINT_TYPE_CALL          0
 #define UNWIND_HINT_TYPE_REGS          1
 #define UNWIND_HINT_TYPE_REGS_PARTIAL  2
 #define UNWIND_HINT_TYPE_FUNC          3
+#define UNWIND_HINT_TYPE_ENTRY         4
+#define UNWIND_HINT_TYPE_SAVE          5
+#define UNWIND_HINT_TYPE_RESTORE       6
 
 #ifdef CONFIG_OBJTOOL
 
@@ -124,7 +129,7 @@ struct unwind_hint {
  * the debuginfo as necessary.  It will also warn if it sees any
  * inconsistencies.
  */
-.macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
 .Lunwind_hint_ip_\@:
        .pushsection .discard.unwind_hints
                /* struct unwind_hint */
@@ -177,7 +182,7 @@ struct unwind_hint {
 #define ASM_REACHABLE
 #else
 #define ANNOTATE_INTRA_FUNCTION_CALL
-.macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
 .endm
 .macro STACK_FRAME_NON_STANDARD func:req
 .endm
index 9e4d056967c6618aad1885f21fbaef388a580e25..0a41b2dcccad545ecda628951a11713ba671e627 100644 (file)
@@ -88,7 +88,7 @@ extern void pm_runtime_get_suppliers(struct device *dev);
 extern void pm_runtime_put_suppliers(struct device *dev);
 extern void pm_runtime_new_link(struct device *dev);
 extern void pm_runtime_drop_link(struct device_link *link);
-extern void pm_runtime_release_supplier(struct device_link *link, bool check_idle);
+extern void pm_runtime_release_supplier(struct device_link *link);
 
 extern int devm_pm_runtime_enable(struct device *dev);
 
@@ -314,8 +314,7 @@ static inline void pm_runtime_get_suppliers(struct device *dev) {}
 static inline void pm_runtime_put_suppliers(struct device *dev) {}
 static inline void pm_runtime_new_link(struct device *dev) {}
 static inline void pm_runtime_drop_link(struct device_link *link) {}
-static inline void pm_runtime_release_supplier(struct device_link *link,
-                                              bool check_idle) {}
+static inline void pm_runtime_release_supplier(struct device_link *link) {}
 
 #endif /* !CONFIG_PM */
 
index 196a157456aa8154caeba618b08de8c80d4528a9..77f4849e34189c1d69e16367d7f9e6c1a14336f0 100644 (file)
@@ -109,7 +109,6 @@ extern struct wakeup_source *wakeup_sources_walk_next(struct wakeup_source *ws);
 extern int device_wakeup_enable(struct device *dev);
 extern int device_wakeup_disable(struct device *dev);
 extern void device_set_wakeup_capable(struct device *dev, bool capable);
-extern int device_init_wakeup(struct device *dev, bool val);
 extern int device_set_wakeup_enable(struct device *dev, bool enable);
 extern void __pm_stay_awake(struct wakeup_source *ws);
 extern void pm_stay_awake(struct device *dev);
@@ -167,13 +166,6 @@ static inline int device_set_wakeup_enable(struct device *dev, bool enable)
        return 0;
 }
 
-static inline int device_init_wakeup(struct device *dev, bool val)
-{
-       device_set_wakeup_capable(dev, val);
-       device_set_wakeup_enable(dev, val);
-       return 0;
-}
-
 static inline bool device_may_wakeup(struct device *dev)
 {
        return dev->power.can_wakeup && dev->power.should_wakeup;
@@ -217,4 +209,27 @@ static inline void pm_wakeup_hard_event(struct device *dev)
        return pm_wakeup_dev_event(dev, 0, true);
 }
 
+/**
+ * device_init_wakeup - Device wakeup initialization.
+ * @dev: Device to handle.
+ * @enable: Whether or not to enable @dev as a wakeup device.
+ *
+ * By default, most devices should leave wakeup disabled.  The exceptions are
+ * devices that everyone expects to be wakeup sources: keyboards, power buttons,
+ * possibly network interfaces, etc.  Also, devices that don't generate their
+ * own wakeup requests but merely forward requests from one bus to another
+ * (like PCI bridges) should have wakeup enabled by default.
+ */
+static inline int device_init_wakeup(struct device *dev, bool enable)
+{
+       if (enable) {
+               device_set_wakeup_capable(dev, true);
+               return device_wakeup_enable(dev);
+       } else {
+               device_wakeup_disable(dev);
+               device_set_wakeup_capable(dev, false);
+               return 0;
+       }
+}
+
 #endif /* _LINUX_PM_WAKEUP_H */
index 8a21b5756c3efba8e1b788cdc5e9ff65e774d341..514ddf003efc772a6043f8042c09da322c4f3c55 100644 (file)
@@ -731,7 +731,7 @@ static inline int __must_check
 devm_reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs,
                                               struct reset_control_bulk_data *rstcs)
 {
-       return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, true);
+       return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, true);
 }
 
 /**
index 159729cffd8e113e4d9b27534f56adb0a07c1d9f..3247ed8e9ff0fb2c5571d6dd55e1845b3125fc0c 100644 (file)
@@ -54,8 +54,6 @@ struct rtsx_ucr {
        struct usb_device       *pusb_dev;
        struct usb_interface    *pusb_intf;
        struct usb_sg_request   current_sg;
-       unsigned char           *iobuf;
-       dma_addr_t              iobuf_dma;
 
        struct timer_list       sg_timer;
        struct mutex            dev_mutex;
index 505aaf9fe4777288ed37d280b7ebf9b1619faaf6..81cab4b01edcb1bb9f40edf2e88de83b207e40f9 100644 (file)
@@ -85,7 +85,7 @@ static inline void exit_thread(struct task_struct *tsk)
 extern __noreturn void do_group_exit(int);
 
 extern void exit_files(struct task_struct *);
-extern void exit_itimers(struct signal_struct *);
+extern void exit_itimers(struct task_struct *);
 
 extern pid_t kernel_clone(struct kernel_clone_args *kargs);
 struct task_struct *create_io_thread(int (*fn)(void *), void *arg, int node);
index 704111f63993739f48d0dda2efd8728ab527122c..a0a246310ba10a65af1d2dcfe57cf6c3d9a93b3a 100644 (file)
@@ -60,6 +60,12 @@ struct scmi_clock_info {
        };
 };
 
+enum scmi_power_scale {
+       SCMI_POWER_BOGOWATTS,
+       SCMI_POWER_MILLIWATTS,
+       SCMI_POWER_MICROWATTS
+};
+
 struct scmi_handle;
 struct scmi_device;
 struct scmi_protocol_handle;
@@ -135,7 +141,7 @@ struct scmi_perf_proto_ops {
                             unsigned long *rate, unsigned long *power);
        bool (*fast_switch_possible)(const struct scmi_protocol_handle *ph,
                                     struct device *dev);
-       bool (*power_scale_mw_get)(const struct scmi_protocol_handle *ph);
+       enum scmi_power_scale (*power_scale_get)(const struct scmi_protocol_handle *ph);
 };
 
 /**
index 657a0fc68a3fbdacf99e34f86b32e2f0a8d4794f..fde258b3decd502110cff11811ed4e2fb66cbdbb 100644 (file)
@@ -390,6 +390,11 @@ static const bool earlycon_acpi_spcr_enable EARLYCON_USED_OR_UNUSED;
 static inline int setup_earlycon(char *buf) { return 0; }
 #endif
 
+static inline bool uart_console_enabled(struct uart_port *port)
+{
+       return uart_console(port) && (port->cons->flags & CON_ENABLED);
+}
+
 struct uart_port *uart_get_console(struct uart_port *ports, int nr,
                                   struct console *c);
 int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
index 29917850f07946b57dfdbd8c5063220c547d5d5d..8df475db88c040456e887696ac725f1b50451c69 100644 (file)
@@ -260,6 +260,7 @@ struct plat_stmmacenet_data {
        bool has_crossts;
        int int_snapshot_num;
        int ext_snapshot_num;
+       bool int_snapshot_en;
        bool ext_snapshot_en;
        bool multi_msi_en;
        int msi_mac_vec;
index 0e40c3d64fcf4228e5d90678aa1c1daafe644725..08fc30cf2f34c48c8826cd96be07fb7c753580f7 100644 (file)
@@ -78,6 +78,15 @@ enum amt_status {
 
 #define AMT_STATUS_MAX (__AMT_STATUS_MAX - 1)
 
+/* Gateway events only */
+enum amt_event {
+       AMT_EVENT_NONE,
+       AMT_EVENT_RECEIVE,
+       AMT_EVENT_SEND_DISCOVERY,
+       AMT_EVENT_SEND_REQUEST,
+       __AMT_EVENT_MAX,
+};
+
 struct amt_header {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
        u8 type:4,
@@ -292,6 +301,12 @@ struct amt_group_node {
        struct hlist_head       sources[];
 };
 
+#define AMT_MAX_EVENTS 16
+struct amt_events {
+       enum amt_event event;
+       struct sk_buff *skb;
+};
+
 struct amt_dev {
        struct net_device       *dev;
        struct net_device       *stream_dev;
@@ -308,6 +323,7 @@ struct amt_dev {
        struct delayed_work     req_wq;
        /* Protected by RTNL */
        struct delayed_work     secret_wq;
+       struct work_struct      event_wq;
        /* AMT status */
        enum amt_status         status;
        /* Generated key */
@@ -345,6 +361,10 @@ struct amt_dev {
        /* Used only in gateway mode */
        u64                     mac:48,
                                reserved:16;
+       /* AMT gateway side message handler queue */
+       struct amt_events       events[AMT_MAX_EVENTS];
+       u8                      event_idx;
+       u8                      nr_events;
 };
 
 #define AMT_TOS                        0xc0
index 6d02e12e4702e91f915136e5cceb15af86da9dce..80f41446b1f0e7302dd39cc8e12267eda9850133 100644 (file)
@@ -8462,11 +8462,12 @@ int cfg80211_bss_color_notify(struct net_device *dev, gfp_t gfp,
  * cfg80211_obss_color_collision_notify - notify about bss color collision
  * @dev: network device
  * @color_bitmap: representations of the colors that the local BSS is aware of
+ * @gfp: allocation flags
  */
 static inline int cfg80211_obss_color_collision_notify(struct net_device *dev,
-                                                      u64 color_bitmap)
+                                                      u64 color_bitmap, gfp_t gfp)
 {
-       return cfg80211_bss_color_notify(dev, GFP_KERNEL,
+       return cfg80211_bss_color_notify(dev, gfp,
                                         NL80211_CMD_OBSS_COLOR_COLLISION,
                                         0, color_bitmap);
 }
index 6484095a8c011681ffbb5898adceecb4902c5255..7ac313858037aebe2c2b89fdb8c26c5785748d30 100644 (file)
@@ -152,6 +152,7 @@ enum flow_action_id {
        FLOW_ACTION_PIPE,
        FLOW_ACTION_VLAN_PUSH_ETH,
        FLOW_ACTION_VLAN_POP_ETH,
+       FLOW_ACTION_CONTINUE,
        NUM_FLOW_ACTIONS,
 };
 
index ebfa3df6f8dc365b4ce5f4c4fb573c37193492ab..fd6b510d114bc103b08c932521998ed25e0c51af 100644 (file)
@@ -179,7 +179,7 @@ static inline bool inet_sk_bound_dev_eq(struct net *net, int bound_dev_if,
                                        int dif, int sdif)
 {
 #if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
-       return inet_bound_dev_eq(!!net->ipv4.sysctl_tcp_l3mdev_accept,
+       return inet_bound_dev_eq(!!READ_ONCE(net->ipv4.sysctl_tcp_l3mdev_accept),
                                 bound_dev_if, dif, sdif);
 #else
        return inet_bound_dev_eq(true, bound_dev_if, dif, sdif);
index daead5fb389aea689637a447370739cd910b5248..6395f6b9a5d299115eb472bf5dfa20fe2768f0ad 100644 (file)
@@ -107,7 +107,8 @@ static inline struct inet_request_sock *inet_rsk(const struct request_sock *sk)
 
 static inline u32 inet_request_mark(const struct sock *sk, struct sk_buff *skb)
 {
-       if (!sk->sk_mark && sock_net(sk)->ipv4.sysctl_tcp_fwmark_accept)
+       if (!sk->sk_mark &&
+           READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fwmark_accept))
                return skb->mark;
 
        return sk->sk_mark;
@@ -120,7 +121,7 @@ static inline int inet_request_bound_dev_if(const struct sock *sk,
 #ifdef CONFIG_NET_L3_MASTER_DEV
        struct net *net = sock_net(sk);
 
-       if (!bound_dev_if && net->ipv4.sysctl_tcp_l3mdev_accept)
+       if (!bound_dev_if && READ_ONCE(net->ipv4.sysctl_tcp_l3mdev_accept))
                return l3mdev_master_ifindex_by_index(net, skb->skb_iif);
 #endif
 
@@ -132,7 +133,7 @@ static inline int inet_sk_bound_l3mdev(const struct sock *sk)
 #ifdef CONFIG_NET_L3_MASTER_DEV
        struct net *net = sock_net(sk);
 
-       if (!net->ipv4.sysctl_tcp_l3mdev_accept)
+       if (!READ_ONCE(net->ipv4.sysctl_tcp_l3mdev_accept))
                return l3mdev_master_ifindex_by_index(net,
                                                      sk->sk_bound_dev_if);
 #endif
@@ -374,7 +375,7 @@ static inline bool inet_get_convert_csum(struct sock *sk)
 static inline bool inet_can_nonlocal_bind(struct net *net,
                                          struct inet_sock *inet)
 {
-       return net->ipv4.sysctl_ip_nonlocal_bind ||
+       return READ_ONCE(net->ipv4.sysctl_ip_nonlocal_bind) ||
                inet->freebind || inet->transparent;
 }
 
index 26fffda78cca4af03f0cfc8194f34b16d99a2fc7..1c979fd1904ce371d372ce42f3359fa277202295 100644 (file)
@@ -357,7 +357,7 @@ static inline bool sysctl_dev_name_is_allowed(const char *name)
 
 static inline bool inet_port_requires_bind_service(struct net *net, unsigned short port)
 {
-       return port < net->ipv4.sysctl_ip_prot_sock;
+       return port < READ_ONCE(net->ipv4.sysctl_ip_prot_sock);
 }
 
 #else
@@ -384,7 +384,7 @@ void ipfrag_init(void);
 void ip_static_sysctl_init(void);
 
 #define IP4_REPLY_MARK(net, mark) \
-       ((net)->ipv4.sysctl_fwmark_reflect ? (mark) : 0)
+       (READ_ONCE((net)->ipv4.sysctl_fwmark_reflect) ? (mark) : 0)
 
 static inline bool ip_is_fragment(const struct iphdr *iph)
 {
@@ -446,7 +446,7 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst,
        struct net *net = dev_net(dst->dev);
        unsigned int mtu;
 
-       if (net->ipv4.sysctl_ip_fwd_use_pmtu ||
+       if (READ_ONCE(net->ipv4.sysctl_ip_fwd_use_pmtu) ||
            ip_mtu_locked(dst) ||
            !forwarding) {
                mtu = rt->rt_pmtu;
index ebadb21039686b3103a01b65f96c867f35ee1056..47642b020706b04334ae505beeaee9ae7c2b8171 100644 (file)
@@ -6960,10 +6960,11 @@ ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw,
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @color_bitmap: a 64 bit bitmap representing the colors that the local BSS is
  *     aware of.
+ * @gfp: allocation flags
  */
 void
 ieeee80211_obss_color_collision_notify(struct ieee80211_vif *vif,
-                                      u64 color_bitmap);
+                                      u64 color_bitmap, gfp_t gfp);
 
 /**
  * ieee80211_is_tx_data - check if frame is a data frame
index 5c4e5a96a984fdb2c9b89760202311dde4da62d1..64cf655c818cc6e0a4c9c80c21021719ddf218e8 100644 (file)
@@ -657,18 +657,22 @@ static inline void nft_set_ext_prepare(struct nft_set_ext_tmpl *tmpl)
        tmpl->len = sizeof(struct nft_set_ext);
 }
 
-static inline void nft_set_ext_add_length(struct nft_set_ext_tmpl *tmpl, u8 id,
-                                         unsigned int len)
+static inline int nft_set_ext_add_length(struct nft_set_ext_tmpl *tmpl, u8 id,
+                                        unsigned int len)
 {
        tmpl->len        = ALIGN(tmpl->len, nft_set_ext_types[id].align);
-       BUG_ON(tmpl->len > U8_MAX);
+       if (tmpl->len > U8_MAX)
+               return -EINVAL;
+
        tmpl->offset[id] = tmpl->len;
        tmpl->len       += nft_set_ext_types[id].len + len;
+
+       return 0;
 }
 
-static inline void nft_set_ext_add(struct nft_set_ext_tmpl *tmpl, u8 id)
+static inline int nft_set_ext_add(struct nft_set_ext_tmpl *tmpl, u8 id)
 {
-       nft_set_ext_add_length(tmpl, id, 0);
+       return nft_set_ext_add_length(tmpl, id, 0);
 }
 
 static inline void nft_set_ext_init(struct nft_set_ext *ext,
index f51c06ae365f5b6cc114d737c2d8f2611b74560a..6aef8cb11cc8c409e5f7a2519f5e747be584c8d5 100644 (file)
@@ -35,8 +35,6 @@
 
 /* This is used to register protocols. */
 struct net_protocol {
-       int                     (*early_demux)(struct sk_buff *skb);
-       int                     (*early_demux_handler)(struct sk_buff *skb);
        int                     (*handler)(struct sk_buff *skb);
 
        /* This returns an error if we weren't able to handle the error. */
@@ -52,8 +50,6 @@ struct net_protocol {
 
 #if IS_ENABLED(CONFIG_IPV6)
 struct inet6_protocol {
-       void    (*early_demux)(struct sk_buff *skb);
-       void    (*early_demux_handler)(struct sk_buff *skb);
        int     (*handler)(struct sk_buff *skb);
 
        /* This returns an error if we weren't able to handle the error. */
index 8ad8df5948536483c3467bff68ec0796b0712e67..c51a635671a73d57a4ad9f20fdebdafedf77116e 100644 (file)
@@ -75,7 +75,7 @@ static inline bool raw_sk_bound_dev_eq(struct net *net, int bound_dev_if,
                                       int dif, int sdif)
 {
 #if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
-       return inet_bound_dev_eq(!!net->ipv4.sysctl_raw_l3mdev_accept,
+       return inet_bound_dev_eq(READ_ONCE(net->ipv4.sysctl_raw_l3mdev_accept),
                                 bound_dev_if, dif, sdif);
 #else
        return inet_bound_dev_eq(true, bound_dev_if, dif, sdif);
index 991a3985712dcb555ff3bd08f15e7f5dad4d1469..bbcf2aba149f9529c8fdabd754161beeef86b525 100644 (file)
@@ -373,7 +373,7 @@ static inline int ip4_dst_hoplimit(const struct dst_entry *dst)
        struct net *net = dev_net(dst->dev);
 
        if (hoplimit == 0)
-               hoplimit = net->ipv4.sysctl_ip_default_ttl;
+               hoplimit = READ_ONCE(net->ipv4.sysctl_ip_default_ttl);
        return hoplimit;
 }
 
index 72ca97ccb46072491179c1225f4e8bab85a7994f..9fa54762e07752313a181fec44df21794cdfc982 100644 (file)
@@ -1529,7 +1529,7 @@ void __sk_mem_reclaim(struct sock *sk, int amount);
 /* sysctl_mem values are in pages, we convert them in SK_MEM_QUANTUM units */
 static inline long sk_prot_mem_limits(const struct sock *sk, int index)
 {
-       long val = sk->sk_prot->sysctl_mem[index];
+       long val = READ_ONCE(sk->sk_prot->sysctl_mem[index]);
 
 #if PAGE_SIZE > SK_MEM_QUANTUM
        val <<= PAGE_SHIFT - SK_MEM_QUANTUM_SHIFT;
index 1e99f5c61f8499c121a9fc50643db559a6021a38..071735e10872c1d6cf603f4673f7a20965fb3a7c 100644 (file)
@@ -932,7 +932,7 @@ extern const struct inet_connection_sock_af_ops ipv6_specific;
 
 INDIRECT_CALLABLE_DECLARE(void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb));
 INDIRECT_CALLABLE_DECLARE(int tcp_v6_rcv(struct sk_buff *skb));
-INDIRECT_CALLABLE_DECLARE(void tcp_v6_early_demux(struct sk_buff *skb));
+void tcp_v6_early_demux(struct sk_buff *skb);
 
 #endif
 
@@ -1403,8 +1403,8 @@ static inline void tcp_slow_start_after_idle_check(struct sock *sk)
        struct tcp_sock *tp = tcp_sk(sk);
        s32 delta;
 
-       if (!sock_net(sk)->ipv4.sysctl_tcp_slow_start_after_idle || tp->packets_out ||
-           ca_ops->cong_control)
+       if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_slow_start_after_idle) ||
+           tp->packets_out || ca_ops->cong_control)
                return;
        delta = tcp_jiffies32 - tp->lsndtime;
        if (delta > inet_csk(sk)->icsk_rto)
@@ -1493,21 +1493,24 @@ static inline int keepalive_intvl_when(const struct tcp_sock *tp)
 {
        struct net *net = sock_net((struct sock *)tp);
 
-       return tp->keepalive_intvl ? : net->ipv4.sysctl_tcp_keepalive_intvl;
+       return tp->keepalive_intvl ? :
+               READ_ONCE(net->ipv4.sysctl_tcp_keepalive_intvl);
 }
 
 static inline int keepalive_time_when(const struct tcp_sock *tp)
 {
        struct net *net = sock_net((struct sock *)tp);
 
-       return tp->keepalive_time ? : net->ipv4.sysctl_tcp_keepalive_time;
+       return tp->keepalive_time ? :
+               READ_ONCE(net->ipv4.sysctl_tcp_keepalive_time);
 }
 
 static inline int keepalive_probes(const struct tcp_sock *tp)
 {
        struct net *net = sock_net((struct sock *)tp);
 
-       return tp->keepalive_probes ? : net->ipv4.sysctl_tcp_keepalive_probes;
+       return tp->keepalive_probes ? :
+               READ_ONCE(net->ipv4.sysctl_tcp_keepalive_probes);
 }
 
 static inline u32 keepalive_time_elapsed(const struct tcp_sock *tp)
@@ -1520,7 +1523,8 @@ static inline u32 keepalive_time_elapsed(const struct tcp_sock *tp)
 
 static inline int tcp_fin_time(const struct sock *sk)
 {
-       int fin_timeout = tcp_sk(sk)->linger2 ? : sock_net(sk)->ipv4.sysctl_tcp_fin_timeout;
+       int fin_timeout = tcp_sk(sk)->linger2 ? :
+               READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fin_timeout);
        const int rto = inet_csk(sk)->icsk_rto;
 
        if (fin_timeout < (rto << 2) - (rto >> 1))
@@ -2023,7 +2027,7 @@ void __tcp_v4_send_check(struct sk_buff *skb, __be32 saddr, __be32 daddr);
 static inline u32 tcp_notsent_lowat(const struct tcp_sock *tp)
 {
        struct net *net = sock_net((struct sock *)tp);
-       return tp->notsent_lowat ?: net->ipv4.sysctl_tcp_notsent_lowat;
+       return tp->notsent_lowat ?: READ_ONCE(net->ipv4.sysctl_tcp_notsent_lowat);
 }
 
 bool tcp_stream_memory_free(const struct sock *sk, int wake);
index 8017f1703447c1abbf48d9f7865b7427b7a2f81d..8bd938f98bdd8fa0f21d173763904c573239f4dc 100644 (file)
@@ -704,7 +704,7 @@ int tls_sw_fallback_init(struct sock *sk,
                         struct tls_crypto_info *crypto_info);
 
 #ifdef CONFIG_TLS_DEVICE
-void tls_device_init(void);
+int tls_device_init(void);
 void tls_device_cleanup(void);
 void tls_device_sk_destruct(struct sock *sk);
 int tls_set_device_offload(struct sock *sk, struct tls_context *ctx);
@@ -724,7 +724,7 @@ static inline bool tls_is_sk_rx_device_offloaded(struct sock *sk)
        return tls_get_ctx(sk)->rx_conf == TLS_HW;
 }
 #else
-static inline void tls_device_init(void) {}
+static inline int tls_device_init(void) { return 0; }
 static inline void tls_device_cleanup(void) {}
 
 static inline int
index b83a003305667d1c1cd1bac00580fec9164958b0..8dd4aa1485a695472fc0413e8b285fe81a940767 100644 (file)
@@ -167,7 +167,7 @@ static inline void udp_csum_pull_header(struct sk_buff *skb)
 typedef struct sock *(*udp_lookup_t)(const struct sk_buff *skb, __be16 sport,
                                     __be16 dport);
 
-INDIRECT_CALLABLE_DECLARE(void udp_v6_early_demux(struct sk_buff *));
+void udp_v6_early_demux(struct sk_buff *skb);
 INDIRECT_CALLABLE_DECLARE(int udpv6_rcv(struct sk_buff *));
 
 struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
@@ -238,7 +238,7 @@ static inline bool udp_sk_bound_dev_eq(struct net *net, int bound_dev_if,
                                       int dif, int sdif)
 {
 #if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
-       return inet_bound_dev_eq(!!net->ipv4.sysctl_udp_l3mdev_accept,
+       return inet_bound_dev_eq(!!READ_ONCE(net->ipv4.sysctl_udp_l3mdev_accept),
                                 bound_dev_if, dif, sdif);
 #else
        return inet_bound_dev_eq(true, bound_dev_if, dif, sdif);
index f20f5f890794ab8b051b8cb7c5c7a16ce0b6afce..b276dcb5d4e8b1f827ab52c9773ea90c228f484a 100644 (file)
@@ -408,8 +408,6 @@ struct snd_soc_jack_pin;
 
 struct snd_soc_jack_gpio;
 
-typedef int (*hw_write_t)(void *,const char* ,int);
-
 enum snd_soc_pcm_subclass {
        SND_SOC_PCM_CLASS_PCM   = 0,
        SND_SOC_PCM_CLASS_BE    = 1,
index e282ce02fa2d60546b557a3f81de9b101273507a..6d1626e7a4ce17905a585ea16a8e304cede7626b 100644 (file)
@@ -160,7 +160,7 @@ TRACE_EVENT(iocost_ioc_vrate_adj,
 
        TP_fast_assign(
                __assign_str(devname, ioc_name(ioc));
-               __entry->old_vrate = atomic64_read(&ioc->vtime_rate);;
+               __entry->old_vrate = atomic64_read(&ioc->vtime_rate);
                __entry->new_vrate = new_vrate;
                __entry->busy_level = ioc->busy_level;
                __entry->read_missed_ppm = missed_ppm[READ];
index af5018aa951775337fcd5be1b883def0bf52c62a..c708521e4ed5d683f624da5071d3ff9b83c8e90c 100644 (file)
@@ -500,6 +500,35 @@ DEFINE_EVENT(dev_pm_qos_request, dev_pm_qos_remove_request,
 
        TP_ARGS(name, type, new_value)
 );
+
+TRACE_EVENT(guest_halt_poll_ns,
+
+       TP_PROTO(bool grow, unsigned int new, unsigned int old),
+
+       TP_ARGS(grow, new, old),
+
+       TP_STRUCT__entry(
+               __field(bool, grow)
+               __field(unsigned int, new)
+               __field(unsigned int, old)
+       ),
+
+       TP_fast_assign(
+               __entry->grow   = grow;
+               __entry->new    = new;
+               __entry->old    = old;
+       ),
+
+       TP_printk("halt_poll_ns %u (%s %u)",
+               __entry->new,
+               __entry->grow ? "grow" : "shrink",
+               __entry->old)
+);
+
+#define trace_guest_halt_poll_ns_grow(new, old) \
+       trace_guest_halt_poll_ns(true, new, old)
+#define trace_guest_halt_poll_ns_shrink(new, old) \
+       trace_guest_halt_poll_ns(false, new, old)
 #endif /* _TRACE_POWER_H */
 
 /* This part must be outside protection */
index 12c315782766a6f9ad227dd59a3c4e968e023819..777ee6cbe93302b53ffeabe1cd1394ebb1284726 100644 (file)
@@ -98,7 +98,7 @@ TRACE_EVENT(sock_exceed_buf_limit,
 
        TP_STRUCT__entry(
                __array(char, name, 32)
-               __field(long *, sysctl_mem)
+               __array(long, sysctl_mem, 3)
                __field(long, allocated)
                __field(int, sysctl_rmem)
                __field(int, rmem_alloc)
@@ -110,7 +110,9 @@ TRACE_EVENT(sock_exceed_buf_limit,
 
        TP_fast_assign(
                strncpy(__entry->name, prot->name, 32);
-               __entry->sysctl_mem = prot->sysctl_mem;
+               __entry->sysctl_mem[0] = READ_ONCE(prot->sysctl_mem[0]);
+               __entry->sysctl_mem[1] = READ_ONCE(prot->sysctl_mem[1]);
+               __entry->sysctl_mem[2] = READ_ONCE(prot->sysctl_mem[2]);
                __entry->allocated = allocated;
                __entry->sysctl_rmem = sk_get_rmem0(sk, prot);
                __entry->rmem_alloc = atomic_read(&sk->sk_rmem_alloc);
index f4009dbdf62daf493beb22e4cbf5befc85a85137..ef78e0e1a75492002824871291648b8e0db8b776 100644 (file)
@@ -5222,22 +5222,25 @@ union bpf_attr {
  *     Return
  *             Nothing. Always succeeds.
  *
- * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset)
+ * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset, u64 flags)
  *     Description
  *             Read *len* bytes from *src* into *dst*, starting from *offset*
  *             into *src*.
+ *             *flags* is currently unused.
  *     Return
  *             0 on success, -E2BIG if *offset* + *len* exceeds the length
- *             of *src*'s data, -EINVAL if *src* is an invalid dynptr.
+ *             of *src*'s data, -EINVAL if *src* is an invalid dynptr or if
+ *             *flags* is not 0.
  *
- * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len)
+ * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len, u64 flags)
  *     Description
  *             Write *len* bytes from *src* into *dst*, starting from *offset*
  *             into *dst*.
+ *             *flags* is currently unused.
  *     Return
  *             0 on success, -E2BIG if *offset* + *len* exceeds the length
  *             of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst*
- *             is a read-only dynptr.
+ *             is a read-only dynptr or if *flags* is not 0.
  *
  * void *bpf_dynptr_data(struct bpf_dynptr *ptr, u32 offset, u32 len)
  *     Description
index ef4257ab30265c67940b2d7a06fc237d776dee80..2557eb7b056178b2b8be98d9cea855eba1bd5aaf 100644 (file)
@@ -78,10 +78,13 @@ struct input_id {
  * Note that input core does not clamp reported values to the
  * [minimum, maximum] limits, such task is left to userspace.
  *
- * The default resolution for main axes (ABS_X, ABS_Y, ABS_Z)
- * is reported in units per millimeter (units/mm), resolution
- * for rotational axes (ABS_RX, ABS_RY, ABS_RZ) is reported
- * in units per radian.
+ * The default resolution for main axes (ABS_X, ABS_Y, ABS_Z,
+ * ABS_MT_POSITION_X, ABS_MT_POSITION_Y) is reported in units
+ * per millimeter (units/mm), resolution for rotational axes
+ * (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian.
+ * The resolution for the size axes (ABS_MT_TOUCH_MAJOR,
+ * ABS_MT_TOUCH_MINOR, ABS_MT_WIDTH_MAJOR, ABS_MT_WIDTH_MINOR)
+ * is reported in units per millimeter (units/mm).
  * When INPUT_PROP_ACCELEROMETER is set the resolution changes.
  * The main axes (ABS_X, ABS_Y, ABS_Z) are then reported in
  * units per g (units/g) and in units per degree per second
index f10b59d6693e310b7024431b20a807dead16497e..0ad3da28d2fce870982d6a175de4086695bffbe0 100644 (file)
@@ -22,7 +22,10 @@ struct io_uring_sqe {
        union {
                __u64   off;    /* offset into file */
                __u64   addr2;
-               __u32   cmd_op;
+               struct {
+                       __u32   cmd_op;
+                       __u32   __pad1;
+               };
        };
        union {
                __u64   addr;   /* pointer to buffer or iovecs */
index 5088bd9f1922851fb62ea7562ccbeb6b64eeed02..860f867c50c0e292fa31ac41388ce2bf50dab97e 100644 (file)
@@ -2083,7 +2083,8 @@ struct kvm_stats_header {
 #define KVM_STATS_UNIT_BYTES           (0x1 << KVM_STATS_UNIT_SHIFT)
 #define KVM_STATS_UNIT_SECONDS         (0x2 << KVM_STATS_UNIT_SHIFT)
 #define KVM_STATS_UNIT_CYCLES          (0x3 << KVM_STATS_UNIT_SHIFT)
-#define KVM_STATS_UNIT_MAX             KVM_STATS_UNIT_CYCLES
+#define KVM_STATS_UNIT_BOOLEAN         (0x4 << KVM_STATS_UNIT_SHIFT)
+#define KVM_STATS_UNIT_MAX             KVM_STATS_UNIT_BOOLEAN
 
 #define KVM_STATS_BASE_SHIFT           8
 #define KVM_STATS_BASE_MASK            (0xF << KVM_STATS_BASE_SHIFT)
index 9d0f06bfbac3e4783dca45b30d98720dfe87f0ae..68aeae2addeca00db3fb162488db15be3ebdbb0c 100644 (file)
@@ -38,8 +38,9 @@
 #define N_NULL         27      /* Null ldisc used for error handling */
 #define N_MCTP         28      /* MCTP-over-serial */
 #define N_DEVELOPMENT  29      /* Manual out-of-tree testing */
+#define N_CAN327       30      /* ELM327 based OBD-II interfaces */
 
 /* Always the newest line discipline + 1 */
-#define NR_LDISCS      30
+#define NR_LDISCS      31
 
 #endif /* _UAPI_LINUX_TTY_H */
index e1126a74882a5f0d0d1678d59c77cf998addb76c..eff166fdd81b95d1e8f284e9fd907ab08f63bc38 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef __LINUX_OF_DISPLAY_TIMING_H
 #define __LINUX_OF_DISPLAY_TIMING_H
 
+#include <linux/errno.h>
+
 struct device_node;
 struct display_timing;
 struct display_timings;
index 754f3237194aa2e7f80a0fabaaf0d375d9623d72..e1fcaedba4fae0768b5b5379b627d431232e0c72 100644 (file)
@@ -64,7 +64,7 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
                goto fail_put;
 
        if (!setup_ipc_sysctls(ns))
-               goto fail_put;
+               goto fail_mq;
 
        sem_init_ns(ns);
        msg_init_ns(ns);
@@ -72,6 +72,9 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
 
        return ns;
 
+fail_mq:
+       retire_mq_sysctls(ns);
+
 fail_put:
        put_user_ns(ns->user_ns);
        ns_free_inum(&ns->ns);
index 5f6f3f829b368aca466b07772a2938629ecb600f..e7961508a47d9c6b5884efb14628909cbed0af97 100644 (file)
@@ -68,11 +68,13 @@ void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, int k, uns
 {
        u8 *ptr = NULL;
 
-       if (k >= SKF_NET_OFF)
+       if (k >= SKF_NET_OFF) {
                ptr = skb_network_header(skb) + k - SKF_NET_OFF;
-       else if (k >= SKF_LL_OFF)
+       } else if (k >= SKF_LL_OFF) {
+               if (unlikely(!skb_mac_header_was_set(skb)))
+                       return NULL;
                ptr = skb_mac_header(skb) + k - SKF_LL_OFF;
-
+       }
        if (ptr >= skb->head && ptr + size <= skb_tail_pointer(skb))
                return ptr;
 
index 225806a02efbe9d3883e39618e6e29cd1f4ab820..bb1254f076672b1f14d32e8df1696a36a4b1f9fc 100644 (file)
@@ -1497,11 +1497,12 @@ const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
        .arg4_type      = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT,
 };
 
-BPF_CALL_4(bpf_dynptr_read, void *, dst, u32, len, struct bpf_dynptr_kern *, src, u32, offset)
+BPF_CALL_5(bpf_dynptr_read, void *, dst, u32, len, struct bpf_dynptr_kern *, src,
+          u32, offset, u64, flags)
 {
        int err;
 
-       if (!src->data)
+       if (!src->data || flags)
                return -EINVAL;
 
        err = bpf_dynptr_check_off_len(src, offset, len);
@@ -1521,13 +1522,15 @@ const struct bpf_func_proto bpf_dynptr_read_proto = {
        .arg2_type      = ARG_CONST_SIZE_OR_ZERO,
        .arg3_type      = ARG_PTR_TO_DYNPTR,
        .arg4_type      = ARG_ANYTHING,
+       .arg5_type      = ARG_ANYTHING,
 };
 
-BPF_CALL_4(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *, src, u32, len)
+BPF_CALL_5(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *, src,
+          u32, len, u64, flags)
 {
        int err;
 
-       if (!dst->data || bpf_dynptr_is_rdonly(dst))
+       if (!dst->data || flags || bpf_dynptr_is_rdonly(dst))
                return -EINVAL;
 
        err = bpf_dynptr_check_off_len(dst, offset, len);
@@ -1547,6 +1550,7 @@ const struct bpf_func_proto bpf_dynptr_write_proto = {
        .arg2_type      = ARG_ANYTHING,
        .arg3_type      = ARG_PTR_TO_MEM | MEM_RDONLY,
        .arg4_type      = ARG_CONST_SIZE_OR_ZERO,
+       .arg5_type      = ARG_ANYTHING,
 };
 
 BPF_CALL_3(bpf_dynptr_data, struct bpf_dynptr_kern *, ptr, u32, offset, u32, len)
index aedac2ac02b9278fa9d2afc0eef948628a7cb311..0efbac0fd126445ee81c76b52270b43e7dd855c7 100644 (file)
@@ -1562,6 +1562,21 @@ static void __reg_bound_offset(struct bpf_reg_state *reg)
        reg->var_off = tnum_or(tnum_clear_subreg(var64_off), var32_off);
 }
 
+static void reg_bounds_sync(struct bpf_reg_state *reg)
+{
+       /* We might have learned new bounds from the var_off. */
+       __update_reg_bounds(reg);
+       /* We might have learned something about the sign bit. */
+       __reg_deduce_bounds(reg);
+       /* We might have learned some bits from the bounds. */
+       __reg_bound_offset(reg);
+       /* Intersecting with the old var_off might have improved our bounds
+        * slightly, e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
+        * then new var_off is (0; 0x7f...fc) which improves our umax.
+        */
+       __update_reg_bounds(reg);
+}
+
 static bool __reg32_bound_s64(s32 a)
 {
        return a >= 0 && a <= S32_MAX;
@@ -1603,16 +1618,8 @@ static void __reg_combine_32_into_64(struct bpf_reg_state *reg)
                 * so they do not impact tnum bounds calculation.
                 */
                __mark_reg64_unbounded(reg);
-               __update_reg_bounds(reg);
        }
-
-       /* Intersecting with the old var_off might have improved our bounds
-        * slightly.  e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
-        * then new var_off is (0; 0x7f...fc) which improves our umax.
-        */
-       __reg_deduce_bounds(reg);
-       __reg_bound_offset(reg);
-       __update_reg_bounds(reg);
+       reg_bounds_sync(reg);
 }
 
 static bool __reg64_bound_s32(s64 a)
@@ -1628,7 +1635,6 @@ static bool __reg64_bound_u32(u64 a)
 static void __reg_combine_64_into_32(struct bpf_reg_state *reg)
 {
        __mark_reg32_unbounded(reg);
-
        if (__reg64_bound_s32(reg->smin_value) && __reg64_bound_s32(reg->smax_value)) {
                reg->s32_min_value = (s32)reg->smin_value;
                reg->s32_max_value = (s32)reg->smax_value;
@@ -1637,14 +1643,7 @@ static void __reg_combine_64_into_32(struct bpf_reg_state *reg)
                reg->u32_min_value = (u32)reg->umin_value;
                reg->u32_max_value = (u32)reg->umax_value;
        }
-
-       /* Intersecting with the old var_off might have improved our bounds
-        * slightly.  e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
-        * then new var_off is (0; 0x7f...fc) which improves our umax.
-        */
-       __reg_deduce_bounds(reg);
-       __reg_bound_offset(reg);
-       __update_reg_bounds(reg);
+       reg_bounds_sync(reg);
 }
 
 /* Mark a register as having a completely unknown (scalar) value. */
@@ -6943,9 +6942,7 @@ static void do_refine_retval_range(struct bpf_reg_state *regs, int ret_type,
        ret_reg->s32_max_value = meta->msize_max_value;
        ret_reg->smin_value = -MAX_ERRNO;
        ret_reg->s32_min_value = -MAX_ERRNO;
-       __reg_deduce_bounds(ret_reg);
-       __reg_bound_offset(ret_reg);
-       __update_reg_bounds(ret_reg);
+       reg_bounds_sync(ret_reg);
 }
 
 static int
@@ -8202,11 +8199,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
 
        if (!check_reg_sane_offset(env, dst_reg, ptr_reg->type))
                return -EINVAL;
-
-       __update_reg_bounds(dst_reg);
-       __reg_deduce_bounds(dst_reg);
-       __reg_bound_offset(dst_reg);
-
+       reg_bounds_sync(dst_reg);
        if (sanitize_check_bounds(env, insn, dst_reg) < 0)
                return -EACCES;
        if (sanitize_needed(opcode)) {
@@ -8944,10 +8937,7 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
        /* ALU32 ops are zero extended into 64bit register */
        if (alu32)
                zext_32_to_64(dst_reg);
-
-       __update_reg_bounds(dst_reg);
-       __reg_deduce_bounds(dst_reg);
-       __reg_bound_offset(dst_reg);
+       reg_bounds_sync(dst_reg);
        return 0;
 }
 
@@ -9136,10 +9126,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
                                                         insn->dst_reg);
                                }
                                zext_32_to_64(dst_reg);
-
-                               __update_reg_bounds(dst_reg);
-                               __reg_deduce_bounds(dst_reg);
-                               __reg_bound_offset(dst_reg);
+                               reg_bounds_sync(dst_reg);
                        }
                } else {
                        /* case: R = imm
@@ -9577,26 +9564,33 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg,
                return;
 
        switch (opcode) {
+       /* JEQ/JNE comparison doesn't change the register equivalence.
+        *
+        * r1 = r2;
+        * if (r1 == 42) goto label;
+        * ...
+        * label: // here both r1 and r2 are known to be 42.
+        *
+        * Hence when marking register as known preserve it's ID.
+        */
        case BPF_JEQ:
+               if (is_jmp32) {
+                       __mark_reg32_known(true_reg, val32);
+                       true_32off = tnum_subreg(true_reg->var_off);
+               } else {
+                       ___mark_reg_known(true_reg, val);
+                       true_64off = true_reg->var_off;
+               }
+               break;
        case BPF_JNE:
-       {
-               struct bpf_reg_state *reg =
-                       opcode == BPF_JEQ ? true_reg : false_reg;
-
-               /* JEQ/JNE comparison doesn't change the register equivalence.
-                * r1 = r2;
-                * if (r1 == 42) goto label;
-                * ...
-                * label: // here both r1 and r2 are known to be 42.
-                *
-                * Hence when marking register as known preserve it's ID.
-                */
-               if (is_jmp32)
-                       __mark_reg32_known(reg, val32);
-               else
-                       ___mark_reg_known(reg, val);
+               if (is_jmp32) {
+                       __mark_reg32_known(false_reg, val32);
+                       false_32off = tnum_subreg(false_reg->var_off);
+               } else {
+                       ___mark_reg_known(false_reg, val);
+                       false_64off = false_reg->var_off;
+               }
                break;
-       }
        case BPF_JSET:
                if (is_jmp32) {
                        false_32off = tnum_and(false_32off, tnum_const(~val32));
@@ -9735,21 +9729,8 @@ static void __reg_combine_min_max(struct bpf_reg_state *src_reg,
                                                        dst_reg->smax_value);
        src_reg->var_off = dst_reg->var_off = tnum_intersect(src_reg->var_off,
                                                             dst_reg->var_off);
-       /* We might have learned new bounds from the var_off. */
-       __update_reg_bounds(src_reg);
-       __update_reg_bounds(dst_reg);
-       /* We might have learned something about the sign bit. */
-       __reg_deduce_bounds(src_reg);
-       __reg_deduce_bounds(dst_reg);
-       /* We might have learned some bits from the bounds. */
-       __reg_bound_offset(src_reg);
-       __reg_bound_offset(dst_reg);
-       /* Intersecting with the old var_off might have improved our bounds
-        * slightly.  e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
-        * then new var_off is (0; 0x7f...fc) which improves our umax.
-        */
-       __update_reg_bounds(src_reg);
-       __update_reg_bounds(dst_reg);
+       reg_bounds_sync(src_reg);
+       reg_bounds_sync(dst_reg);
 }
 
 static void reg_combine_min_max(struct bpf_reg_state *true_src,
index 1779ccddb734d00c53f6968c3445aaf5314aebf6..13c8e91d7862020d0081cca68d10dc71e2aefe52 100644 (file)
@@ -765,7 +765,8 @@ struct css_set init_css_set = {
        .task_iters             = LIST_HEAD_INIT(init_css_set.task_iters),
        .threaded_csets         = LIST_HEAD_INIT(init_css_set.threaded_csets),
        .cgrp_links             = LIST_HEAD_INIT(init_css_set.cgrp_links),
-       .mg_preload_node        = LIST_HEAD_INIT(init_css_set.mg_preload_node),
+       .mg_src_preload_node    = LIST_HEAD_INIT(init_css_set.mg_src_preload_node),
+       .mg_dst_preload_node    = LIST_HEAD_INIT(init_css_set.mg_dst_preload_node),
        .mg_node                = LIST_HEAD_INIT(init_css_set.mg_node),
 
        /*
@@ -1240,7 +1241,8 @@ static struct css_set *find_css_set(struct css_set *old_cset,
        INIT_LIST_HEAD(&cset->threaded_csets);
        INIT_HLIST_NODE(&cset->hlist);
        INIT_LIST_HEAD(&cset->cgrp_links);
-       INIT_LIST_HEAD(&cset->mg_preload_node);
+       INIT_LIST_HEAD(&cset->mg_src_preload_node);
+       INIT_LIST_HEAD(&cset->mg_dst_preload_node);
        INIT_LIST_HEAD(&cset->mg_node);
 
        /* Copy the set of subsystem state objects generated in
@@ -2597,21 +2599,27 @@ int cgroup_migrate_vet_dst(struct cgroup *dst_cgrp)
  */
 void cgroup_migrate_finish(struct cgroup_mgctx *mgctx)
 {
-       LIST_HEAD(preloaded);
        struct css_set *cset, *tmp_cset;
 
        lockdep_assert_held(&cgroup_mutex);
 
        spin_lock_irq(&css_set_lock);
 
-       list_splice_tail_init(&mgctx->preloaded_src_csets, &preloaded);
-       list_splice_tail_init(&mgctx->preloaded_dst_csets, &preloaded);
+       list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_src_csets,
+                                mg_src_preload_node) {
+               cset->mg_src_cgrp = NULL;
+               cset->mg_dst_cgrp = NULL;
+               cset->mg_dst_cset = NULL;
+               list_del_init(&cset->mg_src_preload_node);
+               put_css_set_locked(cset);
+       }
 
-       list_for_each_entry_safe(cset, tmp_cset, &preloaded, mg_preload_node) {
+       list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_dst_csets,
+                                mg_dst_preload_node) {
                cset->mg_src_cgrp = NULL;
                cset->mg_dst_cgrp = NULL;
                cset->mg_dst_cset = NULL;
-               list_del_init(&cset->mg_preload_node);
+               list_del_init(&cset->mg_dst_preload_node);
                put_css_set_locked(cset);
        }
 
@@ -2651,7 +2659,7 @@ void cgroup_migrate_add_src(struct css_set *src_cset,
        if (src_cset->dead)
                return;
 
-       if (!list_empty(&src_cset->mg_preload_node))
+       if (!list_empty(&src_cset->mg_src_preload_node))
                return;
 
        src_cgrp = cset_cgroup_from_root(src_cset, dst_cgrp->root);
@@ -2664,7 +2672,7 @@ void cgroup_migrate_add_src(struct css_set *src_cset,
        src_cset->mg_src_cgrp = src_cgrp;
        src_cset->mg_dst_cgrp = dst_cgrp;
        get_css_set(src_cset);
-       list_add_tail(&src_cset->mg_preload_node, &mgctx->preloaded_src_csets);
+       list_add_tail(&src_cset->mg_src_preload_node, &mgctx->preloaded_src_csets);
 }
 
 /**
@@ -2689,7 +2697,7 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
 
        /* look up the dst cset for each src cset and link it to src */
        list_for_each_entry_safe(src_cset, tmp_cset, &mgctx->preloaded_src_csets,
-                                mg_preload_node) {
+                                mg_src_preload_node) {
                struct css_set *dst_cset;
                struct cgroup_subsys *ss;
                int ssid;
@@ -2708,7 +2716,7 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
                if (src_cset == dst_cset) {
                        src_cset->mg_src_cgrp = NULL;
                        src_cset->mg_dst_cgrp = NULL;
-                       list_del_init(&src_cset->mg_preload_node);
+                       list_del_init(&src_cset->mg_src_preload_node);
                        put_css_set(src_cset);
                        put_css_set(dst_cset);
                        continue;
@@ -2716,8 +2724,8 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
 
                src_cset->mg_dst_cset = dst_cset;
 
-               if (list_empty(&dst_cset->mg_preload_node))
-                       list_add_tail(&dst_cset->mg_preload_node,
+               if (list_empty(&dst_cset->mg_dst_preload_node))
+                       list_add_tail(&dst_cset->mg_dst_preload_node,
                                      &mgctx->preloaded_dst_csets);
                else
                        put_css_set(dst_cset);
@@ -2963,7 +2971,8 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
                goto out_finish;
 
        spin_lock_irq(&css_set_lock);
-       list_for_each_entry(src_cset, &mgctx.preloaded_src_csets, mg_preload_node) {
+       list_for_each_entry(src_cset, &mgctx.preloaded_src_csets,
+                           mg_src_preload_node) {
                struct task_struct *task, *ntask;
 
                /* all tasks in src_csets need to be migrated */
index 80782cddb1dabf6f917b877acf262ead2cd911ae..d2b354991bf5a73982cf817a93fd47a9e6cd50a5 100644 (file)
@@ -6253,10 +6253,10 @@ again:
 
                if (!atomic_inc_not_zero(&event->rb->mmap_count)) {
                        /*
-                        * Raced against perf_mmap_close() through
-                        * perf_event_set_output(). Try again, hope for better
-                        * luck.
+                        * Raced against perf_mmap_close(); remove the
+                        * event and try again.
                         */
+                       ring_buffer_attach(event, NULL);
                        mutex_unlock(&event->mmap_mutex);
                        goto again;
                }
@@ -11825,14 +11825,25 @@ err_size:
        goto out;
 }
 
+static void mutex_lock_double(struct mutex *a, struct mutex *b)
+{
+       if (b < a)
+               swap(a, b);
+
+       mutex_lock(a);
+       mutex_lock_nested(b, SINGLE_DEPTH_NESTING);
+}
+
 static int
 perf_event_set_output(struct perf_event *event, struct perf_event *output_event)
 {
        struct perf_buffer *rb = NULL;
        int ret = -EINVAL;
 
-       if (!output_event)
+       if (!output_event) {
+               mutex_lock(&event->mmap_mutex);
                goto set;
+       }
 
        /* don't allow circular references */
        if (event == output_event)
@@ -11870,8 +11881,15 @@ perf_event_set_output(struct perf_event *event, struct perf_event *output_event)
            event->pmu != output_event->pmu)
                goto out;
 
+       /*
+        * Hold both mmap_mutex to serialize against perf_mmap_close().  Since
+        * output_event is already on rb->event_list, and the list iteration
+        * restarts after every removal, it is guaranteed this new event is
+        * observed *OR* if output_event is already removed, it's guaranteed we
+        * observe !rb->mmap_count.
+        */
+       mutex_lock_double(&event->mmap_mutex, &output_event->mmap_mutex);
 set:
-       mutex_lock(&event->mmap_mutex);
        /* Can't redirect output if we've got an active mmap() */
        if (atomic_read(&event->mmap_count))
                goto unlock;
@@ -11881,6 +11899,12 @@ set:
                rb = ring_buffer_get(output_event);
                if (!rb)
                        goto unlock;
+
+               /* did we race against perf_mmap_close() */
+               if (!atomic_read(&rb->mmap_count)) {
+                       ring_buffer_put(rb);
+                       goto unlock;
+               }
        }
 
        ring_buffer_attach(event, rb);
@@ -11888,20 +11912,13 @@ set:
        ret = 0;
 unlock:
        mutex_unlock(&event->mmap_mutex);
+       if (output_event)
+               mutex_unlock(&output_event->mmap_mutex);
 
 out:
        return ret;
 }
 
-static void mutex_lock_double(struct mutex *a, struct mutex *b)
-{
-       if (b < a)
-               swap(a, b);
-
-       mutex_lock(a);
-       mutex_lock_nested(b, SINGLE_DEPTH_NESTING);
-}
-
 static int perf_event_set_clock(struct perf_event *event, clockid_t clk_id)
 {
        bool nmi_safe = false;
index f072959fcab7f470fc8c49ae6e706d34d72d1901..64c938ce36fe8ad0dfa83ffed6a2d596f0a19970 100644 (file)
@@ -766,7 +766,7 @@ void __noreturn do_exit(long code)
 
 #ifdef CONFIG_POSIX_TIMERS
                hrtimer_cancel(&tsk->signal->real_timer);
-               exit_itimers(tsk->signal);
+               exit_itimers(tsk);
 #endif
                if (tsk->mm)
                        setmax_mm_hiwater_rss(&tsk->signal->maxrss, tsk->mm);
index 145321a5e798a647f299b1728a61231d166621ce..f9261c07b048747c6d594c1c29327628bbb15cac 100644 (file)
 #include <linux/vmalloc.h>
 #include "kexec_internal.h"
 
+#ifdef CONFIG_KEXEC_SIG
+static bool sig_enforce = IS_ENABLED(CONFIG_KEXEC_SIG_FORCE);
+
+void set_kexec_sig_enforced(void)
+{
+       sig_enforce = true;
+}
+#endif
+
 static int kexec_calculate_store_digests(struct kimage *image);
 
 /*
@@ -159,7 +168,7 @@ kimage_validate_signature(struct kimage *image)
                                           image->kernel_buf_len);
        if (ret) {
 
-               if (IS_ENABLED(CONFIG_KEXEC_SIG_FORCE)) {
+               if (sig_enforce) {
                        pr_notice("Enforced kernel signature verification failed (%d).\n", ret);
                        return ret;
                }
index bc5507ab84506062a0d2eb62c972f288b72f3c62..ec104c2950c39f59a2024f8e0c84957d2fbe3fc4 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mutex.h>
 #include <linux/rculist.h>
 #include <linux/rcupdate.h>
+#include <linux/mm.h>
 
 #ifndef ARCH_SHF_SMALL
 #define ARCH_SHF_SMALL 0
  * to ensure complete separation of code and data, but
  * only when CONFIG_STRICT_MODULE_RWX=y
  */
-#ifdef CONFIG_STRICT_MODULE_RWX
-# define strict_align(X) PAGE_ALIGN(X)
-#else
-# define strict_align(X) (X)
-#endif
+static inline unsigned int strict_align(unsigned int size)
+{
+       if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
+               return PAGE_ALIGN(size);
+       else
+               return size;
+}
 
 extern struct mutex module_mutex;
 extern struct list_head modules;
index 3e11523bc6f622b36a14bde544c1e6ad89ccbe0e..77e75bead5698c3ffe86d0a4a991543484ff2c69 100644 (file)
@@ -137,6 +137,7 @@ void layout_symtab(struct module *mod, struct load_info *info)
        info->symoffs = ALIGN(mod->data_layout.size, symsect->sh_addralign ?: 1);
        info->stroffs = mod->data_layout.size = info->symoffs + ndst * sizeof(Elf_Sym);
        mod->data_layout.size += strtab_size;
+       /* Note add_kallsyms() computes strtab_size as core_typeoffs - stroffs */
        info->core_typeoffs = mod->data_layout.size;
        mod->data_layout.size += ndst * sizeof(char);
        mod->data_layout.size = strict_align(mod->data_layout.size);
@@ -169,19 +170,20 @@ void add_kallsyms(struct module *mod, const struct load_info *info)
        Elf_Sym *dst;
        char *s;
        Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
+       unsigned long strtab_size;
 
        /* Set up to point into init section. */
        mod->kallsyms = (void __rcu *)mod->init_layout.base +
                info->mod_kallsyms_init_off;
 
-       preempt_disable();
+       rcu_read_lock();
        /* The following is safe since this pointer cannot change */
-       rcu_dereference_sched(mod->kallsyms)->symtab = (void *)symsec->sh_addr;
-       rcu_dereference_sched(mod->kallsyms)->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
+       rcu_dereference(mod->kallsyms)->symtab = (void *)symsec->sh_addr;
+       rcu_dereference(mod->kallsyms)->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
        /* Make sure we get permanent strtab: don't use info->strtab. */
-       rcu_dereference_sched(mod->kallsyms)->strtab =
+       rcu_dereference(mod->kallsyms)->strtab =
                (void *)info->sechdrs[info->index.str].sh_addr;
-       rcu_dereference_sched(mod->kallsyms)->typetab = mod->init_layout.base + info->init_typeoffs;
+       rcu_dereference(mod->kallsyms)->typetab = mod->init_layout.base + info->init_typeoffs;
 
        /*
         * Now populate the cut down core kallsyms for after init
@@ -190,22 +192,29 @@ void add_kallsyms(struct module *mod, const struct load_info *info)
        mod->core_kallsyms.symtab = dst = mod->data_layout.base + info->symoffs;
        mod->core_kallsyms.strtab = s = mod->data_layout.base + info->stroffs;
        mod->core_kallsyms.typetab = mod->data_layout.base + info->core_typeoffs;
-       src = rcu_dereference_sched(mod->kallsyms)->symtab;
-       for (ndst = i = 0; i < rcu_dereference_sched(mod->kallsyms)->num_symtab; i++) {
-               rcu_dereference_sched(mod->kallsyms)->typetab[i] = elf_type(src + i, info);
+       strtab_size = info->core_typeoffs - info->stroffs;
+       src = rcu_dereference(mod->kallsyms)->symtab;
+       for (ndst = i = 0; i < rcu_dereference(mod->kallsyms)->num_symtab; i++) {
+               rcu_dereference(mod->kallsyms)->typetab[i] = elf_type(src + i, info);
                if (i == 0 || is_livepatch_module(mod) ||
                    is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum,
                                   info->index.pcpu)) {
+                       ssize_t ret;
+
                        mod->core_kallsyms.typetab[ndst] =
-                           rcu_dereference_sched(mod->kallsyms)->typetab[i];
+                           rcu_dereference(mod->kallsyms)->typetab[i];
                        dst[ndst] = src[i];
                        dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
-                       s += strscpy(s,
-                                    &rcu_dereference_sched(mod->kallsyms)->strtab[src[i].st_name],
-                                    KSYM_NAME_LEN) + 1;
+                       ret = strscpy(s,
+                                     &rcu_dereference(mod->kallsyms)->strtab[src[i].st_name],
+                                     strtab_size);
+                       if (ret < 0)
+                               break;
+                       s += ret + 1;
+                       strtab_size -= ret + 1;
                }
        }
-       preempt_enable();
+       rcu_read_unlock();
        mod->core_kallsyms.num_symtab = ndst;
 }
 
index fed58d30725de62bd16abea7a2532ed0fc8cc11a..0548151dd933955f8816d8d3a708e2a65dea7d0e 100644 (file)
@@ -2939,24 +2939,25 @@ static void cfi_init(struct module *mod)
 {
 #ifdef CONFIG_CFI_CLANG
        initcall_t *init;
+#ifdef CONFIG_MODULE_UNLOAD
        exitcall_t *exit;
+#endif
 
        rcu_read_lock_sched();
        mod->cfi_check = (cfi_check_fn)
                find_kallsyms_symbol_value(mod, "__cfi_check");
        init = (initcall_t *)
                find_kallsyms_symbol_value(mod, "__cfi_jt_init_module");
-       exit = (exitcall_t *)
-               find_kallsyms_symbol_value(mod, "__cfi_jt_cleanup_module");
-       rcu_read_unlock_sched();
-
        /* Fix init/exit functions to point to the CFI jump table */
        if (init)
                mod->init = *init;
 #ifdef CONFIG_MODULE_UNLOAD
+       exit = (exitcall_t *)
+               find_kallsyms_symbol_value(mod, "__cfi_jt_cleanup_module");
        if (exit)
                mod->exit = *exit;
 #endif
+       rcu_read_unlock_sched();
 
        cfi_module_add(mod, mod_tree.addr_min);
 #endif
index 6c373f2960e71d1f402aa487d57ba96fee67cdd6..f82111837b8d1da67386595c8207b9be06bcacb3 100644 (file)
@@ -145,7 +145,7 @@ static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd,
 
                /*
                 * The power returned by active_state() is expected to be
-                * positive and to fit into 16 bits.
+                * positive and be in range.
                 */
                if (!power || power > EM_MAX_POWER) {
                        dev_err(dev, "EM: invalid power: %lu\n",
@@ -170,7 +170,7 @@ static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd,
                                goto free_ps_table;
                        }
                } else {
-                       power_res = em_scale_power(table[i].power);
+                       power_res = table[i].power;
                        cost = div64_u64(fmax * power_res, table[i].frequency);
                }
 
@@ -201,9 +201,17 @@ static int em_create_pd(struct device *dev, int nr_states,
 {
        struct em_perf_domain *pd;
        struct device *cpu_dev;
-       int cpu, ret;
+       int cpu, ret, num_cpus;
 
        if (_is_cpu_device(dev)) {
+               num_cpus = cpumask_weight(cpus);
+
+               /* Prevent max possible energy calculation to not overflow */
+               if (num_cpus > EM_MAX_NUM_CPUS) {
+                       dev_err(dev, "EM: too many CPUs, overflow possible\n");
+                       return -EINVAL;
+               }
+
                pd = kzalloc(sizeof(*pd) + cpumask_size(), GFP_KERNEL);
                if (!pd)
                        return -ENOMEM;
@@ -314,13 +322,13 @@ EXPORT_SYMBOL_GPL(em_cpu_get);
  * @cpus       : Pointer to cpumask_t, which in case of a CPU device is
  *             obligatory. It can be taken from i.e. 'policy->cpus'. For other
  *             type of devices this should be set to NULL.
- * @milliwatts : Flag indicating that the power values are in milliWatts or
+ * @microwatts : Flag indicating that the power values are in micro-Watts or
  *             in some other scale. It must be set properly.
  *
  * Create Energy Model tables for a performance domain using the callbacks
  * defined in cb.
  *
- * The @milliwatts is important to set with correct value. Some kernel
+ * The @microwatts is important to set with correct value. Some kernel
  * sub-systems might rely on this flag and check if all devices in the EM are
  * using the same scale.
  *
@@ -331,7 +339,7 @@ EXPORT_SYMBOL_GPL(em_cpu_get);
  */
 int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
                                struct em_data_callback *cb, cpumask_t *cpus,
-                               bool milliwatts)
+                               bool microwatts)
 {
        unsigned long cap, prev_cap = 0;
        unsigned long flags = 0;
@@ -381,8 +389,8 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
                }
        }
 
-       if (milliwatts)
-               flags |= EM_PERF_DOMAIN_MILLIWATTS;
+       if (microwatts)
+               flags |= EM_PERF_DOMAIN_MICROWATTS;
        else if (cb->get_cost)
                flags |= EM_PERF_DOMAIN_ARTIFICIAL;
 
index ec7e1e85923e43f60ea3c5007cdd8035c9cc0596..af51ed6d45ef17e7be6f5a292625abe020201a7c 100644 (file)
@@ -531,7 +531,7 @@ int freq_qos_add_request(struct freq_constraints *qos,
 {
        int ret;
 
-       if (IS_ERR_OR_NULL(qos) || !req)
+       if (IS_ERR_OR_NULL(qos) || !req || value < 0)
                return -EINVAL;
 
        if (WARN(freq_qos_request_active(req),
@@ -563,7 +563,7 @@ EXPORT_SYMBOL_GPL(freq_qos_add_request);
  */
 int freq_qos_update_request(struct freq_qos_request *req, s32 new_value)
 {
-       if (!req)
+       if (!req || new_value < 0)
                return -EINVAL;
 
        if (WARN(!freq_qos_request_active(req),
index ad241b4ff64c58b64252de2f3a0501ee9288357a..d43c2aa583b26b66289185b5bc83a185ce326af8 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "power.h"
 
+static bool need_wait;
 
 static struct snapshot_data {
        struct snapshot_handle handle;
@@ -78,7 +79,7 @@ static int snapshot_open(struct inode *inode, struct file *filp)
                 * Resuming.  We may need to wait for the image device to
                 * appear.
                 */
-               wait_for_device_probe();
+               need_wait = true;
 
                data->swap = -1;
                data->mode = O_WRONLY;
@@ -168,6 +169,11 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf,
        ssize_t res;
        loff_t pg_offp = *offp & ~PAGE_MASK;
 
+       if (need_wait) {
+               wait_for_device_probe();
+               need_wait = false;
+       }
+
        lock_system_sleep();
 
        data = filp->private_data;
@@ -244,6 +250,11 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
        loff_t size;
        sector_t offset;
 
+       if (need_wait) {
+               wait_for_device_probe();
+               need_wait = false;
+       }
+
        if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
                return -ENOTTY;
        if (_IOC_NR(cmd) > SNAPSHOT_IOC_MAXNR)
index b49c6ff6dca01ba9f5acf0834654da65634b61e3..a1a81fd9889bb35d54102ce3cbc84a76cca24020 100644 (file)
@@ -3380,6 +3380,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
                diff = 0;
 
                console_lock();
+
                for_each_console(c) {
                        if (con && con != c)
                                continue;
@@ -3389,11 +3390,19 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
                        if (printk_seq < seq)
                                diff += seq - printk_seq;
                }
-               console_unlock();
 
-               if (diff != last_diff && reset_on_progress)
+               /*
+                * If consoles are suspended, it cannot be expected that they
+                * make forward progress, so timeout immediately. @diff is
+                * still used to return a valid flush status.
+                */
+               if (console_suspended)
+                       remaining = 0;
+               else if (diff != last_diff && reset_on_progress)
                        remaining = timeout_ms;
 
+               console_unlock();
+
                if (diff == 0 || remaining == 0)
                        break;
 
index 156a99283b11d8638dc490edbe0f1a188fccc12b..1893d909e45ca6c575efb105ce12f35da7eadbb7 100644 (file)
@@ -222,7 +222,7 @@ static void ptrace_unfreeze_traced(struct task_struct *task)
        if (lock_task_sighand(task, &flags)) {
                task->jobctl &= ~JOBCTL_PTRACE_FROZEN;
                if (__fatal_signal_pending(task)) {
-                       task->jobctl &= ~TASK_TRACED;
+                       task->jobctl &= ~JOBCTL_TRACED;
                        wake_up_state(task, __TASK_TRACED);
                }
                unlock_task_sighand(task, &flags);
index 50ba70f019dea0996b1ec28e96191eb9e73c98ff..1c304fec89c02df9121b8cfa60087a843bf5f49c 100644 (file)
@@ -511,10 +511,52 @@ static bool srcu_readers_active(struct srcu_struct *ssp)
        return sum;
 }
 
-#define SRCU_INTERVAL          1       // Base delay if no expedited GPs pending.
-#define SRCU_MAX_INTERVAL      10      // Maximum incremental delay from slow readers.
-#define SRCU_MAX_NODELAY_PHASE 1       // Maximum per-GP-phase consecutive no-delay instances.
-#define SRCU_MAX_NODELAY       100     // Maximum consecutive no-delay instances.
+/*
+ * We use an adaptive strategy for synchronize_srcu() and especially for
+ * synchronize_srcu_expedited().  We spin for a fixed time period
+ * (defined below, boot time configurable) to allow SRCU readers to exit
+ * their read-side critical sections.  If there are still some readers
+ * after one jiffy, we repeatedly block for one jiffy time periods.
+ * The blocking time is increased as the grace-period age increases,
+ * with max blocking time capped at 10 jiffies.
+ */
+#define SRCU_DEFAULT_RETRY_CHECK_DELAY         5
+
+static ulong srcu_retry_check_delay = SRCU_DEFAULT_RETRY_CHECK_DELAY;
+module_param(srcu_retry_check_delay, ulong, 0444);
+
+#define SRCU_INTERVAL          1               // Base delay if no expedited GPs pending.
+#define SRCU_MAX_INTERVAL      10              // Maximum incremental delay from slow readers.
+
+#define SRCU_DEFAULT_MAX_NODELAY_PHASE_LO      3UL     // Lowmark on default per-GP-phase
+                                                       // no-delay instances.
+#define SRCU_DEFAULT_MAX_NODELAY_PHASE_HI      1000UL  // Highmark on default per-GP-phase
+                                                       // no-delay instances.
+
+#define SRCU_UL_CLAMP_LO(val, low)     ((val) > (low) ? (val) : (low))
+#define SRCU_UL_CLAMP_HI(val, high)    ((val) < (high) ? (val) : (high))
+#define SRCU_UL_CLAMP(val, low, high)  SRCU_UL_CLAMP_HI(SRCU_UL_CLAMP_LO((val), (low)), (high))
+// per-GP-phase no-delay instances adjusted to allow non-sleeping poll upto
+// one jiffies time duration. Mult by 2 is done to factor in the srcu_get_delay()
+// called from process_srcu().
+#define SRCU_DEFAULT_MAX_NODELAY_PHASE_ADJUSTED        \
+       (2UL * USEC_PER_SEC / HZ / SRCU_DEFAULT_RETRY_CHECK_DELAY)
+
+// Maximum per-GP-phase consecutive no-delay instances.
+#define SRCU_DEFAULT_MAX_NODELAY_PHASE \
+       SRCU_UL_CLAMP(SRCU_DEFAULT_MAX_NODELAY_PHASE_ADJUSTED,  \
+                     SRCU_DEFAULT_MAX_NODELAY_PHASE_LO,        \
+                     SRCU_DEFAULT_MAX_NODELAY_PHASE_HI)
+
+static ulong srcu_max_nodelay_phase = SRCU_DEFAULT_MAX_NODELAY_PHASE;
+module_param(srcu_max_nodelay_phase, ulong, 0444);
+
+// Maximum consecutive no-delay instances.
+#define SRCU_DEFAULT_MAX_NODELAY       (SRCU_DEFAULT_MAX_NODELAY_PHASE > 100 ? \
+                                        SRCU_DEFAULT_MAX_NODELAY_PHASE : 100)
+
+static ulong srcu_max_nodelay = SRCU_DEFAULT_MAX_NODELAY;
+module_param(srcu_max_nodelay, ulong, 0444);
 
 /*
  * Return grace-period delay, zero if there are expedited grace
@@ -522,16 +564,22 @@ static bool srcu_readers_active(struct srcu_struct *ssp)
  */
 static unsigned long srcu_get_delay(struct srcu_struct *ssp)
 {
+       unsigned long gpstart;
+       unsigned long j;
        unsigned long jbase = SRCU_INTERVAL;
 
        if (ULONG_CMP_LT(READ_ONCE(ssp->srcu_gp_seq), READ_ONCE(ssp->srcu_gp_seq_needed_exp)))
                jbase = 0;
-       if (rcu_seq_state(READ_ONCE(ssp->srcu_gp_seq)))
-               jbase += jiffies - READ_ONCE(ssp->srcu_gp_start);
-       if (!jbase) {
-               WRITE_ONCE(ssp->srcu_n_exp_nodelay, READ_ONCE(ssp->srcu_n_exp_nodelay) + 1);
-               if (READ_ONCE(ssp->srcu_n_exp_nodelay) > SRCU_MAX_NODELAY_PHASE)
-                       jbase = 1;
+       if (rcu_seq_state(READ_ONCE(ssp->srcu_gp_seq))) {
+               j = jiffies - 1;
+               gpstart = READ_ONCE(ssp->srcu_gp_start);
+               if (time_after(j, gpstart))
+                       jbase += j - gpstart;
+               if (!jbase) {
+                       WRITE_ONCE(ssp->srcu_n_exp_nodelay, READ_ONCE(ssp->srcu_n_exp_nodelay) + 1);
+                       if (READ_ONCE(ssp->srcu_n_exp_nodelay) > srcu_max_nodelay_phase)
+                               jbase = 1;
+               }
        }
        return jbase > SRCU_MAX_INTERVAL ? SRCU_MAX_INTERVAL : jbase;
 }
@@ -606,15 +654,6 @@ void __srcu_read_unlock(struct srcu_struct *ssp, int idx)
 }
 EXPORT_SYMBOL_GPL(__srcu_read_unlock);
 
-/*
- * We use an adaptive strategy for synchronize_srcu() and especially for
- * synchronize_srcu_expedited().  We spin for a fixed time period
- * (defined below) to allow SRCU readers to exit their read-side critical
- * sections.  If there are still some readers after a few microseconds,
- * we repeatedly block for 1-millisecond time periods.
- */
-#define SRCU_RETRY_CHECK_DELAY         5
-
 /*
  * Start an SRCU grace period.
  */
@@ -700,7 +739,7 @@ static void srcu_schedule_cbs_snp(struct srcu_struct *ssp, struct srcu_node *snp
  */
 static void srcu_gp_end(struct srcu_struct *ssp)
 {
-       unsigned long cbdelay;
+       unsigned long cbdelay = 1;
        bool cbs;
        bool last_lvl;
        int cpu;
@@ -720,7 +759,9 @@ static void srcu_gp_end(struct srcu_struct *ssp)
        spin_lock_irq_rcu_node(ssp);
        idx = rcu_seq_state(ssp->srcu_gp_seq);
        WARN_ON_ONCE(idx != SRCU_STATE_SCAN2);
-       cbdelay = !!srcu_get_delay(ssp);
+       if (ULONG_CMP_LT(READ_ONCE(ssp->srcu_gp_seq), READ_ONCE(ssp->srcu_gp_seq_needed_exp)))
+               cbdelay = 0;
+
        WRITE_ONCE(ssp->srcu_last_gp_end, ktime_get_mono_fast_ns());
        rcu_seq_end(&ssp->srcu_gp_seq);
        gpseq = rcu_seq_current(&ssp->srcu_gp_seq);
@@ -921,12 +962,16 @@ static void srcu_funnel_gp_start(struct srcu_struct *ssp, struct srcu_data *sdp,
  */
 static bool try_check_zero(struct srcu_struct *ssp, int idx, int trycount)
 {
+       unsigned long curdelay;
+
+       curdelay = !srcu_get_delay(ssp);
+
        for (;;) {
                if (srcu_readers_active_idx_check(ssp, idx))
                        return true;
-               if (--trycount + !srcu_get_delay(ssp) <= 0)
+               if ((--trycount + curdelay) <= 0)
                        return false;
-               udelay(SRCU_RETRY_CHECK_DELAY);
+               udelay(srcu_retry_check_delay);
        }
 }
 
@@ -1582,7 +1627,7 @@ static void process_srcu(struct work_struct *work)
                j = jiffies;
                if (READ_ONCE(ssp->reschedule_jiffies) == j) {
                        WRITE_ONCE(ssp->reschedule_count, READ_ONCE(ssp->reschedule_count) + 1);
-                       if (READ_ONCE(ssp->reschedule_count) > SRCU_MAX_NODELAY)
+                       if (READ_ONCE(ssp->reschedule_count) > srcu_max_nodelay)
                                curdelay = 1;
                } else {
                        WRITE_ONCE(ssp->reschedule_count, 1);
@@ -1674,6 +1719,11 @@ static int __init srcu_bootup_announce(void)
        pr_info("Hierarchical SRCU implementation.\n");
        if (exp_holdoff != DEFAULT_SRCU_EXP_HOLDOFF)
                pr_info("\tNon-default auto-expedite holdoff of %lu ns.\n", exp_holdoff);
+       if (srcu_retry_check_delay != SRCU_DEFAULT_RETRY_CHECK_DELAY)
+               pr_info("\tNon-default retry check delay of %lu us.\n", srcu_retry_check_delay);
+       if (srcu_max_nodelay != SRCU_DEFAULT_MAX_NODELAY)
+               pr_info("\tNon-default max no-delay of %lu.\n", srcu_max_nodelay);
+       pr_info("\tMax phase no-delay instances is %lu.\n", srcu_max_nodelay_phase);
        return 0;
 }
 early_initcall(srcu_bootup_announce);
index b5152961b74324f2064b364c0be1f32a751d361b..7bf561262cb86a3b87b2502b842cedcfe2115209 100644 (file)
@@ -1701,7 +1701,10 @@ static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags)
                 * the throttle.
                 */
                p->dl.dl_throttled = 0;
-               BUG_ON(!is_dl_boosted(&p->dl) || flags != ENQUEUE_REPLENISH);
+               if (!(flags & ENQUEUE_REPLENISH))
+                       printk_deferred_once("sched: DL de-boosted task PID %d: REPLENISH flag missing\n",
+                                            task_pid_nr(p));
+
                return;
        }
 
index edb1dc9b00dc8f061780ad6cef324a4237e277fc..6f86fda5e432aeb32ae5dbca2c4264a2781b3dde 100644 (file)
@@ -2029,12 +2029,12 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
        bool autoreap = false;
        u64 utime, stime;
 
-       BUG_ON(sig == -1);
+       WARN_ON_ONCE(sig == -1);
 
-       /* do_notify_parent_cldstop should have been called instead.  */
-       BUG_ON(task_is_stopped_or_traced(tsk));
+       /* do_notify_parent_cldstop should have been called instead.  */
+       WARN_ON_ONCE(task_is_stopped_or_traced(tsk));
 
-       BUG_ON(!tsk->ptrace &&
+       WARN_ON_ONCE(!tsk->ptrace &&
               (tsk->group_leader != tsk || !thread_group_empty(tsk)));
 
        /* Wake up all pidfd waiters */
index e52b6e372c602c02e8993ac246857b94d06fc38e..35d0342195132e3873c32b3063b72f921daa377e 100644 (file)
@@ -446,14 +446,14 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
                if (*negp) {
                        if (*lvalp > (unsigned long) INT_MAX + 1)
                                return -EINVAL;
-                       *valp = -*lvalp;
+                       WRITE_ONCE(*valp, -*lvalp);
                } else {
                        if (*lvalp > (unsigned long) INT_MAX)
                                return -EINVAL;
-                       *valp = *lvalp;
+                       WRITE_ONCE(*valp, *lvalp);
                }
        } else {
-               int val = *valp;
+               int val = READ_ONCE(*valp);
                if (val < 0) {
                        *negp = true;
                        *lvalp = -(unsigned long)val;
@@ -472,9 +472,9 @@ static int do_proc_douintvec_conv(unsigned long *lvalp,
        if (write) {
                if (*lvalp > UINT_MAX)
                        return -EINVAL;
-               *valp = *lvalp;
+               WRITE_ONCE(*valp, *lvalp);
        } else {
-               unsigned int val = *valp;
+               unsigned int val = READ_ONCE(*valp);
                *lvalp = (unsigned long)val;
        }
        return 0;
@@ -857,7 +857,7 @@ static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp,
                if ((param->min && *param->min > tmp) ||
                    (param->max && *param->max < tmp))
                        return -EINVAL;
-               *valp = tmp;
+               WRITE_ONCE(*valp, tmp);
        }
 
        return 0;
@@ -923,7 +923,7 @@ static int do_proc_douintvec_minmax_conv(unsigned long *lvalp,
                    (param->max && *param->max < tmp))
                        return -ERANGE;
 
-               *valp = tmp;
+               WRITE_ONCE(*valp, tmp);
        }
 
        return 0;
@@ -1007,13 +1007,13 @@ int proc_dou8vec_minmax(struct ctl_table *table, int write,
 
        tmp.maxlen = sizeof(val);
        tmp.data = &val;
-       val = *data;
+       val = READ_ONCE(*data);
        res = do_proc_douintvec(&tmp, write, buffer, lenp, ppos,
                                do_proc_douintvec_minmax_conv, &param);
        if (res)
                return res;
        if (write)
-               *data = val;
+               WRITE_ONCE(*data, val);
        return 0;
 }
 EXPORT_SYMBOL_GPL(proc_dou8vec_minmax);
@@ -1090,9 +1090,9 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table,
                                err = -EINVAL;
                                break;
                        }
-                       *i = val;
+                       WRITE_ONCE(*i, val);
                } else {
-                       val = convdiv * (*i) / convmul;
+                       val = convdiv * READ_ONCE(*i) / convmul;
                        if (!first)
                                proc_put_char(&buffer, &left, '\t');
                        proc_put_long(&buffer, &left, val, false);
@@ -1173,9 +1173,12 @@ static int do_proc_dointvec_jiffies_conv(bool *negp, unsigned long *lvalp,
        if (write) {
                if (*lvalp > INT_MAX / HZ)
                        return 1;
-               *valp = *negp ? -(*lvalp*HZ) : (*lvalp*HZ);
+               if (*negp)
+                       WRITE_ONCE(*valp, -*lvalp * HZ);
+               else
+                       WRITE_ONCE(*valp, *lvalp * HZ);
        } else {
-               int val = *valp;
+               int val = READ_ONCE(*valp);
                unsigned long lval;
                if (val < 0) {
                        *negp = true;
@@ -1221,9 +1224,9 @@ static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp,
 
                if (jif > INT_MAX)
                        return 1;
-               *valp = (int)jif;
+               WRITE_ONCE(*valp, (int)jif);
        } else {
-               int val = *valp;
+               int val = READ_ONCE(*valp);
                unsigned long lval;
                if (val < 0) {
                        *negp = true;
@@ -1291,8 +1294,8 @@ int proc_dointvec_userhz_jiffies(struct ctl_table *table, int write,
  * @ppos: the current position in the file
  *
  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
- * values from/to the user buffer, treated as an ASCII string. 
- * The values read are assumed to be in 1/1000 seconds, and 
+ * values from/to the user buffer, treated as an ASCII string.
+ * The values read are assumed to be in 1/1000 seconds, and
  * are converted into jiffies.
  *
  * Returns 0 on success.
@@ -2091,6 +2094,17 @@ static struct ctl_table vm_table[] = {
                .extra1         = SYSCTL_ZERO,
                .extra2         = SYSCTL_TWO_HUNDRED,
        },
+#ifdef CONFIG_NUMA
+       {
+               .procname       = "numa_stat",
+               .data           = &sysctl_vm_numa_stat,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = sysctl_vm_numa_stat_handler,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
+       },
+#endif
 #ifdef CONFIG_HUGETLB_PAGE
        {
                .procname       = "nr_hugepages",
@@ -2107,15 +2121,6 @@ static struct ctl_table vm_table[] = {
                .mode           = 0644,
                .proc_handler   = &hugetlb_mempolicy_sysctl_handler,
        },
-       {
-               .procname               = "numa_stat",
-               .data                   = &sysctl_vm_numa_stat,
-               .maxlen                 = sizeof(int),
-               .mode                   = 0644,
-               .proc_handler   = sysctl_vm_numa_stat_handler,
-               .extra1                 = SYSCTL_ZERO,
-               .extra2                 = SYSCTL_ONE,
-       },
 #endif
         {
                .procname       = "hugetlb_shm_group",
index 1cd10b102c51c31305e08733bba8e8541d42c11c..5dead89308b7424e0c5a718d6c9943ac141c23cc 100644 (file)
@@ -1051,15 +1051,24 @@ retry_delete:
 }
 
 /*
- * This is called by do_exit or de_thread, only when there are no more
- * references to the shared signal_struct.
+ * This is called by do_exit or de_thread, only when nobody else can
+ * modify the signal->posix_timers list. Yet we need sighand->siglock
+ * to prevent the race with /proc/pid/timers.
  */
-void exit_itimers(struct signal_struct *sig)
+void exit_itimers(struct task_struct *tsk)
 {
+       struct list_head timers;
        struct k_itimer *tmr;
 
-       while (!list_empty(&sig->posix_timers)) {
-               tmr = list_entry(sig->posix_timers.next, struct k_itimer, list);
+       if (list_empty(&tsk->signal->posix_timers))
+               return;
+
+       spin_lock_irq(&tsk->sighand->siglock);
+       list_replace_init(&tsk->signal->posix_timers, &timers);
+       spin_unlock_irq(&tsk->sighand->siglock);
+
+       while (!list_empty(&timers)) {
+               tmr = list_first_entry(&timers, struct k_itimer, list);
                itimer_delete(tmr);
        }
 }
index debbbb0832866892bdcedfb97100f0882d19ccd3..ccd6a5ade3e9f669ad7279151f46ffc449151712 100644 (file)
@@ -194,7 +194,8 @@ config FUNCTION_TRACER
          sequence is then dynamically patched into a tracer call when
          tracing is enabled by the administrator. If it's runtime disabled
          (the bootup default), then the overhead of the instructions is very
-         small and not measurable even in micro-benchmarks.
+         small and not measurable even in micro-benchmarks (at least on
+         x86, but may have impact on other architectures).
 
 config FUNCTION_GRAPH_TRACER
        bool "Kernel Function Graph Tracer"
index a8cfac0611bc390c72747b4c8845df9adff07861..b8dd546270750e17c3e7d447bf8b180b02ad0016 100644 (file)
@@ -9864,6 +9864,12 @@ void trace_init_global_iter(struct trace_iterator *iter)
        /* Output in nanoseconds only if we are using a clock in nanoseconds. */
        if (trace_clocks[iter->tr->clock_id].in_ns)
                iter->iter_flags |= TRACE_FILE_TIME_IN_NS;
+
+       /* Can not use kmalloc for iter.temp and iter.fmt */
+       iter->temp = static_temp_buf;
+       iter->temp_size = STATIC_TEMP_BUF_SIZE;
+       iter->fmt = static_fmt_buf;
+       iter->fmt_size = STATIC_FMT_BUF_SIZE;
 }
 
 void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
@@ -9896,11 +9902,6 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
 
        /* Simulate the iterator */
        trace_init_global_iter(&iter);
-       /* Can not use kmalloc for iter.temp and iter.fmt */
-       iter.temp = static_temp_buf;
-       iter.temp_size = STATIC_TEMP_BUF_SIZE;
-       iter.fmt = static_fmt_buf;
-       iter.fmt_size = STATIC_FMT_BUF_SIZE;
 
        for_each_tracing_cpu(cpu) {
                atomic_inc(&per_cpu_ptr(iter.array_buffer->data, cpu)->disabled);
index 48e82e141d54591a28e55670a5f6863e6dbcc962..e87a46794079dd30dac84bfa91fc19c99339bdd7 100644 (file)
@@ -4430,6 +4430,8 @@ static int parse_var_defs(struct hist_trigger_data *hist_data)
 
                        s = kstrdup(field_str, GFP_KERNEL);
                        if (!s) {
+                               kfree(hist_data->attrs->var_defs.name[n_vars]);
+                               hist_data->attrs->var_defs.name[n_vars] = NULL;
                                ret = -ENOMEM;
                                goto free;
                        }
index 230038d4f90818843b5ff69274fea1aa14f5d6ac..bb9962b33f95cec8cd6203f62fe3adf1fca1a480 100644 (file)
@@ -34,6 +34,27 @@ MODULE_LICENSE("GPL");
 #define WATCH_QUEUE_NOTE_SIZE 128
 #define WATCH_QUEUE_NOTES_PER_PAGE (PAGE_SIZE / WATCH_QUEUE_NOTE_SIZE)
 
+/*
+ * This must be called under the RCU read-lock, which makes
+ * sure that the wqueue still exists. It can then take the lock,
+ * and check that the wqueue hasn't been destroyed, which in
+ * turn makes sure that the notification pipe still exists.
+ */
+static inline bool lock_wqueue(struct watch_queue *wqueue)
+{
+       spin_lock_bh(&wqueue->lock);
+       if (unlikely(wqueue->defunct)) {
+               spin_unlock_bh(&wqueue->lock);
+               return false;
+       }
+       return true;
+}
+
+static inline void unlock_wqueue(struct watch_queue *wqueue)
+{
+       spin_unlock_bh(&wqueue->lock);
+}
+
 static void watch_queue_pipe_buf_release(struct pipe_inode_info *pipe,
                                         struct pipe_buffer *buf)
 {
@@ -69,6 +90,10 @@ static const struct pipe_buf_operations watch_queue_pipe_buf_ops = {
 
 /*
  * Post a notification to a watch queue.
+ *
+ * Must be called with the RCU lock for reading, and the
+ * watch_queue lock held, which guarantees that the pipe
+ * hasn't been released.
  */
 static bool post_one_notification(struct watch_queue *wqueue,
                                  struct watch_notification *n)
@@ -85,9 +110,6 @@ static bool post_one_notification(struct watch_queue *wqueue,
 
        spin_lock_irq(&pipe->rd_wait.lock);
 
-       if (wqueue->defunct)
-               goto out;
-
        mask = pipe->ring_size - 1;
        head = pipe->head;
        tail = pipe->tail;
@@ -203,7 +225,10 @@ void __post_watch_notification(struct watch_list *wlist,
                if (security_post_notification(watch->cred, cred, n) < 0)
                        continue;
 
-               post_one_notification(wqueue, n);
+               if (lock_wqueue(wqueue)) {
+                       post_one_notification(wqueue, n);
+                       unlock_wqueue(wqueue);
+               }
        }
 
        rcu_read_unlock();
@@ -462,11 +487,12 @@ int add_watch_to_object(struct watch *watch, struct watch_list *wlist)
                return -EAGAIN;
        }
 
-       spin_lock_bh(&wqueue->lock);
-       kref_get(&wqueue->usage);
-       kref_get(&watch->usage);
-       hlist_add_head(&watch->queue_node, &wqueue->watches);
-       spin_unlock_bh(&wqueue->lock);
+       if (lock_wqueue(wqueue)) {
+               kref_get(&wqueue->usage);
+               kref_get(&watch->usage);
+               hlist_add_head(&watch->queue_node, &wqueue->watches);
+               unlock_wqueue(wqueue);
+       }
 
        hlist_add_head(&watch->list_node, &wlist->watchers);
        return 0;
@@ -520,20 +546,15 @@ found:
 
        wqueue = rcu_dereference(watch->queue);
 
-       /* We don't need the watch list lock for the next bit as RCU is
-        * protecting *wqueue from deallocation.
-        */
-       if (wqueue) {
+       if (lock_wqueue(wqueue)) {
                post_one_notification(wqueue, &n.watch);
 
-               spin_lock_bh(&wqueue->lock);
-
                if (!hlist_unhashed(&watch->queue_node)) {
                        hlist_del_init_rcu(&watch->queue_node);
                        put_watch(watch);
                }
 
-               spin_unlock_bh(&wqueue->lock);
+               unlock_wqueue(wqueue);
        }
 
        if (wlist->release_watch) {
index a9f7eb04776851ac8e5aaeb9d5919fed167636ee..fd15230a703b76e846ec90a2ade25c148d252bee 100644 (file)
@@ -84,6 +84,9 @@ config UBSAN_SHIFT
 config UBSAN_DIV_ZERO
        bool "Perform checking for integer divide-by-zero"
        depends on $(cc-option,-fsanitize=integer-divide-by-zero)
+       # https://github.com/ClangBuiltLinux/linux/issues/1657
+       # https://github.com/llvm/llvm-project/issues/56289
+       depends on !CC_IS_CLANG
        help
          This option enables -fsanitize=integer-divide-by-zero which checks
          for integer division by zero. This is effectively redundant with the
index f4ab4f4aa3c7f5b269dcd1917c65f15f03d2475a..7ecdfdb5309e749b626a7b3db925c20b7846365f 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -491,7 +491,8 @@ void ida_free(struct ida *ida, unsigned int id)
        struct ida_bitmap *bitmap;
        unsigned long flags;
 
-       BUG_ON((int)id < 0);
+       if ((int)id < 0)
+               return;
 
        xas_lock_irqsave(&xas, flags);
        bitmap = xas_load(&xas);
index 59e1653799f83f56842febcda023bbe3e496adab..3c7b9d6dca95d30dfce3e0a41fc63febeb9e0dce 100644 (file)
@@ -336,8 +336,7 @@ static void damon_hugetlb_mkold(pte_t *pte, struct mm_struct *mm,
        if (pte_young(entry)) {
                referenced = true;
                entry = pte_mkold(entry);
-               huge_ptep_set_access_flags(vma, addr, pte, entry,
-                                          vma->vm_flags & VM_WRITE);
+               set_huge_pte_at(mm, addr, pte, entry);
        }
 
 #ifdef CONFIG_MMU_NOTIFIER
index 7a089145cad4b2b2fd32b47390277760eb15cc18..4cf7d4b6c950d9f4cddd2ff92d6f479b568fae44 100644 (file)
@@ -4798,6 +4798,19 @@ static inline vm_fault_t wp_huge_pmd(struct vm_fault *vmf)
 
 static vm_fault_t create_huge_pud(struct vm_fault *vmf)
 {
+#if defined(CONFIG_TRANSPARENT_HUGEPAGE) &&                    \
+       defined(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)
+       /* No support for anonymous transparent PUD pages yet */
+       if (vma_is_anonymous(vmf->vma))
+               return VM_FAULT_FALLBACK;
+       if (vmf->vma->vm_ops->huge_fault)
+               return vmf->vma->vm_ops->huge_fault(vmf, PE_SIZE_PUD);
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+       return VM_FAULT_FALLBACK;
+}
+
+static vm_fault_t wp_huge_pud(struct vm_fault *vmf, pud_t orig_pud)
+{
 #if defined(CONFIG_TRANSPARENT_HUGEPAGE) &&                    \
        defined(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)
        /* No support for anonymous transparent PUD pages yet */
@@ -4812,19 +4825,7 @@ static vm_fault_t create_huge_pud(struct vm_fault *vmf)
 split:
        /* COW or write-notify not handled on PUD level: split pud.*/
        __split_huge_pud(vmf->vma, vmf->pud, vmf->address);
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
-       return VM_FAULT_FALLBACK;
-}
-
-static vm_fault_t wp_huge_pud(struct vm_fault *vmf, pud_t orig_pud)
-{
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-       /* No support for anonymous transparent PUD pages yet */
-       if (vma_is_anonymous(vmf->vma))
-               return VM_FAULT_FALLBACK;
-       if (vmf->vma->vm_ops->huge_fault)
-               return vmf->vma->vm_ops->huge_fault(vmf, PE_SIZE_PUD);
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE && CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
        return VM_FAULT_FALLBACK;
 }
 
index 5bcb334cd6f216f037dcf52771f8dedfb16b7e8e..746c05acad2704ee2467820a3ed19e23047bbe8a 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1899,8 +1899,23 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
                /* Unexpected PMD-mapped THP? */
                VM_BUG_ON_FOLIO(!pvmw.pte, folio);
 
-               subpage = folio_page(folio,
-                               pte_pfn(*pvmw.pte) - folio_pfn(folio));
+               if (folio_is_zone_device(folio)) {
+                       /*
+                        * Our PTE is a non-present device exclusive entry and
+                        * calculating the subpage as for the common case would
+                        * result in an invalid pointer.
+                        *
+                        * Since only PAGE_SIZE pages can currently be
+                        * migrated, just set it to page. This will need to be
+                        * changed when hugepage migrations to device private
+                        * memory are supported.
+                        */
+                       VM_BUG_ON_FOLIO(folio_nr_pages(folio) > 1, folio);
+                       subpage = &folio->page;
+               } else {
+                       subpage = folio_page(folio,
+                                       pte_pfn(*pvmw.pte) - folio_pfn(folio));
+               }
                address = pvmw.address;
                anon_exclusive = folio_test_anon(folio) &&
                                 PageAnonExclusive(subpage);
@@ -1993,15 +2008,7 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
                        /*
                         * No need to invalidate here it will synchronize on
                         * against the special swap migration pte.
-                        *
-                        * The assignment to subpage above was computed from a
-                        * swap PTE which results in an invalid pointer.
-                        * Since only PAGE_SIZE pages can currently be
-                        * migrated, just set it to page. This will need to be
-                        * changed when hugepage migrations to device private
-                        * memory are supported.
                         */
-                       subpage = &folio->page;
                } else if (PageHWPoison(subpage)) {
                        pteval = swp_entry_to_pte(make_hwpoison_entry(subpage));
                        if (folio_test_hugetlb(folio)) {
index f4fa61dbbee3384b52d9fd22839995f45467ff34..dbbd1a7e65f334179dce5faf291b5a29b0b5f084 100644 (file)
@@ -78,6 +78,14 @@ static int __split_vmemmap_huge_pmd(pmd_t *pmd, unsigned long start)
 
        spin_lock(&init_mm.page_table_lock);
        if (likely(pmd_leaf(*pmd))) {
+               /*
+                * Higher order allocations from buddy allocator must be able to
+                * be treated as indepdenent small pages (as they can be freed
+                * individually).
+                */
+               if (!PageReserved(page))
+                       split_page(page, get_order(PMD_SIZE));
+
                /* Make pte visible before pmd. See comment in pmd_install(). */
                smp_wmb();
                pmd_populate_kernel(&init_mm, pmd, pgtable);
index 4f4892a5f767f9f36678226bf8c72d9aa733240b..07d3befc80e4134dd6b54be127197ffaad5c10e2 100644 (file)
@@ -246,7 +246,10 @@ static int mcontinue_atomic_pte(struct mm_struct *dst_mm,
        struct page *page;
        int ret;
 
-       ret = shmem_getpage(inode, pgoff, &page, SGP_READ);
+       ret = shmem_getpage(inode, pgoff, &page, SGP_NOALLOC);
+       /* Our caller expects us to return -EFAULT if we failed to find page. */
+       if (ret == -ENOENT)
+               ret = -EFAULT;
        if (ret)
                goto out;
        if (!page) {
index 53b1955b027f89245eb8dd46ede9d7bfd6e553a3..214532173536b790cf032615f73fb3d868d2aae1 100644 (file)
@@ -182,10 +182,14 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev,
        else if (dev->mtu > max_mtu)
                return -EINVAL;
 
+       /* Note: If this initial vlan_changelink() fails, we need
+        * to call vlan_dev_free_egress_priority() to free memory.
+        */
        err = vlan_changelink(dev, tb, data, extack);
-       if (err)
-               return err;
-       err = register_vlan_dev(dev, extack);
+
+       if (!err)
+               err = register_vlan_dev(dev, extack);
+
        if (err)
                vlan_dev_free_egress_priority(dev);
        return err;
index 59a5c1341c26a71f1605759be1cfc25c9dc79eb3..a0f99baafd357e22e21b1ed520b7247de7de1f2a 100644 (file)
@@ -571,6 +571,7 @@ int hci_dev_close(__u16 dev)
                goto done;
        }
 
+       cancel_work_sync(&hdev->power_on);
        if (hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF))
                cancel_delayed_work(&hdev->power_off);
 
@@ -2675,6 +2676,8 @@ void hci_unregister_dev(struct hci_dev *hdev)
        list_del(&hdev->list);
        write_unlock(&hci_dev_list_lock);
 
+       cancel_work_sync(&hdev->power_on);
+
        hci_cmd_sync_clear(hdev);
 
        if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks))
index 286d6767f0177e65f34db37c070f4785d183e733..1739e8cb3291eff52cfba8f85cc84536deb426c9 100644 (file)
@@ -4088,7 +4088,6 @@ int hci_dev_close_sync(struct hci_dev *hdev)
 
        bt_dev_dbg(hdev, "");
 
-       cancel_work_sync(&hdev->power_on);
        cancel_delayed_work(&hdev->power_off);
        cancel_delayed_work(&hdev->ncmd_timer);
 
index 65ee1b784a30f1876219a3a8695bc48359b84759..e60161bec850a6561f3358a89d7a6ef254bc5a07 100644 (file)
@@ -100,6 +100,7 @@ static inline u64 get_u64(const struct canfd_frame *cp, int offset)
 
 struct bcm_op {
        struct list_head list;
+       struct rcu_head rcu;
        int ifindex;
        canid_t can_id;
        u32 flags;
@@ -718,10 +719,9 @@ static struct bcm_op *bcm_find_op(struct list_head *ops,
        return NULL;
 }
 
-static void bcm_remove_op(struct bcm_op *op)
+static void bcm_free_op_rcu(struct rcu_head *rcu_head)
 {
-       hrtimer_cancel(&op->timer);
-       hrtimer_cancel(&op->thrtimer);
+       struct bcm_op *op = container_of(rcu_head, struct bcm_op, rcu);
 
        if ((op->frames) && (op->frames != &op->sframe))
                kfree(op->frames);
@@ -732,6 +732,14 @@ static void bcm_remove_op(struct bcm_op *op)
        kfree(op);
 }
 
+static void bcm_remove_op(struct bcm_op *op)
+{
+       hrtimer_cancel(&op->timer);
+       hrtimer_cancel(&op->thrtimer);
+
+       call_rcu(&op->rcu, bcm_free_op_rcu);
+}
+
 static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op)
 {
        if (op->rx_reg_dev == dev) {
@@ -757,6 +765,9 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
                if ((op->can_id == mh->can_id) && (op->ifindex == ifindex) &&
                    (op->flags & CAN_FD_FRAME) == (mh->flags & CAN_FD_FRAME)) {
 
+                       /* disable automatic timer on frame reception */
+                       op->flags |= RX_NO_AUTOTIMER;
+
                        /*
                         * Don't care if we're bound or not (due to netdev
                         * problems) can_rx_unregister() is always a save
@@ -785,7 +796,6 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
                                                  bcm_rx_handler, op);
 
                        list_del(&op->list);
-                       synchronize_rcu();
                        bcm_remove_op(op);
                        return 1; /* done */
                }
index 8e6f2296120662eb91a918a26c18f4396194ad79..30a1603a7225c1c6ed2d620410fdd1401caa57ff 100644 (file)
@@ -4863,7 +4863,10 @@ static u32 netif_receive_generic_xdp(struct sk_buff *skb,
 }
 
 /* When doing generic XDP we have to bypass the qdisc layer and the
- * network taps in order to match in-driver-XDP behavior.
+ * network taps in order to match in-driver-XDP behavior. This also means
+ * that XDP packets are able to starve other packets going through a qdisc,
+ * and DDOS attacks will be more effective. In-driver-XDP use dedicated TX
+ * queues, so they do not have this starvation issue.
  */
 void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog)
 {
@@ -4875,7 +4878,7 @@ void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog)
        txq = netdev_core_pick_tx(dev, skb, NULL);
        cpu = smp_processor_id();
        HARD_TX_LOCK(dev, txq, cpu);
-       if (!netif_xmit_stopped(txq)) {
+       if (!netif_xmit_frozen_or_drv_stopped(txq)) {
                rc = netdev_start_xmit(skb, dev, txq, 0);
                if (dev_xmit_complete(rc))
                        free_skb = false;
@@ -4883,6 +4886,7 @@ void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog)
        HARD_TX_UNLOCK(dev, txq);
        if (free_skb) {
                trace_xdp_exception(dev, xdp_prog, XDP_TX);
+               dev_core_stats_tx_dropped_inc(dev);
                kfree_skb(skb);
        }
 }
index 5d16d66727fc8f165b4865c62e349b88dd8badcd..7950f75207658c326b50cd69ce1c2b46863aee28 100644 (file)
@@ -6158,7 +6158,6 @@ static int bpf_push_seg6_encap(struct sk_buff *skb, u32 type, void *hdr, u32 len
        if (err)
                return err;
 
-       ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
        skb_set_transport_header(skb, sizeof(struct ipv6hdr));
 
        return seg6_lookup_nexthop(skb, NULL, 0);
@@ -7042,7 +7041,7 @@ BPF_CALL_5(bpf_tcp_check_syncookie, struct sock *, sk, void *, iph, u32, iph_len
        if (sk->sk_protocol != IPPROTO_TCP || sk->sk_state != TCP_LISTEN)
                return -EINVAL;
 
-       if (!sock_net(sk)->ipv4.sysctl_tcp_syncookies)
+       if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies))
                return -EINVAL;
 
        if (!th->ack || th->rst || th->syn)
@@ -7117,7 +7116,7 @@ BPF_CALL_5(bpf_tcp_gen_syncookie, struct sock *, sk, void *, iph, u32, iph_len,
        if (sk->sk_protocol != IPPROTO_TCP || sk->sk_state != TCP_LISTEN)
                return -EINVAL;
 
-       if (!sock_net(sk)->ipv4.sysctl_tcp_syncookies)
+       if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies))
                return -ENOENT;
 
        if (!th->syn || th->ack || th->fin || th->rst)
index 5f85e01d4093bb01dc52348204626aa29d616fcf..b0ff6153be6232c5df27a64ac6e271a546cfe6ce 100644 (file)
@@ -64,7 +64,7 @@ u32 secure_tcpv6_ts_off(const struct net *net,
                .daddr = *(struct in6_addr *)daddr,
        };
 
-       if (net->ipv4.sysctl_tcp_timestamps != 1)
+       if (READ_ONCE(net->ipv4.sysctl_tcp_timestamps) != 1)
                return 0;
 
        ts_secret_init();
@@ -120,7 +120,7 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
 #ifdef CONFIG_INET
 u32 secure_tcp_ts_off(const struct net *net, __be32 saddr, __be32 daddr)
 {
-       if (net->ipv4.sysctl_tcp_timestamps != 1)
+       if (READ_ONCE(net->ipv4.sysctl_tcp_timestamps) != 1)
                return 0;
 
        ts_secret_init();
index 3f00a28fe762affdd19eabb7777efb9b79586373..5daa1fa542490e884f427bf0a554890768b53907 100644 (file)
@@ -387,7 +387,7 @@ void reuseport_stop_listen_sock(struct sock *sk)
                prog = rcu_dereference_protected(reuse->prog,
                                                 lockdep_is_held(&reuseport_lock));
 
-               if (sock_net(sk)->ipv4.sysctl_tcp_migrate_req ||
+               if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_migrate_req) ||
                    (prog && prog->expected_attach_type == BPF_SK_REUSEPORT_SELECT_OR_MIGRATE)) {
                        /* Migration capable, move sk from the listening section
                         * to the closed section.
@@ -545,7 +545,7 @@ struct sock *reuseport_migrate_sock(struct sock *sk,
        hash = migrating_sk->sk_hash;
        prog = rcu_dereference(reuse->prog);
        if (!prog || prog->expected_attach_type != BPF_SK_REUSEPORT_SELECT_OR_MIGRATE) {
-               if (sock_net(sk)->ipv4.sysctl_tcp_migrate_req)
+               if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_migrate_req))
                        goto select_by_hash;
                goto failure;
        }
index 3738f2d40a0bafbcfbb7b3e6eac93545ba8b37a9..2dd76eb1621c74b514f3e0480a688da7ff44627b 100644 (file)
@@ -248,6 +248,7 @@ static void dsa_port_reset_vlan_filtering(struct dsa_port *dp,
        struct netlink_ext_ack extack = {0};
        bool change_vlan_filtering = false;
        struct dsa_switch *ds = dp->ds;
+       struct dsa_port *other_dp;
        bool vlan_filtering;
        int err;
 
@@ -270,8 +271,8 @@ static void dsa_port_reset_vlan_filtering(struct dsa_port *dp,
         * VLAN-aware bridge.
         */
        if (change_vlan_filtering && ds->vlan_filtering_is_global) {
-               dsa_switch_for_each_port(dp, ds) {
-                       struct net_device *br = dsa_port_bridge_dev_get(dp);
+               dsa_switch_for_each_port(other_dp, ds) {
+                       struct net_device *br = dsa_port_bridge_dev_get(other_dp);
 
                        if (br && br_vlan_enabled(br)) {
                                change_vlan_filtering = false;
@@ -799,7 +800,7 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
                ds->vlan_filtering = vlan_filtering;
 
                dsa_switch_for_each_user_port(other_dp, ds) {
-                       struct net_device *slave = dp->slave;
+                       struct net_device *slave = other_dp->slave;
 
                        /* We might be called in the unbind path, so not
                         * all slave devices might still be registered.
index 93da9f783bec52e4bda6213dc78ef3820e180cc4..252c8bceaba42bc01a8bf266c0acf842521e5871 100644 (file)
@@ -217,7 +217,7 @@ int inet_listen(struct socket *sock, int backlog)
                 * because the socket was in TCP_LISTEN state previously but
                 * was shutdown() rather than close().
                 */
-               tcp_fastopen = sock_net(sk)->ipv4.sysctl_tcp_fastopen;
+               tcp_fastopen = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fastopen);
                if ((tcp_fastopen & TFO_SERVER_WO_SOCKOPT1) &&
                    (tcp_fastopen & TFO_SERVER_ENABLE) &&
                    !inet_csk(sk)->icsk_accept_queue.fastopenq.max_qlen) {
@@ -335,7 +335,7 @@ lookup_protocol:
                        inet->hdrincl = 1;
        }
 
-       if (net->ipv4.sysctl_ip_no_pmtu_disc)
+       if (READ_ONCE(net->ipv4.sysctl_ip_no_pmtu_disc))
                inet->pmtudisc = IP_PMTUDISC_DONT;
        else
                inet->pmtudisc = IP_PMTUDISC_WANT;
@@ -1246,7 +1246,7 @@ static int inet_sk_reselect_saddr(struct sock *sk)
        if (new_saddr == old_saddr)
                return 0;
 
-       if (sock_net(sk)->ipv4.sysctl_ip_dynaddr > 1) {
+       if (READ_ONCE(sock_net(sk)->ipv4.sysctl_ip_dynaddr) > 1) {
                pr_info("%s(): shifting inet->saddr from %pI4 to %pI4\n",
                        __func__, &old_saddr, &new_saddr);
        }
@@ -1301,7 +1301,7 @@ int inet_sk_rebuild_header(struct sock *sk)
                 * Other protocols have to map its equivalent state to TCP_SYN_SENT.
                 * DCCP maps its DCCP_REQUESTING state to TCP_SYN_SENT. -acme
                 */
-               if (!sock_net(sk)->ipv4.sysctl_ip_dynaddr ||
+               if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_ip_dynaddr) ||
                    sk->sk_state != TCP_SYN_SENT ||
                    (sk->sk_userlocks & SOCK_BINDADDR_LOCK) ||
                    (err = inet_sk_reselect_saddr(sk)) != 0)
@@ -1710,24 +1710,14 @@ static const struct net_protocol igmp_protocol = {
 };
 #endif
 
-/* thinking of making this const? Don't.
- * early_demux can change based on sysctl.
- */
-static struct net_protocol tcp_protocol = {
-       .early_demux    =       tcp_v4_early_demux,
-       .early_demux_handler =  tcp_v4_early_demux,
+static const struct net_protocol tcp_protocol = {
        .handler        =       tcp_v4_rcv,
        .err_handler    =       tcp_v4_err,
        .no_policy      =       1,
        .icmp_strict_tag_validation = 1,
 };
 
-/* thinking of making this const? Don't.
- * early_demux can change based on sysctl.
- */
-static struct net_protocol udp_protocol = {
-       .early_demux =  udp_v4_early_demux,
-       .early_demux_handler =  udp_v4_early_demux,
+static const struct net_protocol udp_protocol = {
        .handler =      udp_rcv,
        .err_handler =  udp_err,
        .no_policy =    1,
index 6eea1e9e998d5efd2d476a955282ecf56434baff..f8ad04470d3ace7f2e59ee5890467d689be52752 100644 (file)
@@ -507,7 +507,7 @@ static int ah_init_state(struct xfrm_state *x)
 
        if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
            crypto_ahash_digestsize(ahash)) {
-               pr_info("%s: %s digestsize %u != %hu\n",
+               pr_info("%s: %s digestsize %u != %u\n",
                        __func__, x->aalg->alg_name,
                        crypto_ahash_digestsize(ahash),
                        aalg_desc->uinfo.auth.icv_fullbits / 8);
index 62d5f99760aacd03b006d6256151ed530896e11b..6cd3b6c559f0586961bbb3a254e108cf8130573e 100644 (file)
@@ -239,7 +239,7 @@ static int cipso_v4_cache_check(const unsigned char *key,
        struct cipso_v4_map_cache_entry *prev_entry = NULL;
        u32 hash;
 
-       if (!cipso_v4_cache_enabled)
+       if (!READ_ONCE(cipso_v4_cache_enabled))
                return -ENOENT;
 
        hash = cipso_v4_map_cache_hash(key, key_len);
@@ -296,13 +296,14 @@ static int cipso_v4_cache_check(const unsigned char *key,
 int cipso_v4_cache_add(const unsigned char *cipso_ptr,
                       const struct netlbl_lsm_secattr *secattr)
 {
+       int bkt_size = READ_ONCE(cipso_v4_cache_bucketsize);
        int ret_val = -EPERM;
        u32 bkt;
        struct cipso_v4_map_cache_entry *entry = NULL;
        struct cipso_v4_map_cache_entry *old_entry = NULL;
        u32 cipso_ptr_len;
 
-       if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0)
+       if (!READ_ONCE(cipso_v4_cache_enabled) || bkt_size <= 0)
                return 0;
 
        cipso_ptr_len = cipso_ptr[1];
@@ -322,7 +323,7 @@ int cipso_v4_cache_add(const unsigned char *cipso_ptr,
 
        bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETS - 1);
        spin_lock_bh(&cipso_v4_cache[bkt].lock);
-       if (cipso_v4_cache[bkt].size < cipso_v4_cache_bucketsize) {
+       if (cipso_v4_cache[bkt].size < bkt_size) {
                list_add(&entry->list, &cipso_v4_cache[bkt].list);
                cipso_v4_cache[bkt].size += 1;
        } else {
@@ -1199,7 +1200,8 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
                /* This will send packets using the "optimized" format when
                 * possible as specified in  section 3.4.2.6 of the
                 * CIPSO draft. */
-               if (cipso_v4_rbm_optfmt && ret_val > 0 && ret_val <= 10)
+               if (READ_ONCE(cipso_v4_rbm_optfmt) && ret_val > 0 &&
+                   ret_val <= 10)
                        tag_len = 14;
                else
                        tag_len = 4 + ret_val;
@@ -1603,7 +1605,7 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option)
                         * all the CIPSO validations here but it doesn't
                         * really specify _exactly_ what we need to validate
                         * ... so, just make it a sysctl tunable. */
-                       if (cipso_v4_rbm_strictvalid) {
+                       if (READ_ONCE(cipso_v4_rbm_strictvalid)) {
                                if (cipso_v4_map_lvl_valid(doi_def,
                                                           tag[3]) < 0) {
                                        err_offset = opt_iter + 3;
index b21238df33014dacaf0c9c409101e686f7490f35..b694f352ce7a80a20bc0893a6378d8db69c42a48 100644 (file)
@@ -1108,7 +1108,7 @@ static int esp_init_authenc(struct xfrm_state *x)
                err = -EINVAL;
                if (aalg_desc->uinfo.auth.icv_fullbits / 8 !=
                    crypto_aead_authsize(aead)) {
-                       pr_info("ESP: %s digestsize %u != %hu\n",
+                       pr_info("ESP: %s digestsize %u != %u\n",
                                x->aalg->alg_name,
                                crypto_aead_authsize(aead),
                                aalg_desc->uinfo.auth.icv_fullbits / 8);
index a57ba23571c96eb218939294b0077cdc5fe158f9..db7b2503f068209c30cc0c81295a33fba168ad03 100644 (file)
@@ -1230,7 +1230,7 @@ static int fib_check_nh_nongw(struct net *net, struct fib_nh *nh,
 
        nh->fib_nh_dev = in_dev->dev;
        dev_hold_track(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC);
-       nh->fib_nh_scope = RT_SCOPE_HOST;
+       nh->fib_nh_scope = RT_SCOPE_LINK;
        if (!netif_carrier_ok(nh->fib_nh_dev))
                nh->fib_nh_flags |= RTNH_F_LINKDOWN;
        err = 0;
@@ -1811,7 +1811,7 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
                        goto nla_put_failure;
                if (nexthop_is_blackhole(fi->nh))
                        rtm->rtm_type = RTN_BLACKHOLE;
-               if (!fi->fib_net->ipv4.sysctl_nexthop_compat_mode)
+               if (!READ_ONCE(fi->fib_net->ipv4.sysctl_nexthop_compat_mode))
                        goto offload;
        }
 
@@ -2216,7 +2216,7 @@ void fib_select_multipath(struct fib_result *res, int hash)
        }
 
        change_nexthops(fi) {
-               if (net->ipv4.sysctl_fib_multipath_use_neigh) {
+               if (READ_ONCE(net->ipv4.sysctl_fib_multipath_use_neigh)) {
                        if (!fib_good_nh(nexthop_nh))
                                continue;
                        if (!first) {
index 2734c3af7e2454fe8d57f5171071ae5afe795eda..46e8a5125853aeb95c97252e65be94a185b52c3d 100644 (file)
@@ -498,7 +498,7 @@ static void tnode_free(struct key_vector *tn)
                tn = container_of(head, struct tnode, rcu)->kv;
        }
 
-       if (tnode_free_size >= sysctl_fib_sync_mem) {
+       if (tnode_free_size >= READ_ONCE(sysctl_fib_sync_mem)) {
                tnode_free_size = 0;
                synchronize_rcu();
        }
index efea0e796f064d21fdb5854070c878581427fcb6..d5d745c3e345b710d365d31a5801a006072f0e4e 100644 (file)
@@ -253,11 +253,12 @@ bool icmp_global_allow(void)
        spin_lock(&icmp_global.lock);
        delta = min_t(u32, now - icmp_global.stamp, HZ);
        if (delta >= HZ / 50) {
-               incr = sysctl_icmp_msgs_per_sec * delta / HZ ;
+               incr = READ_ONCE(sysctl_icmp_msgs_per_sec) * delta / HZ;
                if (incr)
                        WRITE_ONCE(icmp_global.stamp, now);
        }
-       credit = min_t(u32, icmp_global.credit + incr, sysctl_icmp_msgs_burst);
+       credit = min_t(u32, icmp_global.credit + incr,
+                      READ_ONCE(sysctl_icmp_msgs_burst));
        if (credit) {
                /* We want to use a credit of one in average, but need to randomize
                 * it for security reasons.
@@ -281,7 +282,7 @@ static bool icmpv4_mask_allow(struct net *net, int type, int code)
                return true;
 
        /* Limit if icmp type is enabled in ratemask. */
-       if (!((1 << type) & net->ipv4.sysctl_icmp_ratemask))
+       if (!((1 << type) & READ_ONCE(net->ipv4.sysctl_icmp_ratemask)))
                return true;
 
        return false;
@@ -319,7 +320,8 @@ static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
 
        vif = l3mdev_master_ifindex(dst->dev);
        peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, vif, 1);
-       rc = inet_peer_xrlim_allow(peer, net->ipv4.sysctl_icmp_ratelimit);
+       rc = inet_peer_xrlim_allow(peer,
+                                  READ_ONCE(net->ipv4.sysctl_icmp_ratelimit));
        if (peer)
                inet_putpeer(peer);
 out:
@@ -692,7 +694,7 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
 
                rcu_read_lock();
                if (rt_is_input_route(rt) &&
-                   net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr)
+                   READ_ONCE(net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr))
                        dev = dev_get_by_index_rcu(net, inet_iif(skb_in));
 
                if (dev)
@@ -879,7 +881,7 @@ static enum skb_drop_reason icmp_unreach(struct sk_buff *skb)
                         * values please see
                         * Documentation/networking/ip-sysctl.rst
                         */
-                       switch (net->ipv4.sysctl_ip_no_pmtu_disc) {
+                       switch (READ_ONCE(net->ipv4.sysctl_ip_no_pmtu_disc)) {
                        default:
                                net_dbg_ratelimited("%pI4: fragmentation needed and DF set\n",
                                                    &iph->daddr);
@@ -932,7 +934,7 @@ static enum skb_drop_reason icmp_unreach(struct sk_buff *skb)
         *      get the other vendor to fix their kit.
         */
 
-       if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses &&
+       if (!READ_ONCE(net->ipv4.sysctl_icmp_ignore_bogus_error_responses) &&
            inet_addr_type_dev_table(net, skb->dev, iph->daddr) == RTN_BROADCAST) {
                net_warn_ratelimited("%pI4 sent an invalid ICMP type %u, code %u error to a broadcast: %pI4 on %s\n",
                                     &ip_hdr(skb)->saddr,
@@ -992,7 +994,7 @@ static enum skb_drop_reason icmp_echo(struct sk_buff *skb)
 
        net = dev_net(skb_dst(skb)->dev);
        /* should there be an ICMP stat for ignored echos? */
-       if (net->ipv4.sysctl_icmp_echo_ignore_all)
+       if (READ_ONCE(net->ipv4.sysctl_icmp_echo_ignore_all))
                return SKB_NOT_DROPPED_YET;
 
        icmp_param.data.icmph      = *icmp_hdr(skb);
@@ -1027,7 +1029,7 @@ bool icmp_build_probe(struct sk_buff *skb, struct icmphdr *icmphdr)
        u16 ident_len;
        u8 status;
 
-       if (!net->ipv4.sysctl_icmp_echo_enable_probe)
+       if (!READ_ONCE(net->ipv4.sysctl_icmp_echo_enable_probe))
                return false;
 
        /* We currently only support probing interfaces on the proxy node
@@ -1248,7 +1250,7 @@ int icmp_rcv(struct sk_buff *skb)
                 */
                if ((icmph->type == ICMP_ECHO ||
                     icmph->type == ICMP_TIMESTAMP) &&
-                   net->ipv4.sysctl_icmp_echo_ignore_broadcasts) {
+                   READ_ONCE(net->ipv4.sysctl_icmp_echo_ignore_broadcasts)) {
                        reason = SKB_DROP_REASON_INVALID_PROTO;
                        goto error;
                }
index b65d074d9620a0e2c5332c29e7741a62c3466c97..e3ab0cb616246b2b120515996e23ce1e748f2fb6 100644 (file)
@@ -467,7 +467,8 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc,
 
        if (pmc->multiaddr == IGMP_ALL_HOSTS)
                return skb;
-       if (ipv4_is_local_multicast(pmc->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports)
+       if (ipv4_is_local_multicast(pmc->multiaddr) &&
+           !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
                return skb;
 
        mtu = READ_ONCE(dev->mtu);
@@ -593,7 +594,7 @@ static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc)
                        if (pmc->multiaddr == IGMP_ALL_HOSTS)
                                continue;
                        if (ipv4_is_local_multicast(pmc->multiaddr) &&
-                            !net->ipv4.sysctl_igmp_llm_reports)
+                           !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
                                continue;
                        spin_lock_bh(&pmc->lock);
                        if (pmc->sfcount[MCAST_EXCLUDE])
@@ -736,7 +737,8 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
        if (type == IGMPV3_HOST_MEMBERSHIP_REPORT)
                return igmpv3_send_report(in_dev, pmc);
 
-       if (ipv4_is_local_multicast(group) && !net->ipv4.sysctl_igmp_llm_reports)
+       if (ipv4_is_local_multicast(group) &&
+           !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
                return 0;
 
        if (type == IGMP_HOST_LEAVE_MESSAGE)
@@ -825,7 +827,7 @@ static void igmp_ifc_event(struct in_device *in_dev)
        struct net *net = dev_net(in_dev->dev);
        if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev))
                return;
-       WRITE_ONCE(in_dev->mr_ifc_count, in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv);
+       WRITE_ONCE(in_dev->mr_ifc_count, in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv));
        igmp_ifc_start_timer(in_dev, 1);
 }
 
@@ -920,7 +922,8 @@ static bool igmp_heard_report(struct in_device *in_dev, __be32 group)
 
        if (group == IGMP_ALL_HOSTS)
                return false;
-       if (ipv4_is_local_multicast(group) && !net->ipv4.sysctl_igmp_llm_reports)
+       if (ipv4_is_local_multicast(group) &&
+           !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
                return false;
 
        rcu_read_lock();
@@ -1006,7 +1009,7 @@ static bool igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
                 * received value was zero, use the default or statically
                 * configured value.
                 */
-               in_dev->mr_qrv = ih3->qrv ?: net->ipv4.sysctl_igmp_qrv;
+               in_dev->mr_qrv = ih3->qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
                in_dev->mr_qi = IGMPV3_QQIC(ih3->qqic)*HZ ?: IGMP_QUERY_INTERVAL;
 
                /* RFC3376, 8.3. Query Response Interval:
@@ -1045,7 +1048,7 @@ static bool igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
                if (im->multiaddr == IGMP_ALL_HOSTS)
                        continue;
                if (ipv4_is_local_multicast(im->multiaddr) &&
-                   !net->ipv4.sysctl_igmp_llm_reports)
+                   !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
                        continue;
                spin_lock_bh(&im->lock);
                if (im->tm_running)
@@ -1186,7 +1189,7 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im,
        pmc->interface = im->interface;
        in_dev_hold(in_dev);
        pmc->multiaddr = im->multiaddr;
-       pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
+       pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
        pmc->sfmode = im->sfmode;
        if (pmc->sfmode == MCAST_INCLUDE) {
                struct ip_sf_list *psf;
@@ -1237,9 +1240,11 @@ static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im)
                        swap(im->tomb, pmc->tomb);
                        swap(im->sources, pmc->sources);
                        for (psf = im->sources; psf; psf = psf->sf_next)
-                               psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
+                               psf->sf_crcount = in_dev->mr_qrv ?:
+                                       READ_ONCE(net->ipv4.sysctl_igmp_qrv);
                } else {
-                       im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
+                       im->crcount = in_dev->mr_qrv ?:
+                               READ_ONCE(net->ipv4.sysctl_igmp_qrv);
                }
                in_dev_put(pmc->interface);
                kfree_pmc(pmc);
@@ -1296,7 +1301,8 @@ static void __igmp_group_dropped(struct ip_mc_list *im, gfp_t gfp)
 #ifdef CONFIG_IP_MULTICAST
        if (im->multiaddr == IGMP_ALL_HOSTS)
                return;
-       if (ipv4_is_local_multicast(im->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports)
+       if (ipv4_is_local_multicast(im->multiaddr) &&
+           !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
                return;
 
        reporter = im->reporter;
@@ -1338,13 +1344,14 @@ static void igmp_group_added(struct ip_mc_list *im)
 #ifdef CONFIG_IP_MULTICAST
        if (im->multiaddr == IGMP_ALL_HOSTS)
                return;
-       if (ipv4_is_local_multicast(im->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports)
+       if (ipv4_is_local_multicast(im->multiaddr) &&
+           !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
                return;
 
        if (in_dev->dead)
                return;
 
-       im->unsolicit_count = net->ipv4.sysctl_igmp_qrv;
+       im->unsolicit_count = READ_ONCE(net->ipv4.sysctl_igmp_qrv);
        if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) {
                spin_lock_bh(&im->lock);
                igmp_start_timer(im, IGMP_INITIAL_REPORT_DELAY);
@@ -1358,7 +1365,7 @@ static void igmp_group_added(struct ip_mc_list *im)
         * IN() to IN(A).
         */
        if (im->sfmode == MCAST_EXCLUDE)
-               im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
+               im->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
 
        igmp_ifc_event(in_dev);
 #endif
@@ -1642,7 +1649,7 @@ static void ip_mc_rejoin_groups(struct in_device *in_dev)
                if (im->multiaddr == IGMP_ALL_HOSTS)
                        continue;
                if (ipv4_is_local_multicast(im->multiaddr) &&
-                   !net->ipv4.sysctl_igmp_llm_reports)
+                   !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
                        continue;
 
                /* a failover is happening and switches
@@ -1749,7 +1756,7 @@ static void ip_mc_reset(struct in_device *in_dev)
 
        in_dev->mr_qi = IGMP_QUERY_INTERVAL;
        in_dev->mr_qri = IGMP_QUERY_RESPONSE_INTERVAL;
-       in_dev->mr_qrv = net->ipv4.sysctl_igmp_qrv;
+       in_dev->mr_qrv = READ_ONCE(net->ipv4.sysctl_igmp_qrv);
 }
 #else
 static void ip_mc_reset(struct in_device *in_dev)
@@ -1883,7 +1890,7 @@ static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,
 #ifdef CONFIG_IP_MULTICAST
                if (psf->sf_oldin &&
                    !IGMP_V1_SEEN(in_dev) && !IGMP_V2_SEEN(in_dev)) {
-                       psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
+                       psf->sf_crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
                        psf->sf_next = pmc->tomb;
                        pmc->tomb = psf;
                        rv = 1;
@@ -1947,7 +1954,7 @@ static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
                /* filter mode change */
                pmc->sfmode = MCAST_INCLUDE;
 #ifdef CONFIG_IP_MULTICAST
-               pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
+               pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
                WRITE_ONCE(in_dev->mr_ifc_count, pmc->crcount);
                for (psf = pmc->sources; psf; psf = psf->sf_next)
                        psf->sf_crcount = 0;
@@ -2126,7 +2133,7 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
 #ifdef CONFIG_IP_MULTICAST
                /* else no filters; keep old mode for reports */
 
-               pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
+               pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
                WRITE_ONCE(in_dev->mr_ifc_count, pmc->crcount);
                for (psf = pmc->sources; psf; psf = psf->sf_next)
                        psf->sf_crcount = 0;
@@ -2192,7 +2199,7 @@ static int __ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr,
                count++;
        }
        err = -ENOBUFS;
-       if (count >= net->ipv4.sysctl_igmp_max_memberships)
+       if (count >= READ_ONCE(net->ipv4.sysctl_igmp_max_memberships))
                goto done;
        iml = sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL);
        if (!iml)
@@ -2379,7 +2386,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
        }
        /* else, add a new source to the filter */
 
-       if (psl && psl->sl_count >= net->ipv4.sysctl_igmp_max_msf) {
+       if (psl && psl->sl_count >= READ_ONCE(net->ipv4.sysctl_igmp_max_msf)) {
                err = -ENOBUFS;
                goto done;
        }
index 53f5f956d9485df5cb863c8287c1fa9989bb29c9..eb31c7158b39cbcefbef4d4f3ee9ce0d8d606ca9 100644 (file)
@@ -263,7 +263,7 @@ next_port:
                goto other_half_scan;
        }
 
-       if (net->ipv4.sysctl_ip_autobind_reuse && !relax) {
+       if (READ_ONCE(net->ipv4.sysctl_ip_autobind_reuse) && !relax) {
                /* We still have a chance to connect to different destinations */
                relax = true;
                goto ports_exhausted;
@@ -833,7 +833,8 @@ static void reqsk_timer_handler(struct timer_list *t)
 
        icsk = inet_csk(sk_listener);
        net = sock_net(sk_listener);
-       max_syn_ack_retries = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_synack_retries;
+       max_syn_ack_retries = icsk->icsk_syn_retries ? :
+               READ_ONCE(net->ipv4.sysctl_tcp_synack_retries);
        /* Normally all the openreqs are young and become mature
         * (i.e. converted to established socket) for first timeout.
         * If synack was not acknowledged for 1 second, it means
index 0ec501845cb3bb51082f8091b4e0ebb32f83bf33..47ccc343c9fb0a995b817d938f25a779dd8221c0 100644 (file)
@@ -156,7 +156,8 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk,
 {
        struct inet_timewait_sock *tw;
 
-       if (refcount_read(&dr->tw_refcount) - 1 >= dr->sysctl_max_tw_buckets)
+       if (refcount_read(&dr->tw_refcount) - 1 >=
+           READ_ONCE(dr->sysctl_max_tw_buckets))
                return NULL;
 
        tw = kmem_cache_alloc(sk->sk_prot_creator->twsk_prot->twsk_slab,
index da21dfce24d7390bdc51899e03a0c7b3efbc3cec..e9fed83e9b3cc5e7d835f3c8c2dfa05233292567 100644 (file)
@@ -141,16 +141,20 @@ static void inet_peer_gc(struct inet_peer_base *base,
                         struct inet_peer *gc_stack[],
                         unsigned int gc_cnt)
 {
+       int peer_threshold, peer_maxttl, peer_minttl;
        struct inet_peer *p;
        __u32 delta, ttl;
        int i;
 
-       if (base->total >= inet_peer_threshold)
+       peer_threshold = READ_ONCE(inet_peer_threshold);
+       peer_maxttl = READ_ONCE(inet_peer_maxttl);
+       peer_minttl = READ_ONCE(inet_peer_minttl);
+
+       if (base->total >= peer_threshold)
                ttl = 0; /* be aggressive */
        else
-               ttl = inet_peer_maxttl
-                               - (inet_peer_maxttl - inet_peer_minttl) / HZ *
-                                       base->total / inet_peer_threshold * HZ;
+               ttl = peer_maxttl - (peer_maxttl - peer_minttl) / HZ *
+                       base->total / peer_threshold * HZ;
        for (i = 0; i < gc_cnt; i++) {
                p = gc_stack[i];
 
index e3aa436a1bdf8f5349b5ab7f8ef3c91a6cd2c3bd..e18931a6d15341d7115e608d614b16ad93f91273 100644 (file)
@@ -157,7 +157,7 @@ int ip_forward(struct sk_buff *skb)
            !skb_sec_path(skb))
                ip_rt_send_redirect(skb);
 
-       if (net->ipv4.sysctl_ip_fwd_update_priority)
+       if (READ_ONCE(net->ipv4.sysctl_ip_fwd_update_priority))
                skb->priority = rt_tos2priority(iph->tos);
 
        return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD,
index b1165f717cd1f21d05e7ea204853ca6b05ac9703..1b512390b3cf30dd123d75a6794b993553589b09 100644 (file)
@@ -312,14 +312,13 @@ static bool ip_can_use_hint(const struct sk_buff *skb, const struct iphdr *iph,
               ip_hdr(hint)->tos == iph->tos;
 }
 
-INDIRECT_CALLABLE_DECLARE(int udp_v4_early_demux(struct sk_buff *));
-INDIRECT_CALLABLE_DECLARE(int tcp_v4_early_demux(struct sk_buff *));
+int tcp_v4_early_demux(struct sk_buff *skb);
+int udp_v4_early_demux(struct sk_buff *skb);
 static int ip_rcv_finish_core(struct net *net, struct sock *sk,
                              struct sk_buff *skb, struct net_device *dev,
                              const struct sk_buff *hint)
 {
        const struct iphdr *iph = ip_hdr(skb);
-       int (*edemux)(struct sk_buff *skb);
        int err, drop_reason;
        struct rtable *rt;
 
@@ -332,21 +331,29 @@ static int ip_rcv_finish_core(struct net *net, struct sock *sk,
                        goto drop_error;
        }
 
-       if (net->ipv4.sysctl_ip_early_demux &&
+       if (READ_ONCE(net->ipv4.sysctl_ip_early_demux) &&
            !skb_dst(skb) &&
            !skb->sk &&
            !ip_is_fragment(iph)) {
-               const struct net_protocol *ipprot;
-               int protocol = iph->protocol;
-
-               ipprot = rcu_dereference(inet_protos[protocol]);
-               if (ipprot && (edemux = READ_ONCE(ipprot->early_demux))) {
-                       err = INDIRECT_CALL_2(edemux, tcp_v4_early_demux,
-                                             udp_v4_early_demux, skb);
-                       if (unlikely(err))
-                               goto drop_error;
-                       /* must reload iph, skb->head might have changed */
-                       iph = ip_hdr(skb);
+               switch (iph->protocol) {
+               case IPPROTO_TCP:
+                       if (READ_ONCE(net->ipv4.sysctl_tcp_early_demux)) {
+                               tcp_v4_early_demux(skb);
+
+                               /* must reload iph, skb->head might have changed */
+                               iph = ip_hdr(skb);
+                       }
+                       break;
+               case IPPROTO_UDP:
+                       if (READ_ONCE(net->ipv4.sysctl_udp_early_demux)) {
+                               err = udp_v4_early_demux(skb);
+                               if (unlikely(err))
+                                       goto drop_error;
+
+                               /* must reload iph, skb->head might have changed */
+                               iph = ip_hdr(skb);
+                       }
+                       break;
                }
        }
 
index 445a9ecaefa19b7ee92bbd98f3c164c2389a2e87..a8a323ecbb54b702e0a744e44f34ddcef7e2d383 100644 (file)
@@ -782,7 +782,7 @@ static int ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval, int optlen)
        /* numsrc >= (4G-140)/128 overflow in 32 bits */
        err = -ENOBUFS;
        if (gsf->gf_numsrc >= 0x1ffffff ||
-           gsf->gf_numsrc > sock_net(sk)->ipv4.sysctl_igmp_max_msf)
+           gsf->gf_numsrc > READ_ONCE(sock_net(sk)->ipv4.sysctl_igmp_max_msf))
                goto out_free_gsf;
 
        err = -EINVAL;
@@ -832,7 +832,7 @@ static int compat_ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
 
        /* numsrc >= (4G-140)/128 overflow in 32 bits */
        err = -ENOBUFS;
-       if (n > sock_net(sk)->ipv4.sysctl_igmp_max_msf)
+       if (n > READ_ONCE(sock_net(sk)->ipv4.sysctl_igmp_max_msf))
                goto out_free_gsf;
        err = set_mcast_msfilter(sk, gf32->gf_interface, n, gf32->gf_fmode,
                                 &gf32->gf_group, gf32->gf_slist_flex);
@@ -1244,7 +1244,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, int optname,
                }
                /* numsrc >= (1G-4) overflow in 32 bits */
                if (msf->imsf_numsrc >= 0x3ffffffcU ||
-                   msf->imsf_numsrc > net->ipv4.sysctl_igmp_max_msf) {
+                   msf->imsf_numsrc > READ_ONCE(net->ipv4.sysctl_igmp_max_msf)) {
                        kfree(msf);
                        err = -ENOBUFS;
                        break;
@@ -1606,7 +1606,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
        {
                struct net *net = sock_net(sk);
                val = (inet->uc_ttl == -1 ?
-                      net->ipv4.sysctl_ip_default_ttl :
+                      READ_ONCE(net->ipv4.sysctl_ip_default_ttl) :
                       inet->uc_ttl);
                break;
        }
index 918c61fda0f3000fc3e8ccbdb65652dc320c19db..d640adcaf1b125590ad60578c815b5a9ce20dfa2 100644 (file)
@@ -62,7 +62,7 @@ struct sk_buff *nf_reject_skb_v4_tcp_reset(struct net *net,
 
        skb_reserve(nskb, LL_MAX_HEADER);
        niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP,
-                                  net->ipv4.sysctl_ip_default_ttl);
+                                  READ_ONCE(net->ipv4.sysctl_ip_default_ttl));
        nf_reject_ip_tcphdr_put(nskb, oldskb, oth);
        niph->tot_len = htons(nskb->len);
        ip_send_check(niph);
@@ -117,7 +117,7 @@ struct sk_buff *nf_reject_skb_v4_unreach(struct net *net,
 
        skb_reserve(nskb, LL_MAX_HEADER);
        niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_ICMP,
-                                  net->ipv4.sysctl_ip_default_ttl);
+                                  READ_ONCE(net->ipv4.sysctl_ip_default_ttl));
 
        skb_reset_transport_header(nskb);
        icmph = skb_put_zero(nskb, sizeof(struct icmphdr));
index e459a391e607d34e16828bef13a5ce22ba6dde89..853a75a8fbafc94806aa3984b5091baed7d805a5 100644 (file)
@@ -1858,7 +1858,7 @@ static void __remove_nexthop_fib(struct net *net, struct nexthop *nh)
                /* __ip6_del_rt does a release, so do a hold here */
                fib6_info_hold(f6i);
                ipv6_stub->ip6_del_rt(net, f6i,
-                                     !net->ipv4.sysctl_nexthop_compat_mode);
+                                     !READ_ONCE(net->ipv4.sysctl_nexthop_compat_mode));
        }
 }
 
@@ -2361,7 +2361,8 @@ out:
        if (!rc) {
                nh_base_seq_inc(net);
                nexthop_notify(RTM_NEWNEXTHOP, new_nh, &cfg->nlinfo);
-               if (replace_notify && net->ipv4.sysctl_nexthop_compat_mode)
+               if (replace_notify &&
+                   READ_ONCE(net->ipv4.sysctl_nexthop_compat_mode))
                        nexthop_replace_notify(net, new_nh, &cfg->nlinfo);
        }
 
index 28836071f0a691dc23952f0273a7faf61b1ebb2c..0088a4c64d77ed89b86b736d1c40b099a817ea27 100644 (file)
@@ -387,7 +387,7 @@ static int snmp_seq_show_ipstats(struct seq_file *seq, void *v)
 
        seq_printf(seq, "\nIp: %d %d",
                   IPV4_DEVCONF_ALL(net, FORWARDING) ? 1 : 2,
-                  net->ipv4.sysctl_ip_default_ttl);
+                  READ_ONCE(net->ipv4.sysctl_ip_default_ttl));
 
        BUILD_BUG_ON(offsetof(struct ipstats_mib, mibs) != 0);
        snmp_get_cpu_field64_batch(buff64, snmp4_ipstats_list,
index 356f535f3443b3aef35f2d8836c618272d290cc1..4702c61207a87133b3d0ef64bb40ea8adaaefec5 100644 (file)
@@ -1398,7 +1398,7 @@ u32 ip_mtu_from_fib_result(struct fib_result *res, __be32 daddr)
        struct fib_info *fi = res->fi;
        u32 mtu = 0;
 
-       if (dev_net(dev)->ipv4.sysctl_ip_fwd_use_pmtu ||
+       if (READ_ONCE(dev_net(dev)->ipv4.sysctl_ip_fwd_use_pmtu) ||
            fi->fib_metrics->metrics[RTAX_LOCK - 1] & (1 << RTAX_MTU))
                mtu = fi->fib_mtu;
 
@@ -1929,7 +1929,7 @@ static u32 fib_multipath_custom_hash_outer(const struct net *net,
                                           const struct sk_buff *skb,
                                           bool *p_has_inner)
 {
-       u32 hash_fields = net->ipv4.sysctl_fib_multipath_hash_fields;
+       u32 hash_fields = READ_ONCE(net->ipv4.sysctl_fib_multipath_hash_fields);
        struct flow_keys keys, hash_keys;
 
        if (!(hash_fields & FIB_MULTIPATH_HASH_FIELD_OUTER_MASK))
@@ -1958,7 +1958,7 @@ static u32 fib_multipath_custom_hash_inner(const struct net *net,
                                           const struct sk_buff *skb,
                                           bool has_inner)
 {
-       u32 hash_fields = net->ipv4.sysctl_fib_multipath_hash_fields;
+       u32 hash_fields = READ_ONCE(net->ipv4.sysctl_fib_multipath_hash_fields);
        struct flow_keys keys, hash_keys;
 
        /* We assume the packet carries an encapsulation, but if none was
@@ -2018,7 +2018,7 @@ static u32 fib_multipath_custom_hash_skb(const struct net *net,
 static u32 fib_multipath_custom_hash_fl4(const struct net *net,
                                         const struct flowi4 *fl4)
 {
-       u32 hash_fields = net->ipv4.sysctl_fib_multipath_hash_fields;
+       u32 hash_fields = READ_ONCE(net->ipv4.sysctl_fib_multipath_hash_fields);
        struct flow_keys hash_keys;
 
        if (!(hash_fields & FIB_MULTIPATH_HASH_FIELD_OUTER_MASK))
@@ -2048,7 +2048,7 @@ int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4,
        struct flow_keys hash_keys;
        u32 mhash = 0;
 
-       switch (net->ipv4.sysctl_fib_multipath_hash_policy) {
+       switch (READ_ONCE(net->ipv4.sysctl_fib_multipath_hash_policy)) {
        case 0:
                memset(&hash_keys, 0, sizeof(hash_keys));
                hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
index f33c31dd7366c06a642bdc5954856efa9d8da0ac..942d2dfa11151170bfc72287fb8f7aeac7b5b9ad 100644 (file)
@@ -247,12 +247,12 @@ bool cookie_timestamp_decode(const struct net *net,
                return true;
        }
 
-       if (!net->ipv4.sysctl_tcp_timestamps)
+       if (!READ_ONCE(net->ipv4.sysctl_tcp_timestamps))
                return false;
 
        tcp_opt->sack_ok = (options & TS_OPT_SACK) ? TCP_SACK_SEEN : 0;
 
-       if (tcp_opt->sack_ok && !net->ipv4.sysctl_tcp_sack)
+       if (tcp_opt->sack_ok && !READ_ONCE(net->ipv4.sysctl_tcp_sack))
                return false;
 
        if ((options & TS_OPT_WSCALE_MASK) == TS_OPT_WSCALE_MASK)
@@ -261,7 +261,7 @@ bool cookie_timestamp_decode(const struct net *net,
        tcp_opt->wscale_ok = 1;
        tcp_opt->snd_wscale = options & TS_OPT_WSCALE_MASK;
 
-       return net->ipv4.sysctl_tcp_window_scaling != 0;
+       return READ_ONCE(net->ipv4.sysctl_tcp_window_scaling) != 0;
 }
 EXPORT_SYMBOL(cookie_timestamp_decode);
 
@@ -273,7 +273,7 @@ bool cookie_ecn_ok(const struct tcp_options_received *tcp_opt,
        if (!ecn_ok)
                return false;
 
-       if (net->ipv4.sysctl_tcp_ecn)
+       if (READ_ONCE(net->ipv4.sysctl_tcp_ecn))
                return true;
 
        return dst_feature(dst, RTAX_FEATURE_ECN);
@@ -340,7 +340,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
        struct flowi4 fl4;
        u32 tsoff = 0;
 
-       if (!sock_net(sk)->ipv4.sysctl_tcp_syncookies || !th->ack || th->rst)
+       if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies) ||
+           !th->ack || th->rst)
                goto out;
 
        if (tcp_synq_no_recent_overflow(sk))
index cd448cdd3b38184d721c8dd09c058dfa24cc2a3b..5490c285668b93b5683328a2c284af66e2f19b0d 100644 (file)
@@ -84,7 +84,7 @@ static int ipv4_local_port_range(struct ctl_table *table, int write,
                 * port limit.
                 */
                if ((range[1] < range[0]) ||
-                   (range[0] < net->ipv4.sysctl_ip_prot_sock))
+                   (range[0] < READ_ONCE(net->ipv4.sysctl_ip_prot_sock)))
                        ret = -EINVAL;
                else
                        set_local_port_range(net, range);
@@ -110,7 +110,7 @@ static int ipv4_privileged_ports(struct ctl_table *table, int write,
                .extra2 = &ip_privileged_port_max,
        };
 
-       pports = net->ipv4.sysctl_ip_prot_sock;
+       pports = READ_ONCE(net->ipv4.sysctl_ip_prot_sock);
 
        ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
 
@@ -122,7 +122,7 @@ static int ipv4_privileged_ports(struct ctl_table *table, int write,
                if (range[0] < pports)
                        ret = -EINVAL;
                else
-                       net->ipv4.sysctl_ip_prot_sock = pports;
+                       WRITE_ONCE(net->ipv4.sysctl_ip_prot_sock, pports);
        }
 
        return ret;
@@ -350,61 +350,6 @@ bad_key:
        return ret;
 }
 
-static void proc_configure_early_demux(int enabled, int protocol)
-{
-       struct net_protocol *ipprot;
-#if IS_ENABLED(CONFIG_IPV6)
-       struct inet6_protocol *ip6prot;
-#endif
-
-       rcu_read_lock();
-
-       ipprot = rcu_dereference(inet_protos[protocol]);
-       if (ipprot)
-               ipprot->early_demux = enabled ? ipprot->early_demux_handler :
-                                               NULL;
-
-#if IS_ENABLED(CONFIG_IPV6)
-       ip6prot = rcu_dereference(inet6_protos[protocol]);
-       if (ip6prot)
-               ip6prot->early_demux = enabled ? ip6prot->early_demux_handler :
-                                                NULL;
-#endif
-       rcu_read_unlock();
-}
-
-static int proc_tcp_early_demux(struct ctl_table *table, int write,
-                               void *buffer, size_t *lenp, loff_t *ppos)
-{
-       int ret = 0;
-
-       ret = proc_dou8vec_minmax(table, write, buffer, lenp, ppos);
-
-       if (write && !ret) {
-               int enabled = init_net.ipv4.sysctl_tcp_early_demux;
-
-               proc_configure_early_demux(enabled, IPPROTO_TCP);
-       }
-
-       return ret;
-}
-
-static int proc_udp_early_demux(struct ctl_table *table, int write,
-                               void *buffer, size_t *lenp, loff_t *ppos)
-{
-       int ret = 0;
-
-       ret = proc_dou8vec_minmax(table, write, buffer, lenp, ppos);
-
-       if (write && !ret) {
-               int enabled = init_net.ipv4.sysctl_udp_early_demux;
-
-               proc_configure_early_demux(enabled, IPPROTO_UDP);
-       }
-
-       return ret;
-}
-
 static int proc_tfo_blackhole_detect_timeout(struct ctl_table *table,
                                             int write, void *buffer,
                                             size_t *lenp, loff_t *ppos)
@@ -599,6 +544,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE
        },
        {
                .procname       = "icmp_echo_enable_probe",
@@ -615,6 +562,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE
        },
        {
                .procname       = "icmp_ignore_bogus_error_responses",
@@ -622,6 +571,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE
        },
        {
                .procname       = "icmp_errors_use_inbound_ifaddr",
@@ -629,6 +580,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE
        },
        {
                .procname       = "icmp_ratelimit",
@@ -668,6 +621,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_TWO,
        },
        {
                .procname       = "tcp_ecn_fallback",
@@ -675,6 +630,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "ip_dynaddr",
@@ -695,14 +652,14 @@ static struct ctl_table ipv4_net_table[] = {
                .data           = &init_net.ipv4.sysctl_udp_early_demux,
                .maxlen         = sizeof(u8),
                .mode           = 0644,
-               .proc_handler   = proc_udp_early_demux
+               .proc_handler   = proc_dou8vec_minmax,
        },
        {
                .procname       = "tcp_early_demux",
                .data           = &init_net.ipv4.sysctl_tcp_early_demux,
                .maxlen         = sizeof(u8),
                .mode           = 0644,
-               .proc_handler   = proc_tcp_early_demux
+               .proc_handler   = proc_dou8vec_minmax,
        },
        {
                .procname       = "nexthop_compat_mode",
index 028513d3e2a2bcf18022d9458e46c9a36c46eb2c..2faaaaf540ac1df534d0e7ded33e07cd3897f3e8 100644 (file)
@@ -441,7 +441,7 @@ void tcp_init_sock(struct sock *sk)
        tp->snd_cwnd_clamp = ~0;
        tp->mss_cache = TCP_MSS_DEFAULT;
 
-       tp->reordering = sock_net(sk)->ipv4.sysctl_tcp_reordering;
+       tp->reordering = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_reordering);
        tcp_assign_congestion_control(sk);
 
        tp->tsoffset = 0;
@@ -1150,7 +1150,8 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
        struct sockaddr *uaddr = msg->msg_name;
        int err, flags;
 
-       if (!(sock_net(sk)->ipv4.sysctl_tcp_fastopen & TFO_CLIENT_ENABLE) ||
+       if (!(READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fastopen) &
+             TFO_CLIENT_ENABLE) ||
            (uaddr && msg->msg_namelen >= sizeof(uaddr->sa_family) &&
             uaddr->sa_family == AF_UNSPEC))
                return -EOPNOTSUPP;
@@ -2715,7 +2716,8 @@ static void tcp_orphan_update(struct timer_list *unused)
 
 static bool tcp_too_many_orphans(int shift)
 {
-       return READ_ONCE(tcp_orphan_cache) << shift > sysctl_tcp_max_orphans;
+       return READ_ONCE(tcp_orphan_cache) << shift >
+               READ_ONCE(sysctl_tcp_max_orphans);
 }
 
 bool tcp_check_oom(struct sock *sk, int shift)
@@ -3616,7 +3618,8 @@ static int do_tcp_setsockopt(struct sock *sk, int level, int optname,
        case TCP_FASTOPEN_CONNECT:
                if (val > 1 || val < 0) {
                        err = -EINVAL;
-               } else if (net->ipv4.sysctl_tcp_fastopen & TFO_CLIENT_ENABLE) {
+               } else if (READ_ONCE(net->ipv4.sysctl_tcp_fastopen) &
+                          TFO_CLIENT_ENABLE) {
                        if (sk->sk_state == TCP_CLOSE)
                                tp->fastopen_connect = val;
                        else
@@ -3966,12 +3969,13 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
                val = keepalive_probes(tp);
                break;
        case TCP_SYNCNT:
-               val = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries;
+               val = icsk->icsk_syn_retries ? :
+                       READ_ONCE(net->ipv4.sysctl_tcp_syn_retries);
                break;
        case TCP_LINGER2:
                val = tp->linger2;
                if (val >= 0)
-                       val = (val ? : net->ipv4.sysctl_tcp_fin_timeout) / HZ;
+                       val = (val ? : READ_ONCE(net->ipv4.sysctl_tcp_fin_timeout)) / HZ;
                break;
        case TCP_DEFER_ACCEPT:
                val = retrans_to_secs(icsk->icsk_accept_queue.rskq_defer_accept,
index fdbcf2a6d08ef4a5164247b5a5b4b222289b191a..825b216d11f52bc79a29b7a696005175a55a6804 100644 (file)
@@ -332,7 +332,7 @@ static bool tcp_fastopen_no_cookie(const struct sock *sk,
                                   const struct dst_entry *dst,
                                   int flag)
 {
-       return (sock_net(sk)->ipv4.sysctl_tcp_fastopen & flag) ||
+       return (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fastopen) & flag) ||
               tcp_sk(sk)->fastopen_no_cookie ||
               (dst && dst_metric(dst, RTAX_FASTOPEN_NO_COOKIE));
 }
@@ -347,7 +347,7 @@ struct sock *tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
                              const struct dst_entry *dst)
 {
        bool syn_data = TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq + 1;
-       int tcp_fastopen = sock_net(sk)->ipv4.sysctl_tcp_fastopen;
+       int tcp_fastopen = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fastopen);
        struct tcp_fastopen_cookie valid_foc = { .len = -1 };
        struct sock *child;
        int ret = 0;
@@ -489,7 +489,7 @@ void tcp_fastopen_active_disable(struct sock *sk)
 {
        struct net *net = sock_net(sk);
 
-       if (!sock_net(sk)->ipv4.sysctl_tcp_fastopen_blackhole_timeout)
+       if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fastopen_blackhole_timeout))
                return;
 
        /* Paired with READ_ONCE() in tcp_fastopen_active_should_disable() */
@@ -510,7 +510,8 @@ void tcp_fastopen_active_disable(struct sock *sk)
  */
 bool tcp_fastopen_active_should_disable(struct sock *sk)
 {
-       unsigned int tfo_bh_timeout = sock_net(sk)->ipv4.sysctl_tcp_fastopen_blackhole_timeout;
+       unsigned int tfo_bh_timeout =
+               READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fastopen_blackhole_timeout);
        unsigned long timeout;
        int tfo_da_times;
        int multiplier;
index 2e2a9ece9af27372e6b653d685a89a2c71ba05d1..07dbcbae7782880baaf5fbca1d344170aa032c12 100644 (file)
@@ -1051,7 +1051,7 @@ static void tcp_check_sack_reordering(struct sock *sk, const u32 low_seq,
                         tp->undo_marker ? tp->undo_retrans : 0);
 #endif
                tp->reordering = min_t(u32, (metric + mss - 1) / mss,
-                                      sock_net(sk)->ipv4.sysctl_tcp_max_reordering);
+                                      READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering));
        }
 
        /* This exciting event is worth to be remembered. 8) */
@@ -2030,7 +2030,7 @@ static void tcp_check_reno_reordering(struct sock *sk, const int addend)
                return;
 
        tp->reordering = min_t(u32, tp->packets_out + addend,
-                              sock_net(sk)->ipv4.sysctl_tcp_max_reordering);
+                              READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_max_reordering));
        tp->reord_seen++;
        NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRENOREORDER);
 }
@@ -2095,7 +2095,8 @@ static inline void tcp_init_undo(struct tcp_sock *tp)
 
 static bool tcp_is_rack(const struct sock *sk)
 {
-       return sock_net(sk)->ipv4.sysctl_tcp_recovery & TCP_RACK_LOSS_DETECTION;
+       return READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_recovery) &
+               TCP_RACK_LOSS_DETECTION;
 }
 
 /* If we detect SACK reneging, forget all SACK information
@@ -2139,6 +2140,7 @@ void tcp_enter_loss(struct sock *sk)
        struct tcp_sock *tp = tcp_sk(sk);
        struct net *net = sock_net(sk);
        bool new_recovery = icsk->icsk_ca_state < TCP_CA_Recovery;
+       u8 reordering;
 
        tcp_timeout_mark_lost(sk);
 
@@ -2159,10 +2161,12 @@ void tcp_enter_loss(struct sock *sk)
        /* Timeout in disordered state after receiving substantial DUPACKs
         * suggests that the degree of reordering is over-estimated.
         */
+       reordering = READ_ONCE(net->ipv4.sysctl_tcp_reordering);
        if (icsk->icsk_ca_state <= TCP_CA_Disorder &&
-           tp->sacked_out >= net->ipv4.sysctl_tcp_reordering)
+           tp->sacked_out >= reordering)
                tp->reordering = min_t(unsigned int, tp->reordering,
-                                      net->ipv4.sysctl_tcp_reordering);
+                                      reordering);
+
        tcp_set_ca_state(sk, TCP_CA_Loss);
        tp->high_seq = tp->snd_nxt;
        tcp_ecn_queue_cwr(tp);
@@ -3464,7 +3468,8 @@ static inline bool tcp_may_raise_cwnd(const struct sock *sk, const int flag)
         * new SACK or ECE mark may first advance cwnd here and later reduce
         * cwnd in tcp_fastretrans_alert() based on more states.
         */
-       if (tcp_sk(sk)->reordering > sock_net(sk)->ipv4.sysctl_tcp_reordering)
+       if (tcp_sk(sk)->reordering >
+           READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_reordering))
                return flag & FLAG_FORWARD_PROGRESS;
 
        return flag & FLAG_DATA_ACKED;
@@ -4056,7 +4061,7 @@ void tcp_parse_options(const struct net *net,
                                break;
                        case TCPOPT_WINDOW:
                                if (opsize == TCPOLEN_WINDOW && th->syn &&
-                                   !estab && net->ipv4.sysctl_tcp_window_scaling) {
+                                   !estab && READ_ONCE(net->ipv4.sysctl_tcp_window_scaling)) {
                                        __u8 snd_wscale = *(__u8 *)ptr;
                                        opt_rx->wscale_ok = 1;
                                        if (snd_wscale > TCP_MAX_WSCALE) {
@@ -4072,7 +4077,7 @@ void tcp_parse_options(const struct net *net,
                        case TCPOPT_TIMESTAMP:
                                if ((opsize == TCPOLEN_TIMESTAMP) &&
                                    ((estab && opt_rx->tstamp_ok) ||
-                                    (!estab && net->ipv4.sysctl_tcp_timestamps))) {
+                                    (!estab && READ_ONCE(net->ipv4.sysctl_tcp_timestamps)))) {
                                        opt_rx->saw_tstamp = 1;
                                        opt_rx->rcv_tsval = get_unaligned_be32(ptr);
                                        opt_rx->rcv_tsecr = get_unaligned_be32(ptr + 4);
@@ -4080,7 +4085,7 @@ void tcp_parse_options(const struct net *net,
                                break;
                        case TCPOPT_SACK_PERM:
                                if (opsize == TCPOLEN_SACK_PERM && th->syn &&
-                                   !estab && net->ipv4.sysctl_tcp_sack) {
+                                   !estab && READ_ONCE(net->ipv4.sysctl_tcp_sack)) {
                                        opt_rx->sack_ok = TCP_SACK_SEEN;
                                        tcp_sack_reset(opt_rx);
                                }
@@ -5567,7 +5572,7 @@ static void tcp_check_urg(struct sock *sk, const struct tcphdr *th)
        struct tcp_sock *tp = tcp_sk(sk);
        u32 ptr = ntohs(th->urg_ptr);
 
-       if (ptr && !sock_net(sk)->ipv4.sysctl_tcp_stdurg)
+       if (ptr && !READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_stdurg))
                ptr--;
        ptr += ntohl(th->seq);
 
@@ -6729,7 +6734,7 @@ static void tcp_ecn_create_request(struct request_sock *req,
 
        ect = !INET_ECN_is_not_ect(TCP_SKB_CB(skb)->ip_dsfield);
        ecn_ok_dst = dst_feature(dst, DST_FEATURE_ECN_MASK);
-       ecn_ok = net->ipv4.sysctl_tcp_ecn || ecn_ok_dst;
+       ecn_ok = READ_ONCE(net->ipv4.sysctl_tcp_ecn) || ecn_ok_dst;
 
        if (((!ect || th->res1) && ecn_ok) || tcp_ca_needs_ecn(listen_sk) ||
            (ecn_ok_dst & DST_FEATURE_ECN_CA) ||
@@ -6797,11 +6802,14 @@ static bool tcp_syn_flood_action(const struct sock *sk, const char *proto)
 {
        struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue;
        const char *msg = "Dropping request";
-       bool want_cookie = false;
        struct net *net = sock_net(sk);
+       bool want_cookie = false;
+       u8 syncookies;
+
+       syncookies = READ_ONCE(net->ipv4.sysctl_tcp_syncookies);
 
 #ifdef CONFIG_SYN_COOKIES
-       if (net->ipv4.sysctl_tcp_syncookies) {
+       if (syncookies) {
                msg = "Sending cookies";
                want_cookie = true;
                __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPREQQFULLDOCOOKIES);
@@ -6809,8 +6817,7 @@ static bool tcp_syn_flood_action(const struct sock *sk, const char *proto)
 #endif
                __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPREQQFULLDROP);
 
-       if (!queue->synflood_warned &&
-           net->ipv4.sysctl_tcp_syncookies != 2 &&
+       if (!queue->synflood_warned && syncookies != 2 &&
            xchg(&queue->synflood_warned, 1) == 0)
                net_info_ratelimited("%s: Possible SYN flooding on port %d. %s.  Check SNMP counters.\n",
                                     proto, sk->sk_num, msg);
@@ -6859,7 +6866,7 @@ u16 tcp_get_syncookie_mss(struct request_sock_ops *rsk_ops,
        struct tcp_sock *tp = tcp_sk(sk);
        u16 mss;
 
-       if (sock_net(sk)->ipv4.sysctl_tcp_syncookies != 2 &&
+       if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies) != 2 &&
            !inet_csk_reqsk_queue_is_full(sk))
                return 0;
 
@@ -6893,13 +6900,15 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
        bool want_cookie = false;
        struct dst_entry *dst;
        struct flowi fl;
+       u8 syncookies;
+
+       syncookies = READ_ONCE(net->ipv4.sysctl_tcp_syncookies);
 
        /* TW buckets are converted to open requests without
         * limitations, they conserve resources and peer is
         * evidently real one.
         */
-       if ((net->ipv4.sysctl_tcp_syncookies == 2 ||
-            inet_csk_reqsk_queue_is_full(sk)) && !isn) {
+       if ((syncookies == 2 || inet_csk_reqsk_queue_is_full(sk)) && !isn) {
                want_cookie = tcp_syn_flood_action(sk, rsk_ops->slab_name);
                if (!want_cookie)
                        goto drop;
@@ -6948,10 +6957,12 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
                tcp_rsk(req)->ts_off = af_ops->init_ts_off(net, skb);
 
        if (!want_cookie && !isn) {
+               int max_syn_backlog = READ_ONCE(net->ipv4.sysctl_max_syn_backlog);
+
                /* Kill the following clause, if you dislike this way. */
-               if (!net->ipv4.sysctl_tcp_syncookies &&
-                   (net->ipv4.sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) <
-                    (net->ipv4.sysctl_max_syn_backlog >> 2)) &&
+               if (!syncookies &&
+                   (max_syn_backlog - inet_csk_reqsk_queue_len(sk) <
+                    (max_syn_backlog >> 2)) &&
                    !tcp_peer_is_proven(req, dst)) {
                        /* Without syncookies last quarter of
                         * backlog is filled with destinations,
index da5a3c44c4fb70f1d3ecc596e694a86267f1c44a..d16e6e40f47ba4aee2b1a412c42d2f9791698e27 100644 (file)
@@ -108,10 +108,10 @@ static u32 tcp_v4_init_ts_off(const struct net *net, const struct sk_buff *skb)
 
 int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
 {
+       int reuse = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_tw_reuse);
        const struct inet_timewait_sock *tw = inet_twsk(sktw);
        const struct tcp_timewait_sock *tcptw = tcp_twsk(sktw);
        struct tcp_sock *tp = tcp_sk(sk);
-       int reuse = sock_net(sk)->ipv4.sysctl_tcp_tw_reuse;
 
        if (reuse == 2) {
                /* Still does not detect *everything* that goes through
index 7029b0e98edb285102dcab4521f296511a70dc57..a501150deaa3b326f1cffdbdd7924d856dde6682 100644 (file)
@@ -428,7 +428,8 @@ void tcp_update_metrics(struct sock *sk)
                if (!tcp_metric_locked(tm, TCP_METRIC_REORDERING)) {
                        val = tcp_metric_get(tm, TCP_METRIC_REORDERING);
                        if (val < tp->reordering &&
-                           tp->reordering != net->ipv4.sysctl_tcp_reordering)
+                           tp->reordering !=
+                           READ_ONCE(net->ipv4.sysctl_tcp_reordering))
                                tcp_metric_set(tm, TCP_METRIC_REORDERING,
                                               tp->reordering);
                }
index 6854bb1fb32b265ef4c0838267bf272c57f7601e..cb95d88497aeae8802b0c42c83fae67352ef4d98 100644 (file)
@@ -173,7 +173,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
                         * Oh well... nobody has a sufficient solution to this
                         * protocol bug yet.
                         */
-                       if (twsk_net(tw)->ipv4.sysctl_tcp_rfc1337 == 0) {
+                       if (!READ_ONCE(twsk_net(tw)->ipv4.sysctl_tcp_rfc1337)) {
 kill:
                                inet_twsk_deschedule_put(tw);
                                return TCP_TW_SUCCESS;
@@ -781,7 +781,7 @@ listen_overflow:
        if (sk != req->rsk_listener)
                __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMIGRATEREQFAILURE);
 
-       if (!sock_net(sk)->ipv4.sysctl_tcp_abort_on_overflow) {
+       if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_abort_on_overflow)) {
                inet_rsk(req)->acked = 1;
                return NULL;
        }
index 1c054431e358328fe3849f5a45aaa88308a1e1c8..c38e07b50639c7f9ac11975d1750d6a0099d74e4 100644 (file)
@@ -324,7 +324,7 @@ static void tcp_ecn_send_syn(struct sock *sk, struct sk_buff *skb)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        bool bpf_needs_ecn = tcp_bpf_ca_needs_ecn(sk);
-       bool use_ecn = sock_net(sk)->ipv4.sysctl_tcp_ecn == 1 ||
+       bool use_ecn = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn) == 1 ||
                tcp_ca_needs_ecn(sk) || bpf_needs_ecn;
 
        if (!use_ecn) {
@@ -346,7 +346,7 @@ static void tcp_ecn_send_syn(struct sock *sk, struct sk_buff *skb)
 
 static void tcp_ecn_clear_syn(struct sock *sk, struct sk_buff *skb)
 {
-       if (sock_net(sk)->ipv4.sysctl_tcp_ecn_fallback)
+       if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn_fallback))
                /* tp->ecn_flags are cleared at a later point in time when
                 * SYN ACK is ultimatively being received.
                 */
@@ -791,18 +791,18 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
        opts->mss = tcp_advertise_mss(sk);
        remaining -= TCPOLEN_MSS_ALIGNED;
 
-       if (likely(sock_net(sk)->ipv4.sysctl_tcp_timestamps && !*md5)) {
+       if (likely(READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_timestamps) && !*md5)) {
                opts->options |= OPTION_TS;
                opts->tsval = tcp_skb_timestamp(skb) + tp->tsoffset;
                opts->tsecr = tp->rx_opt.ts_recent;
                remaining -= TCPOLEN_TSTAMP_ALIGNED;
        }
-       if (likely(sock_net(sk)->ipv4.sysctl_tcp_window_scaling)) {
+       if (likely(READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_window_scaling))) {
                opts->ws = tp->rx_opt.rcv_wscale;
                opts->options |= OPTION_WSCALE;
                remaining -= TCPOLEN_WSCALE_ALIGNED;
        }
-       if (likely(sock_net(sk)->ipv4.sysctl_tcp_sack)) {
+       if (likely(READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_sack))) {
                opts->options |= OPTION_SACK_ADVERTISE;
                if (unlikely(!(OPTION_TS & opts->options)))
                        remaining -= TCPOLEN_SACKPERM_ALIGNED;
@@ -1719,7 +1719,8 @@ static inline int __tcp_mtu_to_mss(struct sock *sk, int pmtu)
        mss_now -= icsk->icsk_ext_hdr_len;
 
        /* Then reserve room for full set of TCP options and 8 bytes of data */
-       mss_now = max(mss_now, sock_net(sk)->ipv4.sysctl_tcp_min_snd_mss);
+       mss_now = max(mss_now,
+                     READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_min_snd_mss));
        return mss_now;
 }
 
@@ -1762,10 +1763,10 @@ void tcp_mtup_init(struct sock *sk)
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct net *net = sock_net(sk);
 
-       icsk->icsk_mtup.enabled = net->ipv4.sysctl_tcp_mtu_probing > 1;
+       icsk->icsk_mtup.enabled = READ_ONCE(net->ipv4.sysctl_tcp_mtu_probing) > 1;
        icsk->icsk_mtup.search_high = tp->rx_opt.mss_clamp + sizeof(struct tcphdr) +
                               icsk->icsk_af_ops->net_header_len;
-       icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, net->ipv4.sysctl_tcp_base_mss);
+       icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, READ_ONCE(net->ipv4.sysctl_tcp_base_mss));
        icsk->icsk_mtup.probe_size = 0;
        if (icsk->icsk_mtup.enabled)
                icsk->icsk_mtup.probe_timestamp = tcp_jiffies32;
@@ -1897,7 +1898,7 @@ static void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited)
                if (tp->packets_out > tp->snd_cwnd_used)
                        tp->snd_cwnd_used = tp->packets_out;
 
-               if (sock_net(sk)->ipv4.sysctl_tcp_slow_start_after_idle &&
+               if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_slow_start_after_idle) &&
                    (s32)(tcp_jiffies32 - tp->snd_cwnd_stamp) >= inet_csk(sk)->icsk_rto &&
                    !ca_ops->cong_control)
                        tcp_cwnd_application_limited(sk);
@@ -2282,7 +2283,7 @@ static inline void tcp_mtu_check_reprobe(struct sock *sk)
        u32 interval;
        s32 delta;
 
-       interval = net->ipv4.sysctl_tcp_probe_interval;
+       interval = READ_ONCE(net->ipv4.sysctl_tcp_probe_interval);
        delta = tcp_jiffies32 - icsk->icsk_mtup.probe_timestamp;
        if (unlikely(delta >= interval * HZ)) {
                int mss = tcp_current_mss(sk);
@@ -2366,7 +2367,7 @@ static int tcp_mtu_probe(struct sock *sk)
         * probing process by not resetting search range to its orignal.
         */
        if (probe_size > tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_high) ||
-               interval < net->ipv4.sysctl_tcp_probe_threshold) {
+           interval < READ_ONCE(net->ipv4.sysctl_tcp_probe_threshold)) {
                /* Check whether enough time has elaplased for
                 * another round of probing.
                 */
@@ -2740,7 +2741,7 @@ bool tcp_schedule_loss_probe(struct sock *sk, bool advancing_rto)
        if (rcu_access_pointer(tp->fastopen_rsk))
                return false;
 
-       early_retrans = sock_net(sk)->ipv4.sysctl_tcp_early_retrans;
+       early_retrans = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_early_retrans);
        /* Schedule a loss probe in 2*RTT for SACK capable connections
         * not in loss recovery, that are either limited by cwnd or application.
         */
@@ -3104,7 +3105,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to,
        struct sk_buff *skb = to, *tmp;
        bool first = true;
 
-       if (!sock_net(sk)->ipv4.sysctl_tcp_retrans_collapse)
+       if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_retrans_collapse))
                return;
        if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)
                return;
@@ -3646,7 +3647,7 @@ static void tcp_connect_init(struct sock *sk)
         * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT.
         */
        tp->tcp_header_len = sizeof(struct tcphdr);
-       if (sock_net(sk)->ipv4.sysctl_tcp_timestamps)
+       if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_timestamps))
                tp->tcp_header_len += TCPOLEN_TSTAMP_ALIGNED;
 
 #ifdef CONFIG_TCP_MD5SIG
@@ -3682,7 +3683,7 @@ static void tcp_connect_init(struct sock *sk)
                                  tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0),
                                  &tp->rcv_wnd,
                                  &tp->window_clamp,
-                                 sock_net(sk)->ipv4.sysctl_tcp_window_scaling,
+                                 READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_window_scaling),
                                  &rcv_wscale,
                                  rcv_wnd);
 
@@ -4089,7 +4090,7 @@ void tcp_send_probe0(struct sock *sk)
 
        icsk->icsk_probes_out++;
        if (err <= 0) {
-               if (icsk->icsk_backoff < net->ipv4.sysctl_tcp_retries2)
+               if (icsk->icsk_backoff < READ_ONCE(net->ipv4.sysctl_tcp_retries2))
                        icsk->icsk_backoff++;
                timeout = tcp_probe0_when(sk, TCP_RTO_MAX);
        } else {
index 48f30e7209f291c9191074e5f4a11501a374961c..50abaa941387d3e7328b6859ea5118937fc12be4 100644 (file)
@@ -14,7 +14,8 @@ static u32 tcp_rack_reo_wnd(const struct sock *sk)
                        return 0;
 
                if (tp->sacked_out >= tp->reordering &&
-                   !(sock_net(sk)->ipv4.sysctl_tcp_recovery & TCP_RACK_NO_DUPTHRESH))
+                   !(READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_recovery) &
+                     TCP_RACK_NO_DUPTHRESH))
                        return 0;
        }
 
@@ -187,7 +188,8 @@ void tcp_rack_update_reo_wnd(struct sock *sk, struct rate_sample *rs)
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
-       if (sock_net(sk)->ipv4.sysctl_tcp_recovery & TCP_RACK_STATIC_REO_WND ||
+       if ((READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_recovery) &
+            TCP_RACK_STATIC_REO_WND) ||
            !rs->prior_delivered)
                return;
 
index 20cf4a98c69d85d07c884d7bc8316191ff962bd8..50bba370486e83a80c562875ecb564d6f7186270 100644 (file)
@@ -143,7 +143,7 @@ static int tcp_out_of_resources(struct sock *sk, bool do_reset)
  */
 static int tcp_orphan_retries(struct sock *sk, bool alive)
 {
-       int retries = sock_net(sk)->ipv4.sysctl_tcp_orphan_retries; /* May be zero. */
+       int retries = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_orphan_retries); /* May be zero. */
 
        /* We know from an ICMP that something is wrong. */
        if (sk->sk_err_soft && !alive)
@@ -163,7 +163,7 @@ static void tcp_mtu_probing(struct inet_connection_sock *icsk, struct sock *sk)
        int mss;
 
        /* Black hole detection */
-       if (!net->ipv4.sysctl_tcp_mtu_probing)
+       if (!READ_ONCE(net->ipv4.sysctl_tcp_mtu_probing))
                return;
 
        if (!icsk->icsk_mtup.enabled) {
@@ -171,9 +171,9 @@ static void tcp_mtu_probing(struct inet_connection_sock *icsk, struct sock *sk)
                icsk->icsk_mtup.probe_timestamp = tcp_jiffies32;
        } else {
                mss = tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_low) >> 1;
-               mss = min(net->ipv4.sysctl_tcp_base_mss, mss);
-               mss = max(mss, net->ipv4.sysctl_tcp_mtu_probe_floor);
-               mss = max(mss, net->ipv4.sysctl_tcp_min_snd_mss);
+               mss = min(READ_ONCE(net->ipv4.sysctl_tcp_base_mss), mss);
+               mss = max(mss, READ_ONCE(net->ipv4.sysctl_tcp_mtu_probe_floor));
+               mss = max(mss, READ_ONCE(net->ipv4.sysctl_tcp_min_snd_mss));
                icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, mss);
        }
        tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
@@ -239,17 +239,18 @@ static int tcp_write_timeout(struct sock *sk)
        if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
                if (icsk->icsk_retransmits)
                        __dst_negative_advice(sk);
-               retry_until = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries;
+               retry_until = icsk->icsk_syn_retries ? :
+                       READ_ONCE(net->ipv4.sysctl_tcp_syn_retries);
                expired = icsk->icsk_retransmits >= retry_until;
        } else {
-               if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1, 0)) {
+               if (retransmits_timed_out(sk, READ_ONCE(net->ipv4.sysctl_tcp_retries1), 0)) {
                        /* Black hole detection */
                        tcp_mtu_probing(icsk, sk);
 
                        __dst_negative_advice(sk);
                }
 
-               retry_until = net->ipv4.sysctl_tcp_retries2;
+               retry_until = READ_ONCE(net->ipv4.sysctl_tcp_retries2);
                if (sock_flag(sk, SOCK_DEAD)) {
                        const bool alive = icsk->icsk_rto < TCP_RTO_MAX;
 
@@ -380,7 +381,7 @@ static void tcp_probe_timer(struct sock *sk)
                 msecs_to_jiffies(icsk->icsk_user_timeout))
                goto abort;
 
-       max_probes = sock_net(sk)->ipv4.sysctl_tcp_retries2;
+       max_probes = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_retries2);
        if (sock_flag(sk, SOCK_DEAD)) {
                const bool alive = inet_csk_rto_backoff(icsk, TCP_RTO_MAX) < TCP_RTO_MAX;
 
@@ -406,12 +407,15 @@ abort:            tcp_write_err(sk);
 static void tcp_fastopen_synack_timer(struct sock *sk, struct request_sock *req)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
-       int max_retries = icsk->icsk_syn_retries ? :
-           sock_net(sk)->ipv4.sysctl_tcp_synack_retries + 1; /* add one more retry for fastopen */
        struct tcp_sock *tp = tcp_sk(sk);
+       int max_retries;
 
        req->rsk_ops->syn_ack_timeout(req);
 
+       /* add one more retry for fastopen */
+       max_retries = icsk->icsk_syn_retries ? :
+               READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_synack_retries) + 1;
+
        if (req->num_timeout >= max_retries) {
                tcp_write_err(sk);
                return;
@@ -574,7 +578,7 @@ out_reset_timer:
         * linear-timeout retransmissions into a black hole
         */
        if (sk->sk_state == TCP_ESTABLISHED &&
-           (tp->thin_lto || net->ipv4.sysctl_tcp_thin_linear_timeouts) &&
+           (tp->thin_lto || READ_ONCE(net->ipv4.sysctl_tcp_thin_linear_timeouts)) &&
            tcp_stream_is_thin(tp) &&
            icsk->icsk_retransmits <= TCP_THIN_LINEAR_RETRIES) {
                icsk->icsk_backoff = 0;
@@ -585,7 +589,7 @@ out_reset_timer:
        }
        inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
                                  tcp_clamp_rto_to_user_timeout(sk), TCP_RTO_MAX);
-       if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1 + 1, 0))
+       if (retransmits_timed_out(sk, READ_ONCE(net->ipv4.sysctl_tcp_retries1) + 1, 0))
                __sk_dst_reset(sk);
 
 out:;
index 70564ddccc4677d0e091ef6ae747b001be4bd1aa..6f354f8be2c57538eef832aee926f225c27aa72c 100644 (file)
@@ -226,7 +226,7 @@ lookup_protocol:
        RCU_INIT_POINTER(inet->mc_list, NULL);
        inet->rcv_tos   = 0;
 
-       if (net->ipv4.sysctl_ip_no_pmtu_disc)
+       if (READ_ONCE(net->ipv4.sysctl_ip_no_pmtu_disc))
                inet->pmtudisc = IP_PMTUDISC_DONT;
        else
                inet->pmtudisc = IP_PMTUDISC_WANT;
index 61770220774ee09b8f780290776ec45353c75c9a..9d92d51c475779f7af72b1c4ea35d4d482874db0 100644 (file)
@@ -925,7 +925,7 @@ static int icmpv6_rcv(struct sk_buff *skb)
                break;
        case ICMPV6_EXT_ECHO_REQUEST:
                if (!net->ipv6.sysctl.icmpv6_echo_ignore_all &&
-                   net->ipv4.sysctl_icmp_echo_enable_probe)
+                   READ_ONCE(net->ipv4.sysctl_icmp_echo_enable_probe))
                        icmpv6_echo_reply(skb);
                break;
 
index 0322cc86b84eaaed7529a4b65fdfba4c97a38375..e1ebf5e42ebe9ac39c13f109b03853c557ff2718 100644 (file)
 #include <net/inet_ecn.h>
 #include <net/dst_metadata.h>
 
-INDIRECT_CALLABLE_DECLARE(void tcp_v6_early_demux(struct sk_buff *));
 static void ip6_rcv_finish_core(struct net *net, struct sock *sk,
                                struct sk_buff *skb)
 {
-       void (*edemux)(struct sk_buff *skb);
-
-       if (net->ipv4.sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == NULL) {
-               const struct inet6_protocol *ipprot;
-
-               ipprot = rcu_dereference(inet6_protos[ipv6_hdr(skb)->nexthdr]);
-               if (ipprot && (edemux = READ_ONCE(ipprot->early_demux)))
-                       INDIRECT_CALL_2(edemux, tcp_v6_early_demux,
-                                       udp_v6_early_demux, skb);
+       if (READ_ONCE(net->ipv4.sysctl_ip_early_demux) &&
+           !skb_dst(skb) && !skb->sk) {
+               switch (ipv6_hdr(skb)->nexthdr) {
+               case IPPROTO_TCP:
+                       if (READ_ONCE(net->ipv4.sysctl_tcp_early_demux))
+                               tcp_v6_early_demux(skb);
+                       break;
+               case IPPROTO_UDP:
+                       if (READ_ONCE(net->ipv4.sysctl_udp_early_demux))
+                               udp_v6_early_demux(skb);
+                       break;
+               }
        }
+
        if (!skb_valid_dst(skb))
                ip6_route_input(skb);
 }
index 828355710c57b6ea588c0a58de7e9ea119c70833..916417944ec8153919533bcfc034f2bb4b6d0180 100644 (file)
@@ -5741,7 +5741,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
                if (nexthop_is_blackhole(rt->nh))
                        rtm->rtm_type = RTN_BLACKHOLE;
 
-               if (net->ipv4.sysctl_nexthop_compat_mode &&
+               if (READ_ONCE(net->ipv4.sysctl_nexthop_compat_mode) &&
                    rt6_fill_node_nexthop(skb, rt->nh, &nh_flags) < 0)
                        goto nla_put_failure;
 
index d64855010948db23eb5ebe5ce0bc4dfff2634afb..e756ba705fd9b4e40bf8a0257b1533a8c51320bc 100644 (file)
@@ -189,6 +189,8 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
        }
 #endif
 
+       hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+
        skb_postpush_rcsum(skb, hdr, tot_len);
 
        return 0;
@@ -241,6 +243,8 @@ int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
        }
 #endif
 
+       hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+
        skb_postpush_rcsum(skb, hdr, sizeof(struct ipv6hdr) + hdrlen);
 
        return 0;
@@ -302,7 +306,6 @@ static int seg6_do_srh(struct sk_buff *skb)
                break;
        }
 
-       ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
        skb_set_transport_header(skb, sizeof(struct ipv6hdr));
        nf_reset_ct(skb);
 
index 98a34287439cc08418255f5baa7eed392cad936c..2cd4a8d3b30ade72515e482b0aa9e82f8d80a40d 100644 (file)
@@ -826,7 +826,6 @@ static int input_action_end_b6(struct sk_buff *skb, struct seg6_local_lwt *slwt)
        if (err)
                goto drop;
 
-       ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
        skb_set_transport_header(skb, sizeof(struct ipv6hdr));
 
        seg6_lookup_nexthop(skb, NULL, 0);
@@ -858,7 +857,6 @@ static int input_action_end_b6_encap(struct sk_buff *skb,
        if (err)
                goto drop;
 
-       ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
        skb_set_transport_header(skb, sizeof(struct ipv6hdr));
 
        seg6_lookup_nexthop(skb, NULL, 0);
index 9cc123f000fbcfbeff7728bfee5339d6dd6470f9..5014aa663452763b9895b2da0579367bfb3d0430 100644 (file)
@@ -141,7 +141,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
        __u8 rcv_wscale;
        u32 tsoff = 0;
 
-       if (!sock_net(sk)->ipv4.sysctl_tcp_syncookies || !th->ack || th->rst)
+       if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies) ||
+           !th->ack || th->rst)
                goto out;
 
        if (tcp_synq_no_recent_overflow(sk))
index f37dd4aa91c6bae1df92a1e4edca362c50cd97b9..9d3ede2932582e716d9fa15dd2fad7795ea1b993 100644 (file)
@@ -1822,7 +1822,7 @@ do_time_wait:
        goto discard_it;
 }
 
-INDIRECT_CALLABLE_SCOPE void tcp_v6_early_demux(struct sk_buff *skb)
+void tcp_v6_early_demux(struct sk_buff *skb)
 {
        const struct ipv6hdr *hdr;
        const struct tcphdr *th;
@@ -2176,12 +2176,7 @@ struct proto tcpv6_prot = {
 };
 EXPORT_SYMBOL_GPL(tcpv6_prot);
 
-/* thinking of making this const? Don't.
- * early_demux can change based on sysctl.
- */
-static struct inet6_protocol tcpv6_protocol = {
-       .early_demux    =       tcp_v6_early_demux,
-       .early_demux_handler =  tcp_v6_early_demux,
+static const struct inet6_protocol tcpv6_protocol = {
        .handler        =       tcp_v6_rcv,
        .err_handler    =       tcp_v6_err,
        .flags          =       INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
index 55afd7f39c0450ff442a0499b7f8e42bf1a613bc..e2f2e087a7531d57cf965a9fa3dd77e35b879d06 100644 (file)
@@ -1052,7 +1052,7 @@ static struct sock *__udp6_lib_demux_lookup(struct net *net,
        return NULL;
 }
 
-INDIRECT_CALLABLE_SCOPE void udp_v6_early_demux(struct sk_buff *skb)
+void udp_v6_early_demux(struct sk_buff *skb)
 {
        struct net *net = dev_net(skb->dev);
        const struct udphdr *uh;
@@ -1660,12 +1660,7 @@ int udpv6_getsockopt(struct sock *sk, int level, int optname,
        return ipv6_getsockopt(sk, level, optname, optval, optlen);
 }
 
-/* thinking of making this const? Don't.
- * early_demux can change based on sysctl.
- */
-static struct inet6_protocol udpv6_protocol = {
-       .early_demux    =       udp_v6_early_demux,
-       .early_demux_handler =  udp_v6_early_demux,
+static const struct inet6_protocol udpv6_protocol = {
        .handler        =       udpv6_rcv,
        .err_handler    =       udpv6_err,
        .flags          =       INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
index f7896f257e1b40a2335110fc606942008cc21893..4ddf297f40f2e6520a8445d828e0c9888656d0d0 100644 (file)
@@ -4468,14 +4468,14 @@ EXPORT_SYMBOL_GPL(ieee80211_color_change_finish);
 
 void
 ieeee80211_obss_color_collision_notify(struct ieee80211_vif *vif,
-                                      u64 color_bitmap)
+                                      u64 color_bitmap, gfp_t gfp)
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 
        if (sdata->vif.color_change_active || sdata->vif.csa_active)
                return;
 
-       cfg80211_obss_color_collision_notify(sdata->dev, color_bitmap);
+       cfg80211_obss_color_collision_notify(sdata->dev, color_bitmap, gfp);
 }
 EXPORT_SYMBOL_GPL(ieeee80211_obss_color_collision_notify);
 
index 41531478437cf0a1fcb110d90abd919cbc918b44..15a73b7fdd75a18dc2d1e5d8d30173a94b6ca2a9 100644 (file)
@@ -377,7 +377,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
        bool cancel_scan;
        struct cfg80211_nan_func *func;
 
+       spin_lock_bh(&local->fq.lock);
        clear_bit(SDATA_STATE_RUNNING, &sdata->state);
+       spin_unlock_bh(&local->fq.lock);
 
        cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata;
        if (cancel_scan)
index 3c08ae04ddbc3f742e574834f963120191ccba57..1675f8cb87f1555dcccf098c8a74d5b1ff3a6f93 100644 (file)
@@ -3217,7 +3217,8 @@ ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx)
                                      IEEE80211_HE_OPERATION_BSS_COLOR_MASK);
                if (color == bss_conf->he_bss_color.color)
                        ieeee80211_obss_color_collision_notify(&rx->sdata->vif,
-                                                              BIT_ULL(color));
+                                                              BIT_ULL(color),
+                                                              GFP_ATOMIC);
        }
 }
 
index 0e4efc08c762d26a1fa4a1bcaa9885f9d4edaf0b..c425f4fb7c2e8cf64aee2376eb8e8e9eaf406261 100644 (file)
@@ -2818,19 +2818,10 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
        /*
         * If the skb is shared we need to obtain our own copy.
         */
-       if (skb_shared(skb)) {
-               struct sk_buff *tmp_skb = skb;
-
-               /* can't happen -- skb is a clone if info_id != 0 */
-               WARN_ON(info_id);
-
-               skb = skb_clone(skb, GFP_ATOMIC);
-               kfree_skb(tmp_skb);
-
-               if (!skb) {
-                       ret = -ENOMEM;
-                       goto free;
-               }
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (unlikely(!skb)) {
+               ret = -ENOMEM;
+               goto free;
        }
 
        hdr.frame_control = fc;
@@ -3539,15 +3530,9 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
 
        /* after this point (skb is modified) we cannot return false */
 
-       if (skb_shared(skb)) {
-               struct sk_buff *tmp_skb = skb;
-
-               skb = skb_clone(skb, GFP_ATOMIC);
-               kfree_skb(tmp_skb);
-
-               if (!skb)
-                       return true;
-       }
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return true;
 
        if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) &&
            ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb))
@@ -4437,7 +4422,7 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
                                struct net_device *dev, struct sta_info *sta,
                                struct ieee80211_key *key, struct sk_buff *skb)
 {
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_tx_info *info;
        struct ieee80211_local *local = sdata->local;
        struct tid_ampdu_tx *tid_tx;
        u8 tid;
@@ -4452,6 +4437,11 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
            test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
                goto out_free;
 
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return;
+
+       info = IEEE80211_SKB_CB(skb);
        memset(info, 0, sizeof(*info));
 
        ieee80211_aggr_check(sdata, sta, skb);
index 1e26b5235add401f8cfce2555d87de3843e6d78f..dad42d42aa84cf688bccc02de237a688ad9d1747 100644 (file)
@@ -301,6 +301,9 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
        local_bh_disable();
        spin_lock(&fq->lock);
 
+       if (!test_bit(SDATA_STATE_RUNNING, &sdata->state))
+               goto out;
+
        if (sdata->vif.type == NL80211_IFTYPE_AP)
                ps = &sdata->bss->ps;
 
index 62c6733e079232aae264b21129101b6bee1ac59b..d50480b317505525b0ddfffb69db7c98aeda3546 100644 (file)
@@ -147,8 +147,8 @@ u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
        bool qos;
 
        /* all mesh/ocb stations are required to support WME */
-       if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
-           sdata->vif.type == NL80211_IFTYPE_OCB)
+       if (sta && (sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
+                   sdata->vif.type == NL80211_IFTYPE_OCB))
                qos = true;
        else if (sta)
                qos = sta->sta.wme;
index aead331866a0ce8612b418f9c0e25f3a6946ef77..bd8f0f425be4ca1d09076a054da1f9e8accf363b 100644 (file)
@@ -1584,6 +1584,9 @@ mp_rst:
                *ptr++ = mptcp_option(MPTCPOPT_MP_PRIO,
                                      TCPOLEN_MPTCP_PRIO,
                                      opts->backup, TCPOPT_NOP);
+
+               MPTCP_INC_STATS(sock_net((const struct sock *)tp),
+                               MPTCP_MIB_MPPRIOTX);
        }
 
 mp_capable_done:
index e099f2a12504a78edff538c9160e2d97d9203593..7c7395b589449a5a82bf12a7c03e33e85b417614 100644 (file)
@@ -717,9 +717,10 @@ void mptcp_pm_nl_addr_send_ack(struct mptcp_sock *msk)
        }
 }
 
-static int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk,
-                                       struct mptcp_addr_info *addr,
-                                       u8 bkup)
+int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk,
+                                struct mptcp_addr_info *addr,
+                                struct mptcp_addr_info *rem,
+                                u8 bkup)
 {
        struct mptcp_subflow_context *subflow;
 
@@ -727,24 +728,29 @@ static int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk,
 
        mptcp_for_each_subflow(msk, subflow) {
                struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
-               struct sock *sk = (struct sock *)msk;
-               struct mptcp_addr_info local;
+               struct mptcp_addr_info local, remote;
+               bool slow;
 
                local_address((struct sock_common *)ssk, &local);
                if (!mptcp_addresses_equal(&local, addr, addr->port))
                        continue;
 
+               if (rem && rem->family != AF_UNSPEC) {
+                       remote_address((struct sock_common *)ssk, &remote);
+                       if (!mptcp_addresses_equal(&remote, rem, rem->port))
+                               continue;
+               }
+
+               slow = lock_sock_fast(ssk);
                if (subflow->backup != bkup)
                        msk->last_snd = NULL;
                subflow->backup = bkup;
                subflow->send_mp_prio = 1;
                subflow->request_bkup = bkup;
-               __MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPPRIOTX);
 
-               spin_unlock_bh(&msk->pm.lock);
                pr_debug("send ack for mp_prio");
-               mptcp_subflow_send_ack(ssk);
-               spin_lock_bh(&msk->pm.lock);
+               __mptcp_subflow_send_ack(ssk);
+               unlock_sock_fast(ssk, slow);
 
                return 0;
        }
@@ -801,7 +807,8 @@ 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[i], msk->pm.id_avail_bitmap);
+               if (rm_type == MPTCP_MIB_RMSUBFLOW)
+                       __set_bit(rm_list->ids[i], msk->pm.id_avail_bitmap);
                if (!removed)
                        continue;
 
@@ -1816,8 +1823,10 @@ static void mptcp_pm_nl_fullmesh(struct mptcp_sock *msk,
 
        list.ids[list.nr++] = addr->id;
 
+       spin_lock_bh(&msk->pm.lock);
        mptcp_pm_nl_rm_subflow_received(msk, &list);
        mptcp_pm_create_subflow_or_signal_addr(msk);
+       spin_unlock_bh(&msk->pm.lock);
 }
 
 static int mptcp_nl_set_flags(struct net *net,
@@ -1835,12 +1844,10 @@ static int mptcp_nl_set_flags(struct net *net,
                        goto next;
 
                lock_sock(sk);
-               spin_lock_bh(&msk->pm.lock);
                if (changed & MPTCP_PM_ADDR_FLAG_BACKUP)
-                       ret = mptcp_pm_nl_mp_prio_send_ack(msk, addr, bkup);
+                       ret = mptcp_pm_nl_mp_prio_send_ack(msk, addr, NULL, bkup);
                if (changed & MPTCP_PM_ADDR_FLAG_FULLMESH)
                        mptcp_pm_nl_fullmesh(msk, addr);
-               spin_unlock_bh(&msk->pm.lock);
                release_sock(sk);
 
 next:
@@ -1854,6 +1861,9 @@ next:
 static int mptcp_nl_cmd_set_flags(struct sk_buff *skb, struct genl_info *info)
 {
        struct mptcp_pm_addr_entry addr = { .addr = { .family = AF_UNSPEC }, }, *entry;
+       struct mptcp_pm_addr_entry remote = { .addr = { .family = AF_UNSPEC }, };
+       struct nlattr *attr_rem = info->attrs[MPTCP_PM_ATTR_ADDR_REMOTE];
+       struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN];
        struct nlattr *attr = info->attrs[MPTCP_PM_ATTR_ADDR];
        struct pm_nl_pernet *pernet = genl_info_pm_nl(info);
        u8 changed, mask = MPTCP_PM_ADDR_FLAG_BACKUP |
@@ -1866,6 +1876,12 @@ static int mptcp_nl_cmd_set_flags(struct sk_buff *skb, struct genl_info *info)
        if (ret < 0)
                return ret;
 
+       if (attr_rem) {
+               ret = mptcp_pm_parse_entry(attr_rem, info, false, &remote);
+               if (ret < 0)
+                       return ret;
+       }
+
        if (addr.flags & MPTCP_PM_ADDR_FLAG_BACKUP)
                bkup = 1;
        if (addr.addr.family == AF_UNSPEC) {
@@ -1874,6 +1890,10 @@ static int mptcp_nl_cmd_set_flags(struct sk_buff *skb, struct genl_info *info)
                        return -EOPNOTSUPP;
        }
 
+       if (token)
+               return mptcp_userspace_pm_set_flags(sock_net(skb->sk),
+                                                   token, &addr, &remote, bkup);
+
        spin_lock_bh(&pernet->lock);
        entry = __lookup_addr(pernet, &addr.addr, lookup_by_id);
        if (!entry) {
index f56378e4f59770430bab72afefd058e9323c4f4a..9e82250cbb703a3987ce1be2448e684aff5d0d16 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include "protocol.h"
+#include "mib.h"
 
 void mptcp_free_local_addr_list(struct mptcp_sock *msk)
 {
@@ -306,15 +307,11 @@ static struct sock *mptcp_nl_find_ssk(struct mptcp_sock *msk,
                                      const struct mptcp_addr_info *local,
                                      const struct mptcp_addr_info *remote)
 {
-       struct sock *sk = &msk->sk.icsk_inet.sk;
        struct mptcp_subflow_context *subflow;
-       struct sock *found = NULL;
 
        if (local->family != remote->family)
                return NULL;
 
-       lock_sock(sk);
-
        mptcp_for_each_subflow(msk, subflow) {
                const struct inet_sock *issk;
                struct sock *ssk;
@@ -347,16 +344,11 @@ static struct sock *mptcp_nl_find_ssk(struct mptcp_sock *msk,
                }
 
                if (issk->inet_sport == local->port &&
-                   issk->inet_dport == remote->port) {
-                       found = ssk;
-                       goto found;
-               }
+                   issk->inet_dport == remote->port)
+                       return ssk;
        }
 
-found:
-       release_sock(sk);
-
-       return found;
+       return NULL;
 }
 
 int mptcp_nl_cmd_sf_destroy(struct sk_buff *skb, struct genl_info *info)
@@ -412,18 +404,51 @@ int mptcp_nl_cmd_sf_destroy(struct sk_buff *skb, struct genl_info *info)
        }
 
        sk = &msk->sk.icsk_inet.sk;
+       lock_sock(sk);
        ssk = mptcp_nl_find_ssk(msk, &addr_l, &addr_r);
        if (ssk) {
                struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
 
                mptcp_subflow_shutdown(sk, ssk, RCV_SHUTDOWN | SEND_SHUTDOWN);
                mptcp_close_ssk(sk, ssk, subflow);
+               MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RMSUBFLOW);
                err = 0;
        } else {
                err = -ESRCH;
        }
+       release_sock(sk);
 
- destroy_err:
+destroy_err:
        sock_put((struct sock *)msk);
        return err;
 }
+
+int mptcp_userspace_pm_set_flags(struct net *net, struct nlattr *token,
+                                struct mptcp_pm_addr_entry *loc,
+                                struct mptcp_pm_addr_entry *rem, u8 bkup)
+{
+       struct mptcp_sock *msk;
+       int ret = -EINVAL;
+       u32 token_val;
+
+       token_val = nla_get_u32(token);
+
+       msk = mptcp_token_get_sock(net, token_val);
+       if (!msk)
+               return ret;
+
+       if (!mptcp_pm_is_userspace(msk))
+               goto set_flags_err;
+
+       if (loc->addr.family == AF_UNSPEC ||
+           rem->addr.family == AF_UNSPEC)
+               goto set_flags_err;
+
+       lock_sock((struct sock *)msk);
+       ret = mptcp_pm_nl_mp_prio_send_ack(msk, &loc->addr, &rem->addr, bkup);
+       release_sock((struct sock *)msk);
+
+set_flags_err:
+       sock_put((struct sock *)msk);
+       return ret;
+}
index e475212f2618bf46d995b43fb2eef0918845b0a7..21a3ed64226e56b589e344d3a726d0e7a1fc1723 100644 (file)
@@ -506,13 +506,18 @@ static inline bool tcp_can_send_ack(const struct sock *ssk)
               (TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_TIME_WAIT | TCPF_CLOSE | TCPF_LISTEN));
 }
 
+void __mptcp_subflow_send_ack(struct sock *ssk)
+{
+       if (tcp_can_send_ack(ssk))
+               tcp_send_ack(ssk);
+}
+
 void mptcp_subflow_send_ack(struct sock *ssk)
 {
        bool slow;
 
        slow = lock_sock_fast(ssk);
-       if (tcp_can_send_ack(ssk))
-               tcp_send_ack(ssk);
+       __mptcp_subflow_send_ack(ssk);
        unlock_sock_fast(ssk, slow);
 }
 
@@ -2914,12 +2919,12 @@ static void mptcp_copy_inaddrs(struct sock *msk, const struct sock *ssk)
 
 static int mptcp_disconnect(struct sock *sk, int flags)
 {
-       struct mptcp_subflow_context *subflow;
+       struct mptcp_subflow_context *subflow, *tmp;
        struct mptcp_sock *msk = mptcp_sk(sk);
 
        inet_sk_state_store(sk, TCP_CLOSE);
 
-       mptcp_for_each_subflow(msk, subflow) {
+       list_for_each_entry_safe(subflow, tmp, &msk->conn_list, node) {
                struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
 
                __mptcp_close_ssk(sk, ssk, subflow, MPTCP_CF_FASTCLOSE);
index c14d70c036d0eef8a8d7a9de415fed3e49fab358..480c5320b86e52cd6e49c9b8d6d076094b8ebe3e 100644 (file)
@@ -607,6 +607,7 @@ void __init mptcp_subflow_init(void);
 void mptcp_subflow_shutdown(struct sock *sk, struct sock *ssk, int how);
 void mptcp_close_ssk(struct sock *sk, struct sock *ssk,
                     struct mptcp_subflow_context *subflow);
+void __mptcp_subflow_send_ack(struct sock *ssk);
 void mptcp_subflow_send_ack(struct sock *ssk);
 void mptcp_subflow_reset(struct sock *ssk);
 void mptcp_subflow_queue_clean(struct sock *ssk);
@@ -771,6 +772,10 @@ void mptcp_pm_rm_addr_received(struct mptcp_sock *msk,
                               const struct mptcp_rm_list *rm_list);
 void mptcp_pm_mp_prio_received(struct sock *sk, u8 bkup);
 void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq);
+int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk,
+                                struct mptcp_addr_info *addr,
+                                struct mptcp_addr_info *rem,
+                                u8 bkup);
 bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk,
                              const struct mptcp_pm_addr_entry *entry);
 void mptcp_pm_free_anno_list(struct mptcp_sock *msk);
@@ -787,7 +792,9 @@ int mptcp_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk,
 int mptcp_userspace_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk,
                                                   unsigned int id,
                                                   u8 *flags, int *ifindex);
-
+int mptcp_userspace_pm_set_flags(struct net *net, struct nlattr *token,
+                                struct mptcp_pm_addr_entry *loc,
+                                struct mptcp_pm_addr_entry *rem, u8 bkup);
 int mptcp_pm_announce_addr(struct mptcp_sock *msk,
                           const struct mptcp_addr_info *addr,
                           bool echo);
index 082a2fd8d85b1529455cfe843f6d121fb3844a3a..369aeabb94fe298ec2cae5b7fc49d198b7dd6f8b 100644 (file)
@@ -729,6 +729,9 @@ static void nf_ct_gc_expired(struct nf_conn *ct)
        if (!refcount_inc_not_zero(&ct->ct_general.use))
                return;
 
+       /* load ->status after refcount increase */
+       smp_acquire__after_ctrl_dep();
+
        if (nf_ct_should_gc(ct))
                nf_ct_kill(ct);
 
@@ -795,6 +798,9 @@ __nf_conntrack_find_get(struct net *net, const struct nf_conntrack_zone *zone,
                 */
                ct = nf_ct_tuplehash_to_ctrack(h);
                if (likely(refcount_inc_not_zero(&ct->ct_general.use))) {
+                       /* re-check key after refcount */
+                       smp_acquire__after_ctrl_dep();
+
                        if (likely(nf_ct_key_equal(h, tuple, zone, net)))
                                goto found;
 
@@ -1387,6 +1393,9 @@ static unsigned int early_drop_list(struct net *net,
                if (!refcount_inc_not_zero(&tmp->ct_general.use))
                        continue;
 
+               /* load ->ct_net and ->status after refcount increase */
+               smp_acquire__after_ctrl_dep();
+
                /* kill only if still in same netns -- might have moved due to
                 * SLAB_TYPESAFE_BY_RCU rules.
                 *
@@ -1536,6 +1545,9 @@ static void gc_worker(struct work_struct *work)
                        if (!refcount_inc_not_zero(&tmp->ct_general.use))
                                continue;
 
+                       /* load ->status after refcount increase */
+                       smp_acquire__after_ctrl_dep();
+
                        if (gc_worker_skip_ct(tmp)) {
                                nf_ct_put(tmp);
                                continue;
@@ -1775,6 +1787,16 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
        if (!exp)
                __nf_ct_try_assign_helper(ct, tmpl, GFP_ATOMIC);
 
+       /* Other CPU might have obtained a pointer to this object before it was
+        * released.  Because refcount is 0, refcount_inc_not_zero() will fail.
+        *
+        * After refcount_set(1) it will succeed; ensure that zeroing of
+        * ct->status and the correct ct->net pointer are visible; else other
+        * core might observe CONFIRMED bit which means the entry is valid and
+        * in the hash table, but its not (anymore).
+        */
+       smp_wmb();
+
        /* Now it is going to be associated with an sk_buff, set refcount to 1. */
        refcount_set(&ct->ct_general.use, 1);
 
index 722af5e309ba280a17553e0d4164dcd25d0754d9..f5905b5201a798bb91cb74b7b384aba7fbc6d007 100644 (file)
@@ -1203,6 +1203,7 @@ restart:
                                           hnnode) {
                        ct = nf_ct_tuplehash_to_ctrack(h);
                        if (nf_ct_is_expired(ct)) {
+                               /* need to defer nf_ct_kill() until lock is released */
                                if (i < ARRAY_SIZE(nf_ct_evict) &&
                                    refcount_inc_not_zero(&ct->ct_general.use))
                                        nf_ct_evict[i++] = ct;
index 6ad7bbc90d38fc026a6dc44186e5c3b5d1a30d48..05895878610c06e7bba4954d661883ac2c8496b2 100644 (file)
@@ -306,6 +306,9 @@ static int ct_seq_show(struct seq_file *s, void *v)
        if (unlikely(!refcount_inc_not_zero(&ct->ct_general.use)))
                return 0;
 
+       /* load ->status after refcount increase */
+       smp_acquire__after_ctrl_dep();
+
        if (nf_ct_should_gc(ct)) {
                nf_ct_kill(ct);
                goto release;
index 77bcb10fc586a1379838d3c2d3a34f967a1c81ff..cb894f0d63e9d300a47bfc1c723a0a79c8913c75 100644 (file)
@@ -67,7 +67,7 @@ dump_arp_packet(struct nf_log_buf *m,
        unsigned int logflags;
        struct arphdr _arph;
 
-       ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
+       ah = skb_header_pointer(skb, nhoff, sizeof(_arph), &_arph);
        if (!ah) {
                nf_log_buf_add(m, "TRUNCATED");
                return;
@@ -96,7 +96,7 @@ dump_arp_packet(struct nf_log_buf *m,
            ah->ar_pln != sizeof(__be32))
                return;
 
-       ap = skb_header_pointer(skb, sizeof(_arph), sizeof(_arpp), &_arpp);
+       ap = skb_header_pointer(skb, nhoff + sizeof(_arph), sizeof(_arpp), &_arpp);
        if (!ap) {
                nf_log_buf_add(m, " INCOMPLETE [%zu bytes]",
                               skb->len - sizeof(_arph));
@@ -149,7 +149,7 @@ static void nf_log_arp_packet(struct net *net, u_int8_t pf,
 
        nf_log_dump_packet_common(m, pf, hooknum, skb, in, out, loginfo,
                                  prefix);
-       dump_arp_packet(m, loginfo, skb, 0);
+       dump_arp_packet(m, loginfo, skb, skb_network_offset(skb));
 
        nf_log_buf_close(m);
 }
@@ -850,7 +850,7 @@ static void nf_log_ip_packet(struct net *net, u_int8_t pf,
        if (in)
                dump_mac_header(m, loginfo, skb);
 
-       dump_ipv4_packet(net, m, loginfo, skb, 0);
+       dump_ipv4_packet(net, m, loginfo, skb, skb_network_offset(skb));
 
        nf_log_buf_close(m);
 }
index e479dd0561c54d0c1a67ffdc3506739fbcd7c434..16915f8eef2b16eec7da7ecaaf8b4a4af5dd94e2 100644 (file)
@@ -405,7 +405,7 @@ synproxy_build_ip(struct net *net, struct sk_buff *skb, __be32 saddr,
        iph->tos        = 0;
        iph->id         = 0;
        iph->frag_off   = htons(IP_DF);
-       iph->ttl        = net->ipv4.sysctl_ip_default_ttl;
+       iph->ttl        = READ_ONCE(net->ipv4.sysctl_ip_default_ttl);
        iph->protocol   = IPPROTO_TCP;
        iph->check      = 0;
        iph->saddr      = saddr;
index 51144fc66889b5d31e9150d8989b4c644f987ee6..646d5fd53604bd94d64770ff6a5030e617b69f72 100644 (file)
@@ -5213,13 +5213,20 @@ static int nft_setelem_parse_data(struct nft_ctx *ctx, struct nft_set *set,
                                  struct nft_data *data,
                                  struct nlattr *attr)
 {
+       u32 dtype;
        int err;
 
        err = nft_data_init(ctx, data, NFT_DATA_VALUE_MAXLEN, desc, attr);
        if (err < 0)
                return err;
 
-       if (desc->type != NFT_DATA_VERDICT && desc->len != set->dlen) {
+       if (set->dtype == NFT_DATA_VERDICT)
+               dtype = NFT_DATA_VERDICT;
+       else
+               dtype = NFT_DATA_VALUE;
+
+       if (dtype != desc->type ||
+           set->dlen != desc->len) {
                nft_data_release(data, desc->type);
                return -EINVAL;
        }
@@ -5826,8 +5833,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
        if (!nla[NFTA_SET_ELEM_KEY] && !(flags & NFT_SET_ELEM_CATCHALL))
                return -EINVAL;
 
-       if (flags != 0)
-               nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
+       if (flags != 0) {
+               err = nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
+               if (err < 0)
+                       return err;
+       }
 
        if (set->flags & NFT_SET_MAP) {
                if (nla[NFTA_SET_ELEM_DATA] == NULL &&
@@ -5936,7 +5946,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                if (err < 0)
                        goto err_set_elem_expr;
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+               if (err < 0)
+                       goto err_parse_key;
        }
 
        if (nla[NFTA_SET_ELEM_KEY_END]) {
@@ -5945,22 +5957,31 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                if (err < 0)
                        goto err_parse_key;
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY_END, set->klen);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY_END, set->klen);
+               if (err < 0)
+                       goto err_parse_key_end;
        }
 
        if (timeout > 0) {
-               nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION);
-               if (timeout != set->timeout)
-                       nft_set_ext_add(&tmpl, NFT_SET_EXT_TIMEOUT);
+               err = nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION);
+               if (err < 0)
+                       goto err_parse_key_end;
+
+               if (timeout != set->timeout) {
+                       err = nft_set_ext_add(&tmpl, NFT_SET_EXT_TIMEOUT);
+                       if (err < 0)
+                               goto err_parse_key_end;
+               }
        }
 
        if (num_exprs) {
                for (i = 0; i < num_exprs; i++)
                        size += expr_array[i]->ops->size;
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_EXPRESSIONS,
-                                      sizeof(struct nft_set_elem_expr) +
-                                      size);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_EXPRESSIONS,
+                                            sizeof(struct nft_set_elem_expr) + size);
+               if (err < 0)
+                       goto err_parse_key_end;
        }
 
        if (nla[NFTA_SET_ELEM_OBJREF] != NULL) {
@@ -5975,7 +5996,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                        err = PTR_ERR(obj);
                        goto err_parse_key_end;
                }
-               nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF);
+               err = nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF);
+               if (err < 0)
+                       goto err_parse_key_end;
        }
 
        if (nla[NFTA_SET_ELEM_DATA] != NULL) {
@@ -6009,7 +6032,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                                                          NFT_VALIDATE_NEED);
                }
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_DATA, desc.len);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_DATA, desc.len);
+               if (err < 0)
+                       goto err_parse_data;
        }
 
        /* The full maximum length of userdata can exceed the maximum
@@ -6019,9 +6044,12 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
        ulen = 0;
        if (nla[NFTA_SET_ELEM_USERDATA] != NULL) {
                ulen = nla_len(nla[NFTA_SET_ELEM_USERDATA]);
-               if (ulen > 0)
-                       nft_set_ext_add_length(&tmpl, NFT_SET_EXT_USERDATA,
-                                              ulen);
+               if (ulen > 0) {
+                       err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_USERDATA,
+                                                    ulen);
+                       if (err < 0)
+                               goto err_parse_data;
+               }
        }
 
        err = -ENOMEM;
@@ -6249,8 +6277,11 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
 
        nft_set_ext_prepare(&tmpl);
 
-       if (flags != 0)
-               nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
+       if (flags != 0) {
+               err = nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
+               if (err < 0)
+                       return err;
+       }
 
        if (nla[NFTA_SET_ELEM_KEY]) {
                err = nft_setelem_parse_key(ctx, set, &elem.key.val,
@@ -6258,16 +6289,20 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
                if (err < 0)
                        return err;
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+               if (err < 0)
+                       goto fail_elem;
        }
 
        if (nla[NFTA_SET_ELEM_KEY_END]) {
                err = nft_setelem_parse_key(ctx, set, &elem.key_end.val,
                                            nla[NFTA_SET_ELEM_KEY_END]);
                if (err < 0)
-                       return err;
+                       goto fail_elem;
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY_END, set->klen);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY_END, set->klen);
+               if (err < 0)
+                       goto fail_elem_key_end;
        }
 
        err = -ENOMEM;
@@ -6275,7 +6310,7 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
                                      elem.key_end.val.data, NULL, 0, 0,
                                      GFP_KERNEL_ACCOUNT);
        if (elem.priv == NULL)
-               goto fail_elem;
+               goto fail_elem_key_end;
 
        ext = nft_set_elem_ext(set, elem.priv);
        if (flags)
@@ -6299,6 +6334,8 @@ fail_ops:
        kfree(trans);
 fail_trans:
        kfree(elem.priv);
+fail_elem_key_end:
+       nft_data_release(&elem.key_end.val, NFT_DATA_VALUE);
 fail_elem:
        nft_data_release(&elem.key.val, NFT_DATA_VALUE);
        return err;
index 2c8051d8cca69ce4e232cbe7e07538ab1262694f..4f9299b9dcddc149135843b8c47a1bbba9ff59ea 100644 (file)
@@ -2124,6 +2124,32 @@ out_scratch:
        return err;
 }
 
+/**
+ * nft_set_pipapo_match_destroy() - Destroy elements from key mapping array
+ * @set:       nftables API set representation
+ * @m:         matching data pointing to key mapping array
+ */
+static void nft_set_pipapo_match_destroy(const struct nft_set *set,
+                                        struct nft_pipapo_match *m)
+{
+       struct nft_pipapo_field *f;
+       int i, r;
+
+       for (i = 0, f = m->f; i < m->field_count - 1; i++, f++)
+               ;
+
+       for (r = 0; r < f->rules; r++) {
+               struct nft_pipapo_elem *e;
+
+               if (r < f->rules - 1 && f->mt[r + 1].e == f->mt[r].e)
+                       continue;
+
+               e = f->mt[r].e;
+
+               nft_set_elem_destroy(set, e, true);
+       }
+}
+
 /**
  * nft_pipapo_destroy() - Free private data for set and all committed elements
  * @set:       nftables API set representation
@@ -2132,26 +2158,13 @@ static void nft_pipapo_destroy(const struct nft_set *set)
 {
        struct nft_pipapo *priv = nft_set_priv(set);
        struct nft_pipapo_match *m;
-       struct nft_pipapo_field *f;
-       int i, r, cpu;
+       int cpu;
 
        m = rcu_dereference_protected(priv->match, true);
        if (m) {
                rcu_barrier();
 
-               for (i = 0, f = m->f; i < m->field_count - 1; i++, f++)
-                       ;
-
-               for (r = 0; r < f->rules; r++) {
-                       struct nft_pipapo_elem *e;
-
-                       if (r < f->rules - 1 && f->mt[r + 1].e == f->mt[r].e)
-                               continue;
-
-                       e = f->mt[r].e;
-
-                       nft_set_elem_destroy(set, e, true);
-               }
+               nft_set_pipapo_match_destroy(set, m);
 
 #ifdef NFT_PIPAPO_ALIGN
                free_percpu(m->scratch_aligned);
@@ -2165,6 +2178,11 @@ static void nft_pipapo_destroy(const struct nft_set *set)
        }
 
        if (priv->clone) {
+               m = priv->clone;
+
+               if (priv->dirty)
+                       nft_set_pipapo_match_destroy(set, m);
+
 #ifdef NFT_PIPAPO_ALIGN
                free_percpu(priv->clone->scratch_aligned);
 #endif
index fee6409c2bb383abe4428dff6f70345d1445387b..eb0b8197ac825479e8fa6c00c77db71b5f74d41b 100644 (file)
@@ -227,8 +227,8 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
 {
        struct rose_neigh *s;
 
-       rose_stop_ftimer(rose_neigh);
-       rose_stop_t0timer(rose_neigh);
+       del_timer_sync(&rose_neigh->ftimer);
+       del_timer_sync(&rose_neigh->t0timer);
 
        skb_queue_purge(&rose_neigh->queue);
 
index 79c8901f66ab1c87554581d81b0e5835582db0f8..b759628a47c204d49aa6caca5031451809ec99fd 100644 (file)
@@ -442,7 +442,7 @@ static int tcf_police_act_to_flow_act(int tc_act, u32 *extval,
                act_id = FLOW_ACTION_JUMP;
                *extval = tc_act & TC_ACT_EXT_VAL_MASK;
        } else if (tc_act == TC_ACT_UNSPEC) {
-               NL_SET_ERR_MSG_MOD(extack, "Offload not supported when conform/exceed action is \"continue\"");
+               act_id = FLOW_ACTION_CONTINUE;
        } else {
                NL_SET_ERR_MSG_MOD(extack, "Unsupported conform/exceed action offload");
        }
index 9bb4d3dcc994fb259c12cfad3fd84f0f164ab1eb..ac366c99086fd3b9f0721c93c53cf930f4e495c5 100644 (file)
@@ -3533,7 +3533,7 @@ int tc_setup_action(struct flow_action *flow_action,
                    struct tc_action *actions[],
                    struct netlink_ext_ack *extack)
 {
-       int i, j, index, err = 0;
+       int i, j, k, index, err = 0;
        struct tc_action *act;
 
        BUILD_BUG_ON(TCA_ACT_HW_STATS_ANY != FLOW_ACTION_HW_STATS_ANY);
@@ -3553,14 +3553,18 @@ int tc_setup_action(struct flow_action *flow_action,
                if (err)
                        goto err_out_locked;
 
-               entry->hw_stats = tc_act_hw_stats(act->hw_stats);
-               entry->hw_index = act->tcfa_index;
                index = 0;
                err = tc_setup_offload_act(act, entry, &index, extack);
-               if (!err)
-                       j += index;
-               else
+               if (err)
                        goto err_out_locked;
+
+               for (k = 0; k < index ; k++) {
+                       entry[k].hw_stats = tc_act_hw_stats(act->hw_stats);
+                       entry[k].hw_index = act->tcfa_index;
+               }
+
+               j += index;
+
                spin_unlock_bh(&act->tcfa_lock);
        }
 
index 35928fefae3327f97688f0857de63bc17e3429d6..1a094b087d88bdcc5cf213c5ecd0a053a9b1b8c6 100644 (file)
@@ -358,7 +358,7 @@ static int sctp_v4_available(union sctp_addr *addr, struct sctp_sock *sp)
        if (addr->v4.sin_addr.s_addr != htonl(INADDR_ANY) &&
           ret != RTN_LOCAL &&
           !sp->inet.freebind &&
-          !net->ipv4.sysctl_ip_nonlocal_bind)
+           !READ_ONCE(net->ipv4.sysctl_ip_nonlocal_bind))
                return 0;
 
        if (ipv6_only_sock(sctp_opt2sk(sp)))
index c4d057b2941d51cd87ae02caa7141cd1a4a3be42..0bde36b564727960352478e24a9c293f09a6189d 100644 (file)
@@ -2122,7 +2122,7 @@ void smc_llc_lgr_init(struct smc_link_group *lgr, struct smc_sock *smc)
        init_waitqueue_head(&lgr->llc_flow_waiter);
        init_waitqueue_head(&lgr->llc_msg_waiter);
        mutex_init(&lgr->llc_conf_mutex);
-       lgr->llc_testlink_time = net->ipv4.sysctl_tcp_keepalive_time;
+       lgr->llc_testlink_time = READ_ONCE(net->ipv4.sysctl_tcp_keepalive_time);
 }
 
 /* called after lgr was removed from lgr_list */
index ec6f4b699a2b32397e07c6afd025587476881eec..879b9024678edf37380e032508ee9c598194c49c 100644 (file)
@@ -97,13 +97,16 @@ static void tls_device_queue_ctx_destruction(struct tls_context *ctx)
        unsigned long flags;
 
        spin_lock_irqsave(&tls_device_lock, flags);
+       if (unlikely(!refcount_dec_and_test(&ctx->refcount)))
+               goto unlock;
+
        list_move_tail(&ctx->list, &tls_device_gc_list);
 
        /* schedule_work inside the spinlock
         * to make sure tls_device_down waits for that work.
         */
        schedule_work(&tls_device_gc_work);
-
+unlock:
        spin_unlock_irqrestore(&tls_device_lock, flags);
 }
 
@@ -194,8 +197,7 @@ void tls_device_sk_destruct(struct sock *sk)
                clean_acked_data_disable(inet_csk(sk));
        }
 
-       if (refcount_dec_and_test(&tls_ctx->refcount))
-               tls_device_queue_ctx_destruction(tls_ctx);
+       tls_device_queue_ctx_destruction(tls_ctx);
 }
 EXPORT_SYMBOL_GPL(tls_device_sk_destruct);
 
@@ -1419,9 +1421,9 @@ static struct notifier_block tls_dev_notifier = {
        .notifier_call  = tls_dev_event,
 };
 
-void __init tls_device_init(void)
+int __init tls_device_init(void)
 {
-       register_netdevice_notifier(&tls_dev_notifier);
+       return register_netdevice_notifier(&tls_dev_notifier);
 }
 
 void __exit tls_device_cleanup(void)
index 2ffede463e4a5c13fdb01de4a79fee98fd8d6b98..d80ab3d1764e7b6d36bb8dc3d151e2e89cf00f5b 100644 (file)
@@ -1048,7 +1048,12 @@ static int __init tls_register(void)
        if (err)
                return err;
 
-       tls_device_init();
+       err = tls_device_init();
+       if (err) {
+               unregister_pernet_subsys(&tls_proc_ops);
+               return err;
+       }
+
        tcp_register_ulp(&tcp_tls_ulp_ops);
 
        return 0;
index 0513f82b8537ed5885f4ff667fa1dd040a4baa6e..e30649f6dde5e913a6c9cb0bfd3b9e70bd471c7a 100644 (file)
@@ -267,9 +267,6 @@ static int tls_do_decryption(struct sock *sk,
        }
        darg->async = false;
 
-       if (ret == -EBADMSG)
-               TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSDECRYPTERROR);
-
        return ret;
 }
 
@@ -1579,8 +1576,11 @@ static int decrypt_skb_update(struct sock *sk, struct sk_buff *skb,
        }
 
        err = decrypt_internal(sk, skb, dest, NULL, darg);
-       if (err < 0)
+       if (err < 0) {
+               if (err == -EBADMSG)
+                       TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSDECRYPTERROR);
                return err;
+       }
        if (darg->async)
                goto decrypt_next;
 
index ff4d48fcbfb2aaa583ce17d7126e240d4da10dd1..607a689110471e7ff7ecf2c9dce33bbc2963ed8f 100644 (file)
@@ -1031,7 +1031,8 @@ void __cfg80211_port_authorized(struct wireless_dev *wdev, const u8 *bssid)
 {
        ASSERT_WDEV_LOCK(wdev);
 
-       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
+                   wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
                return;
 
        if (WARN_ON(!wdev->current_bss) ||
index 87bdd71c7bb66cb3ba0cb6c7fa91b5cd9e52dcca..f70112176b7c1f59c2210b27d02ec74edc51a5e0 100644 (file)
@@ -332,6 +332,7 @@ static void __xp_dma_unmap(struct xsk_dma_map *dma_map, unsigned long attrs)
        for (i = 0; i < dma_map->dma_pages_cnt; i++) {
                dma = &dma_map->dma_pages[i];
                if (*dma) {
+                       *dma &= ~XSK_NEXT_PG_CONTIG_MASK;
                        dma_unmap_page_attrs(dma_map->dev, *dma, PAGE_SIZE,
                                             DMA_BIDIRECTIONAL, attrs);
                        *dma = 0;
index f1876ea61fdce29d15be13c9635b0d6cf7c90587..f1a0bab920a5580a507932974a86f96c08113759 100644 (file)
@@ -2678,8 +2678,10 @@ static int xfrm_expand_policies(const struct flowi *fl, u16 family,
                *num_xfrms = 0;
                return 0;
        }
-       if (IS_ERR(pols[0]))
+       if (IS_ERR(pols[0])) {
+               *num_pols = 0;
                return PTR_ERR(pols[0]);
+       }
 
        *num_xfrms = pols[0]->xfrm_nr;
 
@@ -2694,6 +2696,7 @@ static int xfrm_expand_policies(const struct flowi *fl, u16 family,
                if (pols[1]) {
                        if (IS_ERR(pols[1])) {
                                xfrm_pols_put(pols, *num_pols);
+                               *num_pols = 0;
                                return PTR_ERR(pols[1]);
                        }
                        (*num_pols)++;
index 08564e0eef2037bc13016066a56e864acee89900..ccfb172eb5b8d4f2a1561ecc3dc9b54635011ddb 100644 (file)
@@ -2620,7 +2620,7 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload)
        int err;
 
        if (family == AF_INET &&
-           xs_net(x)->ipv4.sysctl_ip_no_pmtu_disc)
+           READ_ONCE(xs_net(x)->ipv4.sysctl_ip_no_pmtu_disc))
                x->props.flags |= XFRM_STATE_NOPMTUDISC;
 
        err = -EPROTONOSUPPORT;
index 01ee6c8c8382921d253e0a130b8a05df3c60ebc1..e22da8573116e0500c2eb41f2f8672ade8e2bd84 100644 (file)
 
 #define BACKTRACE_DEPTH 16
 #define MAX_SYMBOL_LEN 4096
-struct fprobe sample_probe;
+static struct fprobe sample_probe;
 static unsigned long nhit;
 
 static char symbol[MAX_SYMBOL_LEN] = "kernel_clone";
 module_param_string(symbol, symbol, sizeof(symbol), 0644);
+MODULE_PARM_DESC(symbol, "Probed symbol(s), given by comma separated symbols or a wildcard pattern.");
+
 static char nosymbol[MAX_SYMBOL_LEN] = "";
 module_param_string(nosymbol, nosymbol, sizeof(nosymbol), 0644);
+MODULE_PARM_DESC(nosymbol, "Not-probed symbols, given by a wildcard pattern.");
+
 static bool stackdump = true;
 module_param(stackdump, bool, 0644);
+MODULE_PARM_DESC(stackdump, "Enable stackdump.");
+
 static bool use_trace = false;
 module_param(use_trace, bool, 0644);
+MODULE_PARM_DESC(use_trace, "Use trace_printk instead of printk. This is only for debugging.");
 
 static void show_backtrace(void)
 {
index f991a66b5b022a83c789d544b43a9be89be5a172..fd346f58ddbaf10889d3de29fd7399cd90a94258 100644 (file)
@@ -16,9 +16,8 @@
 #include <linux/module.h>
 #include <linux/kprobes.h>
 
-#define MAX_SYMBOL_LEN 64
-static char symbol[MAX_SYMBOL_LEN] = "kernel_clone";
-module_param_string(symbol, symbol, sizeof(symbol), 0644);
+static char symbol[KSYM_NAME_LEN] = "kernel_clone";
+module_param_string(symbol, symbol, KSYM_NAME_LEN, 0644);
 
 /* For each probe you need to allocate a kprobe structure */
 static struct kprobe kp = {
index 228321ecb16168e1a61311dda0e7deb783d5dd9c..cbf16542d84e7c1527629de66adb7f5ec057ec62 100644 (file)
 #include <linux/module.h>
 #include <linux/kprobes.h>
 #include <linux/ktime.h>
-#include <linux/limits.h>
 #include <linux/sched.h>
 
-static char func_name[NAME_MAX] = "kernel_clone";
-module_param_string(func, func_name, NAME_MAX, S_IRUGO);
+static char func_name[KSYM_NAME_LEN] = "kernel_clone";
+module_param_string(func, func_name, KSYM_NAME_LEN, 0644);
 MODULE_PARM_DESC(func, "Function to kretprobe; this module will report the"
                        " function's execution time");
 
index d1425778664b9956c8a639e21ee8a096b10e2a70..3fb6a99e78c473128c7d4785fbdf073a05435b9a 100644 (file)
@@ -236,6 +236,7 @@ objtool_args =                                                              \
        $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount)             \
        $(if $(CONFIG_UNWINDER_ORC), --orc)                             \
        $(if $(CONFIG_RETPOLINE), --retpoline)                          \
+       $(if $(CONFIG_RETHUNK), --rethunk)                              \
        $(if $(CONFIG_SLS), --sls)                                      \
        $(if $(CONFIG_STACK_VALIDATION), --stackval)                    \
        $(if $(CONFIG_HAVE_STATIC_CALL_INLINE), --static-call)          \
index c2c43a0ecfe02d258d7b353ed846e7d86d05bbff..16a02e9237d360f95cfe41371f91998e3ed84159 100644 (file)
@@ -28,9 +28,6 @@ modules := $(patsubst $(extmod_prefix)%, $(dst)/%$(suffix-y), $(modules))
 __modinst: $(modules)
        @:
 
-quiet_cmd_none =
-      cmd_none = :
-
 #
 # Installation
 #
index 3c97a1564947c7dbd347e3f9375d324b62801c27..84019814f33f09323bcb9b50e8c3b1cae19c1696 100644 (file)
@@ -44,7 +44,7 @@ objtool-enabled := $(or $(delay-objtool),$(CONFIG_NOINSTR_VALIDATION))
 
 objtool_args := \
        $(if $(delay-objtool),$(objtool_args)) \
-       $(if $(CONFIG_NOINSTR_VALIDATION), --noinstr) \
+       $(if $(CONFIG_NOINSTR_VALIDATION), --noinstr $(if $(CONFIG_CPU_UNRET_ENTRY), --unret)) \
        $(if $(CONFIG_GCOV_KERNEL), --no-unreachable) \
        --link
 
index 1d1bde1fd45eb76b4639f8c720619f6712e25dcd..47da25b3ba7d206b7000847597c1519dd9dd3155 100755 (executable)
@@ -157,10 +157,10 @@ def cmdfiles_for_modorder(modorder):
             if ext != '.ko':
                 sys.exit('{}: module path must end with .ko'.format(ko))
             mod = base + '.mod'
-           # The first line of *.mod lists the objects that compose the module.
+            # Read from *.mod, to get a list of objects that compose the module.
             with open(mod) as m:
-                for obj in m.readline().split():
-                    yield to_cmdfile(obj)
+                for mod_line in m:
+                    yield to_cmdfile(mod_line.rstrip())
 
 
 def process_line(root_directory, command_prefix, file_path):
index 46f7542db08cee435642678386bb9a2f2dd76551..dc07b6d12e300ea72d8ba4b1cd6c33b5c9b6936c 100644 (file)
@@ -180,7 +180,7 @@ lx-symbols command."""
                 self.breakpoint.delete()
                 self.breakpoint = None
             self.breakpoint = LoadModuleBreakpoint(
-                "kernel/module.c:do_init_module", self)
+                "kernel/module/main.c:do_init_module", self)
         else:
             gdb.write("Note: symbol update on module loading not supported "
                       "with this gdb version\n")
index f29e4c65698347dac9ebb1ec1267801c2e25afe4..e6db09a779b779c4dfebe6910b2338bf7df6c28d 100644 (file)
@@ -54,17 +54,6 @@ config SECURITY_NETWORK
          implement socket and networking access controls.
          If you are unsure how to answer this question, answer N.
 
-config PAGE_TABLE_ISOLATION
-       bool "Remove the kernel mapping in user mode"
-       default y
-       depends on (X86_64 || X86_PAE) && !UML
-       help
-         This feature reduces the number of hardware side channels by
-         ensuring that the majority of kernel addresses are not mapped
-         into userspace.
-
-         See Documentation/x86/pti.rst for more details.
-
 config SECURITY_INFINIBAND
        bool "Infiniband Security Hooks"
        depends on SECURITY && INFINIBAND
index a733aff02006381826ea7e9c1b588734bbffd4fa..708de9656bbd2a5b4c106e577abdecea8dfff022 100644 (file)
@@ -75,7 +75,7 @@ static struct shash_desc *init_desc(char type, uint8_t hash_algo)
 {
        long rc;
        const char *algo;
-       struct crypto_shash **tfm, *tmp_tfm = NULL;
+       struct crypto_shash **tfm, *tmp_tfm;
        struct shash_desc *desc;
 
        if (type == EVM_XATTR_HMAC) {
@@ -120,16 +120,13 @@ unlock:
 alloc:
        desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(*tfm),
                        GFP_KERNEL);
-       if (!desc) {
-               crypto_free_shash(tmp_tfm);
+       if (!desc)
                return ERR_PTR(-ENOMEM);
-       }
 
        desc->tfm = *tfm;
 
        rc = crypto_shash_init(desc);
        if (rc) {
-               crypto_free_shash(tmp_tfm);
                kfree(desc);
                return ERR_PTR(rc);
        }
index cdb84dccd24e01bf13152c0fe7168af5ba8088e8..bde74fcecee38e9207d601c7b47bb1b814856bba 100644 (file)
@@ -514,7 +514,8 @@ int ima_appraise_measurement(enum ima_hooks func,
                goto out;
        }
 
-       status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint);
+       status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value,
+                                rc < 0 ? 0 : rc, iint);
        switch (status) {
        case INTEGRITY_PASS:
        case INTEGRITY_PASS_IMMUTABLE:
index a7206cc1d7d19129e6511a93f7452e1a9fa4287d..64499056648ad112b00c631df48d4f58e7788601 100644 (file)
@@ -205,6 +205,7 @@ out_array:
 
                crypto_free_shash(ima_algo_array[i].tfm);
        }
+       kfree(ima_algo_array);
 out:
        crypto_free_shash(ima_shash_tfm);
        return rc;
index 71786d01946f4539d6be8933bed6d3829f479961..9db66fe310d424f44c882a6e5702dddbef592f84 100644 (file)
@@ -67,6 +67,8 @@ const char * const *arch_get_ima_policy(void)
        if (IS_ENABLED(CONFIG_IMA_ARCH_POLICY) && arch_ima_get_secureboot()) {
                if (IS_ENABLED(CONFIG_MODULE_SIG))
                        set_module_sig_enforced();
+               if (IS_ENABLED(CONFIG_KEXEC_SIG))
+                       set_kexec_sig_enforced();
                return sb_arch_rules;
        }
        return NULL;
index 73917413365b3cead675a1b2b89d05e8322892d7..a8802b8da946bf3deabe6db47595dba8cc734891 100644 (file)
@@ -2247,6 +2247,10 @@ bool ima_appraise_signature(enum kernel_read_file_id id)
        if (id >= READING_MAX_ID)
                return false;
 
+       if (id == READING_KEXEC_IMAGE && !(ima_appraise & IMA_APPRAISE_ENFORCE)
+           && security_locked_down(LOCKDOWN_KEXEC))
+               return false;
+
        func = read_idmap[id] ?: FILE_CHECK;
 
        rcu_read_lock();
index c877f01a54713ea165219b04fb514f25a85d48c0..7bf9b1507220239e75856922a9a0d0d686e67f53 100644 (file)
@@ -323,10 +323,10 @@ static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize,
        else
                /*
                 * If digest is NULL, the event being recorded is a violation.
-                * Make room for the digest by increasing the offset of
-                * IMA_DIGEST_SIZE.
+                * Make room for the digest by increasing the offset by the
+                * hash algorithm digest size.
                 */
-               offset += IMA_DIGEST_SIZE;
+               offset += hash_digest_size[hash_algo];
 
        return ima_write_template_field_data(buffer, offset + digestsize,
                                             fmt, field_data);
index bd60308769ff7eab6b0da50a72d2e3a6ebe09be6..8634004a606b627111ce149d9597dd34e044ad2b 100644 (file)
@@ -74,36 +74,36 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
        err = snd_cs46xx_create(card, pci,
                                external_amp[dev], thinkpad[dev]);
        if (err < 0)
-               return err;
+               goto error;
        card->private_data = chip;
        chip->accept_valid = mmap_valid[dev];
        err = snd_cs46xx_pcm(chip, 0);
        if (err < 0)
-               return err;
+               goto error;
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
        err = snd_cs46xx_pcm_rear(chip, 1);
        if (err < 0)
-               return err;
+               goto error;
        err = snd_cs46xx_pcm_iec958(chip, 2);
        if (err < 0)
-               return err;
+               goto error;
 #endif
        err = snd_cs46xx_mixer(chip, 2);
        if (err < 0)
-               return err;
+               goto error;
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
        if (chip->nr_ac97_codecs ==2) {
                err = snd_cs46xx_pcm_center_lfe(chip, 3);
                if (err < 0)
-                       return err;
+                       goto error;
        }
 #endif
        err = snd_cs46xx_midi(chip, 0);
        if (err < 0)
-               return err;
+               goto error;
        err = snd_cs46xx_start_dsp(chip);
        if (err < 0)
-               return err;
+               goto error;
 
        snd_cs46xx_gameport(chip);
 
@@ -117,11 +117,15 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
 
        err = snd_card_register(card);
        if (err < 0)
-               return err;
+               goto error;
 
        pci_set_drvdata(pci, card);
        dev++;
        return 0;
+
+ error:
+       snd_card_free(card);
+       return err;
 }
 
 static struct pci_driver cs46xx_driver = {
index 3e541a4c0423325359d0196c7de666e861978598..83ae21a01bbf95ff8df79e267d302d62840618ac 100644 (file)
@@ -944,6 +944,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK),
        SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x82b4, "HP ProDesk 600 G3", CXT_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO),
        SND_PCI_QUIRK(0x103c, 0x837f, "HP ProBook 470 G5", CXT_FIXUP_MUTE_LED_GPIO),
        SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK),
index cee69fa7e246a6200052528b24dd1844989e40ce..2f55bc43bfa9cce2176d497286780c034f6f0755 100644 (file)
@@ -6901,6 +6901,7 @@ enum {
        ALC298_FIXUP_LENOVO_SPK_VOLUME,
        ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER,
        ALC269_FIXUP_ATIV_BOOK_8,
+       ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE,
        ALC221_FIXUP_HP_MIC_NO_PRESENCE,
        ALC256_FIXUP_ASUS_HEADSET_MODE,
        ALC256_FIXUP_ASUS_MIC,
@@ -7837,6 +7838,16 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_NO_SHUTUP
        },
+       [ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { 0x1a, 0x01813030 }, /* use as headphone mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
        [ALC221_FIXUP_HP_MIC_NO_PRESENCE] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = (const struct hda_pintbl[]) {
@@ -8886,6 +8897,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x1290, "Acer Veriton Z4860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
        SND_PCI_QUIRK(0x1025, 0x1291, "Acer Veriton Z4660G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
        SND_PCI_QUIRK(0x1025, 0x129c, "Acer SWIFT SF314-55", ALC256_FIXUP_ACER_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1025, 0x129d, "Acer SWIFT SF313-51", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1025, 0x1300, "Acer SWIFT SF314-56", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1025, 0x1308, "Acer Aspire Z24-890", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
        SND_PCI_QUIRK(0x1025, 0x132a, "Acer TravelMate B114-21", ALC233_FIXUP_ACER_HEADSET_MIC),
@@ -8895,6 +8907,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC),
        SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
+       SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X),
        SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS),
        SND_PCI_QUIRK(0x1028, 0x05bd, "Dell Latitude E6440", ALC292_FIXUP_DELL_E7X),
        SND_PCI_QUIRK(0x1028, 0x05be, "Dell Latitude E6540", ALC292_FIXUP_DELL_E7X),
@@ -9010,6 +9023,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2b5e, "HP 288 Pro G2 MT", ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x802e, "HP Z240 SFF", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x802f, "HP Z240", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x8077, "HP", ALC256_FIXUP_HP_HEADSET_MIC),
@@ -9096,6 +9110,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x89c6, "Zbook Fury 17 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8a78, "HP Dev One", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x103c, 0x8aa0, "HP ProBook 440 G9 (MB 8A9E)", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8aa3, "HP ProBook 450 G9 (MB 8AA1)", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8aa8, "HP EliteBook 640 G9 (MB 8AA6)", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8aab, "HP EliteBook 650 G9 (MB 8AA9)", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -9212,6 +9230,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1558, 0x70f4, "Clevo NH77EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x70f6, "Clevo NH77DPQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x7716, "Clevo NS50PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x7718, "Clevo L140PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8228, "Clevo NR40BU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8520, "Clevo NH50D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8521, "Clevo NH77D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -9354,6 +9373,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
        SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1d72, 0x1945, "Redmi G", ALC256_FIXUP_ASUS_HEADSET_MIC),
        SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
        SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC),
        SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED),
@@ -11216,6 +11236,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
        SND_PCI_QUIRK(0x103c, 0x8719, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
        SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2),
+       SND_PCI_QUIRK(0x103c, 0x877e, "HP 288 Pro G6", ALC671_FIXUP_HP_HEADSET_MIC2),
        SND_PCI_QUIRK(0x103c, 0x885f, "HP 288 Pro G8", ALC671_FIXUP_HP_HEADSET_MIC2),
        SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE),
        SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
index 55e773f92122846781b1b0e287fa4d151926fb3e..93606e5afd8f1424b8a8f4af6d6efd7d2fd6d7cf 100644 (file)
@@ -868,10 +868,12 @@ static void ak4613_parse_of(struct ak4613_priv *priv,
 
        /*
         * connected STDI
+        * TDM support is assuming it is probed via Audio-Graph-Card style here.
+        * Default is SDTIx1 if it was probed via Simple-Audio-Card for now.
         */
        sdti_num = of_graph_get_endpoint_count(np);
-       if (WARN_ON((sdti_num > 3) || (sdti_num < 1)))
-               return;
+       if ((sdti_num >= SDTx_MAX) || (sdti_num < 1))
+               sdti_num = 1;
 
        AK4613_CONFIG_SDTI_set(priv, sdti_num);
 }
index e32871b3f68ac9dd4174a40656ac741a5345b5d2..7434aeeda292ec218faebdaa04011520842cb0ef 100644 (file)
@@ -1760,8 +1760,8 @@ static bool arizona_aif_cfg_changed(struct snd_soc_component *component,
        if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
                return true;
 
-       val = snd_soc_component_read(component, base + ARIZONA_AIF_TX_BCLK_RATE);
-       if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
+       val = snd_soc_component_read(component, base + ARIZONA_AIF_RX_BCLK_RATE);
+       if (lrclk != (val & ARIZONA_AIF1RX_BCPF_MASK))
                return true;
 
        val = snd_soc_component_read(component, base + ARIZONA_AIF_FRAME_CTRL_1);
index 6d3070ea9e06de663aa3b39d606b33e4144954a0..198cfe54a46fc14beb6b1c526181bfdc729642fb 100644 (file)
@@ -37,8 +37,8 @@ static const struct reg_default cs35l41_reg[] = {
        { CS35L41_DAC_PCM1_SRC,                 0x00000008 },
        { CS35L41_ASP_TX1_SRC,                  0x00000018 },
        { CS35L41_ASP_TX2_SRC,                  0x00000019 },
-       { CS35L41_ASP_TX3_SRC,                  0x00000020 },
-       { CS35L41_ASP_TX4_SRC,                  0x00000021 },
+       { CS35L41_ASP_TX3_SRC,                  0x00000000 },
+       { CS35L41_ASP_TX4_SRC,                  0x00000000 },
        { CS35L41_DSP1_RX1_SRC,                 0x00000008 },
        { CS35L41_DSP1_RX2_SRC,                 0x00000009 },
        { CS35L41_DSP1_RX3_SRC,                 0x00000018 },
@@ -644,6 +644,8 @@ static const struct reg_sequence cs35l41_reva0_errata_patch[] = {
        { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 },
        { CS35L41_PWR_CTRL2,             0x00000000 },
        { CS35L41_AMP_GAIN_CTRL,         0x00000000 },
+       { CS35L41_ASP_TX3_SRC,           0x00000000 },
+       { CS35L41_ASP_TX4_SRC,           0x00000000 },
 };
 
 static const struct reg_sequence cs35l41_revb0_errata_patch[] = {
@@ -655,6 +657,8 @@ static const struct reg_sequence cs35l41_revb0_errata_patch[] = {
        { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 },
        { CS35L41_PWR_CTRL2,             0x00000000 },
        { CS35L41_AMP_GAIN_CTRL,         0x00000000 },
+       { CS35L41_ASP_TX3_SRC,           0x00000000 },
+       { CS35L41_ASP_TX4_SRC,           0x00000000 },
 };
 
 static const struct reg_sequence cs35l41_revb2_errata_patch[] = {
@@ -666,6 +670,8 @@ static const struct reg_sequence cs35l41_revb2_errata_patch[] = {
        { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 },
        { CS35L41_PWR_CTRL2,             0x00000000 },
        { CS35L41_AMP_GAIN_CTRL,         0x00000000 },
+       { CS35L41_ASP_TX3_SRC,           0x00000000 },
+       { CS35L41_ASP_TX4_SRC,           0x00000000 },
 };
 
 static const struct reg_sequence cs35l41_fs_errata_patch[] = {
index 3e68a07a3c8e096e0ae00f1fb01cfd60b1a07c07..71ab2a5d1c559c6b6e8d8977e87aff1a551c0bdd 100644 (file)
@@ -333,7 +333,7 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = {
        SOC_SINGLE("HW Noise Gate Enable", CS35L41_NG_CFG, 8, 63, 0),
        SOC_SINGLE("HW Noise Gate Delay", CS35L41_NG_CFG, 4, 7, 0),
        SOC_SINGLE("HW Noise Gate Threshold", CS35L41_NG_CFG, 0, 7, 0),
-       SOC_SINGLE("Aux Noise Gate CH1 Enable",
+       SOC_SINGLE("Aux Noise Gate CH1 Switch",
                   CS35L41_MIXER_NGATE_CH1_CFG, 16, 1, 0),
        SOC_SINGLE("Aux Noise Gate CH1 Entry Delay",
                   CS35L41_MIXER_NGATE_CH1_CFG, 8, 15, 0),
@@ -341,15 +341,15 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = {
                   CS35L41_MIXER_NGATE_CH1_CFG, 0, 7, 0),
        SOC_SINGLE("Aux Noise Gate CH2 Entry Delay",
                   CS35L41_MIXER_NGATE_CH2_CFG, 8, 15, 0),
-       SOC_SINGLE("Aux Noise Gate CH2 Enable",
+       SOC_SINGLE("Aux Noise Gate CH2 Switch",
                   CS35L41_MIXER_NGATE_CH2_CFG, 16, 1, 0),
        SOC_SINGLE("Aux Noise Gate CH2 Threshold",
                   CS35L41_MIXER_NGATE_CH2_CFG, 0, 7, 0),
-       SOC_SINGLE("SCLK Force", CS35L41_SP_FORMAT, CS35L41_SCLK_FRC_SHIFT, 1, 0),
-       SOC_SINGLE("LRCLK Force", CS35L41_SP_FORMAT, CS35L41_LRCLK_FRC_SHIFT, 1, 0),
-       SOC_SINGLE("Invert Class D", CS35L41_AMP_DIG_VOL_CTRL,
+       SOC_SINGLE("SCLK Force Switch", CS35L41_SP_FORMAT, CS35L41_SCLK_FRC_SHIFT, 1, 0),
+       SOC_SINGLE("LRCLK Force Switch", CS35L41_SP_FORMAT, CS35L41_LRCLK_FRC_SHIFT, 1, 0),
+       SOC_SINGLE("Invert Class D Switch", CS35L41_AMP_DIG_VOL_CTRL,
                   CS35L41_AMP_INV_PCM_SHIFT, 1, 0),
-       SOC_SINGLE("Amp Gain ZC", CS35L41_AMP_GAIN_CTRL,
+       SOC_SINGLE("Amp Gain ZC Switch", CS35L41_AMP_GAIN_CTRL,
                   CS35L41_AMP_GAIN_ZC_SHIFT, 1, 0),
        WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
        WM_ADSP_FW_CONTROL("DSP1", 0),
index 391fd7da331fd2d8eda9a0b0ae61bf63c42b2f6e..1c7d52bef8935beae1518972529f09d2f92ce210 100644 (file)
@@ -122,6 +122,9 @@ static int cs47l15_in1_adc_put(struct snd_kcontrol *kcontrol,
                snd_soc_kcontrol_component(kcontrol);
        struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component);
 
+       if (!!ucontrol->value.integer.value[0] == cs47l15->in1_lp_mode)
+               return 0;
+
        switch (ucontrol->value.integer.value[0]) {
        case 0:
                /* Set IN1 to normal mode */
@@ -150,7 +153,7 @@ static int cs47l15_in1_adc_put(struct snd_kcontrol *kcontrol,
                break;
        }
 
-       return 0;
+       return 1;
 }
 
 static const struct snd_kcontrol_new cs47l15_snd_controls[] = {
index a1b8dcdb9f7b7678636be3b0da0f12a24b861773..444026b7d54b3243d393349eb04c704c79e36e24 100644 (file)
@@ -119,7 +119,13 @@ static int cs47l92_put_demux(struct snd_kcontrol *kcontrol,
 end:
        snd_soc_dapm_mutex_unlock(dapm);
 
-       return snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
+       ret = snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
+       if (ret < 0) {
+               dev_err(madera->dev, "Failed to update demux power state: %d\n", ret);
+               return ret;
+       }
+
+       return change;
 }
 
 static SOC_ENUM_SINGLE_DECL(cs47l92_outdemux_enum,
index 272041c6236a996a11ffc615b7d37cc269a4fc6a..b9f19fbd2911453803f07413fa33d2c947730ae2 100644 (file)
@@ -618,7 +618,13 @@ int madera_out1_demux_put(struct snd_kcontrol *kcontrol,
 end:
        snd_soc_dapm_mutex_unlock(dapm);
 
-       return snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
+       ret = snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
+       if (ret < 0) {
+               dev_err(madera->dev, "Failed to update demux power state: %d\n", ret);
+               return ret;
+       }
+
+       return change;
 }
 EXPORT_SYMBOL_GPL(madera_out1_demux_put);
 
@@ -893,7 +899,7 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol,
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        const int adsp_num = e->shift_l;
        const unsigned int item = ucontrol->value.enumerated.item[0];
-       int ret;
+       int ret = 0;
 
        if (item >= e->items)
                return -EINVAL;
@@ -910,10 +916,10 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol,
                         "Cannot change '%s' while in use by active audio paths\n",
                         kcontrol->id.name);
                ret = -EBUSY;
-       } else {
+       } else if (priv->adsp_rate_cache[adsp_num] != e->values[item]) {
                /* Volatile register so defer until the codec is powered up */
                priv->adsp_rate_cache[adsp_num] = e->values[item];
-               ret = 0;
+               ret = 1;
        }
 
        mutex_unlock(&priv->rate_lock);
index f47e956d4f55aca2938acc3c92c96489dc4aa89d..97b64477dde671632e28d9b2c12984ff8c6db08e 100644 (file)
@@ -862,6 +862,16 @@ static int max98373_sdw_probe(struct sdw_slave *slave,
        return max98373_init(slave, regmap);
 }
 
+static int max98373_sdw_remove(struct sdw_slave *slave)
+{
+       struct max98373_priv *max98373 = dev_get_drvdata(&slave->dev);
+
+       if (max98373->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       return 0;
+}
+
 #if defined(CONFIG_OF)
 static const struct of_device_id max98373_of_match[] = {
        { .compatible = "maxim,max98373", },
@@ -893,7 +903,7 @@ static struct sdw_driver max98373_sdw_driver = {
                .pm = &max98373_pm,
        },
        .probe = max98373_sdw_probe,
-       .remove = NULL,
+       .remove = max98373_sdw_remove,
        .ops = &max98373_slave_ops,
        .id_table = max98373_id,
 };
index 56eb62bb041f90146eebfffce098cac1d2426f58..34db38812807566706ef07f3233c08ab572f076f 100644 (file)
@@ -342,12 +342,15 @@ static int max98396_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
        struct snd_soc_component *component = codec_dai->component;
        struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component);
-       unsigned int format = 0;
+       unsigned int format_mask, format = 0;
        unsigned int bclk_pol = 0;
        int ret, status;
        int reg;
        bool update = false;
 
+       format_mask = MAX98396_PCM_MODE_CFG_FORMAT_MASK |
+                     MAX98396_PCM_MODE_CFG_LRCLKEDGE;
+
        dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt);
 
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -395,7 +398,7 @@ static int max98396_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
                ret = regmap_read(max98396->regmap, MAX98396_R2041_PCM_MODE_CFG, &reg);
                if (ret < 0)
                        return -EINVAL;
-               if (format != (reg & MAX98396_PCM_BCLKEDGE_BSEL_MASK)) {
+               if (format != (reg & format_mask)) {
                        update = true;
                } else {
                        ret = regmap_read(max98396->regmap,
@@ -412,8 +415,7 @@ static int max98396_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 
        regmap_update_bits(max98396->regmap,
                           MAX98396_R2041_PCM_MODE_CFG,
-                          MAX98396_PCM_BCLKEDGE_BSEL_MASK,
-                          format);
+                          format_mask, format);
 
        regmap_update_bits(max98396->regmap,
                           MAX98396_R2042_PCM_CLK_SETUP,
index 1c11b42dd76e09c523bf2fddaa93a9007ee24e71..72f673f278eeccdc47c9554185d47f096281e817 100644 (file)
@@ -691,6 +691,16 @@ static int rt1308_sdw_probe(struct sdw_slave *slave,
        return 0;
 }
 
+static int rt1308_sdw_remove(struct sdw_slave *slave)
+{
+       struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev);
+
+       if (rt1308->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       return 0;
+}
+
 static const struct sdw_device_id rt1308_id[] = {
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x1308, 0x2, 0, 0),
        {},
@@ -750,6 +760,7 @@ static struct sdw_driver rt1308_sdw_driver = {
                .pm = &rt1308_pm,
        },
        .probe = rt1308_sdw_probe,
+       .remove = rt1308_sdw_remove,
        .ops = &rt1308_slave_ops,
        .id_table = rt1308_id,
 };
index 60baa9ff190703880a93fa378d51915e044b90a7..2d6b5f9d4d77041b2623e63f3c1ec2cac20b1775 100644 (file)
@@ -676,6 +676,16 @@ static int rt1316_sdw_probe(struct sdw_slave *slave,
        return rt1316_sdw_init(&slave->dev, regmap, slave);
 }
 
+static int rt1316_sdw_remove(struct sdw_slave *slave)
+{
+       struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(&slave->dev);
+
+       if (rt1316->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       return 0;
+}
+
 static const struct sdw_device_id rt1316_id[] = {
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x1316, 0x3, 0x1, 0),
        {},
@@ -735,6 +745,7 @@ static struct sdw_driver rt1316_sdw_driver = {
                .pm = &rt1316_pm,
        },
        .probe = rt1316_sdw_probe,
+       .remove = rt1316_sdw_remove,
        .ops = &rt1316_slave_ops,
        .id_table = rt1316_id,
 };
index 69c80d80ed9d52be92c49152fe737cabe3dd1de3..18b3da9211e325341addd6068931480d92948161 100644 (file)
@@ -1984,7 +1984,12 @@ static int rt5640_set_bias_level(struct snd_soc_component *component,
                snd_soc_component_write(component, RT5640_PWR_DIG2, 0x0000);
                snd_soc_component_write(component, RT5640_PWR_VOL, 0x0000);
                snd_soc_component_write(component, RT5640_PWR_MIXER, 0x0000);
-               snd_soc_component_write(component, RT5640_PWR_ANLG1, 0x0000);
+               if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER)
+                       snd_soc_component_write(component, RT5640_PWR_ANLG1,
+                               0x0018);
+               else
+                       snd_soc_component_write(component, RT5640_PWR_ANLG1,
+                               0x0000);
                snd_soc_component_write(component, RT5640_PWR_ANLG2, 0x0000);
                break;
 
@@ -2393,9 +2398,15 @@ static void rt5640_jack_work(struct work_struct *work)
 static irqreturn_t rt5640_irq(int irq, void *data)
 {
        struct rt5640_priv *rt5640 = data;
+       int delay = 0;
+
+       if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) {
+               cancel_delayed_work_sync(&rt5640->jack_work);
+               delay = 100;
+       }
 
        if (rt5640->jack)
-               queue_delayed_work(system_long_wq, &rt5640->jack_work, 0);
+               queue_delayed_work(system_long_wq, &rt5640->jack_work, delay);
 
        return IRQ_HANDLED;
 }
@@ -2580,6 +2591,12 @@ static void rt5640_enable_hda_jack_detect(
 
        snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x400, 0x0);
 
+       snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
+               RT5640_PWR_VREF2, RT5640_PWR_VREF2);
+       usleep_range(10000, 15000);
+       snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
+               RT5640_PWR_FV2, RT5640_PWR_FV2);
+
        rt5640->jack = jack;
 
        ret = request_irq(rt5640->irq, rt5640_irq,
@@ -2696,16 +2713,13 @@ static int rt5640_probe(struct snd_soc_component *component)
 
        if (device_property_read_u32(component->dev,
                                     "realtek,jack-detect-source", &val) == 0) {
-               if (val <= RT5640_JD_SRC_GPIO4) {
+               if (val <= RT5640_JD_SRC_GPIO4)
                        rt5640->jd_src = val << RT5640_JD_SFT;
-               } else if (val == RT5640_JD_SRC_HDA_HEADER) {
+               else if (val == RT5640_JD_SRC_HDA_HEADER)
                        rt5640->jd_src = RT5640_JD_SRC_HDA_HEADER;
-                       snd_soc_component_update_bits(component, RT5640_DUMMY1,
-                               0x0300, 0x0);
-               } else {
+               else
                        dev_warn(component->dev, "Warning: Invalid jack-detect-source value: %d, leaving jack-detect disabled\n",
                                 val);
-               }
        }
 
        if (!device_property_read_bool(component->dev, "realtek,jack-detect-not-inverted"))
index 248257a2e4e0f32abff0173ad50511292da6fbb7..f04e18c32489ddef2b9f1fc32f49bc56e869688a 100644 (file)
@@ -719,9 +719,12 @@ static int rt5682_sdw_remove(struct sdw_slave *slave)
 {
        struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev);
 
-       if (rt5682 && rt5682->hw_init)
+       if (rt5682->hw_init)
                cancel_delayed_work_sync(&rt5682->jack_detect_work);
 
+       if (rt5682->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
        return 0;
 }
 
index bda5948996642929243d7354c22d0f5c8e88d653..f7439e40ca8b543dff73f464c2a326b4707dd127 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/soundwire/sdw_type.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include "rt700.h"
@@ -463,11 +464,14 @@ static int rt700_sdw_remove(struct sdw_slave *slave)
 {
        struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev);
 
-       if (rt700 && rt700->hw_init) {
+       if (rt700->hw_init) {
                cancel_delayed_work_sync(&rt700->jack_detect_work);
                cancel_delayed_work_sync(&rt700->jack_btn_check_work);
        }
 
+       if (rt700->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
        return 0;
 }
 
index af32295fa9b939a39a8e66434ade078515543eb1..9bceeeb830b15a5cb8c66e0b7bdc70b412baf022 100644 (file)
@@ -162,7 +162,7 @@ static void rt700_jack_detect_handler(struct work_struct *work)
        if (!rt700->hs_jack)
                return;
 
-       if (!rt700->component->card->instantiated)
+       if (!rt700->component->card || !rt700->component->card->instantiated)
                return;
 
        reg = RT700_VERB_GET_PIN_SENSE | RT700_HP_OUT;
@@ -315,17 +315,27 @@ static int rt700_set_jack_detect(struct snd_soc_component *component,
        struct snd_soc_jack *hs_jack, void *data)
 {
        struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
+       int ret;
 
        rt700->hs_jack = hs_jack;
 
-       if (!rt700->hw_init) {
-               dev_dbg(&rt700->slave->dev,
-                       "%s hw_init not ready yet\n", __func__);
+       ret = pm_runtime_resume_and_get(component->dev);
+       if (ret < 0) {
+               if (ret != -EACCES) {
+                       dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
+                       return ret;
+               }
+
+               /* pm_runtime not enabled yet */
+               dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__);
                return 0;
        }
 
        rt700_jack_init(rt700);
 
+       pm_runtime_mark_last_busy(component->dev);
+       pm_runtime_put_autosuspend(component->dev);
+
        return 0;
 }
 
@@ -1115,6 +1125,11 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap,
 
        mutex_init(&rt700->disable_irq_lock);
 
+       INIT_DELAYED_WORK(&rt700->jack_detect_work,
+                         rt700_jack_detect_handler);
+       INIT_DELAYED_WORK(&rt700->jack_btn_check_work,
+                         rt700_btn_check_handler);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -1209,13 +1224,6 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave)
        /* Finish Initial Settings, set power to D3 */
        regmap_write(rt700->regmap, RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
 
-       if (!rt700->first_hw_init) {
-               INIT_DELAYED_WORK(&rt700->jack_detect_work,
-                       rt700_jack_detect_handler);
-               INIT_DELAYED_WORK(&rt700->jack_btn_check_work,
-                       rt700_btn_check_handler);
-       }
-
        /*
         * if set_jack callback occurred early than io_init,
         * we set up the jack detection function now
index aaf5af153d3feab1769a3c6ff8d5d4639e42095d..a085b2f530aa1d268135f3f259ef3b4a72c0c7b8 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mod_devicetable.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 
 #include "rt711-sdca.h"
 #include "rt711-sdca-sdw.h"
@@ -364,11 +365,17 @@ static int rt711_sdca_sdw_remove(struct sdw_slave *slave)
 {
        struct rt711_sdca_priv *rt711 = dev_get_drvdata(&slave->dev);
 
-       if (rt711 && rt711->hw_init) {
+       if (rt711->hw_init) {
                cancel_delayed_work_sync(&rt711->jack_detect_work);
                cancel_delayed_work_sync(&rt711->jack_btn_check_work);
        }
 
+       if (rt711->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       mutex_destroy(&rt711->calibrate_mutex);
+       mutex_destroy(&rt711->disable_irq_lock);
+
        return 0;
 }
 
index 57629c18db384126c53e30e157cdeddde05529d5..5ad53bbc852843feaec6b8026c19fe1641b62eaa 100644 (file)
@@ -34,7 +34,7 @@ static int rt711_sdca_index_write(struct rt711_sdca_priv *rt711,
 
        ret = regmap_write(regmap, addr, value);
        if (ret < 0)
-               dev_err(rt711->component->dev,
+               dev_err(&rt711->slave->dev,
                        "Failed to set private value: %06x <= %04x ret=%d\n",
                        addr, value, ret);
 
@@ -50,7 +50,7 @@ static int rt711_sdca_index_read(struct rt711_sdca_priv *rt711,
 
        ret = regmap_read(regmap, addr, value);
        if (ret < 0)
-               dev_err(rt711->component->dev,
+               dev_err(&rt711->slave->dev,
                        "Failed to get private value: %06x => %04x ret=%d\n",
                        addr, *value, ret);
 
@@ -294,7 +294,7 @@ static void rt711_sdca_jack_detect_handler(struct work_struct *work)
        if (!rt711->hs_jack)
                return;
 
-       if (!rt711->component->card->instantiated)
+       if (!rt711->component->card || !rt711->component->card->instantiated)
                return;
 
        /* SDW_SCP_SDCA_INT_SDCA_0 is used for jack detection */
@@ -487,16 +487,27 @@ static int rt711_sdca_set_jack_detect(struct snd_soc_component *component,
        struct snd_soc_jack *hs_jack, void *data)
 {
        struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+       int ret;
 
        rt711->hs_jack = hs_jack;
 
-       if (!rt711->hw_init) {
-               dev_dbg(&rt711->slave->dev,
-                       "%s hw_init not ready yet\n", __func__);
+       ret = pm_runtime_resume_and_get(component->dev);
+       if (ret < 0) {
+               if (ret != -EACCES) {
+                       dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
+                       return ret;
+               }
+
+               /* pm_runtime not enabled yet */
+               dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__);
                return 0;
        }
 
        rt711_sdca_jack_init(rt711);
+
+       pm_runtime_mark_last_busy(component->dev);
+       pm_runtime_put_autosuspend(component->dev);
+
        return 0;
 }
 
@@ -1190,14 +1201,6 @@ static int rt711_sdca_probe(struct snd_soc_component *component)
        return 0;
 }
 
-static void rt711_sdca_remove(struct snd_soc_component *component)
-{
-       struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
-
-       regcache_cache_only(rt711->regmap, true);
-       regcache_cache_only(rt711->mbq_regmap, true);
-}
-
 static const struct snd_soc_component_driver soc_sdca_dev_rt711 = {
        .probe = rt711_sdca_probe,
        .controls = rt711_sdca_snd_controls,
@@ -1207,7 +1210,6 @@ static const struct snd_soc_component_driver soc_sdca_dev_rt711 = {
        .dapm_routes = rt711_sdca_audio_map,
        .num_dapm_routes = ARRAY_SIZE(rt711_sdca_audio_map),
        .set_jack = rt711_sdca_set_jack_detect,
-       .remove = rt711_sdca_remove,
        .endianness = 1,
 };
 
@@ -1412,8 +1414,12 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap,
        rt711->regmap = regmap;
        rt711->mbq_regmap = mbq_regmap;
 
+       mutex_init(&rt711->calibrate_mutex);
        mutex_init(&rt711->disable_irq_lock);
 
+       INIT_DELAYED_WORK(&rt711->jack_detect_work, rt711_sdca_jack_detect_handler);
+       INIT_DELAYED_WORK(&rt711->jack_btn_check_work, rt711_sdca_btn_check_handler);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -1545,14 +1551,6 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave)
        rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL,
                RT711_PUSH_BTN_INT_CTL0, 0x20, 0x00);
 
-       if (!rt711->first_hw_init) {
-               INIT_DELAYED_WORK(&rt711->jack_detect_work,
-                       rt711_sdca_jack_detect_handler);
-               INIT_DELAYED_WORK(&rt711->jack_btn_check_work,
-                       rt711_sdca_btn_check_handler);
-               mutex_init(&rt711->calibrate_mutex);
-       }
-
        /* calibration */
        ret = rt711_sdca_calibration(rt711);
        if (ret < 0)
index bda2cc9439c98741c3dd833a2d1e365e98c744e1..4fe68bcf2a7c227d0932af0f73687737fde0e58b 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/soundwire/sdw_type.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include "rt711.h"
@@ -464,12 +465,18 @@ static int rt711_sdw_remove(struct sdw_slave *slave)
 {
        struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev);
 
-       if (rt711 && rt711->hw_init) {
+       if (rt711->hw_init) {
                cancel_delayed_work_sync(&rt711->jack_detect_work);
                cancel_delayed_work_sync(&rt711->jack_btn_check_work);
                cancel_work_sync(&rt711->calibration_work);
        }
 
+       if (rt711->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       mutex_destroy(&rt711->calibrate_mutex);
+       mutex_destroy(&rt711->disable_irq_lock);
+
        return 0;
 }
 
index 9838fb4d5b9c01a591a01a73ece0acd35e0772d3..9df800abfc2d8ca729e6561850e6e339fe95f083 100644 (file)
@@ -242,7 +242,7 @@ static void rt711_jack_detect_handler(struct work_struct *work)
        if (!rt711->hs_jack)
                return;
 
-       if (!rt711->component->card->instantiated)
+       if (!rt711->component->card || !rt711->component->card->instantiated)
                return;
 
        if (pm_runtime_status_suspended(rt711->slave->dev.parent)) {
@@ -457,17 +457,27 @@ static int rt711_set_jack_detect(struct snd_soc_component *component,
        struct snd_soc_jack *hs_jack, void *data)
 {
        struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
+       int ret;
 
        rt711->hs_jack = hs_jack;
 
-       if (!rt711->hw_init) {
-               dev_dbg(&rt711->slave->dev,
-                       "%s hw_init not ready yet\n", __func__);
+       ret = pm_runtime_resume_and_get(component->dev);
+       if (ret < 0) {
+               if (ret != -EACCES) {
+                       dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
+                       return ret;
+               }
+
+               /* pm_runtime not enabled yet */
+               dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__);
                return 0;
        }
 
        rt711_jack_init(rt711);
 
+       pm_runtime_mark_last_busy(component->dev);
+       pm_runtime_put_autosuspend(component->dev);
+
        return 0;
 }
 
@@ -932,13 +942,6 @@ static int rt711_probe(struct snd_soc_component *component)
        return 0;
 }
 
-static void rt711_remove(struct snd_soc_component *component)
-{
-       struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
-
-       regcache_cache_only(rt711->regmap, true);
-}
-
 static const struct snd_soc_component_driver soc_codec_dev_rt711 = {
        .probe = rt711_probe,
        .set_bias_level = rt711_set_bias_level,
@@ -949,7 +952,6 @@ static const struct snd_soc_component_driver soc_codec_dev_rt711 = {
        .dapm_routes = rt711_audio_map,
        .num_dapm_routes = ARRAY_SIZE(rt711_audio_map),
        .set_jack = rt711_set_jack_detect,
-       .remove = rt711_remove,
        .endianness = 1,
 };
 
@@ -1204,8 +1206,13 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap,
        rt711->sdw_regmap = sdw_regmap;
        rt711->regmap = regmap;
 
+       mutex_init(&rt711->calibrate_mutex);
        mutex_init(&rt711->disable_irq_lock);
 
+       INIT_DELAYED_WORK(&rt711->jack_detect_work, rt711_jack_detect_handler);
+       INIT_DELAYED_WORK(&rt711->jack_btn_check_work, rt711_btn_check_handler);
+       INIT_WORK(&rt711->calibration_work, rt711_calibration_work);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -1313,15 +1320,8 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave)
 
        if (rt711->first_hw_init)
                rt711_calibration(rt711);
-       else {
-               INIT_DELAYED_WORK(&rt711->jack_detect_work,
-                       rt711_jack_detect_handler);
-               INIT_DELAYED_WORK(&rt711->jack_btn_check_work,
-                       rt711_btn_check_handler);
-               mutex_init(&rt711->calibrate_mutex);
-               INIT_WORK(&rt711->calibration_work, rt711_calibration_work);
+       else
                schedule_work(&rt711->calibration_work);
-       }
 
        /*
         * if set_jack callback occurred early than io_init,
index 0ecd2948f7aa7d7473db4208b98612e5850b9898..13e731d166753ac117f59249a88388b297468df3 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/soundwire/sdw_type.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include "rt715-sdca.h"
@@ -193,6 +194,16 @@ static int rt715_sdca_sdw_probe(struct sdw_slave *slave,
        return rt715_sdca_init(&slave->dev, mbq_regmap, regmap, slave);
 }
 
+static int rt715_sdca_sdw_remove(struct sdw_slave *slave)
+{
+       struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev);
+
+       if (rt715->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       return 0;
+}
+
 static const struct sdw_device_id rt715_sdca_id[] = {
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x715, 0x3, 0x1, 0),
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x714, 0x3, 0x1, 0),
@@ -267,6 +278,7 @@ static struct sdw_driver rt715_sdw_driver = {
                .pm = &rt715_pm,
        },
        .probe = rt715_sdca_sdw_probe,
+       .remove = rt715_sdca_sdw_remove,
        .ops = &rt715_sdca_slave_ops,
        .id_table = rt715_sdca_id,
 };
index a7b21b03c08bb7b506e34e57d61c4d0f61370ebe..b047bf87a100c590241fe4c01ae2e64004e1be79 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/soundwire/sdw_type.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/of.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
@@ -514,6 +515,16 @@ static int rt715_sdw_probe(struct sdw_slave *slave,
        return 0;
 }
 
+static int rt715_sdw_remove(struct sdw_slave *slave)
+{
+       struct rt715_priv *rt715 = dev_get_drvdata(&slave->dev);
+
+       if (rt715->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       return 0;
+}
+
 static const struct sdw_device_id rt715_id[] = {
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x714, 0x2, 0, 0),
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x715, 0x2, 0, 0),
@@ -575,6 +586,7 @@ static struct sdw_driver rt715_sdw_driver = {
                   .pm = &rt715_pm,
                   },
        .probe = rt715_sdw_probe,
+       .remove = rt715_sdw_remove,
        .ops = &rt715_slave_ops,
        .id_table = rt715_id,
 };
index 2aa48aef6a97db86550bbb0120e1d2f7e8e42346..3363d1696ad7cbe5955f73fd7b520f716685a8eb 100644 (file)
@@ -1795,6 +1795,9 @@ static int sgtl5000_i2c_remove(struct i2c_client *client)
 {
        struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client);
 
+       regmap_write(sgtl5000->regmap, SGTL5000_CHIP_DIG_POWER, SGTL5000_DIG_POWER_DEFAULT);
+       regmap_write(sgtl5000->regmap, SGTL5000_CHIP_ANA_POWER, SGTL5000_ANA_POWER_DEFAULT);
+
        clk_disable_unprepare(sgtl5000->mclk);
        regulator_bulk_disable(sgtl5000->num_supplies, sgtl5000->supplies);
        regulator_bulk_free(sgtl5000->num_supplies, sgtl5000->supplies);
@@ -1802,6 +1805,11 @@ static int sgtl5000_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
+static void sgtl5000_i2c_shutdown(struct i2c_client *client)
+{
+       sgtl5000_i2c_remove(client);
+}
+
 static const struct i2c_device_id sgtl5000_id[] = {
        {"sgtl5000", 0},
        {},
@@ -1822,6 +1830,7 @@ static struct i2c_driver sgtl5000_i2c_driver = {
        },
        .probe_new = sgtl5000_i2c_probe,
        .remove = sgtl5000_i2c_remove,
+       .shutdown = sgtl5000_i2c_shutdown,
        .id_table = sgtl5000_id,
 };
 
index 56ec5863f25071ef2f78fd5c018f5b05f27c1e3b..3a808c762299e5f2c073a15f6c0ece5773ff17d6 100644 (file)
@@ -80,6 +80,7 @@
 /*
  * SGTL5000_CHIP_DIG_POWER
  */
+#define SGTL5000_DIG_POWER_DEFAULT             0x0000
 #define SGTL5000_ADC_EN                                0x0040
 #define SGTL5000_DAC_EN                                0x0020
 #define SGTL5000_DAP_POWERUP                   0x0010
index d395feffb30b58014737466f134af4fae40deac3..4cb788f3e5f710b6b16d2527293731609c1812f4 100644 (file)
@@ -42,10 +42,12 @@ static void tas2764_reset(struct tas2764_priv *tas2764)
                gpiod_set_value_cansleep(tas2764->reset_gpio, 0);
                msleep(20);
                gpiod_set_value_cansleep(tas2764->reset_gpio, 1);
+               usleep_range(1000, 2000);
        }
 
        snd_soc_component_write(tas2764->component, TAS2764_SW_RST,
                                TAS2764_RST);
+       usleep_range(1000, 2000);
 }
 
 static int tas2764_set_bias_level(struct snd_soc_component *component,
@@ -107,8 +109,10 @@ static int tas2764_codec_resume(struct snd_soc_component *component)
        struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
        int ret;
 
-       if (tas2764->sdz_gpio)
+       if (tas2764->sdz_gpio) {
                gpiod_set_value_cansleep(tas2764->sdz_gpio, 1);
+               usleep_range(1000, 2000);
+       }
 
        ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
                                            TAS2764_PWR_CTRL_MASK,
@@ -131,7 +135,8 @@ static const char * const tas2764_ASI1_src[] = {
 };
 
 static SOC_ENUM_SINGLE_DECL(
-       tas2764_ASI1_src_enum, TAS2764_TDM_CFG2, 4, tas2764_ASI1_src);
+       tas2764_ASI1_src_enum, TAS2764_TDM_CFG2, TAS2764_TDM_CFG2_SCFG_SHIFT,
+       tas2764_ASI1_src);
 
 static const struct snd_kcontrol_new tas2764_asi1_mux =
        SOC_DAPM_ENUM("ASI1 Source", tas2764_ASI1_src_enum);
@@ -329,20 +334,22 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
        struct snd_soc_component *component = dai->component;
        struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
-       u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0;
-       int iface;
+       u8 tdm_rx_start_slot = 0, asi_cfg_0 = 0, asi_cfg_1 = 0;
        int ret;
 
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_IF:
+               asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
+               fallthrough;
        case SND_SOC_DAIFMT_NB_NF:
                asi_cfg_1 = TAS2764_TDM_CFG1_RX_RISING;
                break;
+       case SND_SOC_DAIFMT_IB_IF:
+               asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
+               fallthrough;
        case SND_SOC_DAIFMT_IB_NF:
                asi_cfg_1 = TAS2764_TDM_CFG1_RX_FALLING;
                break;
-       default:
-               dev_err(tas2764->dev, "ASI format Inverse is not found\n");
-               return -EINVAL;
        }
 
        ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1,
@@ -353,13 +360,13 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
+               asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
+               fallthrough;
        case SND_SOC_DAIFMT_DSP_A:
-               iface = TAS2764_TDM_CFG2_SCFG_I2S;
                tdm_rx_start_slot = 1;
                break;
        case SND_SOC_DAIFMT_DSP_B:
        case SND_SOC_DAIFMT_LEFT_J:
-               iface = TAS2764_TDM_CFG2_SCFG_LEFT_J;
                tdm_rx_start_slot = 0;
                break;
        default:
@@ -368,14 +375,15 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                return -EINVAL;
        }
 
-       ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1,
-                                           TAS2764_TDM_CFG1_MASK,
-                                           (tdm_rx_start_slot << TAS2764_TDM_CFG1_51_SHIFT));
+       ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG0,
+                                           TAS2764_TDM_CFG0_FRAME_START,
+                                           asi_cfg_0);
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG2,
-                                           TAS2764_TDM_CFG2_SCFG_MASK, iface);
+       ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1,
+                                           TAS2764_TDM_CFG1_MASK,
+                                           (tdm_rx_start_slot << TAS2764_TDM_CFG1_51_SHIFT));
        if (ret < 0)
                return ret;
 
@@ -501,8 +509,10 @@ static int tas2764_codec_probe(struct snd_soc_component *component)
 
        tas2764->component = component;
 
-       if (tas2764->sdz_gpio)
+       if (tas2764->sdz_gpio) {
                gpiod_set_value_cansleep(tas2764->sdz_gpio, 1);
+               usleep_range(1000, 2000);
+       }
 
        tas2764_reset(tas2764);
 
@@ -526,12 +536,12 @@ static int tas2764_codec_probe(struct snd_soc_component *component)
 }
 
 static DECLARE_TLV_DB_SCALE(tas2764_digital_tlv, 1100, 50, 0);
-static DECLARE_TLV_DB_SCALE(tas2764_playback_volume, -10000, 50, 0);
+static DECLARE_TLV_DB_SCALE(tas2764_playback_volume, -10050, 50, 1);
 
 static const struct snd_kcontrol_new tas2764_snd_controls[] = {
        SOC_SINGLE_TLV("Speaker Volume", TAS2764_DVC, 0,
                       TAS2764_DVC_MAX, 1, tas2764_playback_volume),
-       SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 0, 0x14, 0,
+       SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 1, 0x14, 0,
                       tas2764_digital_tlv),
 };
 
@@ -556,7 +566,7 @@ static const struct reg_default tas2764_reg_defaults[] = {
        { TAS2764_SW_RST, 0x00 },
        { TAS2764_PWR_CTRL, 0x1a },
        { TAS2764_DVC, 0x00 },
-       { TAS2764_CHNL_0, 0x00 },
+       { TAS2764_CHNL_0, 0x28 },
        { TAS2764_TDM_CFG0, 0x09 },
        { TAS2764_TDM_CFG1, 0x02 },
        { TAS2764_TDM_CFG2, 0x0a },
index 67d6fd903c42cc3bcd872673fe44d483aa6f1345..f015f22a083b56078277627628571223f08de60c 100644 (file)
@@ -47,6 +47,7 @@
 #define TAS2764_TDM_CFG0_MASK          GENMASK(3, 1)
 #define TAS2764_TDM_CFG0_44_1_48KHZ    BIT(3)
 #define TAS2764_TDM_CFG0_88_2_96KHZ    (BIT(3) | BIT(1))
+#define TAS2764_TDM_CFG0_FRAME_START   BIT(0)
 
 /* TDM Configuration Reg1 */
 #define TAS2764_TDM_CFG1               TAS2764_REG(0X0, 0x09)
 #define TAS2764_TDM_CFG2_RXS_16BITS    0x0
 #define TAS2764_TDM_CFG2_RXS_24BITS    BIT(0)
 #define TAS2764_TDM_CFG2_RXS_32BITS    BIT(1)
-#define TAS2764_TDM_CFG2_SCFG_MASK     GENMASK(5, 4)
-#define TAS2764_TDM_CFG2_SCFG_I2S      0x0
-#define TAS2764_TDM_CFG2_SCFG_LEFT_J   BIT(4)
-#define TAS2764_TDM_CFG2_SCFG_RIGHT_J  BIT(5)
+#define TAS2764_TDM_CFG2_SCFG_SHIFT    4
 
 /* TDM Configuration Reg3 */
 #define TAS2764_TDM_CFG3               TAS2764_REG(0X0, 0x0c)
index b55f0b836932ba9655bcba780569f5efdd0f8405..0b729658fde80dc795f4d714e4b0656323f51b3f 100644 (file)
@@ -33,7 +33,6 @@ struct adcx140_priv {
        bool micbias_vg;
 
        unsigned int dai_fmt;
-       unsigned int tdm_delay;
        unsigned int slot_width;
 };
 
@@ -792,12 +791,13 @@ static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_component *component = codec_dai->component;
        struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(component);
-       unsigned int lsb;
 
-       /* TDM based on DSP mode requires slots to be adjacent */
-       lsb = __ffs(tx_mask);
-       if ((lsb + 1) != __fls(tx_mask)) {
-               dev_err(component->dev, "Invalid mask, slots must be adjacent\n");
+       /*
+        * The chip itself supports arbitrary masks, but the driver currently
+        * only supports adjacent slots beginning at the first slot.
+        */
+       if (tx_mask != GENMASK(__fls(tx_mask), 0)) {
+               dev_err(component->dev, "Only lower adjacent slots are supported\n");
                return -EINVAL;
        }
 
@@ -812,7 +812,6 @@ static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
                return -EINVAL;
        }
 
-       adcx140->tdm_delay = lsb;
        adcx140->slot_width = slot_width;
 
        return 0;
index 617a36a89dfed2300f38644fc805e1113a435683..3cb7a3eab8c74be63e1cd49d08c985c2011dec58 100644 (file)
@@ -342,7 +342,7 @@ struct wcd9335_codec {
        struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY];
 
        unsigned int rx_port_value[WCD9335_RX_MAX];
-       unsigned int tx_port_value;
+       unsigned int tx_port_value[WCD9335_TX_MAX];
        int hph_l_gain;
        int hph_r_gain;
        u32 rx_bias_count;
@@ -1287,11 +1287,17 @@ static int slim_rx_mux_put(struct snd_kcontrol *kc,
        struct snd_soc_dapm_update *update = NULL;
        u32 port_id = w->shift;
 
+       if (wcd->rx_port_value[port_id] == ucontrol->value.enumerated.item[0])
+               return 0;
+
        wcd->rx_port_value[port_id] = ucontrol->value.enumerated.item[0];
 
+       /* Remove channel from any list it's in before adding it to a new one */
+       list_del_init(&wcd->rx_chs[port_id].list);
+
        switch (wcd->rx_port_value[port_id]) {
        case 0:
-               list_del_init(&wcd->rx_chs[port_id].list);
+               /* Channel already removed from lists. Nothing to do here */
                break;
        case 1:
                list_add_tail(&wcd->rx_chs[port_id].list,
@@ -1328,8 +1334,13 @@ static int slim_tx_mixer_get(struct snd_kcontrol *kc,
 
        struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc);
        struct wcd9335_codec *wcd = dev_get_drvdata(dapm->dev);
+       struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kc);
+       struct soc_mixer_control *mixer =
+                       (struct soc_mixer_control *)kc->private_value;
+       int dai_id = widget->shift;
+       int port_id = mixer->shift;
 
-       ucontrol->value.integer.value[0] = wcd->tx_port_value;
+       ucontrol->value.integer.value[0] = wcd->tx_port_value[port_id] == dai_id;
 
        return 0;
 }
@@ -1352,12 +1363,12 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kc,
        case AIF2_CAP:
        case AIF3_CAP:
                /* only add to the list if value not set */
-               if (enable && !(wcd->tx_port_value & BIT(port_id))) {
-                       wcd->tx_port_value |= BIT(port_id);
+               if (enable && wcd->tx_port_value[port_id] != dai_id) {
+                       wcd->tx_port_value[port_id] = dai_id;
                        list_add_tail(&wcd->tx_chs[port_id].list,
                                        &wcd->dai[dai_id].slim_ch_list);
-               } else if (!enable && (wcd->tx_port_value & BIT(port_id))) {
-                       wcd->tx_port_value &= ~BIT(port_id);
+               } else if (!enable && wcd->tx_port_value[port_id] == dai_id) {
+                       wcd->tx_port_value[port_id] = -1;
                        list_del_init(&wcd->tx_chs[port_id].list);
                }
                break;
index c1b61b997f696506880191e2fa17d01411bbeecc..781ae569be29036ba2c64423d6cc7c401d8b6989 100644 (file)
@@ -2519,6 +2519,9 @@ static int wcd938x_tx_mode_put(struct snd_kcontrol *kcontrol,
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        int path = e->shift_l;
 
+       if (wcd938x->tx_mode[path] == ucontrol->value.enumerated.item[0])
+               return 0;
+
        wcd938x->tx_mode[path] = ucontrol->value.enumerated.item[0];
 
        return 1;
@@ -2541,6 +2544,9 @@ static int wcd938x_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
 
+       if (wcd938x->hph_mode == ucontrol->value.enumerated.item[0])
+               return 0;
+
        wcd938x->hph_mode = ucontrol->value.enumerated.item[0];
 
        return 1;
@@ -2632,6 +2638,9 @@ static int wcd938x_ldoh_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
 
+       if (wcd938x->ldoh == ucontrol->value.integer.value[0])
+               return 0;
+
        wcd938x->ldoh = ucontrol->value.integer.value[0];
 
        return 1;
@@ -2654,6 +2663,9 @@ static int wcd938x_bcs_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
 
+       if (wcd938x->bcs_dis == ucontrol->value.integer.value[0])
+               return 0;
+
        wcd938x->bcs_dis = ucontrol->value.integer.value[0];
 
        return 1;
index da2f8998df87a6249ab102f932d4c857811a8954..b034df47a5ef1cff7b0d6181a8207256497e2451 100644 (file)
@@ -680,12 +680,17 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+       uint16_t dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data);
+       int ret = 0;
 
        mutex_lock(&arizona->dac_comp_lock);
-       arizona->dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data);
+       if (arizona->dac_comp_coeff != dac_comp_coeff) {
+               arizona->dac_comp_coeff = dac_comp_coeff;
+               ret = 1;
+       }
        mutex_unlock(&arizona->dac_comp_lock);
 
-       return 0;
+       return ret;
 }
 
 static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol,
@@ -706,12 +711,20 @@ static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+       struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
+       int ret = 0;
+
+       if (ucontrol->value.integer.value[0] > mc->max)
+               return -EINVAL;
 
        mutex_lock(&arizona->dac_comp_lock);
-       arizona->dac_comp_enabled = ucontrol->value.integer.value[0];
+       if (arizona->dac_comp_enabled != ucontrol->value.integer.value[0]) {
+               arizona->dac_comp_enabled = ucontrol->value.integer.value[0];
+               ret = 1;
+       }
        mutex_unlock(&arizona->dac_comp_lock);
 
-       return 0;
+       return ret;
 }
 
 static const char * const wm5102_osr_text[] = {
index 4973ba1ed7791af92ce4c61d29c9a0abcd40dab1..4ab7a672f8de8b336ddbd9f302298771523c4f34 100644 (file)
@@ -413,6 +413,7 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
        unsigned int rnew = (!!ucontrol->value.integer.value[1]) << mc->rshift;
        unsigned int lold, rold;
        unsigned int lena, rena;
+       bool change = false;
        int ret;
 
        snd_soc_dapm_mutex_lock(dapm);
@@ -440,8 +441,8 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
                goto err;
        }
 
-       ret = regmap_update_bits(arizona->regmap, ARIZONA_DRE_ENABLE,
-                                mask, lnew | rnew);
+       ret = regmap_update_bits_check(arizona->regmap, ARIZONA_DRE_ENABLE,
+                                      mask, lnew | rnew, &change);
        if (ret) {
                dev_err(arizona->dev, "Failed to set DRE: %d\n", ret);
                goto err;
@@ -454,6 +455,9 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
        if (!rnew && rold)
                wm5110_clear_pga_volume(arizona, mc->rshift);
 
+       if (change)
+               ret = 1;
+
 err:
        snd_soc_dapm_mutex_unlock(dapm);
 
index 00b59fc9b1fe00757a2fdca8e8b0817ccc96cd00..ab5481187c7105c54956a4464b299300a1839107 100644 (file)
@@ -108,6 +108,7 @@ static int wm8998_inmux_put(struct snd_kcontrol *kcontrol,
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int mode_reg, mode_index;
        unsigned int mux, inmode, src_val, mode_val;
+       int change, ret;
 
        mux = ucontrol->value.enumerated.item[0];
        if (mux > 1)
@@ -137,14 +138,20 @@ static int wm8998_inmux_put(struct snd_kcontrol *kcontrol,
        snd_soc_component_update_bits(component, mode_reg,
                                      ARIZONA_IN1_MODE_MASK, mode_val);
 
-       snd_soc_component_update_bits(component, e->reg,
-                                     ARIZONA_IN1L_SRC_MASK |
-                                     ARIZONA_IN1L_SRC_SE_MASK,
-                                     src_val);
+       change = snd_soc_component_update_bits(component, e->reg,
+                                              ARIZONA_IN1L_SRC_MASK |
+                                              ARIZONA_IN1L_SRC_SE_MASK,
+                                              src_val);
 
-       return snd_soc_dapm_mux_update_power(dapm, kcontrol,
-                                            ucontrol->value.enumerated.item[0],
-                                            e, NULL);
+       ret = snd_soc_dapm_mux_update_power(dapm, kcontrol,
+                                           ucontrol->value.enumerated.item[0],
+                                           e, NULL);
+       if (ret < 0) {
+               dev_err(arizona->dev, "Failed to update demux power state: %d\n", ret);
+               return ret;
+       }
+
+       return change;
 }
 
 static const char * const wm8998_inmux_texts[] = {
index 6d7fd88243aa8d6f7cd8e34399b01ec67e80b107..a7784ac15dde694565d9f0a7c71e48e82ad0d238 100644 (file)
@@ -997,7 +997,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
                snd_soc_dapm_sync(dapm);
        }
 
-       return 0;
+       return 1;
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
 
index 77ac4051b827652e8cc4bfb5ddb49b0e361466eb..d34b29a49268e979f0a279df5ddfa3001f8616cb 100644 (file)
@@ -90,12 +90,12 @@ links indicates connection part of CPU side (= A).
                        ports@0 {
 (X) (A)                        mcpu:   port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; };
 (y)                            port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; };
-(y)                            port@1 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; };
+(y)                            port@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; };
                        };
                        ports@1 {
 (X)                            port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; };
-(y)                            port@0 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
-(y)                            port@1 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; };
+(y)                            port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
+(y)                            port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; };
                        };
                };
        };
index 0d11cc8aab0bdacc22665f8f47da2bd76a78612e..6a06fe387d13bde13a3356178ed804a185e65b81 100644 (file)
@@ -128,10 +128,10 @@ struct avs_tplg_token_parser {
 static int
 avs_parse_uuid_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
 {
-       struct snd_soc_tplg_vendor_value_elem *tuple = elem;
+       struct snd_soc_tplg_vendor_uuid_elem *tuple = elem;
        guid_t *val = (guid_t *)((u8 *)object + offset);
 
-       guid_copy((guid_t *)val, (const guid_t *)&tuple->value);
+       guid_copy((guid_t *)val, (const guid_t *)&tuple->uuid);
 
        return 0;
 }
index 00384c6fbcaa5e65c05c3ca38278a8fe21d265a1..330c0ace16387ea54e5662a64aba5830da89c354 100644 (file)
@@ -421,8 +421,17 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
        priv->spkvdd_en_gpio = gpiod_get(codec_dev, "wlf,spkvdd-ena", GPIOD_OUT_LOW);
        put_device(codec_dev);
 
-       if (IS_ERR(priv->spkvdd_en_gpio))
-               return dev_err_probe(dev, PTR_ERR(priv->spkvdd_en_gpio), "getting spkvdd-GPIO\n");
+       if (IS_ERR(priv->spkvdd_en_gpio)) {
+               ret = PTR_ERR(priv->spkvdd_en_gpio);
+               /*
+                * The spkvdd gpio-lookup is registered by: drivers/mfd/arizona-spi.c,
+                * so -ENOENT means that arizona-spi hasn't probed yet.
+                */
+               if (ret == -ENOENT)
+                       ret = -EPROBE_DEFER;
+
+               return dev_err_probe(dev, ret, "getting spkvdd-GPIO\n");
+       }
 
        /* override platform name, if required */
        byt_wm5102_card.dev = dev;
index 5d67a2c87a1d485a565835e1497f7553206abd7c..4a90a0a5d8315b8c68cfcc9103102ea2d8ccab61 100644 (file)
@@ -69,11 +69,10 @@ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
 
 static int is_legacy_cpu;
 
-static struct snd_soc_jack sof_hdmi[3];
-
 struct sof_hdmi_pcm {
        struct list_head head;
        struct snd_soc_dai *codec_dai;
+       struct snd_soc_jack hdmi_jack;
        int device;
 };
 
@@ -434,7 +433,6 @@ static int sof_card_late_probe(struct snd_soc_card *card)
        char jack_name[NAME_SIZE];
        struct sof_hdmi_pcm *pcm;
        int err;
-       int i = 0;
 
        /* HDMI is not supported by SOF on Baytrail/CherryTrail */
        if (is_legacy_cpu || !ctx->idisp_codec)
@@ -455,17 +453,15 @@ static int sof_card_late_probe(struct snd_soc_card *card)
                snprintf(jack_name, sizeof(jack_name),
                         "HDMI/DP, pcm=%d Jack", pcm->device);
                err = snd_soc_card_jack_new(card, jack_name,
-                                           SND_JACK_AVOUT, &sof_hdmi[i]);
+                                           SND_JACK_AVOUT, &pcm->hdmi_jack);
 
                if (err)
                        return err;
 
                err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
-                                         &sof_hdmi[i]);
+                                         &pcm->hdmi_jack);
                if (err < 0)
                        return err;
-
-               i++;
        }
 
        if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) {
index 1f00679b42409fc7f9b70660793bcac375088ec4..ad826ad82d51a78f59fea863fe8747ea0f616675 100644 (file)
@@ -1398,6 +1398,33 @@ static struct snd_soc_card card_sof_sdw = {
        .late_probe = sof_sdw_card_late_probe,
 };
 
+static void mc_dailink_exit_loop(struct snd_soc_card *card)
+{
+       struct snd_soc_dai_link *link;
+       int ret;
+       int i, j;
+
+       for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
+               if (!codec_info_list[i].exit)
+                       continue;
+               /*
+                * We don't need to call .exit function if there is no matched
+                * dai link found.
+                */
+               for_each_card_prelinks(card, j, link) {
+                       if (!strcmp(link->codecs[0].dai_name,
+                                   codec_info_list[i].dai_name)) {
+                               ret = codec_info_list[i].exit(card, link);
+                               if (ret)
+                                       dev_warn(card->dev,
+                                                "codec exit failed %d\n",
+                                                ret);
+                               break;
+                       }
+               }
+       }
+}
+
 static int mc_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = &card_sof_sdw;
@@ -1462,6 +1489,7 @@ static int mc_probe(struct platform_device *pdev)
        ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret) {
                dev_err(card->dev, "snd_soc_register_card failed %d\n", ret);
+               mc_dailink_exit_loop(card);
                return ret;
        }
 
@@ -1473,29 +1501,8 @@ static int mc_probe(struct platform_device *pdev)
 static int mc_remove(struct platform_device *pdev)
 {
        struct snd_soc_card *card = platform_get_drvdata(pdev);
-       struct snd_soc_dai_link *link;
-       int ret;
-       int i, j;
 
-       for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
-               if (!codec_info_list[i].exit)
-                       continue;
-               /*
-                * We don't need to call .exit function if there is no matched
-                * dai link found.
-                */
-               for_each_card_prelinks(card, j, link) {
-                       if (!strcmp(link->codecs[0].dai_name,
-                                   codec_info_list[i].dai_name)) {
-                               ret = codec_info_list[i].exit(card, link);
-                               if (ret)
-                                       dev_warn(&pdev->dev,
-                                                "codec exit failed %d\n",
-                                                ret);
-                               break;
-                       }
-               }
-       }
+       mc_dailink_exit_loop(card);
 
        return 0;
 }
index 2439a574ac2faac2f5ef87555fa49fd8795d276e..deb7b820325e7f9673072713b5213f3967a91467 100644 (file)
@@ -99,7 +99,6 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
        struct nhlt_fmt_cfg *fmt_cfg;
        struct wav_fmt_ext *wav_fmt;
        unsigned long rate;
-       bool present = false;
        int rate_index = 0;
        u16 channels, bps;
        u8 clk_src;
@@ -112,9 +111,12 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
        if (fmt->fmt_count == 0)
                return;
 
+       fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
        for (i = 0; i < fmt->fmt_count; i++) {
-               fmt_cfg = &fmt->fmt_config[i];
-               wav_fmt = &fmt_cfg->fmt_ext;
+               struct nhlt_fmt_cfg *saved_fmt_cfg = fmt_cfg;
+               bool present = false;
+
+               wav_fmt = &saved_fmt_cfg->fmt_ext;
 
                channels = wav_fmt->fmt.channels;
                bps = wav_fmt->fmt.bits_per_sample;
@@ -132,12 +134,18 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
                 * derive the rate.
                 */
                for (j = i; j < fmt->fmt_count; j++) {
-                       fmt_cfg = &fmt->fmt_config[j];
-                       wav_fmt = &fmt_cfg->fmt_ext;
+                       struct nhlt_fmt_cfg *tmp_fmt_cfg = fmt_cfg;
+
+                       wav_fmt = &tmp_fmt_cfg->fmt_ext;
                        if ((fs == wav_fmt->fmt.samples_per_sec) &&
-                          (bps == wav_fmt->fmt.bits_per_sample))
+                          (bps == wav_fmt->fmt.bits_per_sample)) {
                                channels = max_t(u16, channels,
                                                wav_fmt->fmt.channels);
+                               saved_fmt_cfg = tmp_fmt_cfg;
+                       }
+                       /* Move to the next nhlt_fmt_cfg */
+                       tmp_fmt_cfg = (struct nhlt_fmt_cfg *)(tmp_fmt_cfg->config.caps +
+                                                             tmp_fmt_cfg->config.size);
                }
 
                rate = channels * bps * fs;
@@ -153,8 +161,11 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
 
                /* Fill rate and parent for sclk/sclkfs */
                if (!present) {
+                       struct nhlt_fmt_cfg *first_fmt_cfg;
+
+                       first_fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
                        i2s_config_ext = (struct skl_i2s_config_blob_ext *)
-                                               fmt->fmt_config[0].config.caps;
+                                               first_fmt_cfg->config.caps;
 
                        /* MCLK Divider Source Select */
                        if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
@@ -168,6 +179,9 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
 
                        parent = skl_get_parent_clk(clk_src);
 
+                       /* Move to the next nhlt_fmt_cfg */
+                       fmt_cfg = (struct nhlt_fmt_cfg *)(fmt_cfg->config.caps +
+                                                         fmt_cfg->config.size);
                        /*
                         * Do not copy the config data if there is no parent
                         * clock available for this clock source select
@@ -176,9 +190,9 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
                                continue;
 
                        sclk[id].rate_cfg[rate_index].rate = rate;
-                       sclk[id].rate_cfg[rate_index].config = fmt_cfg;
+                       sclk[id].rate_cfg[rate_index].config = saved_fmt_cfg;
                        sclkfs[id].rate_cfg[rate_index].rate = rate;
-                       sclkfs[id].rate_cfg[rate_index].config = fmt_cfg;
+                       sclkfs[id].rate_cfg[rate_index].config = saved_fmt_cfg;
                        sclk[id].parent_name = parent->name;
                        sclkfs[id].parent_name = parent->name;
 
@@ -192,13 +206,13 @@ static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk,
 {
        struct skl_i2s_config_blob_ext *i2s_config_ext;
        struct skl_i2s_config_blob_legacy *i2s_config;
-       struct nhlt_specific_cfg *fmt_cfg;
+       struct nhlt_fmt_cfg *fmt_cfg;
        struct skl_clk_parent_src *parent;
        u32 clkdiv, div_ratio;
        u8 clk_src;
 
-       fmt_cfg = &fmt->fmt_config[0].config;
-       i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->caps;
+       fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
+       i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->config.caps;
 
        /* MCLK Divider Source Select and divider */
        if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
@@ -227,7 +241,7 @@ static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk,
                return;
 
        mclk[id].rate_cfg[0].rate = parent->rate/div_ratio;
-       mclk[id].rate_cfg[0].config = &fmt->fmt_config[0];
+       mclk[id].rate_cfg[0].config = fmt_cfg;
        mclk[id].parent_name = parent->name;
 }
 
index 19c4a90ec1ea96e793f00016c0dc03040428fcfe..ee59ef36b85a614916f0a90fdbdc129ac59f0821 100644 (file)
@@ -147,6 +147,12 @@ static int q6apm_dai_prepare(struct snd_soc_component *component,
        cfg.num_channels = runtime->channels;
        cfg.bit_width = prtd->bits_per_sample;
 
+       if (prtd->state) {
+               /* clear the previous setup if any  */
+               q6apm_graph_stop(prtd->graph);
+               q6apm_unmap_memory_regions(prtd->graph, substream->stream);
+       }
+
        prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
        prtd->pos = 0;
        /* rate and channels are sent to audio driver */
index f424d7aa389a2fa3202f63fdc5ab4e086fc56cf4..794019286c7049ad06600ddca74a40c767345f03 100644 (file)
@@ -75,6 +75,7 @@ static struct audioreach_graph *q6apm_get_audioreach_graph(struct q6apm *apm, ui
        id = idr_alloc(&apm->graph_idr, graph, graph_id, graph_id + 1, GFP_KERNEL);
        if (id < 0) {
                dev_err(apm->dev, "Unable to allocate graph id (%d)\n", graph_id);
+               kfree(graph->graph);
                kfree(graph);
                mutex_unlock(&apm->lock);
                return ERR_PTR(id);
index 869c76506b669ca4f5ad18be57b54566983b9f8d..a8e842e02cdc2435626bfa71b4c4f124ababa42e 100644 (file)
@@ -62,6 +62,8 @@ struct snd_soc_dapm_widget *
 snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
                         const struct snd_soc_dapm_widget *widget);
 
+static unsigned int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg);
+
 /* dapm power sequences - make this per codec in the future */
 static int dapm_up_seq[] = {
        [snd_soc_dapm_pre] = 1,
@@ -442,6 +444,9 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
 
                        snd_soc_dapm_add_path(widget->dapm, data->widget,
                                              widget, NULL, NULL);
+               } else if (e->reg != SND_SOC_NOPM) {
+                       data->value = soc_dapm_read(widget->dapm, e->reg) &
+                                     (e->mask << e->shift_l);
                }
                break;
        default:
index e693070f51fe8113dd5a6d57c378ccb7d460e302..d867f449d82db329fcfa8a579f3d55e101613cfb 100644 (file)
@@ -526,7 +526,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
                return -EINVAL;
        if (mc->platform_max && tmp > mc->platform_max)
                return -EINVAL;
-       if (tmp > mc->max - mc->min + 1)
+       if (tmp > mc->max - mc->min)
                return -EINVAL;
 
        if (invert)
@@ -547,7 +547,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
                        return -EINVAL;
                if (mc->platform_max && tmp > mc->platform_max)
                        return -EINVAL;
-               if (tmp > mc->max - mc->min + 1)
+               if (tmp > mc->max - mc->min)
                        return -EINVAL;
 
                if (invert)
index 000ea906670cbc320047878795518949519469d1..e24eea725acb43654700277319e61755e5c7993b 100644 (file)
@@ -181,12 +181,20 @@ int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask)
  * Power Management.
  */
 
-static int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask)
+int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask)
 {
+       struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+       const struct sof_intel_dsp_desc *chip = hda->desc;
        unsigned int cpa;
        u32 adspcs;
        int ret;
 
+       /* restrict core_mask to host managed cores mask */
+       core_mask &= chip->host_managed_cores_mask;
+       /* return if core_mask is not valid */
+       if (!core_mask)
+               return 0;
+
        /* update bits */
        snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS,
                                HDA_DSP_ADSPCS_SPA_MASK(core_mask),
index 64290125d7cd8fc073c602542c3d542ebafdec0b..145d483bd129f15f6e013dd8a5ed105b859e2676 100644 (file)
@@ -95,9 +95,9 @@ out_put:
 }
 
 /*
- * first boot sequence has some extra steps. core 0 waits for power
- * status on core 1, so power up core 1 also momentarily, keep it in
- * reset/stall and then turn it off
+ * first boot sequence has some extra steps.
+ * power on all host managed cores and only unstall/run the boot core to boot the
+ * DSP then turn off all non boot cores (if any) is powered on.
  */
 static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
 {
@@ -110,7 +110,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
        int ret;
 
        /* step 1: power up corex */
-       ret = hda_dsp_enable_core(sdev, chip->host_managed_cores_mask);
+       ret = hda_dsp_core_power_up(sdev, chip->host_managed_cores_mask);
        if (ret < 0) {
                if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
                        dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n");
@@ -127,7 +127,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
        snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, ipc_hdr);
 
        /* step 3: unset core 0 reset state & unstall/run core 0 */
-       ret = hda_dsp_core_run(sdev, BIT(0));
+       ret = hda_dsp_core_run(sdev, chip->init_core_mask);
        if (ret < 0) {
                if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
                        dev_err(sdev->dev,
@@ -389,7 +389,8 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
        struct snd_dma_buffer dmab;
        int ret, ret1, i;
 
-       if (hda->imrboot_supported && !sdev->first_boot) {
+       if (sdev->system_suspend_target < SOF_SUSPEND_S4 &&
+           hda->imrboot_supported && !sdev->first_boot) {
                dev_dbg(sdev->dev, "IMR restore supported, booting from IMR directly\n");
                hda->boot_iteration = 0;
                ret = hda_dsp_boot_imr(sdev);
index dc1f743730c0d824d928cf7791d3cd42c953e634..6888e0a4665d2d06be1d75719f37983c5d99c83f 100644 (file)
@@ -192,79 +192,7 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
                goto found;
        }
 
-       switch (sof_hda_position_quirk) {
-       case SOF_HDA_POSITION_QUIRK_USE_SKYLAKE_LEGACY:
-               /*
-                * This legacy code, inherited from the Skylake driver,
-                * mixes DPIB registers and DPIB DDR updates and
-                * does not seem to follow any known hardware recommendations.
-                * It's not clear e.g. why there is a different flow
-                * for capture and playback, the only information that matters is
-                * what traffic class is used, and on all SOF-enabled platforms
-                * only VC0 is supported so the work-around was likely not necessary
-                * and quite possibly wrong.
-                */
-
-               /* DPIB/posbuf position mode:
-                * For Playback, Use DPIB register from HDA space which
-                * reflects the actual data transferred.
-                * For Capture, Use the position buffer for pointer, as DPIB
-                * is not accurate enough, its update may be completed
-                * earlier than the data written to DDR.
-                */
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
-                                              AZX_REG_VS_SDXDPIB_XBASE +
-                                              (AZX_REG_VS_SDXDPIB_XINTERVAL *
-                                               hstream->index));
-               } else {
-                       /*
-                        * For capture stream, we need more workaround to fix the
-                        * position incorrect issue:
-                        *
-                        * 1. Wait at least 20us before reading position buffer after
-                        * the interrupt generated(IOC), to make sure position update
-                        * happens on frame boundary i.e. 20.833uSec for 48KHz.
-                        * 2. Perform a dummy Read to DPIB register to flush DMA
-                        * position value.
-                        * 3. Read the DMA Position from posbuf. Now the readback
-                        * value should be >= period boundary.
-                        */
-                       usleep_range(20, 21);
-                       snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
-                                        AZX_REG_VS_SDXDPIB_XBASE +
-                                        (AZX_REG_VS_SDXDPIB_XINTERVAL *
-                                         hstream->index));
-                       pos = snd_hdac_stream_get_pos_posbuf(hstream);
-               }
-               break;
-       case SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS:
-               /*
-                * In case VC1 traffic is disabled this is the recommended option
-                */
-               pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
-                                      AZX_REG_VS_SDXDPIB_XBASE +
-                                      (AZX_REG_VS_SDXDPIB_XINTERVAL *
-                                       hstream->index));
-               break;
-       case SOF_HDA_POSITION_QUIRK_USE_DPIB_DDR_UPDATE:
-               /*
-                * This is the recommended option when VC1 is enabled.
-                * While this isn't needed for SOF platforms it's added for
-                * consistency and debug.
-                */
-               pos = snd_hdac_stream_get_pos_posbuf(hstream);
-               break;
-       default:
-               dev_err_once(sdev->dev, "hda_position_quirk value %d not supported\n",
-                            sof_hda_position_quirk);
-               pos = 0;
-               break;
-       }
-
-       if (pos >= hstream->bufsize)
-               pos = 0;
-
+       pos = hda_dsp_stream_get_position(hstream, substream->stream, true);
 found:
        pos = bytes_to_frames(substream->runtime, pos);
 
index daeb64c495e40204b410c48b34e7168e1cfc3e19..d95ae17e81cc4711a0de6bb2dc2e5c15fc268192 100644 (file)
@@ -707,12 +707,13 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
 }
 
 static void
-hda_dsp_set_bytes_transferred(struct hdac_stream *hstream, u64 buffer_size)
+hda_dsp_compr_bytes_transferred(struct hdac_stream *hstream, int direction)
 {
+       u64 buffer_size = hstream->bufsize;
        u64 prev_pos, pos, num_bytes;
 
        div64_u64_rem(hstream->curr_pos, buffer_size, &prev_pos);
-       pos = snd_hdac_stream_get_pos_posbuf(hstream);
+       pos = hda_dsp_stream_get_position(hstream, direction, false);
 
        if (pos < prev_pos)
                num_bytes = (buffer_size - prev_pos) +  pos;
@@ -748,8 +749,7 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status)
                        if (s->substream && sof_hda->no_ipc_position) {
                                snd_sof_pcm_period_elapsed(s->substream);
                        } else if (s->cstream) {
-                               hda_dsp_set_bytes_transferred(s,
-                                       s->cstream->runtime->buffer_size);
+                               hda_dsp_compr_bytes_transferred(s, s->cstream->direction);
                                snd_compr_fragment_elapsed(s->cstream);
                        }
                }
@@ -1009,3 +1009,89 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev)
                devm_kfree(sdev->dev, hda_stream);
        }
 }
+
+snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
+                                             int direction, bool can_sleep)
+{
+       struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
+       struct sof_intel_hda_stream *hda_stream = hstream_to_sof_hda_stream(hext_stream);
+       struct snd_sof_dev *sdev = hda_stream->sdev;
+       snd_pcm_uframes_t pos;
+
+       switch (sof_hda_position_quirk) {
+       case SOF_HDA_POSITION_QUIRK_USE_SKYLAKE_LEGACY:
+               /*
+                * This legacy code, inherited from the Skylake driver,
+                * mixes DPIB registers and DPIB DDR updates and
+                * does not seem to follow any known hardware recommendations.
+                * It's not clear e.g. why there is a different flow
+                * for capture and playback, the only information that matters is
+                * what traffic class is used, and on all SOF-enabled platforms
+                * only VC0 is supported so the work-around was likely not necessary
+                * and quite possibly wrong.
+                */
+
+               /* DPIB/posbuf position mode:
+                * For Playback, Use DPIB register from HDA space which
+                * reflects the actual data transferred.
+                * For Capture, Use the position buffer for pointer, as DPIB
+                * is not accurate enough, its update may be completed
+                * earlier than the data written to DDR.
+                */
+               if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+                       pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
+                                              AZX_REG_VS_SDXDPIB_XBASE +
+                                              (AZX_REG_VS_SDXDPIB_XINTERVAL *
+                                               hstream->index));
+               } else {
+                       /*
+                        * For capture stream, we need more workaround to fix the
+                        * position incorrect issue:
+                        *
+                        * 1. Wait at least 20us before reading position buffer after
+                        * the interrupt generated(IOC), to make sure position update
+                        * happens on frame boundary i.e. 20.833uSec for 48KHz.
+                        * 2. Perform a dummy Read to DPIB register to flush DMA
+                        * position value.
+                        * 3. Read the DMA Position from posbuf. Now the readback
+                        * value should be >= period boundary.
+                        */
+                       if (can_sleep)
+                               usleep_range(20, 21);
+
+                       snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
+                                        AZX_REG_VS_SDXDPIB_XBASE +
+                                        (AZX_REG_VS_SDXDPIB_XINTERVAL *
+                                         hstream->index));
+                       pos = snd_hdac_stream_get_pos_posbuf(hstream);
+               }
+               break;
+       case SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS:
+               /*
+                * In case VC1 traffic is disabled this is the recommended option
+                */
+               pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
+                                      AZX_REG_VS_SDXDPIB_XBASE +
+                                      (AZX_REG_VS_SDXDPIB_XINTERVAL *
+                                       hstream->index));
+               break;
+       case SOF_HDA_POSITION_QUIRK_USE_DPIB_DDR_UPDATE:
+               /*
+                * This is the recommended option when VC1 is enabled.
+                * While this isn't needed for SOF platforms it's added for
+                * consistency and debug.
+                */
+               pos = snd_hdac_stream_get_pos_posbuf(hstream);
+               break;
+       default:
+               dev_err_once(sdev->dev, "hda_position_quirk value %d not supported\n",
+                            sof_hda_position_quirk);
+               pos = 0;
+               break;
+       }
+
+       if (pos >= hstream->bufsize)
+               pos = 0;
+
+       return pos;
+}
index 3e0f7b0c586a265e3c846a3f08d20431ef9a6284..06476ffe96d73a77cdc74498c130f66e9cdb6313 100644 (file)
@@ -497,6 +497,7 @@ struct sof_intel_hda_stream {
  */
 int hda_dsp_probe(struct snd_sof_dev *sdev);
 int hda_dsp_remove(struct snd_sof_dev *sdev);
+int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask);
 int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask);
 int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask);
 int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev,
@@ -564,6 +565,9 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev,
 bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
 bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev);
 
+snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
+                                             int direction, bool can_sleep);
+
 struct hdac_ext_stream *
        hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags);
 int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag);
index 043554d7cb4a6ef044ede54560547b8fcbcdea1d..10740c55294dc0ed91167ad825a3f1ae180d6e98 100644 (file)
@@ -1577,24 +1577,23 @@ static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_
        struct sof_ipc_ctrl_data *cdata;
        int ret;
 
-       scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL);
-       if (!scontrol->ipc_control_data)
-               return -ENOMEM;
-
-       if (scontrol->max_size < sizeof(*cdata) ||
-           scontrol->max_size < sizeof(struct sof_abi_hdr)) {
-               ret = -EINVAL;
-               goto err;
+       if (scontrol->max_size < (sizeof(*cdata) + sizeof(struct sof_abi_hdr))) {
+               dev_err(sdev->dev, "%s: insufficient size for a bytes control: %zu.\n",
+                       __func__, scontrol->max_size);
+               return -EINVAL;
        }
 
-       /* init the get/put bytes data */
        if (scontrol->priv_size > scontrol->max_size - sizeof(*cdata)) {
-               dev_err(sdev->dev, "err: bytes data size %zu exceeds max %zu.\n",
+               dev_err(sdev->dev,
+                       "%s: bytes data size %zu exceeds max %zu.\n", __func__,
                        scontrol->priv_size, scontrol->max_size - sizeof(*cdata));
-               ret = -EINVAL;
-               goto err;
+               return -EINVAL;
        }
 
+       scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL);
+       if (!scontrol->ipc_control_data)
+               return -ENOMEM;
+
        scontrol->size = sizeof(struct sof_ipc_ctrl_data) + scontrol->priv_size;
 
        cdata = scontrol->ipc_control_data;
index 3333a0634e29dc34d2c002ea6630015f549149d2..e006532caf2f0528da6a472aa9ddedf0e030d22b 100644 (file)
@@ -392,7 +392,7 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev)
                                                      PLATFORM_DEVID_NONE,
                                                      pdev, sizeof(*pdev));
        if (IS_ERR(priv->ipc_dev)) {
-               ret = IS_ERR(priv->ipc_dev);
+               ret = PTR_ERR(priv->ipc_dev);
                dev_err(sdev->dev, "failed to create mtk-adsp-ipc device\n");
                goto err_adsp_off;
        }
index 18eb327a57f039eafbaa2a4709ce93e1e50dac01..df740be645e844f143e754d351b4561f7d2d57f3 100644 (file)
@@ -23,6 +23,9 @@ static u32 snd_sof_dsp_power_target(struct snd_sof_dev *sdev)
        u32 target_dsp_state;
 
        switch (sdev->system_suspend_target) {
+       case SOF_SUSPEND_S5:
+       case SOF_SUSPEND_S4:
+               /* DSP should be in D3 if the system is suspending to S3+ */
        case SOF_SUSPEND_S3:
                /* DSP should be in D3 if the system is suspending to S3 */
                target_dsp_state = SOF_DSP_PM_D3;
@@ -335,8 +338,24 @@ int snd_sof_prepare(struct device *dev)
                return 0;
 
 #if defined(CONFIG_ACPI)
-       if (acpi_target_system_state() == ACPI_STATE_S0)
+       switch (acpi_target_system_state()) {
+       case ACPI_STATE_S0:
                sdev->system_suspend_target = SOF_SUSPEND_S0IX;
+               break;
+       case ACPI_STATE_S1:
+       case ACPI_STATE_S2:
+       case ACPI_STATE_S3:
+               sdev->system_suspend_target = SOF_SUSPEND_S3;
+               break;
+       case ACPI_STATE_S4:
+               sdev->system_suspend_target = SOF_SUSPEND_S4;
+               break;
+       case ACPI_STATE_S5:
+               sdev->system_suspend_target = SOF_SUSPEND_S5;
+               break;
+       default:
+               break;
+       }
 #endif
 
        return 0;
index 9d7f53ff9c70ef2f6990f8138f34461ec41acc3c..f0f3d72c0da73bec5e4f2378fea42ad769e51619 100644 (file)
@@ -85,6 +85,8 @@ enum sof_system_suspend_state {
        SOF_SUSPEND_NONE = 0,
        SOF_SUSPEND_S0IX,
        SOF_SUSPEND_S3,
+       SOF_SUSPEND_S4,
+       SOF_SUSPEND_S5,
 };
 
 enum sof_dfsentry_type {
index 7865cda4bf0ad28653599707284528455b262f2a..da519ea1f30387254b7e83cc3808abfb8bcd20ba 100644 (file)
@@ -316,8 +316,6 @@ static inline int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg,
 
 /* Sidetone specific API */
 int omap_mcbsp_st_init(struct platform_device *pdev);
-void omap_mcbsp_st_cleanup(struct platform_device *pdev);
-
 int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp);
 int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp);
 
index 0bc7d26c660aa42c0e45d4781d80c83cb837c9fa..7e8179cae92ebaaf334dbd25a055a9714a03ec1a 100644 (file)
@@ -347,7 +347,7 @@ int omap_mcbsp_st_init(struct platform_device *pdev)
        if (!st_data)
                return -ENOMEM;
 
-       st_data->mcbsp_iclk = clk_get(mcbsp->dev, "ick");
+       st_data->mcbsp_iclk = devm_clk_get(mcbsp->dev, "ick");
        if (IS_ERR(st_data->mcbsp_iclk)) {
                dev_warn(mcbsp->dev,
                         "Failed to get ick, sidetone might be broken\n");
@@ -359,7 +359,7 @@ int omap_mcbsp_st_init(struct platform_device *pdev)
        if (!st_data->io_base_st)
                return -ENOMEM;
 
-       ret = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
+       ret = devm_device_add_group(mcbsp->dev, &sidetone_attr_group);
        if (ret)
                return ret;
 
@@ -368,16 +368,6 @@ int omap_mcbsp_st_init(struct platform_device *pdev)
        return 0;
 }
 
-void omap_mcbsp_st_cleanup(struct platform_device *pdev)
-{
-       struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
-
-       if (mcbsp->st_data) {
-               sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
-               clk_put(mcbsp->st_data->mcbsp_iclk);
-       }
-}
-
 static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
                                    struct snd_ctl_elem_info *uinfo)
 {
index 4479d74f0a458f4045c968d2be59dac25e5bfaf8..9933b33c80caac53729f5b0e9a3caed6d8225df4 100644 (file)
@@ -702,8 +702,7 @@ static int omap_mcbsp_init(struct platform_device *pdev)
                mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
                mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
 
-               ret = sysfs_create_group(&mcbsp->dev->kobj,
-                                        &additional_attr_group);
+               ret = devm_device_add_group(mcbsp->dev, &additional_attr_group);
                if (ret) {
                        dev_err(mcbsp->dev,
                                "Unable to create additional controls\n");
@@ -711,16 +710,7 @@ static int omap_mcbsp_init(struct platform_device *pdev)
                }
        }
 
-       ret = omap_mcbsp_st_init(pdev);
-       if (ret)
-               goto err_st;
-
-       return 0;
-
-err_st:
-       if (mcbsp->pdata->buffer_size)
-               sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
-       return ret;
+       return omap_mcbsp_st_init(pdev);
 }
 
 /*
@@ -1431,11 +1421,6 @@ static int asoc_mcbsp_remove(struct platform_device *pdev)
        if (cpu_latency_qos_request_active(&mcbsp->pm_qos_req))
                cpu_latency_qos_remove_request(&mcbsp->pm_qos_req);
 
-       if (mcbsp->pdata->buffer_size)
-               sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
-
-       omap_mcbsp_st_cleanup(pdev);
-
        return 0;
 }
 
index 4f56e1784932a29e21d92ee6508b6b54030d7164..f93201a830b5a7404483c048364a8bf31067d772 100644 (file)
@@ -3802,6 +3802,54 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 
+/*
+ * MacroSilicon MS2100/MS2106 based AV capture cards
+ *
+ * These claim 96kHz 1ch in the descriptors, but are actually 48kHz 2ch.
+ * They also need QUIRK_FLAG_ALIGN_TRANSFER, which makes one wonder if
+ * they pretend to be 96kHz mono as a workaround for stereo being broken
+ * by that...
+ *
+ * They also have an issue with initial stream alignment that causes the
+ * channels to be swapped and out of phase, which is dealt with in quirks.c.
+ */
+{
+       USB_AUDIO_DEVICE(0x534d, 0x0021),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "MacroSilicon",
+               .product_name = "MS210x",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = &(const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_STANDARD_MIXER,
+                       },
+                       {
+                               .ifnum = 3,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                       .channels = 2,
+                                       .iface = 3,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = 0,
+                                       .endpoint = 0x82,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                               USB_ENDPOINT_SYNC_ASYNC,
+                                       .rates = SNDRV_PCM_RATE_CONTINUOUS,
+                                       .rate_min = 48000,
+                                       .rate_max = 48000,
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
+
 /*
  * MacroSilicon MS2109 based HDMI capture cards
  *
@@ -4119,6 +4167,206 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       /*
+        * Fiero SC-01 (firmware v1.0.0 @ 48 kHz)
+        */
+       USB_DEVICE(0x2b53, 0x0023),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Fiero",
+               .product_name = "SC-01",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = &(const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       /* Playback */
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x01,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC,
+                                       .rates = SNDRV_PCM_RATE_48000,
+                                       .rate_min = 48000,
+                                       .rate_max = 48000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 48000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       /* Capture */
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 2,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x82,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC |
+                                                  USB_ENDPOINT_USAGE_IMPLICIT_FB,
+                                       .rates = SNDRV_PCM_RATE_48000,
+                                       .rate_min = 48000,
+                                       .rate_max = 48000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 48000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
+{
+       /*
+        * Fiero SC-01 (firmware v1.0.0 @ 96 kHz)
+        */
+       USB_DEVICE(0x2b53, 0x0024),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Fiero",
+               .product_name = "SC-01",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = &(const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       /* Playback */
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x01,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC,
+                                       .rates = SNDRV_PCM_RATE_96000,
+                                       .rate_min = 96000,
+                                       .rate_max = 96000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 96000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       /* Capture */
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 2,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x82,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC |
+                                                  USB_ENDPOINT_USAGE_IMPLICIT_FB,
+                                       .rates = SNDRV_PCM_RATE_96000,
+                                       .rate_min = 96000,
+                                       .rate_max = 96000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 96000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
+{
+       /*
+        * Fiero SC-01 (firmware v1.1.0)
+        */
+       USB_DEVICE(0x2b53, 0x0031),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Fiero",
+               .product_name = "SC-01",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = &(const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       /* Playback */
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x01,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC,
+                                       .rates = SNDRV_PCM_RATE_48000 |
+                                                SNDRV_PCM_RATE_96000,
+                                       .rate_min = 48000,
+                                       .rate_max = 96000,
+                                       .nr_rates = 2,
+                                       .rate_table = (unsigned int[]) { 48000, 96000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       /* Capture */
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 2,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x82,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC |
+                                                  USB_ENDPOINT_USAGE_IMPLICIT_FB,
+                                       .rates = SNDRV_PCM_RATE_48000 |
+                                                SNDRV_PCM_RATE_96000,
+                                       .rate_min = 48000,
+                                       .rate_max = 96000,
+                                       .nr_rates = 2,
+                                       .rate_table = (unsigned int[]) { 48000, 96000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 
 #undef USB_DEVICE_VENDOR_SPEC
 #undef USB_AUDIO_DEVICE
index e8468f9b007d1fa69a6e66df4c6018e518dc1a84..968d90caeefa09a19a10b5106514b18a3f458b16 100644 (file)
@@ -1478,6 +1478,7 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
        case USB_ID(0x041e, 0x3f19): /* E-Mu 0204 USB */
                set_format_emu_quirk(subs, fmt);
                break;
+       case USB_ID(0x534d, 0x0021): /* MacroSilicon MS2100/MS2106 */
        case USB_ID(0x534d, 0x2109): /* MacroSilicon MS2109 */
                subs->stream_offset_adj = 2;
                break;
@@ -1842,6 +1843,10 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
                   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
        DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */
                   QUIRK_FLAG_GET_SAMPLE_RATE),
+       DEVICE_FLG(0x1397, 0x0508, /* Behringer UMC204HD */
+                  QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+       DEVICE_FLG(0x1397, 0x0509, /* Behringer UMC404HD */
+                  QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
        DEVICE_FLG(0x13e5, 0x0001, /* Serato Phono */
                   QUIRK_FLAG_IGNORE_CTL_ERROR),
        DEVICE_FLG(0x154e, 0x1002, /* Denon DCD-1500RE */
@@ -1904,10 +1909,18 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
                   QUIRK_FLAG_IGNORE_CTL_ERROR),
        DEVICE_FLG(0x413c, 0xa506, /* Dell AE515 sound bar */
                   QUIRK_FLAG_GET_SAMPLE_RATE),
+       DEVICE_FLG(0x534d, 0x0021, /* MacroSilicon MS2100/MS2106 */
+                  QUIRK_FLAG_ALIGN_TRANSFER),
        DEVICE_FLG(0x534d, 0x2109, /* MacroSilicon MS2109 */
                   QUIRK_FLAG_ALIGN_TRANSFER),
        DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */
                   QUIRK_FLAG_GET_SAMPLE_RATE),
+       DEVICE_FLG(0x2b53, 0x0023, /* Fiero SC-01 (firmware v1.0.0 @ 48 kHz) */
+                  QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+       DEVICE_FLG(0x2b53, 0x0024, /* Fiero SC-01 (firmware v1.0.0 @ 96 kHz) */
+                  QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+       DEVICE_FLG(0x2b53, 0x0031, /* Fiero SC-01 (firmware v1.1.0) */
+                  QUIRK_FLAG_GENERIC_IMPLICIT_FB),
 
        /* Vendor matches */
        VENDOR_FLG(0x045e, /* MS Lifecam */
index 03acc823838a7e46f739ce301af252543168dcd7..00f5227c8459870d142a4dce759a997467448b50 100644 (file)
 #define X86_FEATURE_PROC_FEEDBACK      ( 7*32+ 9) /* AMD ProcFeedbackInterface */
 #define X86_FEATURE_XCOMPACTED         ( 7*32+10) /* "" Use compacted XSTATE (XSAVES or XSAVEC) */
 #define X86_FEATURE_PTI                        ( 7*32+11) /* Kernel Page Table Isolation enabled */
-#define X86_FEATURE_RETPOLINE          ( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
-#define X86_FEATURE_RETPOLINE_LFENCE   ( 7*32+13) /* "" Use LFENCE for Spectre variant 2 */
+#define X86_FEATURE_KERNEL_IBRS                ( 7*32+12) /* "" Set/clear IBRS on kernel entry/exit */
+#define X86_FEATURE_RSB_VMEXIT         ( 7*32+13) /* "" Fill RSB on VM-Exit */
 #define X86_FEATURE_INTEL_PPIN         ( 7*32+14) /* Intel Processor Inventory Number */
 #define X86_FEATURE_CDP_L2             ( 7*32+15) /* Code and Data Prioritization L2 */
 #define X86_FEATURE_MSR_SPEC_CTRL      ( 7*32+16) /* "" MSR SPEC_CTRL is implemented */
 #define X86_FEATURE_PER_THREAD_MBA     (11*32+ 7) /* "" Per-thread Memory Bandwidth Allocation */
 #define X86_FEATURE_SGX1               (11*32+ 8) /* "" Basic SGX */
 #define X86_FEATURE_SGX2               (11*32+ 9) /* "" SGX Enclave Dynamic Memory Management (EDMM) */
+#define X86_FEATURE_ENTRY_IBPB         (11*32+10) /* "" Issue an IBPB on kernel entry */
+#define X86_FEATURE_RRSBA_CTRL         (11*32+11) /* "" RET prediction control */
+#define X86_FEATURE_RETPOLINE          (11*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
+#define X86_FEATURE_RETPOLINE_LFENCE   (11*32+13) /* "" Use LFENCE for Spectre variant 2 */
+#define X86_FEATURE_RETHUNK            (11*32+14) /* "" Use REturn THUNK */
+#define X86_FEATURE_UNRET              (11*32+15) /* "" AMD BTB untrain return */
 
 /* 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_VIRT_SSBD          (13*32+25) /* Virtualized Speculative Store Bypass Disable */
 #define X86_FEATURE_AMD_SSB_NO         (13*32+26) /* "" Speculative Store Bypass is fixed in hardware. */
 #define X86_FEATURE_CPPC               (13*32+27) /* Collaborative Processor Performance Control */
+#define X86_FEATURE_BTC_NO             (13*32+29) /* "" Not vulnerable to Branch Type Confusion */
 #define X86_FEATURE_BRS                        (13*32+31) /* Branch Sampling available */
 
 /* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */
 #define X86_BUG_ITLB_MULTIHIT          X86_BUG(23) /* CPU may incur MCE during certain page attribute changes */
 #define X86_BUG_SRBDS                  X86_BUG(24) /* CPU may leak RNG bits if not mitigated */
 #define X86_BUG_MMIO_STALE_DATA                X86_BUG(25) /* CPU is affected by Processor MMIO Stale Data vulnerabilities */
+#define X86_BUG_RETBLEED               X86_BUG(26) /* CPU is affected by RETBleed */
 
 #endif /* _ASM_X86_CPUFEATURES_H */
index 36369e76cc631ecbb488c175d3c330cebee88737..33d2cd04d2544791b1363f8d7578a7d45b7fc749 100644 (file)
 # define DISABLE_PTI           (1 << (X86_FEATURE_PTI & 31))
 #endif
 
+#ifdef CONFIG_RETPOLINE
+# define DISABLE_RETPOLINE     0
+#else
+# define DISABLE_RETPOLINE     ((1 << (X86_FEATURE_RETPOLINE & 31)) | \
+                                (1 << (X86_FEATURE_RETPOLINE_LFENCE & 31)))
+#endif
+
+#ifdef CONFIG_RETHUNK
+# define DISABLE_RETHUNK       0
+#else
+# define DISABLE_RETHUNK       (1 << (X86_FEATURE_RETHUNK & 31))
+#endif
+
+#ifdef CONFIG_CPU_UNRET_ENTRY
+# define DISABLE_UNRET         0
+#else
+# define DISABLE_UNRET         (1 << (X86_FEATURE_UNRET & 31))
+#endif
+
 #ifdef CONFIG_INTEL_IOMMU_SVM
 # define DISABLE_ENQCMD                0
 #else
 #define DISABLED_MASK8 (DISABLE_TDX_GUEST)
 #define DISABLED_MASK9 (DISABLE_SGX)
 #define DISABLED_MASK10        0
-#define DISABLED_MASK11        0
+#define DISABLED_MASK11        (DISABLE_RETPOLINE|DISABLE_RETHUNK|DISABLE_UNRET)
 #define DISABLED_MASK12        0
 #define DISABLED_MASK13        0
 #define DISABLED_MASK14        0
index d27e0581b7777ba086a772453cc52f6afacdcdeb..cc615be27a54b2daf55352ab1d34c244ee0790c6 100644 (file)
@@ -51,6 +51,8 @@
 #define SPEC_CTRL_STIBP                        BIT(SPEC_CTRL_STIBP_SHIFT)      /* STIBP mask */
 #define SPEC_CTRL_SSBD_SHIFT           2          /* Speculative Store Bypass Disable bit */
 #define SPEC_CTRL_SSBD                 BIT(SPEC_CTRL_SSBD_SHIFT)       /* Speculative Store Bypass Disable */
+#define SPEC_CTRL_RRSBA_DIS_S_SHIFT    6          /* Disable RRSBA behavior */
+#define SPEC_CTRL_RRSBA_DIS_S          BIT(SPEC_CTRL_RRSBA_DIS_S_SHIFT)
 
 #define MSR_IA32_PRED_CMD              0x00000049 /* Prediction Command */
 #define PRED_CMD_IBPB                  BIT(0)     /* Indirect Branch Prediction Barrier */
@@ -93,6 +95,7 @@
 #define MSR_IA32_ARCH_CAPABILITIES     0x0000010a
 #define ARCH_CAP_RDCL_NO               BIT(0)  /* Not susceptible to Meltdown */
 #define ARCH_CAP_IBRS_ALL              BIT(1)  /* Enhanced IBRS support */
+#define ARCH_CAP_RSBA                  BIT(2)  /* RET may use alternative branch predictors */
 #define ARCH_CAP_SKIP_VMENTRY_L1DFLUSH BIT(3)  /* Skip L1D flush on vmentry */
 #define ARCH_CAP_SSB_NO                        BIT(4)  /*
                                                 * Not susceptible to Speculative Store Bypass
                                                 * bit available to control VERW
                                                 * behavior.
                                                 */
+#define ARCH_CAP_RRSBA                 BIT(19) /*
+                                                * Indicates RET may use predictors
+                                                * other than the RSB. With eIBRS
+                                                * enabled predictions in kernel mode
+                                                * are restricted to targets in
+                                                * kernel.
+                                                */
 
 #define MSR_IA32_FLUSH_CMD             0x0000010b
 #define L1D_FLUSH                      BIT(0)  /*
 /* Fam 17h MSRs */
 #define MSR_F17H_IRPERF                        0xc00000e9
 
+#define MSR_ZEN2_SPECTRAL_CHICKEN      0xc00110e3
+#define MSR_ZEN2_SPECTRAL_CHICKEN_BIT  BIT_ULL(1)
+
 /* Fam 16h MSRs */
 #define MSR_F16H_L2I_PERF_CTL          0xc0010230
 #define MSR_F16H_L2I_PERF_CTR          0xc0010231
index 15b940ec1eac9d72c0f35c34e52d368fe00a5219..10bc88cc3bf6b8bc4865baf006151a4a25383795 100644 (file)
@@ -32,11 +32,16 @@ struct unwind_hint {
  *
  * UNWIND_HINT_FUNC: Generate the unwind metadata of a callable function.
  * Useful for code which doesn't have an ELF function annotation.
+ *
+ * UNWIND_HINT_ENTRY: machine entry without stack, SYSCALL/SYSENTER etc.
  */
 #define UNWIND_HINT_TYPE_CALL          0
 #define UNWIND_HINT_TYPE_REGS          1
 #define UNWIND_HINT_TYPE_REGS_PARTIAL  2
 #define UNWIND_HINT_TYPE_FUNC          3
+#define UNWIND_HINT_TYPE_ENTRY         4
+#define UNWIND_HINT_TYPE_SAVE          5
+#define UNWIND_HINT_TYPE_RESTORE       6
 
 #ifdef CONFIG_OBJTOOL
 
@@ -124,7 +129,7 @@ struct unwind_hint {
  * the debuginfo as necessary.  It will also warn if it sees any
  * inconsistencies.
  */
-.macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
 .Lunwind_hint_ip_\@:
        .pushsection .discard.unwind_hints
                /* struct unwind_hint */
@@ -177,7 +182,7 @@ struct unwind_hint {
 #define ASM_REACHABLE
 #else
 #define ANNOTATE_INTRA_FUNCTION_CALL
-.macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
 .endm
 .macro STACK_FRAME_NON_STANDARD func:req
 .endm
index f4009dbdf62daf493beb22e4cbf5befc85a85137..ef78e0e1a75492002824871291648b8e0db8b776 100644 (file)
@@ -5222,22 +5222,25 @@ union bpf_attr {
  *     Return
  *             Nothing. Always succeeds.
  *
- * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset)
+ * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset, u64 flags)
  *     Description
  *             Read *len* bytes from *src* into *dst*, starting from *offset*
  *             into *src*.
+ *             *flags* is currently unused.
  *     Return
  *             0 on success, -E2BIG if *offset* + *len* exceeds the length
- *             of *src*'s data, -EINVAL if *src* is an invalid dynptr.
+ *             of *src*'s data, -EINVAL if *src* is an invalid dynptr or if
+ *             *flags* is not 0.
  *
- * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len)
+ * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len, u64 flags)
  *     Description
  *             Write *len* bytes from *src* into *dst*, starting from *offset*
  *             into *dst*.
+ *             *flags* is currently unused.
  *     Return
  *             0 on success, -E2BIG if *offset* + *len* exceeds the length
  *             of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst*
- *             is a read-only dynptr.
+ *             is a read-only dynptr or if *flags* is not 0.
  *
  * void *bpf_dynptr_data(struct bpf_dynptr *ptr, u32 offset, u32 len)
  *     Description
index 5088bd9f1922851fb62ea7562ccbeb6b64eeed02..860f867c50c0e292fa31ac41388ce2bf50dab97e 100644 (file)
@@ -2083,7 +2083,8 @@ struct kvm_stats_header {
 #define KVM_STATS_UNIT_BYTES           (0x1 << KVM_STATS_UNIT_SHIFT)
 #define KVM_STATS_UNIT_SECONDS         (0x2 << KVM_STATS_UNIT_SHIFT)
 #define KVM_STATS_UNIT_CYCLES          (0x3 << KVM_STATS_UNIT_SHIFT)
-#define KVM_STATS_UNIT_MAX             KVM_STATS_UNIT_CYCLES
+#define KVM_STATS_UNIT_BOOLEAN         (0x4 << KVM_STATS_UNIT_SHIFT)
+#define KVM_STATS_UNIT_MAX             KVM_STATS_UNIT_BOOLEAN
 
 #define KVM_STATS_BASE_SHIFT           8
 #define KVM_STATS_BASE_MASK            (0xF << KVM_STATS_BASE_SHIFT)
index 8b990a52aadac1e26ecb33ff97e114ddd789a94f..c260006106be7cfdb62e1c7e541231fdab6bc465 100644 (file)
@@ -787,3 +787,8 @@ bool arch_is_retpoline(struct symbol *sym)
 {
        return !strncmp(sym->name, "__x86_indirect_", 15);
 }
+
+bool arch_is_rethunk(struct symbol *sym)
+{
+       return !strcmp(sym->name, "__x86_return_thunk");
+}
index f4c3a50917379abaa6ccb17d3f578a5cbe1d83f9..24fbe803a0d3206246863bdb59f10bd38704b145 100644 (file)
@@ -68,6 +68,8 @@ const struct option check_options[] = {
        OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"),
        OPT_BOOLEAN('o', "orc", &opts.orc, "generate ORC metadata"),
        OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"),
+       OPT_BOOLEAN(0,   "rethunk", &opts.rethunk, "validate and annotate rethunk usage"),
+       OPT_BOOLEAN(0,   "unret", &opts.unret, "validate entry unret placement"),
        OPT_BOOLEAN('l', "sls", &opts.sls, "validate straight-line-speculation mitigations"),
        OPT_BOOLEAN('s', "stackval", &opts.stackval, "validate frame pointer rules"),
        OPT_BOOLEAN('t', "static-call", &opts.static_call, "annotate static calls"),
@@ -123,6 +125,7 @@ static bool opts_valid(void)
            opts.noinstr                ||
            opts.orc                    ||
            opts.retpoline              ||
+           opts.rethunk                ||
            opts.sls                    ||
            opts.stackval               ||
            opts.static_call            ||
@@ -135,6 +138,11 @@ static bool opts_valid(void)
                return true;
        }
 
+       if (opts.unret && !opts.rethunk) {
+               ERROR("--unret requires --rethunk");
+               return false;
+       }
+
        if (opts.dump_orc)
                return true;
 
@@ -163,6 +171,11 @@ static bool link_opts_valid(struct objtool_file *file)
                return false;
        }
 
+       if (opts.unret) {
+               ERROR("--unret requires --link");
+               return false;
+       }
+
        return true;
 }
 
index 864bb9dd358452e936e9b3b5f581d212b742a8fe..b341f8a8c7c56d606fc002163fd53fc1ec7f1a91 100644 (file)
@@ -376,7 +376,8 @@ static int decode_instructions(struct objtool_file *file)
                        sec->text = true;
 
                if (!strcmp(sec->name, ".noinstr.text") ||
-                   !strcmp(sec->name, ".entry.text"))
+                   !strcmp(sec->name, ".entry.text") ||
+                   !strncmp(sec->name, ".text.__x86.", 12))
                        sec->noinstr = true;
 
                for (offset = 0; offset < sec->sh.sh_size; offset += insn->len) {
@@ -749,6 +750,52 @@ static int create_retpoline_sites_sections(struct objtool_file *file)
        return 0;
 }
 
+static int create_return_sites_sections(struct objtool_file *file)
+{
+       struct instruction *insn;
+       struct section *sec;
+       int idx;
+
+       sec = find_section_by_name(file->elf, ".return_sites");
+       if (sec) {
+               WARN("file already has .return_sites, skipping");
+               return 0;
+       }
+
+       idx = 0;
+       list_for_each_entry(insn, &file->return_thunk_list, call_node)
+               idx++;
+
+       if (!idx)
+               return 0;
+
+       sec = elf_create_section(file->elf, ".return_sites", 0,
+                                sizeof(int), idx);
+       if (!sec) {
+               WARN("elf_create_section: .return_sites");
+               return -1;
+       }
+
+       idx = 0;
+       list_for_each_entry(insn, &file->return_thunk_list, call_node) {
+
+               int *site = (int *)sec->data->d_buf + idx;
+               *site = 0;
+
+               if (elf_add_reloc_to_insn(file->elf, sec,
+                                         idx * sizeof(int),
+                                         R_X86_64_PC32,
+                                         insn->sec, insn->offset)) {
+                       WARN("elf_add_reloc_to_insn: .return_sites");
+                       return -1;
+               }
+
+               idx++;
+       }
+
+       return 0;
+}
+
 static int create_ibt_endbr_seal_sections(struct objtool_file *file)
 {
        struct instruction *insn;
@@ -1083,6 +1130,11 @@ __weak bool arch_is_retpoline(struct symbol *sym)
        return false;
 }
 
+__weak bool arch_is_rethunk(struct symbol *sym)
+{
+       return false;
+}
+
 #define NEGATIVE_RELOC ((void *)-1L)
 
 static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
@@ -1250,6 +1302,19 @@ static void add_retpoline_call(struct objtool_file *file, struct instruction *in
        annotate_call_site(file, insn, false);
 }
 
+static void add_return_call(struct objtool_file *file, struct instruction *insn, bool add)
+{
+       /*
+        * Return thunk tail calls are really just returns in disguise,
+        * so convert them accordingly.
+        */
+       insn->type = INSN_RETURN;
+       insn->retpoline_safe = true;
+
+       if (add)
+               list_add_tail(&insn->call_node, &file->return_thunk_list);
+}
+
 static bool same_function(struct instruction *insn1, struct instruction *insn2)
 {
        return insn1->func->pfunc == insn2->func->pfunc;
@@ -1302,6 +1367,9 @@ static int add_jump_destinations(struct objtool_file *file)
                } else if (reloc->sym->retpoline_thunk) {
                        add_retpoline_call(file, insn);
                        continue;
+               } else if (reloc->sym->return_thunk) {
+                       add_return_call(file, insn, true);
+                       continue;
                } else if (insn->func) {
                        /*
                         * External sibling call or internal sibling call with
@@ -1320,6 +1388,21 @@ static int add_jump_destinations(struct objtool_file *file)
 
                jump_dest = find_insn(file, dest_sec, dest_off);
                if (!jump_dest) {
+                       struct symbol *sym = find_symbol_by_offset(dest_sec, dest_off);
+
+                       /*
+                        * This is a special case for zen_untrain_ret().
+                        * It jumps to __x86_return_thunk(), but objtool
+                        * can't find the thunk's starting RET
+                        * instruction, because the RET is also in the
+                        * middle of another instruction.  Objtool only
+                        * knows about the outer instruction.
+                        */
+                       if (sym && sym->return_thunk) {
+                               add_return_call(file, insn, false);
+                               continue;
+                       }
+
                        WARN_FUNC("can't find jump dest instruction at %s+0x%lx",
                                  insn->sec, insn->offset, dest_sec->name,
                                  dest_off);
@@ -1949,16 +2032,35 @@ static int read_unwind_hints(struct objtool_file *file)
 
                insn->hint = true;
 
-               if (opts.ibt && hint->type == UNWIND_HINT_TYPE_REGS_PARTIAL) {
+               if (hint->type == UNWIND_HINT_TYPE_SAVE) {
+                       insn->hint = false;
+                       insn->save = true;
+                       continue;
+               }
+
+               if (hint->type == UNWIND_HINT_TYPE_RESTORE) {
+                       insn->restore = true;
+                       continue;
+               }
+
+               if (hint->type == UNWIND_HINT_TYPE_REGS_PARTIAL) {
                        struct symbol *sym = find_symbol_by_offset(insn->sec, insn->offset);
 
-                       if (sym && sym->bind == STB_GLOBAL &&
-                           insn->type != INSN_ENDBR && !insn->noendbr) {
-                               WARN_FUNC("UNWIND_HINT_IRET_REGS without ENDBR",
-                                         insn->sec, insn->offset);
+                       if (sym && sym->bind == STB_GLOBAL) {
+                               if (opts.ibt && insn->type != INSN_ENDBR && !insn->noendbr) {
+                                       WARN_FUNC("UNWIND_HINT_IRET_REGS without ENDBR",
+                                                 insn->sec, insn->offset);
+                               }
+
+                               insn->entry = 1;
                        }
                }
 
+               if (hint->type == UNWIND_HINT_TYPE_ENTRY) {
+                       hint->type = UNWIND_HINT_TYPE_CALL;
+                       insn->entry = 1;
+               }
+
                if (hint->type == UNWIND_HINT_TYPE_FUNC) {
                        insn->cfi = &func_cfi;
                        continue;
@@ -2032,8 +2134,10 @@ static int read_retpoline_hints(struct objtool_file *file)
                }
 
                if (insn->type != INSN_JUMP_DYNAMIC &&
-                   insn->type != INSN_CALL_DYNAMIC) {
-                       WARN_FUNC("retpoline_safe hint not an indirect jump/call",
+                   insn->type != INSN_CALL_DYNAMIC &&
+                   insn->type != INSN_RETURN &&
+                   insn->type != INSN_NOP) {
+                       WARN_FUNC("retpoline_safe hint not an indirect jump/call/ret/nop",
                                  insn->sec, insn->offset);
                        return -1;
                }
@@ -2184,6 +2288,9 @@ static int classify_symbols(struct objtool_file *file)
                        if (arch_is_retpoline(func))
                                func->retpoline_thunk = true;
 
+                       if (arch_is_rethunk(func))
+                               func->return_thunk = true;
+
                        if (!strcmp(func->name, "__fentry__"))
                                func->fentry = true;
 
@@ -3218,8 +3325,8 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
                        return 1;
                }
 
-               visited = 1 << state.uaccess;
-               if (insn->visited) {
+               visited = VISITED_BRANCH << state.uaccess;
+               if (insn->visited & VISITED_BRANCH_MASK) {
                        if (!insn->hint && !insn_cfi_match(insn, &state.cfi))
                                return 1;
 
@@ -3233,6 +3340,35 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
                        state.instr += insn->instr;
 
                if (insn->hint) {
+                       if (insn->restore) {
+                               struct instruction *save_insn, *i;
+
+                               i = insn;
+                               save_insn = NULL;
+
+                               sym_for_each_insn_continue_reverse(file, func, i) {
+                                       if (i->save) {
+                                               save_insn = i;
+                                               break;
+                                       }
+                               }
+
+                               if (!save_insn) {
+                                       WARN_FUNC("no corresponding CFI save for CFI restore",
+                                                 sec, insn->offset);
+                                       return 1;
+                               }
+
+                               if (!save_insn->visited) {
+                                       WARN_FUNC("objtool isn't smart enough to handle this CFI save/restore combo",
+                                                 sec, insn->offset);
+                                       return 1;
+                               }
+
+                               insn->cfi = save_insn->cfi;
+                               nr_cfi_reused++;
+                       }
+
                        state.cfi = *insn->cfi;
                } else {
                        /* XXX track if we actually changed state.cfi */
@@ -3433,6 +3569,145 @@ static int validate_unwind_hints(struct objtool_file *file, struct section *sec)
        return warnings;
 }
 
+/*
+ * Validate rethunk entry constraint: must untrain RET before the first RET.
+ *
+ * Follow every branch (intra-function) and ensure ANNOTATE_UNRET_END comes
+ * before an actual RET instruction.
+ */
+static int validate_entry(struct objtool_file *file, struct instruction *insn)
+{
+       struct instruction *next, *dest;
+       int ret, warnings = 0;
+
+       for (;;) {
+               next = next_insn_to_validate(file, insn);
+
+               if (insn->visited & VISITED_ENTRY)
+                       return 0;
+
+               insn->visited |= VISITED_ENTRY;
+
+               if (!insn->ignore_alts && !list_empty(&insn->alts)) {
+                       struct alternative *alt;
+                       bool skip_orig = false;
+
+                       list_for_each_entry(alt, &insn->alts, list) {
+                               if (alt->skip_orig)
+                                       skip_orig = true;
+
+                               ret = validate_entry(file, alt->insn);
+                               if (ret) {
+                                       if (opts.backtrace)
+                                               BT_FUNC("(alt)", insn);
+                                       return ret;
+                               }
+                       }
+
+                       if (skip_orig)
+                               return 0;
+               }
+
+               switch (insn->type) {
+
+               case INSN_CALL_DYNAMIC:
+               case INSN_JUMP_DYNAMIC:
+               case INSN_JUMP_DYNAMIC_CONDITIONAL:
+                       WARN_FUNC("early indirect call", insn->sec, insn->offset);
+                       return 1;
+
+               case INSN_JUMP_UNCONDITIONAL:
+               case INSN_JUMP_CONDITIONAL:
+                       if (!is_sibling_call(insn)) {
+                               if (!insn->jump_dest) {
+                                       WARN_FUNC("unresolved jump target after linking?!?",
+                                                 insn->sec, insn->offset);
+                                       return -1;
+                               }
+                               ret = validate_entry(file, insn->jump_dest);
+                               if (ret) {
+                                       if (opts.backtrace) {
+                                               BT_FUNC("(branch%s)", insn,
+                                                       insn->type == INSN_JUMP_CONDITIONAL ? "-cond" : "");
+                                       }
+                                       return ret;
+                               }
+
+                               if (insn->type == INSN_JUMP_UNCONDITIONAL)
+                                       return 0;
+
+                               break;
+                       }
+
+                       /* fallthrough */
+               case INSN_CALL:
+                       dest = find_insn(file, insn->call_dest->sec,
+                                        insn->call_dest->offset);
+                       if (!dest) {
+                               WARN("Unresolved function after linking!?: %s",
+                                    insn->call_dest->name);
+                               return -1;
+                       }
+
+                       ret = validate_entry(file, dest);
+                       if (ret) {
+                               if (opts.backtrace)
+                                       BT_FUNC("(call)", insn);
+                               return ret;
+                       }
+                       /*
+                        * If a call returns without error, it must have seen UNTRAIN_RET.
+                        * Therefore any non-error return is a success.
+                        */
+                       return 0;
+
+               case INSN_RETURN:
+                       WARN_FUNC("RET before UNTRAIN", insn->sec, insn->offset);
+                       return 1;
+
+               case INSN_NOP:
+                       if (insn->retpoline_safe)
+                               return 0;
+                       break;
+
+               default:
+                       break;
+               }
+
+               if (!next) {
+                       WARN_FUNC("teh end!", insn->sec, insn->offset);
+                       return -1;
+               }
+               insn = next;
+       }
+
+       return warnings;
+}
+
+/*
+ * Validate that all branches starting at 'insn->entry' encounter UNRET_END
+ * before RET.
+ */
+static int validate_unret(struct objtool_file *file)
+{
+       struct instruction *insn;
+       int ret, warnings = 0;
+
+       for_each_insn(file, insn) {
+               if (!insn->entry)
+                       continue;
+
+               ret = validate_entry(file, insn);
+               if (ret < 0) {
+                       WARN_FUNC("Failed UNRET validation", insn->sec, insn->offset);
+                       return ret;
+               }
+               warnings += ret;
+       }
+
+       return warnings;
+}
+
 static int validate_retpoline(struct objtool_file *file)
 {
        struct instruction *insn;
@@ -3440,7 +3715,8 @@ static int validate_retpoline(struct objtool_file *file)
 
        for_each_insn(file, insn) {
                if (insn->type != INSN_JUMP_DYNAMIC &&
-                   insn->type != INSN_CALL_DYNAMIC)
+                   insn->type != INSN_CALL_DYNAMIC &&
+                   insn->type != INSN_RETURN)
                        continue;
 
                if (insn->retpoline_safe)
@@ -3455,9 +3731,17 @@ static int validate_retpoline(struct objtool_file *file)
                if (!strcmp(insn->sec->name, ".init.text") && !opts.module)
                        continue;
 
-               WARN_FUNC("indirect %s found in RETPOLINE build",
-                         insn->sec, insn->offset,
-                         insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call");
+               if (insn->type == INSN_RETURN) {
+                       if (opts.rethunk) {
+                               WARN_FUNC("'naked' return found in RETHUNK build",
+                                         insn->sec, insn->offset);
+                       } else
+                               continue;
+               } else {
+                       WARN_FUNC("indirect %s found in RETPOLINE build",
+                                 insn->sec, insn->offset,
+                                 insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call");
+               }
 
                warnings++;
        }
@@ -3826,8 +4110,7 @@ static int validate_ibt(struct objtool_file *file)
                    !strcmp(sec->name, "__bug_table")                   ||
                    !strcmp(sec->name, "__ex_table")                    ||
                    !strcmp(sec->name, "__jump_table")                  ||
-                   !strcmp(sec->name, "__mcount_loc")                  ||
-                   !strcmp(sec->name, "__tracepoints"))
+                   !strcmp(sec->name, "__mcount_loc"))
                        continue;
 
                list_for_each_entry(reloc, &sec->reloc->reloc_list, list)
@@ -3946,6 +4229,17 @@ int check(struct objtool_file *file)
                warnings += ret;
        }
 
+       if (opts.unret) {
+               /*
+                * Must be after validate_branch() and friends, it plays
+                * further games with insn->visited.
+                */
+               ret = validate_unret(file);
+               if (ret < 0)
+                       return ret;
+               warnings += ret;
+       }
+
        if (opts.ibt) {
                ret = validate_ibt(file);
                if (ret < 0)
@@ -3974,6 +4268,13 @@ int check(struct objtool_file *file)
                warnings += ret;
        }
 
+       if (opts.rethunk) {
+               ret = create_return_sites_sections(file);
+               if (ret < 0)
+                       goto out;
+               warnings += ret;
+       }
+
        if (opts.mcount) {
                ret = create_mcount_loc_sections(file);
                if (ret < 0)
index 9b19cc3041955bab4375a280e8d209b5e1054d42..beb2f3aa94ffc0960aed21802e9548a669f561fe 100644 (file)
@@ -89,6 +89,7 @@ const char *arch_ret_insn(int len);
 int arch_decode_hint_reg(u8 sp_reg, int *base);
 
 bool arch_is_retpoline(struct symbol *sym);
+bool arch_is_rethunk(struct symbol *sym);
 
 int arch_rewrite_retpolines(struct objtool_file *file);
 
index 280ea18b7f2b9efde38cf0c070130dfc4a1f45bb..42a52f1a0add54affe6378618659e767c23ab2b1 100644 (file)
@@ -19,6 +19,8 @@ struct opts {
        bool noinstr;
        bool orc;
        bool retpoline;
+       bool rethunk;
+       bool unret;
        bool sls;
        bool stackval;
        bool static_call;
index f10d7374f388afb325e4c00d68a6e392dafa2ce1..036129cebeeefae3205e545ef837ae359cdc027e 100644 (file)
@@ -46,16 +46,19 @@ struct instruction {
        enum insn_type type;
        unsigned long immediate;
 
-       u8 dead_end     : 1,
-          ignore       : 1,
-          ignore_alts  : 1,
-          hint         : 1,
-          retpoline_safe : 1,
-          noendbr      : 1;
-               /* 2 bit hole */
+       u16 dead_end            : 1,
+          ignore               : 1,
+          ignore_alts          : 1,
+          hint                 : 1,
+          save                 : 1,
+          restore              : 1,
+          retpoline_safe       : 1,
+          noendbr              : 1,
+          entry                : 1;
+               /* 7 bit hole */
+
        s8 instr;
        u8 visited;
-       /* u8 hole */
 
        struct alt_group *alt_group;
        struct symbol *call_dest;
@@ -69,6 +72,11 @@ struct instruction {
        struct cfi_state *cfi;
 };
 
+#define VISITED_BRANCH         0x01
+#define VISITED_BRANCH_UACCESS 0x02
+#define VISITED_BRANCH_MASK    0x03
+#define VISITED_ENTRY          0x04
+
 static inline bool is_static_jump(struct instruction *insn)
 {
        return insn->type == INSN_JUMP_CONDITIONAL ||
index adebfbc2b51834b80daf01fac7b447e846f16e1e..16f4067b82aea5f44c85c7a67b9526458e34275c 100644 (file)
@@ -57,6 +57,7 @@ struct symbol {
        u8 uaccess_safe      : 1;
        u8 static_call_tramp : 1;
        u8 retpoline_thunk   : 1;
+       u8 return_thunk      : 1;
        u8 fentry            : 1;
        u8 profiling_func    : 1;
        struct list_head pv_target;
index a6e72d916807d4e7e18f6c1b915a78afeab84cdc..7f2d1b09533335b7526007d981b44c70c4d7f11f 100644 (file)
@@ -24,6 +24,7 @@ struct objtool_file {
        struct list_head insn_list;
        DECLARE_HASHTABLE(insn_hash, 20);
        struct list_head retpoline_call_list;
+       struct list_head return_thunk_list;
        struct list_head static_call_list;
        struct list_head mcount_loc_list;
        struct list_head endbr_list;
index 512669ce064c807b7bede63498f0871664434de0..a7ecc32e35125d49fae642d9d57c104620a625bb 100644 (file)
@@ -102,6 +102,7 @@ struct objtool_file *objtool_open_read(const char *_objname)
        INIT_LIST_HEAD(&file.insn_list);
        hash_init(file.insn_hash);
        INIT_LIST_HEAD(&file.retpoline_call_list);
+       INIT_LIST_HEAD(&file.return_thunk_list);
        INIT_LIST_HEAD(&file.static_call_list);
        INIT_LIST_HEAD(&file.mcount_loc_list);
        INIT_LIST_HEAD(&file.endbr_list);
index 897fc504918b9120ded4cefd33c371f5e51c90fe..f075cf37a65ef8b00aa03396b7308664a29ea361 100644 (file)
@@ -4280,6 +4280,7 @@ static int trace__replay(struct trace *trace)
                goto out;
 
        evsel = evlist__find_tracepoint_by_name(session->evlist, "raw_syscalls:sys_enter");
+       trace->syscalls.events.sys_enter = evsel;
        /* older kernels have syscalls tp versus raw_syscalls */
        if (evsel == NULL)
                evsel = evlist__find_tracepoint_by_name(session->evlist, "syscalls:sys_enter");
@@ -4292,6 +4293,7 @@ static int trace__replay(struct trace *trace)
        }
 
        evsel = evlist__find_tracepoint_by_name(session->evlist, "raw_syscalls:sys_exit");
+       trace->syscalls.events.sys_exit = evsel;
        if (evsel == NULL)
                evsel = evlist__find_tracepoint_by_name(session->evlist, "syscalls:sys_exit");
        if (evsel &&
index 4ad0dfbc8b21fda12f5c6468b8fdd1095efa73f3..7c7d20fc503adbc98ff42c7ab6124f0a030c72cd 100644 (file)
@@ -20,8 +20,6 @@
 #include "tsc.h"
 #include "mmap.h"
 #include "tests.h"
-#include "pmu.h"
-#include "pmu-hybrid.h"
 
 /*
  * Except x86_64/i386 and Arm64, other archs don't support TSC in perf.  Just
@@ -106,28 +104,21 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su
 
        evlist__config(evlist, &opts, NULL);
 
-       evsel = evlist__first(evlist);
-
-       evsel->core.attr.comm = 1;
-       evsel->core.attr.disabled = 1;
-       evsel->core.attr.enable_on_exec = 0;
-
-       /*
-        * For hybrid "cycles:u", it creates two events.
-        * Init the second evsel here.
-        */
-       if (perf_pmu__has_hybrid() && perf_pmu__hybrid_mounted("cpu_atom")) {
-               evsel = evsel__next(evsel);
+       /* For hybrid "cycles:u", it creates two events */
+       evlist__for_each_entry(evlist, evsel) {
                evsel->core.attr.comm = 1;
                evsel->core.attr.disabled = 1;
                evsel->core.attr.enable_on_exec = 0;
        }
 
-       if (evlist__open(evlist) == -ENOENT) {
-               err = TEST_SKIP;
+       ret = evlist__open(evlist);
+       if (ret < 0) {
+               if (ret == -ENOENT)
+                       err = TEST_SKIP;
+               else
+                       pr_debug("evlist__open() failed\n");
                goto out_err;
        }
-       CHECK__(evlist__open(evlist));
 
        CHECK__(evlist__mmap(evlist, UINT_MAX));
 
@@ -167,10 +158,12 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su
                                goto next_event;
 
                        if (strcmp(event->comm.comm, comm1) == 0) {
+                               CHECK_NOT_NULL__(evsel = evlist__event2evsel(evlist, event));
                                CHECK__(evsel__parse_sample(evsel, event, &sample));
                                comm1_time = sample.time;
                        }
                        if (strcmp(event->comm.comm, comm2) == 0) {
+                               CHECK_NOT_NULL__(evsel = evlist__event2evsel(evlist, event));
                                CHECK__(evsel__parse_sample(evsel, event, &sample));
                                comm2_time = sample.time;
                        }
index da468bd510ca2f182887fde22d8615717f98bb51..e6020c0d59ec31a00ce363d54a2ed9beddf8e031 100644 (file)
@@ -6,7 +6,7 @@
    |_|                    |___/          |_|
 
    pm-graph: suspend/resume/boot timing analysis tools
-    Version: 5.8
+    Version: 5.9
      Author: Todd Brandt <todd.e.brandt@intel.com>
   Home Page: https://01.org/pm-graph
 
@@ -97,8 +97,8 @@
         (kernel/pre-3.15/enable_trace_events_suspend_resume.patch)
         (kernel/pre-3.15/enable_trace_events_device_pm_callback.patch)
 
-       If you're using a kernel older than 3.15.0, the following
-        additional kernel parameters are required:
+       If you're using bootgraph, or sleepgraph with a kernel older than 3.15.0,
+               the following additional kernel parameters are required:
         (e.g. in file /etc/default/grub)
         GRUB_CMDLINE_LINUX_DEFAULT="... initcall_debug log_buf_len=32M ..."
 
index 2823cd3122f7bb325af60d5ea6d6a9528a9ef287..f96f50e0c3365143db71a1efcf153f376abd9415 100755 (executable)
@@ -69,22 +69,24 @@ class SystemValues(aslib.SystemValues):
        bootloader = 'grub'
        blexec = []
        def __init__(self):
-               self.hostname = platform.node()
+               self.kernel, self.hostname = 'unknown', platform.node()
                self.testtime = datetime.now().strftime('%Y-%m-%d_%H:%M:%S')
                if os.path.exists('/proc/version'):
                        fp = open('/proc/version', 'r')
-                       val = fp.read().strip()
+                       self.kernel = self.kernelVersion(fp.read().strip())
                        fp.close()
-                       self.kernel = self.kernelVersion(val)
-               else:
-                       self.kernel = 'unknown'
                self.testdir = datetime.now().strftime('boot-%y%m%d-%H%M%S')
        def kernelVersion(self, msg):
-               return msg.split()[2]
+               m = re.match('^[Ll]inux *[Vv]ersion *(?P<v>\S*) .*', msg)
+               if m:
+                       return m.group('v')
+               return 'unknown'
        def checkFtraceKernelVersion(self):
-               val = tuple(map(int, self.kernel.split('-')[0].split('.')))
-               if val >= (4, 10, 0):
-                       return True
+               m = re.match('^(?P<x>[0-9]*)\.(?P<y>[0-9]*)\.(?P<z>[0-9]*).*', self.kernel)
+               if m:
+                       val = tuple(map(int, m.groups()))
+                       if val >= (4, 10, 0):
+                               return True
                return False
        def kernelParams(self):
                cmdline = 'initcall_debug log_buf_len=32M'
index 962e5768681c6bf7878842aa8a2b66582b8c745b..4f80ad7d72755b308bdc4d963f620a9548dcdbb3 100644 (file)
@@ -125,7 +125,7 @@ acpi_suspend_begin:
 suspend_console:
 acpi_pm_prepare:
 syscore_suspend:
-arch_thaw_secondary_cpus_end:
+arch_enable_nonboot_cpus_end:
 syscore_resume:
 acpi_pm_finish:
 resume_console:
index ffd50953a024fbb3c856e24c90b12530247a23ea..33981adcdd687ea1841cda51a5e727d847a96d0e 100755 (executable)
@@ -66,8 +66,13 @@ from threading import Thread
 from subprocess import call, Popen, PIPE
 import base64
 
+debugtiming = False
+mystarttime = time.time()
 def pprint(msg):
-       print(msg)
+       if debugtiming:
+               print('[%09.3f] %s' % (time.time()-mystarttime, msg))
+       else:
+               print(msg)
        sys.stdout.flush()
 
 def ascii(text):
@@ -81,13 +86,14 @@ def ascii(text):
 #       store system values and test parameters
 class SystemValues:
        title = 'SleepGraph'
-       version = '5.8'
+       version = '5.9'
        ansi = False
        rs = 0
        display = ''
        gzip = False
        sync = False
        wifi = False
+       netfix = False
        verbose = False
        testlog = True
        dmesglog = True
@@ -108,6 +114,7 @@ class SystemValues:
        cpucount = 0
        memtotal = 204800
        memfree = 204800
+       osversion = ''
        srgap = 0
        cgexp = False
        testdir = ''
@@ -116,6 +123,7 @@ class SystemValues:
        fpdtpath = '/sys/firmware/acpi/tables/FPDT'
        epath = '/sys/kernel/debug/tracing/events/power/'
        pmdpath = '/sys/power/pm_debug_messages'
+       s0ixpath = '/sys/module/intel_pmc_core/parameters/warn_on_s0ix_failures'
        acpipath='/sys/module/acpi/parameters/debug_level'
        traceevents = [
                'suspend_resume',
@@ -156,6 +164,7 @@ class SystemValues:
        ftop = False
        usetraceevents = False
        usetracemarkers = True
+       useftrace = True
        usekprobes = True
        usedevsrc = False
        useprocmon = False
@@ -279,10 +288,16 @@ class SystemValues:
                'intel_fbdev_set_suspend': {},
        }
        infocmds = [
+               [0, 'sysinfo', 'uname', '-a'],
+               [0, 'cpuinfo', 'head', '-7', '/proc/cpuinfo'],
                [0, 'kparams', 'cat', '/proc/cmdline'],
                [0, 'mcelog', 'mcelog'],
                [0, 'pcidevices', 'lspci', '-tv'],
-               [0, 'usbdevices', 'lsusb', '-t'],
+               [0, 'usbdevices', 'lsusb', '-tv'],
+               [0, 'acpidevices', 'sh', '-c', 'ls -l /sys/bus/acpi/devices/*/physical_node'],
+               [0, 's0ix_require', 'cat', '/sys/kernel/debug/pmc_core/substate_requirements'],
+               [0, 's0ix_debug', 'cat', '/sys/kernel/debug/pmc_core/slp_s0_debug_status'],
+               [1, 's0ix_residency', 'cat', '/sys/kernel/debug/pmc_core/slp_s0_residency_usec'],
                [1, 'interrupts', 'cat', '/proc/interrupts'],
                [1, 'wakeups', 'cat', '/sys/kernel/debug/wakeup_sources'],
                [2, 'gpecounts', 'sh', '-c', 'grep -v invalid /sys/firmware/acpi/interrupts/*'],
@@ -358,8 +373,19 @@ class SystemValues:
                        self.outputResult({'error':msg})
                        sys.exit(1)
                return False
-       def usable(self, file):
-               return (os.path.exists(file) and os.path.getsize(file) > 0)
+       def usable(self, file, ishtml=False):
+               if not os.path.exists(file) or os.path.getsize(file) < 1:
+                       return False
+               if ishtml:
+                       try:
+                               fp = open(file, 'r')
+                               res = fp.read(1000)
+                               fp.close()
+                       except:
+                               return False
+                       if '<html>' not in res:
+                               return False
+               return True
        def getExec(self, cmd):
                try:
                        fp = Popen(['which', cmd], stdout=PIPE, stderr=PIPE).stdout
@@ -413,12 +439,16 @@ class SystemValues:
                r = info['bios-release-date'] if 'bios-release-date' in info else ''
                self.sysstamp = '# sysinfo | man:%s | plat:%s | cpu:%s | bios:%s | biosdate:%s | numcpu:%d | memsz:%d | memfr:%d' % \
                        (m, p, c, b, r, self.cpucount, self.memtotal, self.memfree)
+               if self.osversion:
+                       self.sysstamp += ' | os:%s' % self.osversion
        def printSystemInfo(self, fatal=False):
                self.rootCheck(True)
                out = dmidecode(self.mempath, fatal)
                if len(out) < 1:
                        return
                fmt = '%-24s: %s'
+               if self.osversion:
+                       print(fmt % ('os-version', self.osversion))
                for name in sorted(out):
                        print(fmt % (name, out[name]))
                print(fmt % ('cpucount', ('%d' % self.cpucount)))
@@ -426,20 +456,25 @@ class SystemValues:
                print(fmt % ('memfree', ('%d kB' % self.memfree)))
        def cpuInfo(self):
                self.cpucount = 0
-               fp = open('/proc/cpuinfo', 'r')
-               for line in fp:
-                       if re.match('^processor[ \t]*:[ \t]*[0-9]*', line):
-                               self.cpucount += 1
-               fp.close()
-               fp = open('/proc/meminfo', 'r')
-               for line in fp:
-                       m = re.match('^MemTotal:[ \t]*(?P<sz>[0-9]*) *kB', line)
-                       if m:
-                               self.memtotal = int(m.group('sz'))
-                       m = re.match('^MemFree:[ \t]*(?P<sz>[0-9]*) *kB', line)
-                       if m:
-                               self.memfree = int(m.group('sz'))
-               fp.close()
+               if os.path.exists('/proc/cpuinfo'):
+                       with open('/proc/cpuinfo', 'r') as fp:
+                               for line in fp:
+                                       if re.match('^processor[ \t]*:[ \t]*[0-9]*', line):
+                                               self.cpucount += 1
+               if os.path.exists('/proc/meminfo'):
+                       with open('/proc/meminfo', 'r') as fp:
+                               for line in fp:
+                                       m = re.match('^MemTotal:[ \t]*(?P<sz>[0-9]*) *kB', line)
+                                       if m:
+                                               self.memtotal = int(m.group('sz'))
+                                       m = re.match('^MemFree:[ \t]*(?P<sz>[0-9]*) *kB', line)
+                                       if m:
+                                               self.memfree = int(m.group('sz'))
+               if os.path.exists('/etc/os-release'):
+                       with open('/etc/os-release', 'r') as fp:
+                               for line in fp:
+                                       if line.startswith('PRETTY_NAME='):
+                                               self.osversion = line[12:].strip().replace('"', '')
        def initTestOutput(self, name):
                self.prefix = self.hostname
                v = open('/proc/version', 'r').read().strip()
@@ -698,6 +733,8 @@ class SystemValues:
                        return False
                return True
        def fsetVal(self, val, path):
+               if not self.useftrace:
+                       return False
                return self.setVal(val, self.tpath+path)
        def getVal(self, file):
                res = ''
@@ -711,9 +748,11 @@ class SystemValues:
                        pass
                return res
        def fgetVal(self, path):
+               if not self.useftrace:
+                       return ''
                return self.getVal(self.tpath+path)
        def cleanupFtrace(self):
-               if(self.usecallgraph or self.usetraceevents or self.usedevsrc):
+               if self.useftrace:
                        self.fsetVal('0', 'events/kprobes/enable')
                        self.fsetVal('', 'kprobe_events')
                        self.fsetVal('1024', 'buffer_size_kb')
@@ -734,13 +773,14 @@ class SystemValues:
                                return True
                return False
        def initFtrace(self, quiet=False):
+               if not self.useftrace:
+                       return
                if not quiet:
                        sysvals.printSystemInfo(False)
                        pprint('INITIALIZING FTRACE...')
                # turn trace off
                self.fsetVal('0', 'tracing_on')
                self.cleanupFtrace()
-               self.testVal(self.pmdpath, 'basic', '1')
                # set the trace clock to global
                self.fsetVal('global', 'trace_clock')
                self.fsetVal('nop', 'current_tracer')
@@ -766,6 +806,10 @@ class SystemValues:
                        # set trace type
                        self.fsetVal('function_graph', 'current_tracer')
                        self.fsetVal('', 'set_ftrace_filter')
+                       # temporary hack to fix https://bugzilla.kernel.org/show_bug.cgi?id=212761
+                       fp = open(self.tpath+'set_ftrace_notrace', 'w')
+                       fp.write('native_queued_spin_lock_slowpath\ndev_driver_string')
+                       fp.close()
                        # set trace format options
                        self.fsetVal('print-parent', 'trace_options')
                        self.fsetVal('funcgraph-abstime', 'trace_options')
@@ -846,6 +890,8 @@ class SystemValues:
                                fp.write('# turbostat %s\n' % test['turbo'])
                        if 'wifi' in test:
                                fp.write('# wifi %s\n' % test['wifi'])
+                       if 'netfix' in test:
+                               fp.write('# netfix %s\n' % test['netfix'])
                        if test['error'] or len(testdata) > 1:
                                fp.write('# enter_sleep_error %s\n' % test['error'])
                return fp
@@ -865,6 +911,8 @@ class SystemValues:
                        fp.write('error%s: %s\n' % (n, testdata['error']))
                else:
                        fp.write('result%s: pass\n' % n)
+               if 'mode' in testdata:
+                       fp.write('mode%s: %s\n' % (n, testdata['mode']))
                for v in ['suspend', 'resume', 'boot', 'lastinit']:
                        if v in testdata:
                                fp.write('%s%s: %.3f\n' % (v, n, testdata[v]))
@@ -901,6 +949,8 @@ class SystemValues:
                        fp.write(text)
                        fp.close()
        def dlog(self, text):
+               if not self.dmesgfile:
+                       return
                self.putlog(self.dmesgfile, '# %s\n' % text)
        def flog(self, text):
                self.putlog(self.ftracefile, text)
@@ -954,34 +1004,31 @@ class SystemValues:
                        dirname = props[dev].syspath
                        if not dirname or not os.path.exists(dirname):
                                continue
-                       with open(dirname+'/power/async') as fp:
-                               text = fp.read()
-                               props[dev].isasync = False
-                               if 'enabled' in text:
+                       props[dev].isasync = False
+                       if os.path.exists(dirname+'/power/async'):
+                               fp = open(dirname+'/power/async')
+                               if 'enabled' in fp.read():
                                        props[dev].isasync = True
+                               fp.close()
                        fields = os.listdir(dirname)
-                       if 'product' in fields:
-                               with open(dirname+'/product', 'rb') as fp:
-                                       props[dev].altname = ascii(fp.read())
-                       elif 'name' in fields:
-                               with open(dirname+'/name', 'rb') as fp:
-                                       props[dev].altname = ascii(fp.read())
-                       elif 'model' in fields:
-                               with open(dirname+'/model', 'rb') as fp:
-                                       props[dev].altname = ascii(fp.read())
-                       elif 'description' in fields:
-                               with open(dirname+'/description', 'rb') as fp:
-                                       props[dev].altname = ascii(fp.read())
-                       elif 'id' in fields:
-                               with open(dirname+'/id', 'rb') as fp:
-                                       props[dev].altname = ascii(fp.read())
-                       elif 'idVendor' in fields and 'idProduct' in fields:
-                               idv, idp = '', ''
-                               with open(dirname+'/idVendor', 'rb') as fp:
-                                       idv = ascii(fp.read()).strip()
-                               with open(dirname+'/idProduct', 'rb') as fp:
-                                       idp = ascii(fp.read()).strip()
-                               props[dev].altname = '%s:%s' % (idv, idp)
+                       for file in ['product', 'name', 'model', 'description', 'id', 'idVendor']:
+                               if file not in fields:
+                                       continue
+                               try:
+                                       with open(os.path.join(dirname, file), 'rb') as fp:
+                                               props[dev].altname = ascii(fp.read())
+                               except:
+                                       continue
+                               if file == 'idVendor':
+                                       idv, idp = props[dev].altname.strip(), ''
+                                       try:
+                                               with open(os.path.join(dirname, 'idProduct'), 'rb') as fp:
+                                                       idp = ascii(fp.read()).strip()
+                                       except:
+                                               props[dev].altname = ''
+                                               break
+                                       props[dev].altname = '%s:%s' % (idv, idp)
+                               break
                        if props[dev].altname:
                                out = props[dev].altname.strip().replace('\n', ' ')\
                                        .replace(',', ' ').replace(';', ' ')
@@ -1047,7 +1094,7 @@ class SystemValues:
                                self.cmd1[name] = self.dictify(info, delta)
                        elif not debug and delta and name in self.cmd1:
                                before, after = self.cmd1[name], self.dictify(info, delta)
-                               dinfo = ('\t%s\n' % before['@']) if '@' in before else ''
+                               dinfo = ('\t%s\n' % before['@']) if '@' in before and len(before) > 1 else ''
                                prefix = self.commonPrefix(list(before.keys()))
                                for key in sorted(before):
                                        if key in after and before[key] != after[key]:
@@ -1128,6 +1175,22 @@ class SystemValues:
                        val = valline[idx]
                        out.append('%s=%s' % (key, val))
                return '|'.join(out)
+       def netfixon(self, net='both'):
+               cmd = self.getExec('netfix')
+               if not cmd:
+                       return ''
+               fp = Popen([cmd, '-s', net, 'on'], stdout=PIPE, stderr=PIPE).stdout
+               out = ascii(fp.read()).strip()
+               fp.close()
+               return out
+       def wifiRepair(self):
+               out = self.netfixon('wifi')
+               if not out or 'error' in out.lower():
+                       return ''
+               m = re.match('WIFI \S* ONLINE (?P<action>\S*)', out)
+               if not m:
+                       return 'dead'
+               return m.group('action')
        def wifiDetails(self, dev):
                try:
                        info = open('/sys/class/net/%s/device/uevent' % dev, 'r').read().strip()
@@ -1144,12 +1207,12 @@ class SystemValues:
                except:
                        return ''
                for line in reversed(w.split('\n')):
-                       m = re.match(' *(?P<dev>.*): (?P<stat>[0-9a-f]*) .*', w.split('\n')[-1])
+                       m = re.match(' *(?P<dev>.*): (?P<stat>[0-9a-f]*) .*', line)
                        if not m or (dev and dev != m.group('dev')):
                                continue
                        return m.group('dev')
                return ''
-       def pollWifi(self, dev, timeout=60):
+       def pollWifi(self, dev, timeout=10):
                start = time.time()
                while (time.time() - start) < timeout:
                        w = self.checkWifi(dev)
@@ -1157,6 +1220,11 @@ class SystemValues:
                                return '%s reconnected %.2f' % \
                                        (self.wifiDetails(dev), max(0, time.time() - start))
                        time.sleep(0.01)
+               if self.netfix:
+                       res = self.wifiRepair()
+                       if res:
+                               timeout = max(0, time.time() - start)
+                               return '%s %s %d' % (self.wifiDetails(dev), res, timeout)
                return '%s timeout %d' % (self.wifiDetails(dev), timeout)
        def errorSummary(self, errinfo, msg):
                found = False
@@ -1283,10 +1351,10 @@ sysvals = SystemValues()
 switchvalues = ['enable', 'disable', 'on', 'off', 'true', 'false', '1', '0']
 switchoff = ['disable', 'off', 'false', '0']
 suspendmodename = {
-       'freeze': 'Freeze (S0)',
-       'standby': 'Standby (S1)',
-       'mem': 'Suspend (S3)',
-       'disk': 'Hibernate (S4)'
+       'standby': 'standby (S1)',
+       'freeze': 'freeze (S2idle)',
+       'mem': 'suspend (S3)',
+       'disk': 'hibernate (S4)'
 }
 
 # Class: DevProps
@@ -1376,6 +1444,7 @@ class Data:
                'INVALID' : r'(?i).*\bINVALID\b.*',
                'CRASH'   : r'(?i).*\bCRASHED\b.*',
                'TIMEOUT' : r'(?i).*\bTIMEOUT\b.*',
+               'ABORT'   : r'(?i).*\bABORT\b.*',
                'IRQ'     : r'.*\bgenirq: .*',
                'TASKFAIL': r'.*Freezing of tasks *.*',
                'ACPI'    : r'.*\bACPI *(?P<b>[A-Za-z]*) *Error[: ].*',
@@ -1724,9 +1793,9 @@ class Data:
                                if 'waking' in self.dmesg[lp]:
                                        tCnt = self.dmesg[lp]['waking'][0]
                                        if self.dmesg[lp]['waking'][1] >= 0.001:
-                                               tTry = '-%.0f' % (round(self.dmesg[lp]['waking'][1] * 1000))
+                                               tTry = '%.0f' % (round(self.dmesg[lp]['waking'][1] * 1000))
                                        else:
-                                               tTry = '-%.3f' % (self.dmesg[lp]['waking'][1] * 1000)
+                                               tTry = '%.3f' % (self.dmesg[lp]['waking'][1] * 1000)
                                        text = '%.0f (%s ms waking %d times)' % (tL * 1000, tTry, tCnt)
                                else:
                                        text = '%.0f' % (tL * 1000)
@@ -2107,6 +2176,30 @@ class Data:
                # set resume complete to end at end marker
                if 'resume_complete' in dm:
                        dm['resume_complete']['end'] = time
+       def initcall_debug_call(self, line, quick=False):
+               m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: '+\
+                       'PM: *calling .* @ (?P<n>.*), parent: (?P<p>.*)', line)
+               if not m:
+                       m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: '+\
+                               'calling .* @ (?P<n>.*), parent: (?P<p>.*)', line)
+               if not m:
+                       m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) calling  '+\
+                               '(?P<f>.*)\+ @ (?P<n>.*), parent: (?P<p>.*)', line)
+               if m:
+                       return True if quick else m.group('t', 'f', 'n', 'p')
+               return False if quick else ('', '', '', '')
+       def initcall_debug_return(self, line, quick=False):
+               m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: PM: '+\
+                       '.* returned (?P<r>[0-9]*) after (?P<dt>[0-9]*) usecs', line)
+               if not m:
+                       m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: '+\
+                               '.* returned (?P<r>[0-9]*) after (?P<dt>[0-9]*) usecs', line)
+               if not m:
+                       m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) call '+\
+                               '(?P<f>.*)\+ returned .* after (?P<dt>.*) usecs', line)
+               if m:
+                       return True if quick else m.group('t', 'f', 'dt')
+               return False if quick else ('', '', '')
        def debugPrint(self):
                for p in self.sortedPhases():
                        list = self.dmesg[p]['list']
@@ -2880,10 +2973,11 @@ class TestProps:
        cmdlinefmt = '^# command \| (?P<cmd>.*)'
        kparamsfmt = '^# kparams \| (?P<kp>.*)'
        devpropfmt = '# Device Properties: .*'
-       pinfofmt   = '# platform-(?P<val>[a-z,A-Z,0-9]*): (?P<info>.*)'
+       pinfofmt   = '# platform-(?P<val>[a-z,A-Z,0-9,_]*): (?P<info>.*)'
        tracertypefmt = '# tracer: (?P<t>.*)'
        firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$'
        procexecfmt = 'ps - (?P<ps>.*)$'
+       procmultifmt = '@(?P<n>[0-9]*)\|(?P<ps>.*)$'
        ftrace_line_fmt_fg = \
                '^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)'+\
                ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\|'+\
@@ -2893,6 +2987,9 @@ class TestProps:
                '(?P<flags>\S*) *(?P<time>[0-9\.]*): *'+\
                '(?P<msg>.*)'
        machinesuspend = 'machine_suspend\[.*'
+       multiproclist = dict()
+       multiproctime = 0.0
+       multiproccnt = 0
        def __init__(self):
                self.stamp = ''
                self.sysinfo = ''
@@ -3063,6 +3160,7 @@ class TestRun:
                self.ttemp = dict()
 
 class ProcessMonitor:
+       maxchars = 512
        def __init__(self):
                self.proclist = dict()
                self.running = False
@@ -3088,19 +3186,23 @@ class ProcessMonitor:
                        if ujiff > 0 or kjiff > 0:
                                running[pid] = ujiff + kjiff
                process.wait()
-               out = ''
+               out = ['']
                for pid in running:
                        jiffies = running[pid]
                        val = self.proclist[pid]
-                       if out:
-                               out += ','
-                       out += '%s-%s %d' % (val['name'], pid, jiffies)
-               return 'ps - '+out
+                       if len(out[-1]) > self.maxchars:
+                               out.append('')
+                       elif len(out[-1]) > 0:
+                               out[-1] += ','
+                       out[-1] += '%s-%s %d' % (val['name'], pid, jiffies)
+               if len(out) > 1:
+                       for line in out:
+                               sysvals.fsetVal('ps - @%d|%s' % (len(out), line), 'trace_marker')
+               else:
+                       sysvals.fsetVal('ps - %s' % out[0], 'trace_marker')
        def processMonitor(self, tid):
                while self.running:
-                       out = self.procstat()
-                       if out:
-                               sysvals.fsetVal(out, 'trace_marker')
+                       self.procstat()
        def start(self):
                self.thread = Thread(target=self.processMonitor, args=(0,))
                self.running = True
@@ -3144,7 +3246,6 @@ def doesTraceLogHaveTraceEvents():
 
 # Function: appendIncompleteTraceLog
 # Description:
-#       [deprecated for kernel 3.15 or newer]
 #       Adds callgraph data which lacks trace event data. This is only
 #       for timelines generated from 3.15 or older
 # Arguments:
@@ -3246,6 +3347,61 @@ def appendIncompleteTraceLog(testruns):
                                                                dev['ftrace'] = cg
                                                break
 
+# Function: loadTraceLog
+# Description:
+#       load the ftrace file into memory and fix up any ordering issues
+# Output:
+#       TestProps instance and an array of lines in proper order
+def loadTraceLog():
+       tp, data, lines, trace = TestProps(), dict(), [], []
+       tf = sysvals.openlog(sysvals.ftracefile, 'r')
+       for line in tf:
+               # remove any latent carriage returns
+               line = line.replace('\r\n', '')
+               if tp.stampInfo(line, sysvals):
+                       continue
+               # ignore all other commented lines
+               if line[0] == '#':
+                       continue
+               # ftrace line: parse only valid lines
+               m = re.match(tp.ftrace_line_fmt, line)
+               if(not m):
+                       continue
+               dur = m.group('dur') if tp.cgformat else 'traceevent'
+               info = (m.group('time'), m.group('proc'), m.group('pid'),
+                       m.group('msg'), dur)
+               # group the data by timestamp
+               t = float(info[0])
+               if t in data:
+                       data[t].append(info)
+               else:
+                       data[t] = [info]
+               # we only care about trace event ordering
+               if (info[3].startswith('suspend_resume:') or \
+                       info[3].startswith('tracing_mark_write:')) and t not in trace:
+                               trace.append(t)
+       tf.close()
+       for t in sorted(data):
+               first, last, blk = [], [], data[t]
+               if len(blk) > 1 and t in trace:
+                       # move certain lines to the start or end of a timestamp block
+                       for i in range(len(blk)):
+                               if 'SUSPEND START' in blk[i][3]:
+                                       first.append(i)
+                               elif re.match('.* timekeeping_freeze.*begin', blk[i][3]):
+                                       last.append(i)
+                               elif re.match('.* timekeeping_freeze.*end', blk[i][3]):
+                                       first.append(i)
+                               elif 'RESUME COMPLETE' in blk[i][3]:
+                                       last.append(i)
+                       if len(first) == 1 and len(last) == 0:
+                               blk.insert(0, blk.pop(first[0]))
+                       elif len(last) == 1 and len(first) == 0:
+                               blk.append(blk.pop(last[0]))
+               for info in blk:
+                       lines.append(info)
+       return (tp, lines)
+
 # Function: parseTraceLog
 # Description:
 #       Analyze an ftrace log output file generated from this app during
@@ -3271,32 +3427,12 @@ def parseTraceLog(live=False):
 
        # extract the callgraph and traceevent data
        s2idle_enter = hwsus = False
-       tp = TestProps()
        testruns, testdata = [], []
        testrun, data, limbo = 0, 0, True
-       tf = sysvals.openlog(sysvals.ftracefile, 'r')
        phase = 'suspend_prepare'
-       for line in tf:
-               # remove any latent carriage returns
-               line = line.replace('\r\n', '')
-               if tp.stampInfo(line, sysvals):
-                       continue
-               # ignore all other commented lines
-               if line[0] == '#':
-                       continue
-               # ftrace line: parse only valid lines
-               m = re.match(tp.ftrace_line_fmt, line)
-               if(not m):
-                       continue
+       tp, tf = loadTraceLog()
+       for m_time, m_proc, m_pid, m_msg, m_param3 in tf:
                # gather the basic message data from the line
-               m_time = m.group('time')
-               m_proc = m.group('proc')
-               m_pid = m.group('pid')
-               m_msg = m.group('msg')
-               if(tp.cgformat):
-                       m_param3 = m.group('dur')
-               else:
-                       m_param3 = 'traceevent'
                if(m_time and m_pid and m_msg):
                        t = FTraceLine(m_time, m_msg, m_param3)
                        pid = int(m_pid)
@@ -3322,14 +3458,29 @@ def parseTraceLog(live=False):
                if t.type == 'tracing_mark_write':
                        m = re.match(tp.procexecfmt, t.name)
                        if(m):
-                               proclist = dict()
-                               for ps in m.group('ps').split(','):
+                               parts, msg = 1, m.group('ps')
+                               m = re.match(tp.procmultifmt, msg)
+                               if(m):
+                                       parts, msg = int(m.group('n')), m.group('ps')
+                                       if tp.multiproccnt == 0:
+                                               tp.multiproctime = t.time
+                                               tp.multiproclist = dict()
+                                       proclist = tp.multiproclist
+                                       tp.multiproccnt += 1
+                               else:
+                                       proclist = dict()
+                                       tp.multiproccnt = 0
+                               for ps in msg.split(','):
                                        val = ps.split()
-                                       if not val:
+                                       if not val or len(val) != 2:
                                                continue
                                        name = val[0].replace('--', '-')
                                        proclist[name] = int(val[1])
-                               data.pstl[t.time] = proclist
+                               if parts == 1:
+                                       data.pstl[t.time] = proclist
+                               elif parts == tp.multiproccnt:
+                                       data.pstl[tp.multiproctime] = proclist
+                                       tp.multiproccnt = 0
                                continue
                # find the end of resume
                if(t.endMarker()):
@@ -3545,7 +3696,6 @@ def parseTraceLog(live=False):
                                testrun.ftemp[key].append(FTraceCallGraph(pid, sysvals))
                        if(res == -1):
                                testrun.ftemp[key][-1].addLine(t)
-       tf.close()
        if len(testdata) < 1:
                sysvals.vprint('WARNING: ftrace start marker is missing')
        if data and not data.devicegroups:
@@ -3667,7 +3817,13 @@ def parseTraceLog(live=False):
                        if p not in data.dmesg:
                                if not terr:
                                        ph = p if 'machine' in p else lp
-                                       terr = '%s%s failed in %s phase' % (sysvals.suspendmode, tn, ph)
+                                       if p == 'suspend_machine':
+                                               sm = sysvals.suspendmode
+                                               if sm in suspendmodename:
+                                                       sm = suspendmodename[sm]
+                                               terr = 'test%s did not enter %s power mode' % (tn, sm)
+                                       else:
+                                               terr = '%s%s failed in %s phase' % (sysvals.suspendmode, tn, ph)
                                        pprint('TEST%s FAILED: %s' % (tn, terr))
                                        error.append(terr)
                                        if data.tSuspended == 0:
@@ -3708,9 +3864,7 @@ def parseTraceLog(live=False):
 
 # Function: loadKernelLog
 # Description:
-#       [deprecated for kernel 3.15.0 or newer]
 #       load the dmesg file into memory and fix up any ordering issues
-#       The dmesg filename is taken from sysvals
 # Output:
 #       An array of empty Data objects with only their dmesgtext attributes set
 def loadKernelLog():
@@ -3736,7 +3890,8 @@ def loadKernelLog():
                if(not m):
                        continue
                msg = m.group("msg")
-               if(re.match('PM: Syncing filesystems.*', msg)):
+               if re.match('PM: Syncing filesystems.*', msg) or \
+                       re.match('PM: suspend entry.*', msg):
                        if(data):
                                testruns.append(data)
                        data = Data(len(testruns))
@@ -3747,11 +3902,17 @@ def loadKernelLog():
                if(m):
                        sysvals.stamp['kernel'] = m.group('k')
                m = re.match('PM: Preparing system for (?P<m>.*) sleep', msg)
-               if(m):
+               if not m:
+                       m = re.match('PM: Preparing system for sleep \((?P<m>.*)\)', msg)
+               if m:
                        sysvals.stamp['mode'] = sysvals.suspendmode = m.group('m')
                data.dmesgtext.append(line)
        lf.close()
 
+       if sysvals.suspendmode == 's2idle':
+               sysvals.suspendmode = 'freeze'
+       elif sysvals.suspendmode == 'deep':
+               sysvals.suspendmode = 'mem'
        if data:
                testruns.append(data)
        if len(testruns) < 1:
@@ -3762,12 +3923,9 @@ def loadKernelLog():
        for data in testruns:
                last = ''
                for line in data.dmesgtext:
-                       mc = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) calling  '+\
-                               '(?P<f>.*)\+ @ .*, parent: .*', line)
-                       mr = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) call '+\
-                               '(?P<f>.*)\+ returned .* after (?P<dt>.*) usecs', last)
-                       if(mc and mr and (mc.group('t') == mr.group('t')) and
-                               (mc.group('f') == mr.group('f'))):
+                       ct, cf, n, p = data.initcall_debug_call(line)
+                       rt, rf, l = data.initcall_debug_return(last)
+                       if ct and rt and ct == rt and cf == rf:
                                i = data.dmesgtext.index(last)
                                j = data.dmesgtext.index(line)
                                data.dmesgtext[i] = line
@@ -3777,7 +3935,6 @@ def loadKernelLog():
 
 # Function: parseKernelLog
 # Description:
-#       [deprecated for kernel 3.15.0 or newer]
 #       Analyse a dmesg log output file generated from this app during
 #       the execution phase. Create a set of device structures in memory
 #       for subsequent formatting in the html output file
@@ -3796,30 +3953,30 @@ def parseKernelLog(data):
 
        # dmesg phase match table
        dm = {
-               'suspend_prepare': ['PM: Syncing filesystems.*'],
-                       'suspend': ['PM: Entering [a-z]* sleep.*', 'Suspending console.*'],
-                  'suspend_late': ['PM: suspend of devices complete after.*'],
-                 'suspend_noirq': ['PM: late suspend of devices complete after.*'],
-               'suspend_machine': ['PM: noirq suspend of devices complete after.*'],
-                'resume_machine': ['ACPI: Low-level resume complete.*'],
-                  'resume_noirq': ['ACPI: Waking up from system sleep state.*'],
-                  'resume_early': ['PM: noirq resume of devices complete after.*'],
-                        'resume': ['PM: early resume of devices complete after.*'],
-               'resume_complete': ['PM: resume of devices complete after.*'],
+               'suspend_prepare': ['PM: Syncing filesystems.*', 'PM: suspend entry.*'],
+                       'suspend': ['PM: Entering [a-z]* sleep.*', 'Suspending console.*',
+                                   'PM: Suspending system .*'],
+                  'suspend_late': ['PM: suspend of devices complete after.*',
+                                                       'PM: freeze of devices complete after.*'],
+                 'suspend_noirq': ['PM: late suspend of devices complete after.*',
+                                                       'PM: late freeze of devices complete after.*'],
+               'suspend_machine': ['PM: suspend-to-idle',
+                                                       'PM: noirq suspend of devices complete after.*',
+                                                       'PM: noirq freeze of devices complete after.*'],
+                'resume_machine': ['PM: Timekeeping suspended for.*',
+                                                       'ACPI: Low-level resume complete.*',
+                                                       'ACPI: resume from mwait',
+                                                       'Suspended for [0-9\.]* seconds'],
+                  'resume_noirq': ['PM: resume from suspend-to-idle',
+                                                       'ACPI: Waking up from system sleep state.*'],
+                  'resume_early': ['PM: noirq resume of devices complete after.*',
+                                                       'PM: noirq restore of devices complete after.*'],
+                        'resume': ['PM: early resume of devices complete after.*',
+                                                       'PM: early restore of devices complete after.*'],
+               'resume_complete': ['PM: resume of devices complete after.*',
+                                                       'PM: restore of devices complete after.*'],
                    'post_resume': ['.*Restarting tasks \.\.\..*'],
        }
-       if(sysvals.suspendmode == 'standby'):
-               dm['resume_machine'] = ['PM: Restoring platform NVS memory']
-       elif(sysvals.suspendmode == 'disk'):
-               dm['suspend_late'] = ['PM: freeze of devices complete after.*']
-               dm['suspend_noirq'] = ['PM: late freeze of devices complete after.*']
-               dm['suspend_machine'] = ['PM: noirq freeze of devices complete after.*']
-               dm['resume_machine'] = ['PM: Restoring platform NVS memory']
-               dm['resume_early'] = ['PM: noirq restore of devices complete after.*']
-               dm['resume'] = ['PM: early restore of devices complete after.*']
-               dm['resume_complete'] = ['PM: restore of devices complete after.*']
-       elif(sysvals.suspendmode == 'freeze'):
-               dm['resume_machine'] = ['ACPI: resume from mwait']
 
        # action table (expected events that occur and show up in dmesg)
        at = {
@@ -3867,12 +4024,13 @@ def parseKernelLog(data):
                        for s in dm[p]:
                                if(re.match(s, msg)):
                                        phasechange, phase = True, p
+                                       dm[p] = [s]
                                        break
 
                # hack for determining resume_machine end for freeze
                if(not sysvals.usetraceevents and sysvals.suspendmode == 'freeze' \
                        and phase == 'resume_machine' and \
-                       re.match('calling  (?P<f>.*)\+ @ .*, parent: .*', msg)):
+                       data.initcall_debug_call(line, True)):
                        data.setPhase(phase, ktime, False)
                        phase = 'resume_noirq'
                        data.setPhase(phase, ktime, True)
@@ -3945,26 +4103,18 @@ def parseKernelLog(data):
                # -- device callbacks --
                if(phase in data.sortedPhases()):
                        # device init call
-                       if(re.match('calling  (?P<f>.*)\+ @ .*, parent: .*', msg)):
-                               sm = re.match('calling  (?P<f>.*)\+ @ '+\
-                                       '(?P<n>.*), parent: (?P<p>.*)', msg);
-                               f = sm.group('f')
-                               n = sm.group('n')
-                               p = sm.group('p')
-                               if(f and n and p):
-                                       data.newAction(phase, f, int(n), p, ktime, -1, '')
-                       # device init return
-                       elif(re.match('call (?P<f>.*)\+ returned .* after '+\
-                               '(?P<t>.*) usecs', msg)):
-                               sm = re.match('call (?P<f>.*)\+ returned .* after '+\
-                                       '(?P<t>.*) usecs(?P<a>.*)', msg);
-                               f = sm.group('f')
-                               t = sm.group('t')
-                               list = data.dmesg[phase]['list']
-                               if(f in list):
-                                       dev = list[f]
-                                       dev['length'] = int(t)
-                                       dev['end'] = ktime
+                       t, f, n, p = data.initcall_debug_call(line)
+                       if t and f and n and p:
+                               data.newAction(phase, f, int(n), p, ktime, -1, '')
+                       else:
+                               # device init return
+                               t, f, l = data.initcall_debug_return(line)
+                               if t and f and l:
+                                       list = data.dmesg[phase]['list']
+                                       if(f in list):
+                                               dev = list[f]
+                                               dev['length'] = int(l)
+                                               dev['end'] = ktime
 
                # if trace events are not available, these are better than nothing
                if(not sysvals.usetraceevents):
@@ -4006,6 +4156,8 @@ def parseKernelLog(data):
        # fill in any missing phases
        phasedef = data.phasedef
        terr, lp = '', 'suspend_prepare'
+       if lp not in data.dmesg:
+               doError('dmesg log format has changed, could not find start of suspend')
        for p in sorted(phasedef, key=lambda k:phasedef[k]['order']):
                if p not in data.dmesg:
                        if not terr:
@@ -5302,7 +5454,7 @@ def executeSuspend(quiet=False):
        sv.dlog('read dmesg')
        sv.initdmesg()
        # start ftrace
-       if(sv.usecallgraph or sv.usetraceevents):
+       if sv.useftrace:
                if not quiet:
                        pprint('START TRACING')
                sv.dlog('start ftrace tracing')
@@ -5334,8 +5486,7 @@ def executeSuspend(quiet=False):
                        sv.dlog('enable RTC wake alarm')
                        sv.rtcWakeAlarmOn()
                # start of suspend trace marker
-               if(sv.usecallgraph or sv.usetraceevents):
-                       sv.fsetVal(datetime.now().strftime(sv.tmstart), 'trace_marker')
+               sv.fsetVal(datetime.now().strftime(sv.tmstart), 'trace_marker')
                # predelay delay
                if(count == 1 and sv.predelay > 0):
                        sv.fsetVal('WAIT %d' % sv.predelay, 'trace_marker')
@@ -5384,11 +5535,17 @@ def executeSuspend(quiet=False):
                        sv.fsetVal('WAIT END', 'trace_marker')
                # return from suspend
                pprint('RESUME COMPLETE')
-               if(sv.usecallgraph or sv.usetraceevents):
-                       sv.fsetVal(datetime.now().strftime(sv.tmend), 'trace_marker')
+               sv.fsetVal(datetime.now().strftime(sv.tmend), 'trace_marker')
                if sv.wifi and wifi:
                        tdata['wifi'] = sv.pollWifi(wifi)
                        sv.dlog('wifi check, %s' % tdata['wifi'])
+                       if sv.netfix:
+                               netfixout = sv.netfixon('wired')
+               elif sv.netfix:
+                       netfixout = sv.netfixon()
+               if sv.netfix and netfixout:
+                       tdata['netfix'] = netfixout
+                       sv.dlog('netfix, %s' % tdata['netfix'])
                if(sv.suspendmode == 'mem' or sv.suspendmode == 'command'):
                        sv.dlog('read the ACPI FPDT')
                        tdata['fw'] = getFPDT(False)
@@ -5396,7 +5553,7 @@ def executeSuspend(quiet=False):
        sv.dlog('run the cmdinfo list after')
        cmdafter = sv.cmdinfo(False)
        # stop ftrace
-       if(sv.usecallgraph or sv.usetraceevents):
+       if sv.useftrace:
                if sv.useprocmon:
                        sv.dlog('stop the process monitor')
                        pm.stop()
@@ -5407,7 +5564,7 @@ def executeSuspend(quiet=False):
        sysvals.dlog('EXECUTION TRACE END')
        sv.getdmesg(testdata)
        # grab a copy of the ftrace output
-       if(sv.usecallgraph or sv.usetraceevents):
+       if sv.useftrace:
                if not quiet:
                        pprint('CAPTURING TRACE')
                op = sv.writeDatafileHeader(sv.ftracefile, testdata)
@@ -5838,13 +5995,19 @@ def statusCheck(probecheck=False):
                        pprint('      please choose one with -m')
 
        # check if ftrace is available
-       res = sysvals.colorText('NO')
-       ftgood = sysvals.verifyFtrace()
-       if(ftgood):
-               res = 'YES'
-       elif(sysvals.usecallgraph):
-               status = 'ftrace is not properly supported'
-       pprint('    is ftrace supported: %s' % res)
+       if sysvals.useftrace:
+               res = sysvals.colorText('NO')
+               sysvals.useftrace = sysvals.verifyFtrace()
+               efmt = '"{0}" uses ftrace, and it is not properly supported'
+               if sysvals.useftrace:
+                       res = 'YES'
+               elif sysvals.usecallgraph:
+                       status = efmt.format('-f')
+               elif sysvals.usedevsrc:
+                       status = efmt.format('-dev')
+               elif sysvals.useprocmon:
+                       status = efmt.format('-proc')
+               pprint('    is ftrace supported: %s' % res)
 
        # check if kprobes are available
        if sysvals.usekprobes:
@@ -5857,8 +6020,8 @@ def statusCheck(probecheck=False):
                pprint('    are kprobes supported: %s' % res)
 
        # what data source are we using
-       res = 'DMESG'
-       if(ftgood):
+       res = 'DMESG (very limited, ftrace is preferred)'
+       if sysvals.useftrace:
                sysvals.usetraceevents = True
                for e in sysvals.traceevents:
                        if not os.path.exists(sysvals.epath+e):
@@ -5879,7 +6042,7 @@ def statusCheck(probecheck=False):
        pprint('    optional commands this tool may use for info:')
        no = sysvals.colorText('MISSING')
        yes = sysvals.colorText('FOUND', 32)
-       for c in ['turbostat', 'mcelog', 'lspci', 'lsusb']:
+       for c in ['turbostat', 'mcelog', 'lspci', 'lsusb', 'netfix']:
                if c == 'turbostat':
                        res = yes if sysvals.haveTurbostat() else no
                else:
@@ -5971,7 +6134,7 @@ def processData(live=False, quiet=False):
        if not sysvals.stamp:
                pprint('ERROR: data does not include the expected stamp')
                return (testruns, {'error': 'timeline generation failed'})
-       shown = ['bios', 'biosdate', 'cpu', 'host', 'kernel', 'man', 'memfr',
+       shown = ['os', 'bios', 'biosdate', 'cpu', 'host', 'kernel', 'man', 'memfr',
                        'memsz', 'mode', 'numcpu', 'plat', 'time', 'wifi']
        sysvals.vprint('System Info:')
        for key in sorted(sysvals.stamp):
@@ -6052,6 +6215,8 @@ def runTest(n=0, quiet=False):
                if sysvals.display:
                        ret = sysvals.displayControl('init')
                        sysvals.dlog('xset display init, ret = %d' % ret)
+       sysvals.testVal(sysvals.pmdpath, 'basic', '1')
+       sysvals.testVal(sysvals.s0ixpath, 'basic', 'Y')
        sysvals.dlog('initialize ftrace')
        sysvals.initFtrace(quiet)
 
@@ -6145,9 +6310,12 @@ def data_from_html(file, outpath, issues, fulldetail=False):
                                elist[err[0]] += 1
                for i in elist:
                        ilist.append('%sx%d' % (i, elist[i]) if elist[i] > 1 else i)
-       wifi = find_in_html(html, 'Wifi Resume: ', '</td>')
-       if wifi:
-               extra['wifi'] = wifi
+               line = find_in_html(log, '# wifi ', '\n')
+               if line:
+                       extra['wifi'] = line
+               line = find_in_html(log, '# netfix ', '\n')
+               if line:
+                       extra['netfix'] = line
        low = find_in_html(html, 'freeze time: <b>', ' ms</b>')
        for lowstr in ['waking', '+']:
                if not low:
@@ -6243,7 +6411,7 @@ def genHtml(subdir, force=False):
                                        sysvals.ftracefile = file
                sysvals.setOutputFile()
                if (sysvals.dmesgfile or sysvals.ftracefile) and sysvals.htmlfile and \
-                       (force or not sysvals.usable(sysvals.htmlfile)):
+                       (force or not sysvals.usable(sysvals.htmlfile, True)):
                        pprint('FTRACE: %s' % sysvals.ftracefile)
                        if sysvals.dmesgfile:
                                pprint('DMESG : %s' % sysvals.dmesgfile)
@@ -6533,6 +6701,7 @@ def printHelp():
        '   -skiphtml    Run the test and capture the trace logs, but skip the timeline (default: disabled)\n'\
        '   -result fn   Export a results table to a text file for parsing.\n'\
        '   -wifi        If a wifi connection is available, check that it reconnects after resume.\n'\
+       '   -netfix      Use netfix to reset the network in the event it fails to resume.\n'\
        '  [testprep]\n'\
        '   -sync        Sync the filesystems before starting the test\n'\
        '   -rs on/off   Enable/disable runtime suspend for all devices, restore all after test\n'\
@@ -6615,6 +6784,8 @@ if __name__ == '__main__':
                elif(arg == '-v'):
                        pprint("Version %s" % sysvals.version)
                        sys.exit(0)
+               elif(arg == '-debugtiming'):
+                       debugtiming = True
                elif(arg == '-x2'):
                        sysvals.execcount = 2
                elif(arg == '-x2delay'):
@@ -6657,6 +6828,8 @@ if __name__ == '__main__':
                        sysvals.sync = True
                elif(arg == '-wifi'):
                        sysvals.wifi = True
+               elif(arg == '-netfix'):
+                       sysvals.netfix = True
                elif(arg == '-gzip'):
                        sysvals.gzip = True
                elif(arg == '-info'):
@@ -6819,7 +6992,7 @@ if __name__ == '__main__':
                        sysvals.outdir = val
                        sysvals.notestrun = True
                        if(os.path.isdir(val) == False):
-                               doError('%s is not accessible' % val)
+                               doError('%s is not accesible' % val)
                elif(arg == '-filter'):
                        try:
                                val = next(args)
@@ -6942,12 +7115,11 @@ if __name__ == '__main__':
                                time.sleep(sysvals.multitest['delay'])
                        fmt = 'suspend-%y%m%d-%H%M%S'
                        sysvals.testdir = os.path.join(sysvals.outdir, datetime.now().strftime(fmt))
-                       ret = runTest(i+1, True)
+                       ret = runTest(i+1, not sysvals.verbose)
                        failcnt = 0 if not ret else failcnt + 1
                        if sysvals.maxfail > 0 and failcnt >= sysvals.maxfail:
                                pprint('Maximum fail count of %d reached, aborting multitest' % (sysvals.maxfail))
                                break
-                       time.sleep(5)
                        sysvals.resetlog()
                        sysvals.multistat(False, i, finish)
                        if 'time' in sysvals.multitest and datetime.now() >= finish:
index d811cff7359722957a874bf4d5d914e2d2517872..0a26c243e6e9c54604f83a63334cdfcdf092b45f 100644 (file)
@@ -140,12 +140,12 @@ int use_after_invalid(void *ctx)
 
        bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(read_data), 0, &ptr);
 
-       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
+       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
 
        bpf_ringbuf_submit_dynptr(&ptr, 0);
 
        /* this should fail */
-       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
+       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
 
        return 0;
 }
@@ -338,7 +338,7 @@ int invalid_helper2(void *ctx)
        get_map_val_dynptr(&ptr);
 
        /* this should fail */
-       bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 8, 0);
+       bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 8, 0, 0);
 
        return 0;
 }
@@ -377,7 +377,7 @@ int invalid_write2(void *ctx)
        memcpy((void *)&ptr + 8, &x, sizeof(x));
 
        /* this should fail */
-       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
+       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
 
        bpf_ringbuf_submit_dynptr(&ptr, 0);
 
@@ -473,7 +473,7 @@ int invalid_read2(void *ctx)
        get_map_val_dynptr(&ptr);
 
        /* this should fail */
-       bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 1, 0);
+       bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 1, 0, 0);
 
        return 0;
 }
index d67be48df4b2b674037c67dacf5245599d4641b5..a3a6103c8569436dd0336ee2e37b192feb1932dd 100644 (file)
@@ -43,10 +43,10 @@ int test_read_write(void *ctx)
        bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr);
 
        /* Write data into the dynptr */
-       err = err ?: bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data));
+       err = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);
 
        /* Read the data that was written into the dynptr */
-       err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
+       err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
 
        /* Ensure the data we read matches the data we wrote */
        for (i = 0; i < sizeof(read_data); i++) {
index 6ddc418fdfafa84028b94e6ed8b79dba83619e8a..1a27a62105543308c905059b3e0b0b047097f579 100644 (file)
        .result = ACCEPT,
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
+{
+       "jeq32/jne32: bounds checking",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_6, 563),
+       BPF_MOV64_IMM(BPF_REG_2, 0),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
+       BPF_ALU32_REG(BPF_OR, BPF_REG_2, BPF_REG_6),
+       BPF_JMP32_IMM(BPF_JNE, BPF_REG_2, 8, 5),
+       BPF_JMP_IMM(BPF_JSGE, BPF_REG_2, 500, 2),
+       BPF_MOV64_IMM(BPF_REG_0, 2),
+       BPF_EXIT_INSN(),
+       BPF_MOV64_REG(BPF_REG_0, BPF_REG_4),
+       BPF_EXIT_INSN(),
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_EXIT_INSN(),
+       },
+       .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+       .result = ACCEPT,
+       .retval = 1,
+},
index 6f951d1ff0a44b3e02351f139cf64fdd8e648bfd..497fe17d2eaf6a3a47599cde177d4a11c7adf611 100644 (file)
        .result = ACCEPT,
        .retval = 3,
 },
+{
+       "jump & dead code elimination",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_MOV64_IMM(BPF_REG_3, 0),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_3, 0),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_3, 0),
+       BPF_ALU64_IMM(BPF_OR, BPF_REG_3, 32767),
+       BPF_JMP_IMM(BPF_JSGE, BPF_REG_3, 0, 1),
+       BPF_EXIT_INSN(),
+       BPF_JMP_IMM(BPF_JSLE, BPF_REG_3, 0x8000, 1),
+       BPF_EXIT_INSN(),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, -32767),
+       BPF_MOV64_IMM(BPF_REG_0, 2),
+       BPF_JMP_IMM(BPF_JLE, BPF_REG_3, 0, 1),
+       BPF_MOV64_REG(BPF_REG_0, BPF_REG_4),
+       BPF_EXIT_INSN(),
+       },
+       .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+       .result = ACCEPT,
+       .retval = 2,
+},
index 71b3066023685fc3df4f17d727de85f821c4ba3a..616ed40196554eda9fa746b4d536ab220a0f6c52 100644 (file)
@@ -3,6 +3,6 @@
 TEST_PROGS := gpio-mockup.sh gpio-sim.sh
 TEST_FILES := gpio-mockup-sysfs.sh
 TEST_GEN_PROGS_EXTENDED := gpio-mockup-cdev gpio-chip-info gpio-line-name
-CFLAGS += -O2 -g -Wall -I../../../../usr/include/
+CFLAGS += -O2 -g -Wall -I../../../../usr/include/ $(KHDR_INCLUDES)
 
 include ../lib.mk
index 4158da0da2bba8e5e8ea12acd87f6cff6206e3ae..2237d1aac801411bd1b3f3cadb1324d6603c03a8 100644 (file)
@@ -82,8 +82,9 @@ static int next_cpu(int cpu)
        return cpu;
 }
 
-static void *migration_worker(void *ign)
+static void *migration_worker(void *__rseq_tid)
 {
+       pid_t rseq_tid = (pid_t)(unsigned long)__rseq_tid;
        cpu_set_t allowed_mask;
        int r, i, cpu;
 
@@ -106,7 +107,7 @@ static void *migration_worker(void *ign)
                 * stable, i.e. while changing affinity is in-progress.
                 */
                smp_wmb();
-               r = sched_setaffinity(0, sizeof(allowed_mask), &allowed_mask);
+               r = sched_setaffinity(rseq_tid, sizeof(allowed_mask), &allowed_mask);
                TEST_ASSERT(!r, "sched_setaffinity failed, errno = %d (%s)",
                            errno, strerror(errno));
                smp_wmb();
@@ -231,7 +232,8 @@ int main(int argc, char *argv[])
        vm = vm_create_default(VCPU_ID, 0, guest_code);
        ucall_init(vm, NULL);
 
-       pthread_create(&migration_thread, NULL, migration_worker, 0);
+       pthread_create(&migration_thread, NULL, migration_worker,
+                      (void *)(unsigned long)gettid());
 
        for (i = 0; !done; i++) {
                vcpu_run(vm, VCPU_ID);
index a29f796189347e67b4ad20a7fd65e63f5bbfa8a8..ffc35a22e9143eeaca6b7234464f31ec9e0e75b5 100644 (file)
@@ -36,4 +36,5 @@ test_unix_oob
 gro
 ioam6_parser
 toeplitz
+tun
 cmsg_sender
index ddad703ace348f624f7cce131c85a3e193115300..db05b3764b7716d0e4f5d21fe9d1d87759777973 100644 (file)
@@ -11,7 +11,7 @@ TEST_PROGS += udpgso_bench.sh fib_rule_tests.sh msg_zerocopy.sh psock_snd.sh
 TEST_PROGS += udpgro_bench.sh udpgro.sh test_vxlan_under_vrf.sh reuseport_addr_any.sh
 TEST_PROGS += test_vxlan_fdb_changelink.sh so_txtime.sh ipv6_flowlabel.sh
 TEST_PROGS += tcp_fastopen_backup_key.sh fcnal-test.sh l2tp.sh traceroute.sh
-TEST_PROGS += fin_ack_lat.sh fib_nexthop_multiprefix.sh fib_nexthops.sh
+TEST_PROGS += fin_ack_lat.sh fib_nexthop_multiprefix.sh fib_nexthops.sh fib_nexthop_nongw.sh
 TEST_PROGS += altnames.sh icmp.sh icmp_redirect.sh ip6_gre_headroom.sh
 TEST_PROGS += route_localnet.sh
 TEST_PROGS += reuseaddr_ports_exhausted.sh
diff --git a/tools/testing/selftests/net/fib_nexthop_nongw.sh b/tools/testing/selftests/net/fib_nexthop_nongw.sh
new file mode 100755 (executable)
index 0000000..b7b928b
--- /dev/null
@@ -0,0 +1,119 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# ns: h1               | ns: h2
+#   192.168.0.1/24     |
+#            eth0      |
+#                      |       192.168.1.1/32
+#            veth0 <---|---> veth1
+# Validate source address selection for route without gateway
+
+PAUSE_ON_FAIL=no
+VERBOSE=0
+ret=0
+
+################################################################################
+# helpers
+
+log_test()
+{
+       local rc=$1
+       local expected=$2
+       local msg="$3"
+
+       if [ ${rc} -eq ${expected} ]; then
+               printf "TEST: %-60s  [ OK ]\n" "${msg}"
+               nsuccess=$((nsuccess+1))
+       else
+               ret=1
+               nfail=$((nfail+1))
+               printf "TEST: %-60s  [FAIL]\n" "${msg}"
+               if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
+                       echo
+                       echo "hit enter to continue, 'q' to quit"
+                       read a
+                       [ "$a" = "q" ] && exit 1
+               fi
+       fi
+
+       [ "$VERBOSE" = "1" ] && echo
+}
+
+run_cmd()
+{
+       local cmd="$*"
+       local out
+       local rc
+
+       if [ "$VERBOSE" = "1" ]; then
+               echo "COMMAND: $cmd"
+       fi
+
+       out=$(eval $cmd 2>&1)
+       rc=$?
+       if [ "$VERBOSE" = "1" -a -n "$out" ]; then
+               echo "$out"
+       fi
+
+       [ "$VERBOSE" = "1" ] && echo
+
+       return $rc
+}
+
+################################################################################
+# config
+setup()
+{
+       ip netns add h1
+       ip -n h1 link set lo up
+       ip netns add h2
+       ip -n h2 link set lo up
+
+       # Add a fake eth0 to support an ip address
+       ip -n h1 link add name eth0 type dummy
+       ip -n h1 link set eth0 up
+       ip -n h1 address add 192.168.0.1/24 dev eth0
+
+       # Configure veths (same @mac, arp off)
+       ip -n h1 link add name veth0 type veth peer name veth1 netns h2
+       ip -n h1 link set veth0 up
+
+       ip -n h2 link set veth1 up
+
+       # Configure @IP in the peer netns
+       ip -n h2 address add 192.168.1.1/32 dev veth1
+       ip -n h2 route add default dev veth1
+
+       # Add a nexthop without @gw and use it in a route
+       ip -n h1 nexthop add id 1 dev veth0
+       ip -n h1 route add 192.168.1.1 nhid 1
+}
+
+cleanup()
+{
+       ip netns del h1 2>/dev/null
+       ip netns del h2 2>/dev/null
+}
+
+trap cleanup EXIT
+
+################################################################################
+# main
+
+while getopts :pv o
+do
+       case $o in
+               p) PAUSE_ON_FAIL=yes;;
+               v) VERBOSE=1;;
+       esac
+done
+
+cleanup
+setup
+
+run_cmd ip -netns h1 route get 192.168.1.1
+log_test $? 0 "nexthop: get route with nexthop without gw"
+run_cmd ip netns exec h1 ping -c1 192.168.1.1
+log_test $? 0 "nexthop: ping through nexthop without gw"
+
+exit $ret
index 8f481218a4924d7a30dd64ff548b3f34b27fa11c..57b84e0c879e6bf8070f00367de5d2d3746399ca 100644 (file)
@@ -37,6 +37,7 @@ TEST_PROGS = bridge_igmp.sh \
        ipip_hier_gre_key.sh \
        ipip_hier_gre_keys.sh \
        ipip_hier_gre.sh \
+       local_termination.sh \
        loopback.sh \
        mirror_gre_bound.sh \
        mirror_gre_bridge_1d.sh \
@@ -52,6 +53,7 @@ TEST_PROGS = bridge_igmp.sh \
        mirror_gre_vlan_bridge_1q.sh \
        mirror_gre_vlan.sh \
        mirror_vlan.sh \
+       no_forwarding.sh \
        pedit_dsfield.sh \
        pedit_ip.sh \
        pedit_l4port.sh \
index 37ae49d47853686505c5fd6cf5bdbe202e2f8c86..3ffb9d6c09504cc926fada53618922bdce3d4880 100755 (executable)
@@ -1240,6 +1240,7 @@ learning_test()
        # FDB entry was installed.
        bridge link set dev $br_port1 flood off
 
+       ip link set $host1_if promisc on
        tc qdisc add dev $host1_if ingress
        tc filter add dev $host1_if ingress protocol ip pref 1 handle 101 \
                flower dst_mac $mac action drop
@@ -1250,7 +1251,7 @@ learning_test()
        tc -j -s filter show dev $host1_if ingress \
                | jq -e ".[] | select(.options.handle == 101) \
                | select(.options.actions[0].stats.packets == 1)" &> /dev/null
-       check_fail $? "Packet reached second host when should not"
+       check_fail $? "Packet reached first host when should not"
 
        $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
        sleep 1
@@ -1289,6 +1290,7 @@ learning_test()
 
        tc filter del dev $host1_if ingress protocol ip pref 1 handle 101 flower
        tc qdisc del dev $host1_if ingress
+       ip link set $host1_if promisc off
 
        bridge link set dev $br_port1 flood on
 
@@ -1306,6 +1308,7 @@ flood_test_do()
 
        # Add an ACL on `host2_if` which will tell us whether the packet
        # was flooded to it or not.
+       ip link set $host2_if promisc on
        tc qdisc add dev $host2_if ingress
        tc filter add dev $host2_if ingress protocol ip pref 1 handle 101 \
                flower dst_mac $mac action drop
@@ -1323,6 +1326,7 @@ flood_test_do()
 
        tc filter del dev $host2_if ingress protocol ip pref 1 handle 101 flower
        tc qdisc del dev $host2_if ingress
+       ip link set $host2_if promisc off
 
        return $err
 }
index f905d5358e681a78fcc9e7d137278cbb062556d1..48a99e1453e116e11b7dfd0a2449cf8147d1bc6c 100644 (file)
@@ -6,7 +6,7 @@ KSFT_KHDR_INSTALL := 1
 CFLAGS =  -Wall -Wl,--no-as-needed -O2 -g -I$(top_srcdir)/usr/include $(KHDR_INCLUDES)
 
 TEST_PROGS := mptcp_connect.sh pm_netlink.sh mptcp_join.sh diag.sh \
-             simult_flows.sh mptcp_sockopt.sh
+             simult_flows.sh mptcp_sockopt.sh userspace_pm.sh
 
 TEST_GEN_FILES = mptcp_connect pm_nl_ctl mptcp_sockopt mptcp_inq
 
index 6a2f4b981e1d92ca888dfcbad715c00ba396281d..cb79f0719e3b5ece397bb3a2b10897178e321887 100644 (file)
@@ -39,7 +39,7 @@ static void syntax(char *argv[])
        fprintf(stderr, "\tdsf lip <local-ip> lport <local-port> rip <remote-ip> rport <remote-port> token <token>\n");
        fprintf(stderr, "\tdel <id> [<ip>]\n");
        fprintf(stderr, "\tget <id>\n");
-       fprintf(stderr, "\tset [<ip>] [id <nr>] flags [no]backup|[no]fullmesh [port <nr>]\n");
+       fprintf(stderr, "\tset [<ip>] [id <nr>] flags [no]backup|[no]fullmesh [port <nr>] [token <token>] [rip <ip>] [rport <port>]\n");
        fprintf(stderr, "\tflush\n");
        fprintf(stderr, "\tdump\n");
        fprintf(stderr, "\tlimits [<rcv addr max> <subflow max>]\n");
@@ -1279,7 +1279,10 @@ int set_flags(int fd, int pm_family, int argc, char *argv[])
        struct rtattr *rta, *nest;
        struct nlmsghdr *nh;
        u_int32_t flags = 0;
+       u_int32_t token = 0;
+       u_int16_t rport = 0;
        u_int16_t family;
+       void *rip = NULL;
        int nest_start;
        int use_id = 0;
        u_int8_t id;
@@ -1339,7 +1342,13 @@ int set_flags(int fd, int pm_family, int argc, char *argv[])
                error(1, 0, " missing flags keyword");
 
        for (; arg < argc; arg++) {
-               if (!strcmp(argv[arg], "flags")) {
+               if (!strcmp(argv[arg], "token")) {
+                       if (++arg >= argc)
+                               error(1, 0, " missing token value");
+
+                       /* token */
+                       token = atoi(argv[arg]);
+               } else if (!strcmp(argv[arg], "flags")) {
                        char *tok, *str;
 
                        /* flags */
@@ -1378,12 +1387,72 @@ int set_flags(int fd, int pm_family, int argc, char *argv[])
                        rta->rta_len = RTA_LENGTH(2);
                        memcpy(RTA_DATA(rta), &port, 2);
                        off += NLMSG_ALIGN(rta->rta_len);
+               } else if (!strcmp(argv[arg], "rport")) {
+                       if (++arg >= argc)
+                               error(1, 0, " missing remote port");
+
+                       rport = atoi(argv[arg]);
+               } else if (!strcmp(argv[arg], "rip")) {
+                       if (++arg >= argc)
+                               error(1, 0, " missing remote ip");
+
+                       rip = argv[arg];
                } else {
                        error(1, 0, "unknown keyword %s", argv[arg]);
                }
        }
        nest->rta_len = off - nest_start;
 
+       /* token */
+       if (token) {
+               rta = (void *)(data + off);
+               rta->rta_type = MPTCP_PM_ATTR_TOKEN;
+               rta->rta_len = RTA_LENGTH(4);
+               memcpy(RTA_DATA(rta), &token, 4);
+               off += NLMSG_ALIGN(rta->rta_len);
+       }
+
+       /* remote addr/port */
+       if (rip) {
+               nest_start = off;
+               nest = (void *)(data + off);
+               nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR_REMOTE;
+               nest->rta_len = RTA_LENGTH(0);
+               off += NLMSG_ALIGN(nest->rta_len);
+
+               /* addr data */
+               rta = (void *)(data + off);
+               if (inet_pton(AF_INET, rip, RTA_DATA(rta))) {
+                       family = AF_INET;
+                       rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
+                       rta->rta_len = RTA_LENGTH(4);
+               } else if (inet_pton(AF_INET6, rip, RTA_DATA(rta))) {
+                       family = AF_INET6;
+                       rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
+                       rta->rta_len = RTA_LENGTH(16);
+               } else {
+                       error(1, errno, "can't parse ip %s", (char *)rip);
+               }
+               off += NLMSG_ALIGN(rta->rta_len);
+
+               /* family */
+               rta = (void *)(data + off);
+               rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
+               rta->rta_len = RTA_LENGTH(2);
+               memcpy(RTA_DATA(rta), &family, 2);
+               off += NLMSG_ALIGN(rta->rta_len);
+
+               if (rport) {
+                       rta = (void *)(data + off);
+                       rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;
+                       rta->rta_len = RTA_LENGTH(2);
+                       memcpy(RTA_DATA(rta), &rport, 2);
+                       off += NLMSG_ALIGN(rta->rta_len);
+               }
+
+               nest->rta_len = off - nest_start;
+       }
+
        do_nl_req(fd, nh, off, 0);
        return 0;
 }
index 78d0bb640b117bd6ab5f3484d16c0f200f81a834..abe3d4ebe55492e80c8172bea8826e0dc0b22ee4 100755 (executable)
@@ -770,10 +770,42 @@ test_subflows()
        rm -f "$evts"
 }
 
+test_prio()
+{
+       local count
+
+       # Send MP_PRIO signal from client to server machine
+       ip netns exec "$ns2" ./pm_nl_ctl set 10.0.1.2 port "$client4_port" flags backup token "$client4_token" rip 10.0.1.1 rport "$server4_port"
+       sleep 0.5
+
+       # Check TX
+       stdbuf -o0 -e0 printf "MP_PRIO TX                                                 \t"
+       count=$(ip netns exec "$ns2" nstat -as | grep MPTcpExtMPPrioTx | awk '{print $2}')
+       [ -z "$count" ] && count=0
+       if [ $count != 1 ]; then
+               stdbuf -o0 -e0 printf "[FAIL]\n"
+               exit 1
+       else
+               stdbuf -o0 -e0 printf "[OK]\n"
+       fi
+
+       # Check RX
+       stdbuf -o0 -e0 printf "MP_PRIO RX                                                 \t"
+       count=$(ip netns exec "$ns1" nstat -as | grep MPTcpExtMPPrioRx | awk '{print $2}')
+       [ -z "$count" ] && count=0
+       if [ $count != 1 ]; then
+               stdbuf -o0 -e0 printf "[FAIL]\n"
+               exit 1
+       else
+               stdbuf -o0 -e0 printf "[OK]\n"
+       fi
+}
+
 make_connection
 make_connection "v6"
 test_announce
 test_remove
 test_subflows
+test_prio
 
 exit 0
index f8a19f548ae9d5274a284e325ad2ded3be81a2cd..ebbd0b282432721f8b5265dab7b22bead3803304 100755 (executable)
@@ -34,7 +34,7 @@ cfg_veth() {
        ip -netns "${PEER_NS}" addr add dev veth1 192.168.1.1/24
        ip -netns "${PEER_NS}" addr add dev veth1 2001:db8::1/64 nodad
        ip -netns "${PEER_NS}" link set dev veth1 up
-       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp_dummy
+       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp
 }
 
 run_one() {
index 820bc50f6b6871fdf99a46774e2dbb6ac1e2c1f0..fad2d1a71cac36a996b03f2bcce615212f4fa6ac 100755 (executable)
@@ -34,7 +34,7 @@ run_one() {
        ip -netns "${PEER_NS}" addr add dev veth1 2001:db8::1/64 nodad
        ip -netns "${PEER_NS}" link set dev veth1 up
 
-       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp_dummy
+       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp
        ip netns exec "${PEER_NS}" ./udpgso_bench_rx ${rx_args} -r &
        ip netns exec "${PEER_NS}" ./udpgso_bench_rx -t ${rx_args} -r &
 
index 807b74c8fd80fa13d822474549325d68c143e4d0..832c738cc3c299357146e1084a4741a57a640670 100755 (executable)
@@ -36,7 +36,7 @@ run_one() {
        ip netns exec "${PEER_NS}" ethtool -K veth1 rx-gro-list on
 
 
-       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp_dummy
+       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp
        tc -n "${PEER_NS}" qdisc add dev veth1 clsact
        tc -n "${PEER_NS}" filter add dev veth1 ingress prio 4 protocol ipv6 bpf object-file ../bpf/nat6to4.o section schedcls/ingress6/nat_6  direct-action
        tc -n "${PEER_NS}" filter add dev veth1 egress prio 4 protocol ip bpf object-file ../bpf/nat6to4.o section schedcls/egress4/snat4 direct-action
index 6f05e06f67613d2bbabb8233581c9afec1551b58..1bcd82e1f662eea57b0c604187bbe865caca82bc 100755 (executable)
@@ -46,7 +46,7 @@ create_ns() {
                ip -n $BASE$ns addr add dev veth$ns $BM_NET_V4$ns/24
                ip -n $BASE$ns addr add dev veth$ns $BM_NET_V6$ns/64 nodad
        done
-       ip -n $NS_DST link set veth$DST xdp object ../bpf/xdp_dummy.o section xdp_dummy 2>/dev/null
+       ip -n $NS_DST link set veth$DST xdp object ../bpf/xdp_dummy.o section xdp 2>/dev/null
 }
 
 create_vxlan_endpoint() {
index 19eac3e44c0652dc3654771a29a1c8fcc607c048..430895d1a2b63e2748fc6a4f776051f79d13cdde 100755 (executable)
@@ -289,14 +289,14 @@ if [ $CPUS -gt 1 ]; then
        ip netns exec $NS_SRC ethtool -L veth$SRC rx 1 tx 2 2>/dev/null
        printf "%-60s" "bad setting: XDP with RX nr less than TX"
        ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o \
-               section xdp_dummy 2>/dev/null &&\
+               section xdp 2>/dev/null &&\
                echo "fail - set operation successful ?!?" || echo " ok "
 
        # the following tests will run with multiple channels active
        ip netns exec $NS_SRC ethtool -L veth$SRC rx 2
        ip netns exec $NS_DST ethtool -L veth$DST rx 2
        ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o \
-               section xdp_dummy 2>/dev/null
+               section xdp 2>/dev/null
        printf "%-60s" "bad setting: reducing RX nr below peer TX with XDP set"
        ip netns exec $NS_DST ethtool -L veth$DST rx 1 2>/dev/null &&\
                echo "fail - set operation successful ?!?" || echo " ok "
@@ -311,7 +311,7 @@ if [ $CPUS -gt 2 ]; then
        chk_channels "setting invalid channels nr" $DST 2 2
 fi
 
-ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o section xdp_dummy 2>/dev/null
+ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o section xdp 2>/dev/null
 chk_gro_flag "with xdp attached - gro flag" $DST on
 chk_gro_flag "        - peer gro flag" $SRC off
 chk_tso_flag "        - tso flag" $SRC off
index 7d1b80988d8aff56b0c0d1970f245bf0eabcd193..9700358e433743ac52b704bcded536efa4afc78e 100644 (file)
@@ -19,8 +19,6 @@ endif
 MIRROR := https://download.wireguard.com/qemu-test/distfiles/
 
 KERNEL_BUILD_PATH := $(BUILD_PATH)/kernel$(if $(findstring yes,$(DEBUG_KERNEL)),-debug)
-rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
-WIREGUARD_SOURCES := $(call rwildcard,$(KERNEL_PATH)/drivers/net/wireguard/,*)
 
 default: qemu
 
@@ -109,20 +107,22 @@ CHOST := x86_64-linux-musl
 QEMU_ARCH := x86_64
 KERNEL_ARCH := x86_64
 KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/x86/boot/bzImage
+QEMU_VPORT_RESULT := virtio-serial-device
 ifeq ($(HOST_ARCH),$(ARCH))
-QEMU_MACHINE := -cpu host -machine q35,accel=kvm
+QEMU_MACHINE := -cpu host -machine microvm,accel=kvm,pit=off,pic=off,rtc=off -no-acpi
 else
-QEMU_MACHINE := -cpu max -machine q35
+QEMU_MACHINE := -cpu max -machine microvm -no-acpi
 endif
 else ifeq ($(ARCH),i686)
 CHOST := i686-linux-musl
 QEMU_ARCH := i386
 KERNEL_ARCH := x86
 KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/x86/boot/bzImage
+QEMU_VPORT_RESULT := virtio-serial-device
 ifeq ($(subst x86_64,i686,$(HOST_ARCH)),$(ARCH))
-QEMU_MACHINE := -cpu host -machine q35,accel=kvm
+QEMU_MACHINE := -cpu host -machine microvm,accel=kvm,pit=off,pic=off,rtc=off -no-acpi
 else
-QEMU_MACHINE := -cpu max -machine q35
+QEMU_MACHINE := -cpu coreduo -machine microvm -no-acpi
 endif
 else ifeq ($(ARCH),mips64)
 CHOST := mips64-linux-musl
@@ -208,10 +208,11 @@ QEMU_ARCH := m68k
 KERNEL_ARCH := m68k
 KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux
 KERNEL_CMDLINE := $(shell sed -n 's/CONFIG_CMDLINE=\(.*\)/\1/p' arch/m68k.config)
+QEMU_VPORT_RESULT := virtio-serial-device
 ifeq ($(HOST_ARCH),$(ARCH))
-QEMU_MACHINE := -cpu host,accel=kvm -machine q800 -append $(KERNEL_CMDLINE)
+QEMU_MACHINE := -cpu host,accel=kvm -machine virt -append $(KERNEL_CMDLINE)
 else
-QEMU_MACHINE := -machine q800 -smp 1 -append $(KERNEL_CMDLINE)
+QEMU_MACHINE := -machine virt -smp 1 -append $(KERNEL_CMDLINE)
 endif
 else ifeq ($(ARCH),riscv64)
 CHOST := riscv64-linux-musl
@@ -322,8 +323,9 @@ $(KERNEL_BUILD_PATH)/.config: $(TOOLCHAIN_PATH)/.installed kernel.config arch/$(
        cd $(KERNEL_BUILD_PATH) && ARCH=$(KERNEL_ARCH) $(KERNEL_PATH)/scripts/kconfig/merge_config.sh -n $(KERNEL_BUILD_PATH)/.config $(KERNEL_BUILD_PATH)/minimal.config
        $(if $(findstring yes,$(DEBUG_KERNEL)),cp debug.config $(KERNEL_BUILD_PATH) && cd $(KERNEL_BUILD_PATH) && ARCH=$(KERNEL_ARCH) $(KERNEL_PATH)/scripts/kconfig/merge_config.sh -n $(KERNEL_BUILD_PATH)/.config debug.config,)
 
-$(KERNEL_BZIMAGE): $(TOOLCHAIN_PATH)/.installed $(KERNEL_BUILD_PATH)/.config $(BUILD_PATH)/init-cpio-spec.txt $(IPERF_PATH)/src/iperf3 $(IPUTILS_PATH)/ping $(BASH_PATH)/bash $(IPROUTE2_PATH)/misc/ss $(IPROUTE2_PATH)/ip/ip $(IPTABLES_PATH)/iptables/xtables-legacy-multi $(NMAP_PATH)/ncat/ncat $(WIREGUARD_TOOLS_PATH)/src/wg $(BUILD_PATH)/init ../netns.sh $(WIREGUARD_SOURCES)
+$(KERNEL_BZIMAGE): $(TOOLCHAIN_PATH)/.installed $(KERNEL_BUILD_PATH)/.config $(BUILD_PATH)/init-cpio-spec.txt $(IPERF_PATH)/src/iperf3 $(IPUTILS_PATH)/ping $(BASH_PATH)/bash $(IPROUTE2_PATH)/misc/ss $(IPROUTE2_PATH)/ip/ip $(IPTABLES_PATH)/iptables/xtables-legacy-multi $(NMAP_PATH)/ncat/ncat $(WIREGUARD_TOOLS_PATH)/src/wg $(BUILD_PATH)/init
        $(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE)
+.PHONY: $(KERNEL_BZIMAGE)
 
 $(TOOLCHAIN_PATH)/$(CHOST)/include/linux/.installed: | $(KERNEL_BUILD_PATH)/.config $(TOOLCHAIN_PATH)/.installed
        rm -rf $(TOOLCHAIN_PATH)/$(CHOST)/include/linux
index fc7959bef9c252dc430da09283c1914692129784..0579c66be83ee8620d57dce9ab7031bbbdf9f49d 100644 (file)
@@ -7,6 +7,7 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 CONFIG_VIRTIO_MENU=y
 CONFIG_VIRTIO_MMIO=y
 CONFIG_VIRTIO_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyAMA0 wg.success=vport0p1 panic_on_warn=1"
 CONFIG_FRAME_WARN=1024
index f3066be81c1998e67f1827d784ec1fd2133d9794..2a3307bbe534f032aaf70c6b010410e236721aee 100644 (file)
@@ -7,6 +7,7 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 CONFIG_VIRTIO_MENU=y
 CONFIG_VIRTIO_MMIO=y
 CONFIG_VIRTIO_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyAMA0 wg.success=vport0p1 panic_on_warn=1"
 CONFIG_CPU_BIG_ENDIAN=y
index 6d90892a85a242040f71cb62a1aec559b2a88581..35b06502606f23df98103c5583c5e00f43596449 100644 (file)
@@ -1,6 +1,10 @@
-CONFIG_ACPI=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_VIRTIO_MENU=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
+CONFIG_CMDLINE="console=ttyS0 wg.success=vport0p1 panic_on_warn=1 reboot=t"
 CONFIG_FRAME_WARN=1024
index 82c925e49beb7dd2794c6b726d6ee5f08f4d146d..39c48cba56b70b09444a07de108e51a23f94a34f 100644 (file)
@@ -1,9 +1,7 @@
 CONFIG_MMU=y
+CONFIG_VIRT=y
 CONFIG_M68KCLASSIC=y
-CONFIG_M68040=y
-CONFIG_MAC=y
-CONFIG_SERIAL_PMACZILOG=y
-CONFIG_SERIAL_PMACZILOG_TTYS=y
-CONFIG_SERIAL_PMACZILOG_CONSOLE=y
-CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_CMDLINE="console=ttyGF0 wg.success=vport0p1 panic_on_warn=1"
 CONFIG_FRAME_WARN=1024
index d7ec63c17b30e664ccec04a01d6ab879e89df528..2a84402353ab850d6cab37f25db4db1dba6e908e 100644 (file)
@@ -6,6 +6,7 @@ CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
 CONFIG_FRAME_WARN=1024
index 18a498293737637708824f28a360a6a104c6181c..56146a101e7e4d141d356cfa05ecd166f73b51d2 100644 (file)
@@ -7,6 +7,7 @@ CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
 CONFIG_FRAME_WARN=1024
index 5e04882e8e35b3f8d0b8fb2732460a3511193fea..174a9ffe2a362611fdab3c4e6695ccd8a53fec2d 100644 (file)
@@ -4,6 +4,7 @@ CONFIG_PPC_85xx=y
 CONFIG_PHYS_64BIT=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_MATH_EMULATION=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
index efa00693e08bfac6992b70230ff92732413dfec5..cf2d1376d1219a5bb3b5b5cd0b9d0b6af92910c3 100644 (file)
@@ -1,6 +1,9 @@
-CONFIG_ACPI=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_VIRTIO_MENU=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
+CONFIG_CMDLINE="console=ttyS0 wg.success=vport0p1 panic_on_warn=1 reboot=t"
 CONFIG_FRAME_WARN=1280
index c9e128436546f8552794352aec43b5662004bc2a..3e49924dd77e8feb24afa0e5da5c1a6781c38691 100644 (file)
@@ -11,6 +11,7 @@
 #include <stdlib.h>
 #include <stdbool.h>
 #include <fcntl.h>
+#include <time.h>
 #include <sys/wait.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
@@ -70,6 +71,15 @@ static void seed_rng(void)
        close(fd);
 }
 
+static void set_time(void)
+{
+       if (time(NULL))
+               return;
+       pretty_message("[+] Setting fake time...");
+       if (stime(&(time_t){1433512680}) < 0)
+               panic("settimeofday()");
+}
+
 static void mount_filesystems(void)
 {
        pretty_message("[+] Mounting filesystems...");
@@ -259,6 +269,7 @@ int main(int argc, char *argv[])
        print_banner();
        mount_filesystems();
        seed_rng();
+       set_time();
        kmod_selftests();
        enable_logging();
        clear_leaks();