proj/linux-patches:6.18 commit in: /
"Mike Pagano" <[email protected]> Mon, 03 Aug 2026 11:18:13 +0000 (UTC)
| Newsgroups | gmane.linux.gentoo.cvs |
|---|---|
| Message-ID | <1785755880.05b1550c0f3b8ad37f3ee26dd31cc0305f8fb233.mpagano@gentoo> |
commit: 05b1550c0f3b8ad37f3ee26dd31cc0305f8fb233 Author: Mike Pagano <mpagano <AT> gentoo <DOT> org> AuthorDate: Mon Aug 3 11:18:00 2026 +0000 Commit: Mike Pagano <mpagano <AT> gentoo <DOT> org> CommitDate: Mon Aug 3 11:18:00 2026 +0000 URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=05b1550c Linux patch 6.18.42 Signed-off-by: Mike Pagano <mpagano <AT> gentoo.org> 0000_README | 4 + 1041_linux-6.18.42.patch | 38448 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 38452 insertions(+) diff --git a/0000_README b/0000_README index 84f13891..cd39e2db 100644 --- a/0000_README +++ b/0000_README @@ -207,6 +207,10 @@ Patch: 1040_linux-6.18.41.patch From: https://www.kernel.org Desc: Linux 6.18.41 +Patch: 1041_linux-6.18.42.patch +From: https://www.kernel.org +Desc: Linux 6.18.42 + Patch: 1510_fs-enable-link-security-restrictions-by-default.patch From: http://sources.debian.net/src/linux/3.16.7-ckt4-3/debian/patches/debian/fs-enable-link-security-restrictions-by-default.patch/ Desc: Enable link security restrictions by default. diff --git a/1041_linux-6.18.42.patch b/1041_linux-6.18.42.patch new file mode 100644 index 00000000..587570a1 --- /dev/null +++ b/1041_linux-6.18.42.patch @@ -0,0 +1,38448 @@ +diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst +index d55751cad67cf9..8e0d31230b29b5 100644 +--- a/Documentation/gpu/drm-mm.rst ++++ b/Documentation/gpu/drm-mm.rst +@@ -509,8 +509,14 @@ DRM GPUVM Function References + DRM Buddy Allocator + =================== + +-DRM Buddy Function References +------------------------------ ++Buddy Allocator Function References (GPU buddy) ++----------------------------------------------- ++ ++.. kernel-doc:: drivers/gpu/buddy.c ++ :export: ++ ++DRM Buddy Specific Logging Function References ++---------------------------------------------- + + .. kernel-doc:: drivers/gpu/drm/drm_buddy.c + :export: +diff --git a/Documentation/netlink/specs/rt-link.yaml b/Documentation/netlink/specs/rt-link.yaml +index ae4db7e032770f..692b3cd47c3108 100644 +--- a/Documentation/netlink/specs/rt-link.yaml ++++ b/Documentation/netlink/specs/rt-link.yaml +@@ -1564,31 +1564,31 @@ attribute-sets: + type: u32 + - + name: mode +- type: flag ++ type: u8 + - + name: guard +- type: flag ++ type: u8 + - + name: protect +- type: flag ++ type: u8 + - + name: fast-leave +- type: flag ++ type: u8 + - + name: learning +- type: flag ++ type: u8 + - + name: unicast-flood +- type: flag ++ type: u8 + - + name: proxyarp +- type: flag ++ type: u8 + - + name: learning-sync +- type: flag ++ type: u8 + - + name: proxyarp-wifi +- type: flag ++ type: u8 + - + name: root-id + type: binary +@@ -1635,34 +1635,34 @@ attribute-sets: + type: pad + - + name: mcast-flood +- type: flag ++ type: u8 + - + name: mcast-to-ucast +- type: flag ++ type: u8 + - + name: vlan-tunnel +- type: flag ++ type: u8 + - + name: bcast-flood +- type: flag ++ type: u8 + - + name: group-fwd-mask + type: u16 + - + name: neigh-suppress +- type: flag ++ type: u8 + - + name: isolated +- type: flag ++ type: u8 + - + name: backup-port + type: u32 + - + name: mrp-ring-open +- type: flag ++ type: u8 + - + name: mrp-in-open +- type: flag ++ type: u8 + - + name: mcast-eht-hosts-limit + type: u32 +@@ -1671,10 +1671,10 @@ attribute-sets: + type: u32 + - + name: locked +- type: flag ++ type: u8 + - + name: mab +- type: flag ++ type: u8 + - + name: mcast-n-groups + type: u32 +@@ -1683,7 +1683,7 @@ attribute-sets: + type: u32 + - + name: neigh-vlan-suppress +- type: flag ++ type: u8 + - + name: backup-nhid + type: u32 +diff --git a/MAINTAINERS b/MAINTAINERS +index cbfe2a7dd993fd..d27beeb0d9b8d3 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -8656,6 +8656,19 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git + F: drivers/gpu/drm/ttm/ + F: include/drm/ttm/ + ++GPU BUDDY ALLOCATOR ++M: Matthew Auld <[email protected]> ++M: Arun Pravin <[email protected]> ++R: Christian Koenig <[email protected]> ++L: [email protected] ++S: Maintained ++T: git https://gitlab.freedesktop.org/drm/misc/kernel.git ++F: drivers/gpu/drm_buddy.c ++F: drivers/gpu/buddy.c ++F: drivers/gpu/tests/gpu_buddy_test.c ++F: include/linux/gpu_buddy.h ++F: include/drm/drm_buddy.h ++ + DRM AUTOMATED TESTING + M: Helen Koike <[email protected]> + M: Vignesh Raman <vignesh.raman-ZGY8ohtN/[email protected]> +diff --git a/Makefile b/Makefile +index f3c450a0a2fbb6..05ccceb3a87c5d 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 18 +-SUBLEVEL = 41 ++SUBLEVEL = 42 + EXTRAVERSION = + NAME = Baby Opossum Posse + +@@ -470,6 +470,10 @@ KBUILD_USERLDFLAGS := $(USERLDFLAGS) + + # These flags apply to all Rust code in the tree, including the kernel and + # host programs. ++# ++# `-Aclippy::unwrap_or_default`: the lint is buggy [1] and ignores our ++# MSRV. It can trigger depending on the optimization level. ++# [1] https://github.com/rust-lang/rust-clippy/issues/17379 + export rust_common_flags := --edition=2021 \ + -Zbinary_dep_depinfo=y \ + -Astable_features \ +@@ -497,6 +501,7 @@ export rust_common_flags := --edition=2021 \ + -Aclippy::uninlined_format_args \ + -Wclippy::unnecessary_safety_comment \ + -Wclippy::unnecessary_safety_doc \ ++ -Aclippy::unwrap_or_default \ + -Wrustdoc::missing_crate_level_docs \ + -Wrustdoc::unescaped_backticks + +diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts/nvidia/tegra234.dtsi +index 5b245977d6a037..345587fa1d9ad0 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi ++++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi +@@ -5345,7 +5345,7 @@ + #size-cells = <0>; + + cpu0_0: cpu@0 { +- compatible = "arm,cortex-a78"; ++ compatible = "arm,cortex-a78ae"; + device_type = "cpu"; + reg = <0x00000>; + +@@ -5364,7 +5364,7 @@ + }; + + cpu0_1: cpu@100 { +- compatible = "arm,cortex-a78"; ++ compatible = "arm,cortex-a78ae"; + device_type = "cpu"; + reg = <0x00100>; + +@@ -5383,7 +5383,7 @@ + }; + + cpu0_2: cpu@200 { +- compatible = "arm,cortex-a78"; ++ compatible = "arm,cortex-a78ae"; + device_type = "cpu"; + reg = <0x00200>; + +@@ -5402,7 +5402,7 @@ + }; + + cpu0_3: cpu@300 { +- compatible = "arm,cortex-a78"; ++ compatible = "arm,cortex-a78ae"; + device_type = "cpu"; + reg = <0x00300>; + +@@ -5421,7 +5421,7 @@ + }; + + cpu1_0: cpu@10000 { +- compatible = "arm,cortex-a78"; ++ compatible = "arm,cortex-a78ae"; + device_type = "cpu"; + reg = <0x10000>; + +@@ -5440,7 +5440,7 @@ + }; + + cpu1_1: cpu@10100 { +- compatible = "arm,cortex-a78"; ++ compatible = "arm,cortex-a78ae"; + device_type = "cpu"; + reg = <0x10100>; + +@@ -5459,7 +5459,7 @@ + }; + + cpu1_2: cpu@10200 { +- compatible = "arm,cortex-a78"; ++ compatible = "arm,cortex-a78ae"; + device_type = "cpu"; + reg = <0x10200>; + +@@ -5478,7 +5478,7 @@ + }; + + cpu1_3: cpu@10300 { +- compatible = "arm,cortex-a78"; ++ compatible = "arm,cortex-a78ae"; + device_type = "cpu"; + reg = <0x10300>; + +@@ -5497,7 +5497,7 @@ + }; + + cpu2_0: cpu@20000 { +- compatible = "arm,cortex-a78"; ++ compatible = "arm,cortex-a78ae"; + device_type = "cpu"; + reg = <0x20000>; + +@@ -5516,7 +5516,7 @@ + }; + + cpu2_1: cpu@20100 { +- compatible = "arm,cortex-a78"; ++ compatible = "arm,cortex-a78ae"; + device_type = "cpu"; + reg = <0x20100>; + +@@ -5535,7 +5535,7 @@ + }; + + cpu2_2: cpu@20200 { +- compatible = "arm,cortex-a78"; ++ compatible = "arm,cortex-a78ae"; + device_type = "cpu"; + reg = <0x20200>; + +@@ -5554,7 +5554,7 @@ + }; + + cpu2_3: cpu@20300 { +- compatible = "arm,cortex-a78"; ++ compatible = "arm,cortex-a78ae"; + device_type = "cpu"; + reg = <0x20300>; + +diff --git a/arch/arm64/boot/dts/nvidia/tegra264.dtsi b/arch/arm64/boot/dts/nvidia/tegra264.dtsi +index 872a69553e3c82..b16d380209a50a 100644 +--- a/arch/arm64/boot/dts/nvidia/tegra264.dtsi ++++ b/arch/arm64/boot/dts/nvidia/tegra264.dtsi +@@ -50,7 +50,7 @@ + }; + + gpcdma: dma-controller@8400000 { +- compatible = "nvidia,tegra264-gpcdma", "nvidia,tegra186-gpcdma"; ++ compatible = "nvidia,tegra264-gpcdma"; + reg = <0x0 0x08400000 0x0 0x210000>; + interrupts = <GIC_SPI 584 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 585 IRQ_TYPE_LEVEL_HIGH>, +diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi +index 5c00d2e89fb8c6..496e319d7b1113 100644 +--- a/arch/arm64/boot/dts/qcom/lemans.dtsi ++++ b/arch/arm64/boot/dts/qcom/lemans.dtsi +@@ -5146,8 +5146,8 @@ + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +@@ -5234,8 +5234,8 @@ + dp1_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi +index 892b3d2f1bf990..dc96d3d5e943be 100644 +--- a/arch/arm64/boot/dts/qcom/sc7180.dtsi ++++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi +@@ -3452,8 +3452,8 @@ + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi +index ed87bcb0d4b69d..0f566dd75c964e 100644 +--- a/arch/arm64/boot/dts/qcom/sc7280.dtsi ++++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi +@@ -5196,8 +5196,8 @@ + edp_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +@@ -5295,8 +5295,8 @@ + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sc8180x.dtsi b/arch/arm64/boot/dts/qcom/sc8180x.dtsi +index e20a096aac7f9b..c6d96022c666d6 100644 +--- a/arch/arm64/boot/dts/qcom/sc8180x.dtsi ++++ b/arch/arm64/boot/dts/qcom/sc8180x.dtsi +@@ -3303,8 +3303,8 @@ + dp0_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +@@ -3385,8 +3385,8 @@ + dp1_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +@@ -3461,8 +3461,8 @@ + edp_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi +index d89938e17e0930..40649fe7a50950 100644 +--- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi ++++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi +@@ -4754,8 +4754,8 @@ + mdss0_dp0_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +@@ -4836,8 +4836,8 @@ + mdss0_dp1_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +@@ -4916,8 +4916,8 @@ + mdss0_dp2_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +@@ -4991,8 +4991,8 @@ + mdss0_dp3_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +@@ -6110,8 +6110,8 @@ + mdss1_dp0_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +@@ -6190,8 +6190,8 @@ + mdss1_dp1_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +@@ -6270,8 +6270,8 @@ + mdss1_dp2_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +@@ -6345,8 +6345,8 @@ + mdss1_dp3_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sm6350.dtsi b/arch/arm64/boot/dts/qcom/sm6350.dtsi +index 19a7b9f9ea8bcf..0c6787d46ddcd9 100644 +--- a/arch/arm64/boot/dts/qcom/sm6350.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm6350.dtsi +@@ -2306,8 +2306,8 @@ + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi +index acdba79612aa8f..e1f480e3ed0b73 100644 +--- a/arch/arm64/boot/dts/qcom/sm8150.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi +@@ -3939,8 +3939,8 @@ + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi +index adf6b49b52c48c..79ba2c0c96b7e7 100644 +--- a/arch/arm64/boot/dts/qcom/sm8250.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi +@@ -4824,8 +4824,8 @@ + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi +index fc4ce9d4977e81..af892b76322fdf 100644 +--- a/arch/arm64/boot/dts/qcom/sm8350.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi +@@ -2925,8 +2925,8 @@ + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi +index 2d49df7b69e4b6..991f3cbde1c8d5 100644 +--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi +@@ -3483,8 +3483,8 @@ + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; ++ opp-162000000 { ++ opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + +diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi +index ee9c12600f95a1..adb18c10dbd9fe 100644 +--- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi ++++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi +@@ -5522,18 +5522,18 @@ + mdss_dp0_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; +- required-opps = <&rpmhpd_opp_low_svs>; +- }; +- + opp-270000000 { + opp-hz = /bits/ 64 <270000000>; +- required-opps = <&rpmhpd_opp_svs>; ++ required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; ++ required-opps = <&rpmhpd_opp_svs>; ++ }; ++ ++ opp-594000000 { ++ opp-hz = /bits/ 64 <594000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + +@@ -5574,7 +5574,7 @@ + <&usb_1_ss1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>, + <&usb_1_ss1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>; + +- operating-points-v2 = <&mdss_dp1_opp_table>; ++ operating-points-v2 = <&mdss_dp0_opp_table>; + + power-domains = <&rpmhpd RPMHPD_MMCX>; + +@@ -5606,30 +5606,6 @@ + }; + }; + }; +- +- mdss_dp1_opp_table: opp-table { +- compatible = "operating-points-v2"; +- +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; +- required-opps = <&rpmhpd_opp_low_svs>; +- }; +- +- opp-270000000 { +- opp-hz = /bits/ 64 <270000000>; +- required-opps = <&rpmhpd_opp_svs>; +- }; +- +- opp-540000000 { +- opp-hz = /bits/ 64 <540000000>; +- required-opps = <&rpmhpd_opp_svs_l1>; +- }; +- +- opp-810000000 { +- opp-hz = /bits/ 64 <810000000>; +- required-opps = <&rpmhpd_opp_nom>; +- }; +- }; + }; + + mdss_dp2: displayport-controller@ae9a000 { +@@ -5662,7 +5638,7 @@ + <&usb_1_ss2_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>, + <&usb_1_ss2_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>; + +- operating-points-v2 = <&mdss_dp2_opp_table>; ++ operating-points-v2 = <&mdss_dp0_opp_table>; + + power-domains = <&rpmhpd RPMHPD_MMCX>; + +@@ -5693,30 +5669,6 @@ + }; + }; + }; +- +- mdss_dp2_opp_table: opp-table { +- compatible = "operating-points-v2"; +- +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; +- required-opps = <&rpmhpd_opp_low_svs>; +- }; +- +- opp-270000000 { +- opp-hz = /bits/ 64 <270000000>; +- required-opps = <&rpmhpd_opp_svs>; +- }; +- +- opp-540000000 { +- opp-hz = /bits/ 64 <540000000>; +- required-opps = <&rpmhpd_opp_svs_l1>; +- }; +- +- opp-810000000 { +- opp-hz = /bits/ 64 <810000000>; +- required-opps = <&rpmhpd_opp_nom>; +- }; +- }; + }; + + mdss_dp3: displayport-controller@aea0000 { +@@ -5779,19 +5731,14 @@ + mdss_dp3_opp_table: opp-table { + compatible = "operating-points-v2"; + +- opp-160000000 { +- opp-hz = /bits/ 64 <160000000>; +- required-opps = <&rpmhpd_opp_low_svs>; +- }; +- + opp-270000000 { + opp-hz = /bits/ 64 <270000000>; +- required-opps = <&rpmhpd_opp_svs>; ++ required-opps = <&rpmhpd_opp_low_svs>; + }; + +- opp-540000000 { +- opp-hz = /bits/ 64 <540000000>; +- required-opps = <&rpmhpd_opp_svs_l1>; ++ opp-594000000 { ++ opp-hz = /bits/ 64 <594000000>; ++ required-opps = <&rpmhpd_opp_svs>; + }; + + opp-810000000 { +diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h +index e1deed82446450..31058567eee465 100644 +--- a/arch/arm64/include/asm/esr.h ++++ b/arch/arm64/include/asm/esr.h +@@ -130,7 +130,7 @@ + * Annoyingly, the negative levels for Address size faults aren't laid out + * contiguously (or in the desired order) + */ +-#define ESR_ELx_FSC_ADDRSZ_nL(n) ((n) == -1 ? 0x25 : 0x2C) ++#define ESR_ELx_FSC_ADDRSZ_nL(n) ((n) == -1 ? 0x29 : 0x2C) + #define ESR_ELx_FSC_ADDRSZ_L(n) ((n) < 0 ? ESR_ELx_FSC_ADDRSZ_nL(n) : \ + (ESR_ELx_FSC_ADDRSZ + (n))) + +diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c +index 1d90a7e753336d..fa63c96dbf79d0 100644 +--- a/arch/arm64/mm/hugetlbpage.c ++++ b/arch/arm64/mm/hugetlbpage.c +@@ -91,7 +91,7 @@ static int find_num_contig(struct mm_struct *mm, unsigned long addr, + p4dp = p4d_offset(pgdp, addr); + pudp = pud_offset(p4dp, addr); + pmdp = pmd_offset(pudp, addr); +- if ((pte_t *)pmdp == ptep) { ++ if ((pte_t *)PTR_ALIGN_DOWN(pmdp, sizeof(*pmdp) * CONT_PMDS) == ptep) { + *pgsize = PMD_SIZE; + return CONT_PMDS; + } +diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c +index 88ad24d1e729a5..fb9a167ee7a064 100644 +--- a/arch/loongarch/kernel/acpi.c ++++ b/arch/loongarch/kernel/acpi.c +@@ -201,10 +201,12 @@ static void __init acpi_process_madt(void) + } + + int pptt_enabled; ++static int acpi_nr_packages; ++static int acpi_package_ids[MAX_PACKAGES]; + + int __init parse_acpi_topology(void) + { +- int cpu, topology_id; ++ int i, cpu, topology_id; + + for_each_possible_cpu(cpu) { + topology_id = find_acpi_cpu_topology(cpu, 0); +@@ -222,6 +224,29 @@ int __init parse_acpi_topology(void) + + cpu_data[cpu].core = topology_id; + } ++ ++ topology_id = find_acpi_cpu_topology_package(cpu); ++ if (topology_id < 0) { ++ pr_warn("Invalid BIOS PPTT\n"); ++ return -ENOENT; ++ } ++ ++ for (i = 0; i < acpi_nr_packages; i++) ++ if (acpi_package_ids[i] == topology_id) ++ break; ++ ++ if (i == acpi_nr_packages) ++ acpi_package_ids[acpi_nr_packages++] = topology_id; ++ ++ cpu_data[cpu].package = topology_id; ++ } ++ ++ for_each_possible_cpu(cpu) { ++ for (i = 0; i < acpi_nr_packages; i++) ++ if (cpu_data[cpu].package == acpi_package_ids[i]) { ++ cpu_data[cpu].package = i; /* Canonicalize */ ++ break; ++ } + } + + pptt_enabled = 1; +diff --git a/arch/loongarch/kernel/kgdb.c b/arch/loongarch/kernel/kgdb.c +index 7be5b4c0c90020..6728b2d67dd325 100644 +--- a/arch/loongarch/kernel/kgdb.c ++++ b/arch/loongarch/kernel/kgdb.c +@@ -252,7 +252,8 @@ static int kgdb_loongarch_notify(struct notifier_block *self, unsigned long cmd, + if (atomic_read(&kgdb_active) != -1) + kgdb_nmicallback(smp_processor_id(), regs); + +- if (kgdb_handle_exception(args->trapnr, args->signr, cmd, regs)) ++ if (kgdb_handle_exception(regs->csr_era == stepped_address ? 0 : args->trapnr, ++ args->signr, cmd, regs)) + return NOTIFY_DONE; + + if (atomic_read(&kgdb_setting_breakpoint)) +diff --git a/arch/loongarch/kernel/machine_kexec.c b/arch/loongarch/kernel/machine_kexec.c +index d7fafda1d5417c..1883cae93bc31a 100644 +--- a/arch/loongarch/kernel/machine_kexec.c ++++ b/arch/loongarch/kernel/machine_kexec.c +@@ -42,6 +42,7 @@ static unsigned long first_ind_entry; + int machine_kexec_prepare(struct kimage *kimage) + { + int i; ++ char head[8]; + char *bootloader = "kexec"; + void *cmdline_ptr = (void *)KEXEC_CMDLINE_ADDR; + +@@ -59,7 +60,9 @@ int machine_kexec_prepare(struct kimage *kimage) + } else { + /* Find the command line */ + for (i = 0; i < kimage->nr_segments; i++) { +- if (!strncmp(bootloader, (char __user *)kimage->segment[i].buf, strlen(bootloader))) { ++ if (copy_from_user(head, kimage->segment[i].buf, strlen(bootloader))) ++ continue; ++ if (!strncmp(bootloader, head, strlen(bootloader))) { + if (!copy_from_user(cmdline_ptr, kimage->segment[i].buf, COMMAND_LINE_SIZE)) + kimage->arch.cmdline_ptr = (unsigned long)cmdline_ptr; + break; +diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c +index 75e3dfa0605530..c0b59b813f8e9d 100644 +--- a/arch/loongarch/kernel/setup.c ++++ b/arch/loongarch/kernel/setup.c +@@ -610,6 +610,7 @@ void __init setup_arch(char **cmdline_p) + memblock_init(); + pagetable_init(); + bootcmdline_init(cmdline_p); ++ jump_label_init(); /* Initialise the static keys for early params */ + parse_early_param(); + reserve_initrd_mem(); + +@@ -617,8 +618,6 @@ void __init setup_arch(char **cmdline_p) + arch_mem_init(cmdline_p); + + resource_init(); +- jump_label_init(); /* Initialise the static keys for paravirtualization */ +- + #ifdef CONFIG_SMP + plat_smp_setup(); + prefill_possible_map(); +diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c +index 5d6a60294fb2d5..fc3817bd1919ce 100644 +--- a/arch/loongarch/kernel/smp.c ++++ b/arch/loongarch/kernel/smp.c +@@ -412,10 +412,10 @@ void loongson_init_secondary(void) + numa_add_cpu(cpu); + #endif + per_cpu(cpu_state, cpu) = CPU_ONLINE; +- cpu_data[cpu].package = +- cpu_logical_map(cpu) / loongson_sysconf.cores_per_package; + cpu_data[cpu].core = pptt_enabled ? cpu_data[cpu].core : + cpu_logical_map(cpu) % loongson_sysconf.cores_per_package; ++ cpu_data[cpu].package = pptt_enabled ? cpu_data[cpu].package : ++ cpu_logical_map(cpu) / loongson_sysconf.cores_per_package; + cpu_data[cpu].global_id = cpu_logical_map(cpu); + } + +diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c +index b4472288e0d434..11145c40183dd1 100644 +--- a/arch/powerpc/kernel/time.c ++++ b/arch/powerpc/kernel/time.c +@@ -376,6 +376,47 @@ void vtime_task_switch(struct task_struct *prev) + acct->starttime = acct0->starttime; + } + } ++ ++/** ++ * vtime_reset - Fast forward vtime entry clocks ++ * ++ * Called from dynticks idle IRQ entry to fast-forward the clocks to current time ++ * so that the IRQ time is still accounted by vtime while nohz cputime is paused. ++ */ ++void vtime_reset(void) ++{ ++ struct cpu_accounting_data *acct = get_accounting(current); ++ ++ acct->starttime = mftb(); ++#ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME ++ acct->startspurr = read_spurr(acct->starttime); ++#endif ++} ++ ++#ifdef CONFIG_NO_HZ_COMMON ++/** ++ * vtime_dyntick_start - Inform vtime about entry to idle-dynticks ++ * ++ * Called when idle enters in dyntick mode. The idle cputime that elapsed so far ++ * is accumulated and the tick subsystem takes over the idle cputime accounting. ++ */ ++void vtime_dyntick_start(void) ++{ ++ vtime_account_idle(current); ++} ++ ++/** ++ * vtime_dyntick_stop - Inform vtime about exit from idle-dynticks ++ * ++ * Called when idle exits from dyntick mode. The vtime entry clocks are ++ * fast-forward to current time so that idle accounting restarts elapsing from ++ * now. ++ */ ++void vtime_dyntick_stop(void) ++{ ++ vtime_reset(); ++} ++#endif /* CONFIG_NO_HZ_COMMON */ + #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ + + void __no_kcsan __delay(unsigned long loops) +@@ -892,6 +933,7 @@ static void __init set_decrementer_max(void) + static void __init init_decrementer_clockevent(void) + { + register_decrementer_clockevent(smp_processor_id()); ++ vtime_reset(); + } + + void secondary_cpu_time_init(void) +@@ -907,6 +949,7 @@ void secondary_cpu_time_init(void) + /* FIME: Should make unrelated change to move snapshot_timebase + * call here ! */ + register_decrementer_clockevent(smp_processor_id()); ++ vtime_reset(); + } + + /* +diff --git a/arch/powerpc/platforms/85xx/common.c b/arch/powerpc/platforms/85xx/common.c +index 757811155587db..c11deb2f50ed45 100644 +--- a/arch/powerpc/platforms/85xx/common.c ++++ b/arch/powerpc/platforms/85xx/common.c +@@ -42,6 +42,8 @@ static const struct of_device_id mpc85xx_common_ids[] __initconst = { + { .compatible = "fsl,qoriq-pcie-v2.3", }, + { .compatible = "fsl,qoriq-pcie-v2.2", }, + { .compatible = "fsl,fman", }, ++ /* IFC NAND and NOR controllers */ ++ { .compatible = "fsl,ifc", }, + {}, + }; + +diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h +index 4d794573e3dbe8..fd3ba183cd8241 100644 +--- a/arch/riscv/include/asm/kvm_host.h ++++ b/arch/riscv/include/asm/kvm_host.h +@@ -220,13 +220,13 @@ struct kvm_vcpu_arch { + /* + * VCPU interrupts + * +- * We have a lockless approach for tracking pending VCPU interrupts +- * implemented using atomic bitops. The irqs_pending bitmap represent +- * pending interrupts whereas irqs_pending_mask represent bits changed +- * in irqs_pending. Our approach is modeled around multiple producer +- * and single consumer problem where the consumer is the VCPU itself. ++ * The irqs_pending bitmap represents pending interrupts whereas ++ * irqs_pending_mask represents bits changed in irqs_pending. Updates ++ * to these bitmaps are serialized so vcpu interrupt sync/flush cannot ++ * drop a newly injected interrupt while syncing guest-visible HVIP. + */ + #define KVM_RISCV_VCPU_NR_IRQS 64 ++ raw_spinlock_t irqs_pending_lock; + DECLARE_BITMAP(irqs_pending, KVM_RISCV_VCPU_NR_IRQS); + DECLARE_BITMAP(irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS); + +diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c +index 199d13f86f3135..460fb297672e68 100644 +--- a/arch/riscv/kernel/sys_hwprobe.c ++++ b/arch/riscv/kernel/sys_hwprobe.c +@@ -409,6 +409,7 @@ static int hwprobe_get_cpus(struct riscv_hwprobe __user *pairs, + if (cpusetsize > cpumask_size()) + cpusetsize = cpumask_size(); + ++ cpumask_clear(&cpus); + ret = copy_from_user(&cpus, cpus_user, cpusetsize); + if (ret) + return -EFAULT; +diff --git a/arch/riscv/kvm/aia.c b/arch/riscv/kvm/aia.c +index dad3181856600f..b8b50608215564 100644 +--- a/arch/riscv/kvm/aia.c ++++ b/arch/riscv/kvm/aia.c +@@ -50,12 +50,15 @@ void kvm_riscv_vcpu_aia_flush_interrupts(struct kvm_vcpu *vcpu) + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; + unsigned long mask, val; + ++ lockdep_assert_held(&vcpu->arch.irqs_pending_lock); ++ + if (!kvm_riscv_aia_available()) + return; + +- if (READ_ONCE(vcpu->arch.irqs_pending_mask[1])) { +- mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[1], 0); +- val = READ_ONCE(vcpu->arch.irqs_pending[1]) & mask; ++ mask = vcpu->arch.irqs_pending_mask[1]; ++ if (mask) { ++ vcpu->arch.irqs_pending_mask[1] = 0; ++ val = vcpu->arch.irqs_pending[1] & mask; + + csr->hviph &= ~mask; + csr->hviph |= val; +@@ -66,6 +69,8 @@ void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu) + { + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; + ++ lockdep_assert_held(&vcpu->arch.irqs_pending_lock); ++ + if (kvm_riscv_aia_available()) + csr->vsieh = ncsr_read(CSR_VSIEH); + } +@@ -74,13 +79,22 @@ void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu) + bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu, u64 mask) + { + unsigned long seip; ++#ifdef CONFIG_32BIT ++ unsigned long flags; ++ bool pending; ++#endif + + if (!kvm_riscv_aia_available()) + return false; + + #ifdef CONFIG_32BIT +- if (READ_ONCE(vcpu->arch.irqs_pending[1]) & +- (vcpu->arch.aia_context.guest_csr.vsieh & upper_32_bits(mask))) ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ pending = vcpu->arch.irqs_pending[1] & ++ (vcpu->arch.aia_context.guest_csr.vsieh & ++ upper_32_bits(mask)); ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); ++ ++ if (pending) + return true; + #endif + +@@ -198,6 +212,9 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu, + unsigned long val) + { + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; ++#ifdef CONFIG_32BIT ++ unsigned long flags; ++#endif + + if (reg_num >= sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long)) + return -ENOENT; +@@ -206,8 +223,12 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu, + ((unsigned long *)csr)[reg_num] = val; + + #ifdef CONFIG_32BIT +- if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph)) +- WRITE_ONCE(vcpu->arch.irqs_pending_mask[1], 0); ++ if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph)) { ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ vcpu->arch.irqs_pending_mask[1] = 0; ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, ++ flags); ++ } + #endif + } + +diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c +index d26c4967c20e24..6f8e9b105da7e4 100644 +--- a/arch/riscv/kvm/vcpu.c ++++ b/arch/riscv/kvm/vcpu.c +@@ -78,6 +78,7 @@ static void kvm_riscv_vcpu_context_reset(struct kvm_vcpu *vcpu, + + static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu, bool kvm_sbi_reset) + { ++ unsigned long flags; + bool loaded; + + /** +@@ -102,8 +103,10 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu, bool kvm_sbi_reset) + + kvm_riscv_vcpu_aia_reset(vcpu); + ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); + bitmap_zero(vcpu->arch.irqs_pending, KVM_RISCV_VCPU_NR_IRQS); + bitmap_zero(vcpu->arch.irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS); ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + + kvm_riscv_vcpu_pmu_reset(vcpu); + +@@ -147,6 +150,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) + + /* Setup VCPU hfence queue */ + spin_lock_init(&vcpu->arch.hfence_lock); ++ raw_spin_lock_init(&vcpu->arch.irqs_pending_lock); + + spin_lock_init(&vcpu->arch.reset_state.lock); + +@@ -348,10 +352,14 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu) + { + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; + unsigned long mask, val; ++ unsigned long flags; + +- if (READ_ONCE(vcpu->arch.irqs_pending_mask[0])) { +- mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[0], 0); +- val = READ_ONCE(vcpu->arch.irqs_pending[0]) & mask; ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ ++ mask = vcpu->arch.irqs_pending_mask[0]; ++ if (mask) { ++ vcpu->arch.irqs_pending_mask[0] = 0; ++ val = vcpu->arch.irqs_pending[0] & mask; + + csr->hvip &= ~mask; + csr->hvip |= val; +@@ -359,11 +367,14 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu) + + /* Flush AIA high interrupts */ + kvm_riscv_vcpu_aia_flush_interrupts(vcpu); ++ ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + } + + void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu) + { + unsigned long hvip; ++ unsigned long flags; + struct kvm_vcpu_arch *v = &vcpu->arch; + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; + +@@ -372,34 +383,41 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu) + + /* Sync-up HVIP.VSSIP bit changes does by Guest */ + hvip = ncsr_read(CSR_HVIP); ++ ++ raw_spin_lock_irqsave(&v->irqs_pending_lock, flags); ++ + if ((csr->hvip ^ hvip) & (1UL << IRQ_VS_SOFT)) { + if (hvip & (1UL << IRQ_VS_SOFT)) { +- if (!test_and_set_bit(IRQ_VS_SOFT, +- v->irqs_pending_mask)) +- set_bit(IRQ_VS_SOFT, v->irqs_pending); ++ if (!__test_and_set_bit(IRQ_VS_SOFT, ++ v->irqs_pending_mask)) ++ __set_bit(IRQ_VS_SOFT, v->irqs_pending); + } else { +- if (!test_and_set_bit(IRQ_VS_SOFT, +- v->irqs_pending_mask)) +- clear_bit(IRQ_VS_SOFT, v->irqs_pending); ++ if (!__test_and_set_bit(IRQ_VS_SOFT, ++ v->irqs_pending_mask)) ++ __clear_bit(IRQ_VS_SOFT, v->irqs_pending); + } + } + + /* Sync up the HVIP.LCOFIP bit changes (only clear) by the guest */ + if ((csr->hvip ^ hvip) & (1UL << IRQ_PMU_OVF)) { + if (!(hvip & (1UL << IRQ_PMU_OVF)) && +- !test_and_set_bit(IRQ_PMU_OVF, v->irqs_pending_mask)) +- clear_bit(IRQ_PMU_OVF, v->irqs_pending); ++ !__test_and_set_bit(IRQ_PMU_OVF, v->irqs_pending_mask)) ++ __clear_bit(IRQ_PMU_OVF, v->irqs_pending); + } + + /* Sync-up AIA high interrupts */ + kvm_riscv_vcpu_aia_sync_interrupts(vcpu); + ++ raw_spin_unlock_irqrestore(&v->irqs_pending_lock, flags); ++ + /* Sync-up timer CSRs */ + kvm_riscv_vcpu_timer_sync(vcpu); + } + + int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) + { ++ unsigned long flags; ++ + /* + * We only allow VS-mode software, timer, and external + * interrupts when irq is one of the local interrupts +@@ -412,9 +430,10 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) + irq != IRQ_PMU_OVF) + return -EINVAL; + +- set_bit(irq, vcpu->arch.irqs_pending); +- smp_mb__before_atomic(); +- set_bit(irq, vcpu->arch.irqs_pending_mask); ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ __set_bit(irq, vcpu->arch.irqs_pending); ++ __set_bit(irq, vcpu->arch.irqs_pending_mask); ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + + kvm_vcpu_kick(vcpu); + +@@ -423,6 +442,8 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) + + int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) + { ++ unsigned long flags; ++ + /* + * We only allow VS-mode software, timer, counter overflow and external + * interrupts when irq is one of the local interrupts +@@ -435,26 +456,33 @@ int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) + irq != IRQ_PMU_OVF) + return -EINVAL; + +- clear_bit(irq, vcpu->arch.irqs_pending); +- smp_mb__before_atomic(); +- set_bit(irq, vcpu->arch.irqs_pending_mask); ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ __clear_bit(irq, vcpu->arch.irqs_pending); ++ __set_bit(irq, vcpu->arch.irqs_pending_mask); ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + + return 0; + } + + bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask) + { ++ unsigned long flags; + unsigned long ie; ++ bool ret; + ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); + ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK) + << VSIP_TO_HVIP_SHIFT) & (unsigned long)mask; + ie |= vcpu->arch.guest_csr.vsie & ~IRQ_LOCAL_MASK & + (unsigned long)mask; +- if (READ_ONCE(vcpu->arch.irqs_pending[0]) & ie) +- return true; ++ ret = vcpu->arch.irqs_pending[0] & ie; ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + + /* Check AIA high interrupts */ +- return kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask); ++ if (!ret) ++ ret = kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask); ++ ++ return ret; + } + + void __kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu) +diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c +index 865dae903aa0f6..3e8f9a28341215 100644 +--- a/arch/riscv/kvm/vcpu_onereg.c ++++ b/arch/riscv/kvm/vcpu_onereg.c +@@ -522,6 +522,7 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu, + unsigned long reg_val) + { + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; ++ unsigned long flags; + + if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long)) + return -ENOENT; +@@ -533,8 +534,11 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu, + + ((unsigned long *)csr)[reg_num] = reg_val; + +- if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) +- WRITE_ONCE(vcpu->arch.irqs_pending_mask[0], 0); ++ if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) { ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ vcpu->arch.irqs_pending_mask[0] = 0; ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); ++ } + + return 0; + } +diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c +index 63517b85f4c930..246fc5b936fa65 100644 +--- a/arch/s390/kernel/time.c ++++ b/arch/s390/kernel/time.c +@@ -66,6 +66,7 @@ ATOMIC_NOTIFIER_HEAD(s390_epoch_delta_notifier); + EXPORT_SYMBOL(s390_epoch_delta_notifier); + + unsigned char ptff_function_mask[16]; ++EXPORT_SYMBOL(ptff_function_mask); + + static unsigned long lpar_offset; + static unsigned long initial_leap_seconds; +diff --git a/arch/s390/lib/csum-partial.c b/arch/s390/lib/csum-partial.c +index 458abd9bac7025..9d74ceff136c54 100644 +--- a/arch/s390/lib/csum-partial.c ++++ b/arch/s390/lib/csum-partial.c +@@ -23,7 +23,7 @@ static __always_inline __wsum csum_copy(void *dst, const void *src, int len, __w + if (!cpu_has_vx()) { + if (copy) + memcpy(dst, src, len); +- return cksm(dst, len, sum); ++ return cksm(src, len, sum); + } + kernel_fpu_begin(&vxstate, KERNEL_VXR_V16V23); + fpu_vlvgf(16, (__force u32)sum, 1); +diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile +index 2013840d6318ff..99d85503e50931 100644 +--- a/arch/x86/boot/compressed/Makefile ++++ b/arch/x86/boot/compressed/Makefile +@@ -27,6 +27,7 @@ targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \ + KBUILD_CFLAGS := -m$(BITS) -O2 $(CLANG_FLAGS) + KBUILD_CFLAGS += -std=gnu11 + KBUILD_CFLAGS += -fno-strict-aliasing -fPIE ++KBUILD_CFLAGS += -fno-jump-tables + KBUILD_CFLAGS += -Wundef + KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING + cflags-$(CONFIG_X86_32) := -march=i386 +diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c +index 79a1f2d5f5019c..f9025779292a84 100644 +--- a/arch/x86/kernel/cpu/resctrl/core.c ++++ b/arch/x86/kernel/cpu/resctrl/core.c +@@ -363,7 +363,7 @@ static void ctrl_domain_free(struct rdt_hw_ctrl_domain *hw_dom) + kfree(hw_dom); + } + +-static void mon_domain_free(struct rdt_hw_mon_domain *hw_dom) ++static void l3_mon_domain_free(struct rdt_hw_l3_mon_domain *hw_dom) + { + int idx; + +@@ -396,11 +396,13 @@ static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_ctrl_domain * + } + + /** +- * arch_domain_mbm_alloc() - Allocate arch private storage for the MBM counters ++ * l3_mon_domain_mbm_alloc() - Allocate arch private storage for the MBM counters + * @num_rmid: The size of the MBM counter array + * @hw_dom: The domain that owns the allocated arrays ++ * ++ * Return: 0 for success, or -ENOMEM. + */ +-static int arch_domain_mbm_alloc(u32 num_rmid, struct rdt_hw_mon_domain *hw_dom) ++static int l3_mon_domain_mbm_alloc(u32 num_rmid, struct rdt_hw_l3_mon_domain *hw_dom) + { + size_t tsize = sizeof(*hw_dom->arch_mbm_states[0]); + enum resctrl_event_id eventid; +@@ -499,9 +501,9 @@ static void domain_add_cpu_mon(int cpu, struct rdt_resource *r) + { + int id = get_domain_id_from_scope(cpu, r->mon_scope); + struct list_head *add_pos = NULL; +- struct rdt_hw_mon_domain *hw_dom; ++ struct rdt_hw_l3_mon_domain *hw_dom; + struct rdt_domain_hdr *hdr; +- struct rdt_mon_domain *d; ++ struct rdt_l3_mon_domain *d; + struct cacheinfo *ci; + int err; + +@@ -517,7 +519,7 @@ static void domain_add_cpu_mon(int cpu, struct rdt_resource *r) + if (hdr) { + if (WARN_ON_ONCE(hdr->type != RESCTRL_MON_DOMAIN)) + return; +- d = container_of(hdr, struct rdt_mon_domain, hdr); ++ d = container_of(hdr, struct rdt_l3_mon_domain, hdr); + + cpumask_set_cpu(cpu, &d->hdr.cpu_mask); + /* Update the mbm_assign_mode state for the CPU if supported */ +@@ -536,7 +538,7 @@ static void domain_add_cpu_mon(int cpu, struct rdt_resource *r) + ci = get_cpu_cacheinfo_level(cpu, RESCTRL_L3_CACHE); + if (!ci) { + pr_warn_once("Can't find L3 cache for CPU:%d resource %s\n", cpu, r->name); +- mon_domain_free(hw_dom); ++ l3_mon_domain_free(hw_dom); + return; + } + d->ci_id = ci->id; +@@ -548,8 +550,8 @@ static void domain_add_cpu_mon(int cpu, struct rdt_resource *r) + + arch_mon_domain_online(r, d); + +- if (arch_domain_mbm_alloc(r->mon.num_rmid, hw_dom)) { +- mon_domain_free(hw_dom); ++ if (l3_mon_domain_mbm_alloc(r->mon.num_rmid, hw_dom)) { ++ l3_mon_domain_free(hw_dom); + return; + } + +@@ -559,7 +561,7 @@ static void domain_add_cpu_mon(int cpu, struct rdt_resource *r) + if (err) { + list_del_rcu(&d->hdr.list); + synchronize_rcu(); +- mon_domain_free(hw_dom); ++ l3_mon_domain_free(hw_dom); + } + } + +@@ -620,9 +622,9 @@ static void domain_remove_cpu_ctrl(int cpu, struct rdt_resource *r) + static void domain_remove_cpu_mon(int cpu, struct rdt_resource *r) + { + int id = get_domain_id_from_scope(cpu, r->mon_scope); +- struct rdt_hw_mon_domain *hw_dom; ++ struct rdt_hw_l3_mon_domain *hw_dom; + struct rdt_domain_hdr *hdr; +- struct rdt_mon_domain *d; ++ struct rdt_l3_mon_domain *d; + + lockdep_assert_held(&domain_list_lock); + +@@ -642,7 +644,7 @@ static void domain_remove_cpu_mon(int cpu, struct rdt_resource *r) + if (WARN_ON_ONCE(hdr->type != RESCTRL_MON_DOMAIN)) + return; + +- d = container_of(hdr, struct rdt_mon_domain, hdr); ++ d = container_of(hdr, struct rdt_l3_mon_domain, hdr); + hw_dom = resctrl_to_arch_mon_dom(d); + + cpumask_clear_cpu(cpu, &d->hdr.cpu_mask); +@@ -650,7 +652,7 @@ static void domain_remove_cpu_mon(int cpu, struct rdt_resource *r) + resctrl_offline_mon_domain(r, d); + list_del_rcu(&d->hdr.list); + synchronize_rcu(); +- mon_domain_free(hw_dom); ++ l3_mon_domain_free(hw_dom); + + return; + } +@@ -897,7 +899,7 @@ static __init bool get_rdt_mon_resources(void) + if (!ret) + return false; + +- return !rdt_get_mon_l3_config(r); ++ return !rdt_get_l3_mon_config(r); + } + + static __init void __check_quirks_intel(void) +diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h +index 6da9bd1a188b96..6c9e75440c10eb 100644 +--- a/arch/x86/kernel/cpu/resctrl/internal.h ++++ b/arch/x86/kernel/cpu/resctrl/internal.h +@@ -63,17 +63,17 @@ struct rdt_hw_ctrl_domain { + }; + + /** +- * struct rdt_hw_mon_domain - Arch private attributes of a set of CPUs that share +- * a resource for a monitor function +- * @d_resctrl: Properties exposed to the resctrl file system ++ * struct rdt_hw_l3_mon_domain - Arch private attributes of a set of CPUs sharing ++ * RDT_RESOURCE_L3 monitoring ++ * @d_resctrl: Properties exposed to the resctrl file system + * @arch_mbm_states: Per-event pointer to the MBM event's saved state. + * An MBM event's state is an array of struct arch_mbm_state + * indexed by RMID on x86. + * + * Members of this structure are accessed via helpers that provide abstraction. + */ +-struct rdt_hw_mon_domain { +- struct rdt_mon_domain d_resctrl; ++struct rdt_hw_l3_mon_domain { ++ struct rdt_l3_mon_domain d_resctrl; + struct arch_mbm_state *arch_mbm_states[QOS_NUM_L3_MBM_EVENTS]; + }; + +@@ -82,9 +82,9 @@ static inline struct rdt_hw_ctrl_domain *resctrl_to_arch_ctrl_dom(struct rdt_ctr + return container_of(r, struct rdt_hw_ctrl_domain, d_resctrl); + } + +-static inline struct rdt_hw_mon_domain *resctrl_to_arch_mon_dom(struct rdt_mon_domain *r) ++static inline struct rdt_hw_l3_mon_domain *resctrl_to_arch_mon_dom(struct rdt_l3_mon_domain *r) + { +- return container_of(r, struct rdt_hw_mon_domain, d_resctrl); ++ return container_of(r, struct rdt_hw_l3_mon_domain, d_resctrl); + } + + /** +@@ -138,7 +138,7 @@ static inline struct rdt_hw_resource *resctrl_to_arch_res(struct rdt_resource *r + + extern struct rdt_hw_resource rdt_resources_all[]; + +-void arch_mon_domain_online(struct rdt_resource *r, struct rdt_mon_domain *d); ++void arch_mon_domain_online(struct rdt_resource *r, struct rdt_l3_mon_domain *d); + + /* CPUID.(EAX=10H, ECX=ResID=1).EAX */ + union cpuid_0x10_1_eax { +@@ -211,7 +211,7 @@ union l3_qos_abmc_cfg { + + void rdt_ctrl_update(void *arg); + +-int rdt_get_mon_l3_config(struct rdt_resource *r); ++int rdt_get_l3_mon_config(struct rdt_resource *r); + + bool rdt_cpu_has(int flag); + +diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c +index 4b2b539ddff953..9fc3adb4b232ca 100644 +--- a/arch/x86/kernel/cpu/resctrl/monitor.c ++++ b/arch/x86/kernel/cpu/resctrl/monitor.c +@@ -109,7 +109,7 @@ static inline u64 get_corrected_mbm_count(u32 rmid, unsigned long val) + * + * In RMID sharing mode there are fewer "logical RMID" values available + * to accumulate data ("physical RMIDs" are divided evenly between SNC +- * nodes that share an L3 cache). Linux creates an rdt_mon_domain for ++ * nodes that share an L3 cache). Linux creates an rdt_l3_mon_domain for + * each SNC node. + * + * The value loaded into IA32_PQR_ASSOC is the "logical RMID". +@@ -157,7 +157,7 @@ static int __rmid_read_phys(u32 prmid, enum resctrl_event_id eventid, u64 *val) + return 0; + } + +-static struct arch_mbm_state *get_arch_mbm_state(struct rdt_hw_mon_domain *hw_dom, ++static struct arch_mbm_state *get_arch_mbm_state(struct rdt_hw_l3_mon_domain *hw_dom, + u32 rmid, + enum resctrl_event_id eventid) + { +@@ -171,11 +171,11 @@ static struct arch_mbm_state *get_arch_mbm_state(struct rdt_hw_mon_domain *hw_do + return state ? &state[rmid] : NULL; + } + +-void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_mon_domain *d, ++void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + u32 unused, u32 rmid, + enum resctrl_event_id eventid) + { +- struct rdt_hw_mon_domain *hw_dom = resctrl_to_arch_mon_dom(d); ++ struct rdt_hw_l3_mon_domain *hw_dom = resctrl_to_arch_mon_dom(d); + int cpu = cpumask_any(&d->hdr.cpu_mask); + struct arch_mbm_state *am; + u32 prmid; +@@ -194,9 +194,9 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_mon_domain *d, + * Assumes that hardware counters are also reset and thus that there is + * no need to record initial non-zero counts. + */ +-void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_mon_domain *d) ++void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_l3_mon_domain *d) + { +- struct rdt_hw_mon_domain *hw_dom = resctrl_to_arch_mon_dom(d); ++ struct rdt_hw_l3_mon_domain *hw_dom = resctrl_to_arch_mon_dom(d); + enum resctrl_event_id eventid; + int idx; + +@@ -217,10 +217,10 @@ static u64 mbm_overflow_count(u64 prev_msr, u64 cur_msr, unsigned int width) + return chunks >> shift; + } + +-static u64 get_corrected_val(struct rdt_resource *r, struct rdt_mon_domain *d, ++static u64 get_corrected_val(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + u32 rmid, enum resctrl_event_id eventid, u64 msr_val) + { +- struct rdt_hw_mon_domain *hw_dom = resctrl_to_arch_mon_dom(d); ++ struct rdt_hw_l3_mon_domain *hw_dom = resctrl_to_arch_mon_dom(d); + struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); + struct arch_mbm_state *am; + u64 chunks; +@@ -238,11 +238,11 @@ static u64 get_corrected_val(struct rdt_resource *r, struct rdt_mon_domain *d, + return chunks * hw_res->mon_scale; + } + +-int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_mon_domain *d, ++int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + u32 unused, u32 rmid, enum resctrl_event_id eventid, + u64 *val, void *ignored) + { +- struct rdt_hw_mon_domain *hw_dom = resctrl_to_arch_mon_dom(d); ++ struct rdt_hw_l3_mon_domain *hw_dom = resctrl_to_arch_mon_dom(d); + struct arch_mbm_state *am; + u64 msr_val; + u32 prmid; +@@ -308,11 +308,11 @@ static int __cntr_id_read(u32 cntr_id, u64 *val) + return 0; + } + +-void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_mon_domain *d, ++void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + u32 unused, u32 rmid, int cntr_id, + enum resctrl_event_id eventid) + { +- struct rdt_hw_mon_domain *hw_dom = resctrl_to_arch_mon_dom(d); ++ struct rdt_hw_l3_mon_domain *hw_dom = resctrl_to_arch_mon_dom(d); + struct arch_mbm_state *am; + + am = get_arch_mbm_state(hw_dom, rmid, eventid); +@@ -324,7 +324,7 @@ void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_mon_domain *d, + } + } + +-int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_mon_domain *d, ++int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + u32 unused, u32 rmid, int cntr_id, + enum resctrl_event_id eventid, u64 *val) + { +@@ -354,7 +354,7 @@ int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_mon_domain *d, + * must adjust RMID counter numbers based on SNC node. See + * logical_rmid_to_physical_rmid() for code that does this. + */ +-void arch_mon_domain_online(struct rdt_resource *r, struct rdt_mon_domain *d) ++void arch_mon_domain_online(struct rdt_resource *r, struct rdt_l3_mon_domain *d) + { + if (snc_nodes_per_l3_cache > 1) + msr_clear_bit(MSR_RMID_SNC_CONFIG, 0); +@@ -423,7 +423,7 @@ static __init int snc_get_config(void) + return ret; + } + +-int __init rdt_get_mon_l3_config(struct rdt_resource *r) ++int __init rdt_get_l3_mon_config(struct rdt_resource *r) + { + unsigned int mbm_offset = boot_cpu_data.x86_cache_mbm_width_offset; + struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); +@@ -515,7 +515,7 @@ static void resctrl_abmc_set_one_amd(void *arg) + */ + static void _resctrl_abmc_enable(struct rdt_resource *r, bool enable) + { +- struct rdt_mon_domain *d; ++ struct rdt_l3_mon_domain *d; + + lockdep_assert_cpus_held(); + +@@ -554,11 +554,11 @@ static void resctrl_abmc_config_one_amd(void *info) + /* + * Send an IPI to the domain to assign the counter to RMID, event pair. + */ +-void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_mon_domain *d, ++void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + enum resctrl_event_id evtid, u32 rmid, u32 closid, + u32 cntr_id, bool assign) + { +- struct rdt_hw_mon_domain *hw_dom = resctrl_to_arch_mon_dom(d); ++ struct rdt_hw_l3_mon_domain *hw_dom = resctrl_to_arch_mon_dom(d); + union l3_qos_abmc_cfg abmc_cfg = { 0 }; + struct arch_mbm_state *am; + +diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c +index f895019a55e578..e6e747507fd3ef 100644 +--- a/arch/x86/kvm/lapic.c ++++ b/arch/x86/kvm/lapic.c +@@ -2065,7 +2065,7 @@ static void apic_timer_expired(struct kvm_lapic *apic, bool from_timer_fn) + if (apic_lvtt_tscdeadline(apic) || ktimer->hv_timer_in_use) + ktimer->expired_tscdeadline = ktimer->tscdeadline; + +- if (!from_timer_fn && apic->apicv_active) { ++ if (!from_timer_fn && apic->apicv_active && vcpu->wants_to_run) { + WARN_ON(kvm_get_running_vcpu() != vcpu); + kvm_apic_inject_pending_timer_irqs(apic); + return; +diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c +index eadeca9786f6fd..e95d96dccfe4a9 100644 +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -4806,16 +4806,17 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault + if (r != RET_PF_CONTINUE) + return r; + +- r = RET_PF_RETRY; + write_lock(&vcpu->kvm->mmu_lock); + +- if (is_page_fault_stale(vcpu, fault)) +- goto out_unlock; +- + r = make_mmu_pages_available(vcpu); + if (r) + goto out_unlock; + ++ if (is_page_fault_stale(vcpu, fault)) { ++ r = RET_PF_RETRY; ++ goto out_unlock; ++ } ++ + r = direct_map(vcpu, fault); + + out_unlock: +@@ -7392,7 +7393,9 @@ void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, u64 gen) + static void mmu_destroy_caches(void) + { + kmem_cache_destroy(pte_list_desc_cache); ++ pte_list_desc_cache = NULL; + kmem_cache_destroy(mmu_page_header_cache); ++ mmu_page_header_cache = NULL; + } + + static void kvm_wake_nx_recovery_thread(struct kvm *kvm) +diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h +index ed762bb4b007b9..af220c9c8ab8dd 100644 +--- a/arch/x86/kvm/mmu/paging_tmpl.h ++++ b/arch/x86/kvm/mmu/paging_tmpl.h +@@ -827,15 +827,17 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault + } + #endif + +- r = RET_PF_RETRY; + write_lock(&vcpu->kvm->mmu_lock); + +- if (is_page_fault_stale(vcpu, fault)) +- goto out_unlock; +- + r = make_mmu_pages_available(vcpu); + if (r) + goto out_unlock; ++ ++ if (is_page_fault_stale(vcpu, fault)) { ++ r = RET_PF_RETRY; ++ goto out_unlock; ++ } ++ + r = FNAME(fetch)(vcpu, fault, &walker); + + out_unlock: +diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c +index bb034896bf6dfe..36fad2f95bd2e0 100644 +--- a/arch/x86/kvm/svm/svm.c ++++ b/arch/x86/kvm/svm/svm.c +@@ -523,7 +523,12 @@ static int svm_enable_virtualization_cpu(void) + return -EBUSY; + + sd = per_cpu_ptr(&svm_data, me); +- sd->asid_generation = 1; ++ /* ++ * Bump the current asid_generation value to ensure any vCPU that ++ * previously ran on this CPU sees a stale generation and is forced ++ * to acquire a new ASID, preventing a latent ASID collision. ++ */ ++ sd->asid_generation++; + sd->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1; + sd->next_asid = sd->max_asid + 1; + sd->min_asid = max_sev_asid + 1; +diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c +index a5a525ae8e7832..afb4be700f9a3d 100644 +--- a/arch/x86/kvm/vmx/nested.c ++++ b/arch/x86/kvm/vmx/nested.c +@@ -333,6 +333,7 @@ static void nested_put_vmcs12_pages(struct kvm_vcpu *vcpu) + static void free_nested(struct kvm_vcpu *vcpu) + { + struct vcpu_vmx *vmx = to_vmx(vcpu); ++ struct vmcs *shadow_vmcs; + + if (WARN_ON_ONCE(vmx->loaded_vmcs != &vmx->vmcs01)) + vmx_switch_vmcs(vcpu, &vmx->vmcs01); +@@ -350,9 +351,15 @@ static void free_nested(struct kvm_vcpu *vcpu) + vmx->nested.current_vmptr = INVALID_GPA; + if (enable_shadow_vmcs) { + vmx_disable_shadow_vmcs(vmx); +- vmcs_clear(vmx->vmcs01.shadow_vmcs); +- free_vmcs(vmx->vmcs01.shadow_vmcs); ++ ++ /* ++ * Keep the pointer visible until after VMCLEAR, so migration ++ * can clear an active shadow VMCS on the old CPU. ++ */ ++ shadow_vmcs = vmx->vmcs01.shadow_vmcs; ++ vmcs_clear(shadow_vmcs); + vmx->vmcs01.shadow_vmcs = NULL; ++ free_vmcs(shadow_vmcs); + } + kfree(vmx->nested.cached_vmcs12); + vmx->nested.cached_vmcs12 = NULL; +diff --git a/drivers/accel/amdxdna/amdxdna_ctx.c b/drivers/accel/amdxdna/amdxdna_ctx.c +index cfee89681ff3cf..a49c059e6ed495 100644 +--- a/drivers/accel/amdxdna/amdxdna_ctx.c ++++ b/drivers/accel/amdxdna/amdxdna_ctx.c +@@ -393,6 +393,7 @@ void amdxdna_sched_job_cleanup(struct amdxdna_sched_job *job) + amdxdna_arg_bos_put(job); + amdxdna_gem_put_obj(job->cmd_bo); + dma_fence_put(job->fence); ++ mmdrop(job->mm); + } + + int amdxdna_cmd_submit(struct amdxdna_client *client, +@@ -405,6 +406,10 @@ int amdxdna_cmd_submit(struct amdxdna_client *client, + int ret, idx; + + XDNA_DBG(xdna, "Command BO hdl %d, Arg BO count %d", cmd_bo_hdl, arg_bo_cnt); ++ ++ if (!xdna->dev_info->ops->cmd_submit) ++ return -EOPNOTSUPP; ++ + job = kzalloc(struct_size(job, bos, arg_bo_cnt), GFP_KERNEL); + if (!job) + return -ENOMEM; +@@ -443,6 +448,7 @@ int amdxdna_cmd_submit(struct amdxdna_client *client, + + job->hwctx = hwctx; + job->mm = current->mm; ++ mmgrab(job->mm); + + job->fence = amdxdna_fence_create(hwctx); + if (!job->fence) { +@@ -475,6 +481,8 @@ unlock_srcu: + cmd_put: + amdxdna_gem_put_obj(job->cmd_bo); + free_job: ++ if (job->mm) ++ mmdrop(job->mm); + kfree(job); + return ret; + } +diff --git a/drivers/accel/ivpu/ivpu_hw_btrs.c b/drivers/accel/ivpu/ivpu_hw_btrs.c +index aa33f562d29c12..e9786204feca43 100644 +--- a/drivers/accel/ivpu/ivpu_hw_btrs.c ++++ b/drivers/accel/ivpu/ivpu_hw_btrs.c +@@ -845,7 +845,7 @@ static void diagnose_failure_mtl(struct ivpu_device *vdev) + + static void diagnose_failure_lnl(struct ivpu_device *vdev) + { +- u32 reg = REGB_RD32(VPU_HW_BTRS_MTL_INTERRUPT_STAT) & BTRS_LNL_IRQ_MASK; ++ u32 reg = REGB_RD32(VPU_HW_BTRS_LNL_INTERRUPT_STAT) & BTRS_LNL_IRQ_MASK; + + if (REG_TEST_FLD(VPU_HW_BTRS_LNL_INTERRUPT_STAT, ATS_ERR, reg)) { + ivpu_err(vdev, "ATS_ERR_LOG1 0x%08x ATS_ERR_LOG2 0x%08x\n", +diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thread.rs +index ad8bdf762ddc6f..93b550e6b60e71 100644 +--- a/drivers/android/binder/thread.rs ++++ b/drivers/android/binder/thread.rs +@@ -1268,14 +1268,14 @@ impl Thread { + inner.extended_error = + ExtendedError::new(info.debug_id as u32, err.reply, source.to_errno()); + } +- } + +- pr_warn!( +- "{}:{} transaction to {} failed: {err:?}", +- info.from_pid, +- info.from_tid, +- info.to_pid +- ); ++ pr_warn!( ++ "{}:{} transaction to {} failed: {err:?}", ++ info.from_pid, ++ info.from_tid, ++ info.to_pid ++ ); ++ } + } + } + +diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c +index 22ce6accbc5bb5..f0753f5e57a8e1 100644 +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -2833,6 +2833,24 @@ static void ata_dev_config_cpr(struct ata_device *dev) + if (!nr_cpr) + goto out; + ++ /* ++ * The device reports the number of CPR descriptors independently of the ++ * log size, and that count is also used to emit VPD page B9h into the ++ * fixed-size rbuf. Reject a count larger than what that buffer can hold ++ * (ATA_DEV_MAX_CPR) or larger than the log the device actually returned. ++ */ ++ if (nr_cpr > ATA_DEV_MAX_CPR) { ++ ata_dev_warn(dev, ++ "Too many concurrent positioning ranges\n"); ++ goto out; ++ } ++ ++ if (buf_len < 64 + (size_t)nr_cpr * 32) { ++ ata_dev_warn(dev, ++ "Invalid number of concurrent positioning ranges\n"); ++ goto out; ++ } ++ + cpr_log = kzalloc(struct_size(cpr_log, cpr, nr_cpr), GFP_KERNEL); + if (!cpr_log) + goto out; +diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c +index 46ef1ef6f81282..a7916b50cbfcad 100644 +--- a/drivers/ata/libata-scsi.c ++++ b/drivers/ata/libata-scsi.c +@@ -37,8 +37,6 @@ + #include "libata.h" + #include "libata-transport.h" + +-#define ATA_SCSI_RBUF_SIZE 2048 +- + static DEFINE_SPINLOCK(ata_scsi_rbuf_lock); + static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE]; + +diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h +index 0002994ddfc9b4..56c4136b741798 100644 +--- a/drivers/ata/libata.h ++++ b/drivers/ata/libata.h +@@ -144,6 +144,15 @@ static inline void ata_acpi_bind_dev(struct ata_device *dev) {} + #endif + + /* libata-scsi.c */ ++#define ATA_SCSI_RBUF_SIZE 2048 ++ ++/* ++ * Maximum number of concurrent positioning ranges (CPR) supported. The ACS ++ * specifications allow up to 255, but we limit this to the number of CPR ++ * descriptors that fit in the rbuf buffer used to emit VPD page B9h. ++ */ ++#define ATA_DEV_MAX_CPR min(255, ((ATA_SCSI_RBUF_SIZE - 64) / 32)) ++ + extern struct ata_device *ata_scsi_find_dev(struct ata_port *ap, + const struct scsi_device *scsidev); + extern int ata_scsi_add_hosts(struct ata_host *host, +diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c +index 7a4f59202156ec..36cc28b8986509 100644 +--- a/drivers/ata/sata_dwc_460ex.c ++++ b/drivers/ata/sata_dwc_460ex.c +@@ -19,7 +19,6 @@ + #include <linux/device.h> + #include <linux/dmaengine.h> + #include <linux/of.h> +-#include <linux/of_irq.h> + #include <linux/platform_device.h> + #include <linux/phy/phy.h> + #include <linux/libata.h> +@@ -226,7 +225,6 @@ static int sata_dwc_dma_init_old(struct platform_device *pdev, + struct sata_dwc_device *hsdev) + { + struct device *dev = &pdev->dev; +- struct device_node *np = dev->of_node; + + hsdev->dma = devm_kzalloc(dev, sizeof(*hsdev->dma), GFP_KERNEL); + if (!hsdev->dma) +@@ -236,11 +234,9 @@ static int sata_dwc_dma_init_old(struct platform_device *pdev, + hsdev->dma->id = pdev->id; + + /* Get SATA DMA interrupt number */ +- hsdev->dma->irq = irq_of_parse_and_map(np, 1); +- if (!hsdev->dma->irq) { +- dev_err(dev, "no SATA DMA irq\n"); +- return -ENODEV; +- } ++ hsdev->dma->irq = platform_get_irq(pdev, 1); ++ if (hsdev->dma->irq < 0) ++ return hsdev->dma->irq; + + /* Get physical SATA DMA register base address */ + hsdev->dma->regs = devm_platform_ioremap_resource(pdev, 1); +@@ -398,8 +394,7 @@ static void clear_serror(struct ata_port *ap) + + static void clear_interrupt_bit(struct sata_dwc_device *hsdev, u32 bit) + { +- sata_dwc_writel(&hsdev->sata_dwc_regs->intpr, +- sata_dwc_readl(&hsdev->sata_dwc_regs->intpr)); ++ sata_dwc_writel(&hsdev->sata_dwc_regs->intpr, bit); + } + + static u32 qcmd_tag_to_mask(u8 tag) +@@ -612,14 +607,9 @@ DRVSTILLBUSY: + status = ap->ops->sff_check_status(ap); + dev_dbg(ap->dev, "%s ATA status register=0x%x\n", __func__, status); + +- tag = 0; + while (tag_mask) { +- while (!(tag_mask & 0x00000001)) { +- tag++; +- tag_mask <<= 1; +- } +- +- tag_mask &= (~0x00000001); ++ tag = __ffs(tag_mask); ++ tag_mask &= ~(1U << tag); + qc = ata_qc_from_tag(ap, tag); + if (unlikely(!qc)) { + dev_err(ap->dev, "failed to get qc"); +@@ -1125,7 +1115,6 @@ static const struct ata_port_info sata_dwc_port_info[] = { + static int sata_dwc_probe(struct platform_device *ofdev) + { + struct device *dev = &ofdev->dev; +- struct device_node *np = dev->of_node; + struct sata_dwc_device *hsdev; + u32 idr, versionr; + char *ver = (char *)&versionr; +@@ -1168,18 +1157,13 @@ static int sata_dwc_probe(struct platform_device *ofdev) + /* Save dev for later use in dev_xxx() routines */ + hsdev->dev = dev; + +- /* Enable SATA Interrupts */ +- sata_dwc_enable_interrupts(hsdev); +- + /* Get SATA interrupt number */ +- irq = irq_of_parse_and_map(np, 0); +- if (!irq) { +- dev_err(dev, "no SATA DMA irq\n"); +- return -ENODEV; +- } ++ irq = platform_get_irq(ofdev, 0); ++ if (irq < 0) ++ return irq; + + #ifdef CONFIG_SATA_DWC_OLD_DMA +- if (!of_property_present(np, "dmas")) { ++ if (!of_property_present(dev->of_node, "dmas")) { + err = sata_dwc_dma_init_old(ofdev, hsdev); + if (err) + return err; +@@ -1203,6 +1187,8 @@ static int sata_dwc_probe(struct platform_device *ofdev) + if (err) + dev_err(dev, "failed to activate host"); + ++ /* Enable SATA Interrupts */ ++ sata_dwc_enable_interrupts(hsdev); + return 0; + + error_out: +diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c +index 97cd8cf7bad301..6c802f029f57d4 100644 +--- a/drivers/block/rbd.c ++++ b/drivers/block/rbd.c +@@ -1957,9 +1957,14 @@ static int rbd_object_map_update_finish(struct rbd_obj_request *obj_req, + bool has_current_state; + void *p; + +- if (osd_req->r_result) ++ if (osd_req->r_result < 0) + return osd_req->r_result; + ++ /* ++ * Writes aren't allowed to return a data payload. ++ */ ++ WARN_ON_ONCE(osd_req->r_result > 0); ++ + /* + * Nothing to do for a snapshot object map. + */ +diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c +index c339222513b03c..cb31e96f01cdd6 100644 +--- a/drivers/block/ublk_drv.c ++++ b/drivers/block/ublk_drv.c +@@ -19,6 +19,7 @@ + #include <linux/errno.h> + #include <linux/major.h> + #include <linux/wait.h> ++#include <linux/wait_bit.h> + #include <linux/blkdev.h> + #include <linux/init.h> + #include <linux/swap.h> +@@ -26,7 +27,6 @@ + #include <linux/compat.h> + #include <linux/mutex.h> + #include <linux/writeback.h> +-#include <linux/completion.h> + #include <linux/highmem.h> + #include <linux/sysfs.h> + #include <linux/miscdevice.h> +@@ -230,7 +230,6 @@ struct ublk_device { + + struct ublk_params params; + +- struct completion completion; + u32 nr_io_ready; + bool unprivileged_daemons; + struct mutex cancel_mutex; +@@ -2150,9 +2149,13 @@ static void ublk_mark_io_ready(struct ublk_device *ub) + + ub->nr_io_ready++; + if (ublk_dev_ready(ub)) { +- /* now we are ready for handling ublk io request */ ++ /* ++ * now we are ready for handling ublk io request, clear ++ * device-level canceling flag and wake ublk_dev_ready() ++ * waiters ++ */ + ublk_reset_io_flags(ub); +- complete_all(&ub->completion); ++ wake_up_var(&ub->nr_io_ready); + } + } + +@@ -2829,7 +2832,6 @@ static int ublk_init_queues(struct ublk_device *ub) + goto fail; + } + +- init_completion(&ub->completion); + return 0; + + fail: +@@ -2966,6 +2968,26 @@ static bool ublk_validate_user_pid(struct ublk_device *ub, pid_t ublksrv_pid) + return ub->ublksrv_tgid == ublksrv_pid; + } + ++/* ++ * Wait until all queues have fetched their I/O commands, and return with ++ * ub->mutex held and readiness guaranteed: then every queue's ->canceling ++ * is cleared. Ready may regress between wakeup and mutex_lock() (daemon ++ * death), so re-check it under the mutex and wait again. ++ */ ++static int ublk_wait_dev_ready_and_lock(struct ublk_device *ub) ++{ ++ while (true) { ++ if (wait_var_event_interruptible(&ub->nr_io_ready, ++ ublk_dev_ready(ub))) ++ return -EINTR; ++ ++ mutex_lock(&ub->mutex); ++ if (ublk_dev_ready(ub)) ++ return 0; ++ mutex_unlock(&ub->mutex); ++ } ++} ++ + static int ublk_ctrl_start_dev(struct ublk_device *ub, + const struct ublksrv_ctrl_cmd *header) + { +@@ -3031,13 +3053,13 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub, + lim.max_segments = ub->params.seg.max_segments; + } + +- if (wait_for_completion_interruptible(&ub->completion) != 0) ++ if (ublk_wait_dev_ready_and_lock(ub)) + return -EINTR; + +- if (!ublk_validate_user_pid(ub, ublksrv_pid)) +- return -EINVAL; +- +- mutex_lock(&ub->mutex); ++ if (!ublk_validate_user_pid(ub, ublksrv_pid)) { ++ ret = -EINVAL; ++ goto out_unlock; ++ } + if (ub->dev_info.state == UBLK_S_DEV_LIVE || + test_bit(UB_STATE_USED, &ub->state)) { + ret = -EEXIST; +@@ -3549,7 +3571,6 @@ static int ublk_ctrl_start_recovery(struct ublk_device *ub, + goto out_unlock; + } + pr_devel("%s: start recovery for dev id %d.\n", __func__, header->dev_id); +- init_completion(&ub->completion); + ret = 0; + out_unlock: + mutex_unlock(&ub->mutex); +@@ -3565,16 +3586,17 @@ static int ublk_ctrl_end_recovery(struct ublk_device *ub, + pr_devel("%s: Waiting for all FETCH_REQs, dev id %d...\n", __func__, + header->dev_id); + +- if (wait_for_completion_interruptible(&ub->completion)) ++ if (ublk_wait_dev_ready_and_lock(ub)) + return -EINTR; + + pr_devel("%s: All FETCH_REQs received, dev id %d\n", __func__, + header->dev_id); + +- if (!ublk_validate_user_pid(ub, ublksrv_pid)) +- return -EINVAL; ++ if (!ublk_validate_user_pid(ub, ublksrv_pid)) { ++ ret = -EINVAL; ++ goto out_unlock; ++ } + +- mutex_lock(&ub->mutex); + if (ublk_nosrv_should_stop_dev(ub)) + goto out_unlock; + +diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c +index 86a48d009d1ba2..afab479ac89448 100644 +--- a/drivers/bluetooth/btqca.c ++++ b/drivers/bluetooth/btqca.c +@@ -413,7 +413,7 @@ static int qca_tlv_check_data(struct hci_dev *hdev, + + idx = 0; + data = tlv->data; +- while (idx < length - sizeof(struct tlv_type_nvm)) { ++ while (idx + sizeof(struct tlv_type_nvm) <= length) { + tlv_nvm = (struct tlv_type_nvm *)(data + idx); + + tag_id = le16_to_cpu(tlv_nvm->tag_id); +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index b9e5adecfed609..fea3cb502a4e03 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -2716,7 +2716,9 @@ static int btusb_setup_realtek(struct hci_dev *hdev) + + static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb) + { +- if (skb->data[0] == HCI_VENDOR_PKT && skb->data[2] == RTK_SUB_EVENT_CODE_COREDUMP) { ++ if (skb->len >= HCI_EVENT_HDR_SIZE + 1 && ++ skb->data[0] == HCI_VENDOR_PKT && ++ skb->data[2] == RTK_SUB_EVENT_CODE_COREDUMP) { + struct rtk_dev_coredump_hdr hdr = { + .code = RTK_DEVCOREDUMP_CODE_MEMDUMP, + }; +diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c +index c649a3f702c042..b510b03dae870f 100644 +--- a/drivers/bluetooth/hci_qca.c ++++ b/drivers/bluetooth/hci_qca.c +@@ -1083,6 +1083,10 @@ static void qca_controller_memdump(struct work_struct *work) + if (!(qca_memdump->ram_dump_size)) { + bt_dev_err(hu->hdev, "Rx invalid memdump size"); + kfree(qca_memdump); ++ qca->qca_memdump = NULL; ++ qca->memdump_state = QCA_MEMDUMP_COLLECTED; ++ clear_and_wake_up_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); ++ clear_bit(QCA_IBS_DISABLED, &qca->flags); + kfree_skb(skb); + mutex_unlock(&qca->hci_memdump_lock); + return; +diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c +index e30414f0d45605..ce2de543bac322 100644 +--- a/drivers/cdrom/cdrom.c ++++ b/drivers/cdrom/cdrom.c +@@ -3187,6 +3187,7 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi, + + /* set volume */ + cgc->buffer = buffer + offset - 8; ++ cgc->buflen -= offset - 8; + memset(cgc->buffer, 0, 8); + return cdrom_mode_select(cdi, cgc); + } +diff --git a/drivers/comedi/drivers/comedi_parport.c b/drivers/comedi/drivers/comedi_parport.c +index 098738a688fe64..db9f58792ab919 100644 +--- a/drivers/comedi/drivers/comedi_parport.c ++++ b/drivers/comedi/drivers/comedi_parport.c +@@ -211,6 +211,13 @@ static irqreturn_t parport_interrupt(int irq, void *d) + unsigned int ctrl; + unsigned short val = 0; + ++ /* ++ * Check device is fully attached. Device interrupts should have ++ * been disabled, but do this in case of bad hardware. ++ */ ++ if (!dev->attached) ++ return IRQ_NONE; ++ + ctrl = inb(dev->iobase + PARPORT_CTRL_REG); + if (!(ctrl & PARPORT_CTRL_IRQ_ENA)) + return IRQ_NONE; +@@ -231,6 +238,9 @@ static int parport_attach(struct comedi_device *dev, + if (ret) + return ret; + ++ outb(0, dev->iobase + PARPORT_DATA_REG); ++ outb(0, dev->iobase + PARPORT_CTRL_REG); ++ + if (it->options[1]) { + ret = request_irq(it->options[1], parport_interrupt, 0, + dev->board_name, dev); +@@ -286,9 +296,6 @@ static int parport_attach(struct comedi_device *dev, + s->cancel = parport_intr_cancel; + } + +- outb(0, dev->iobase + PARPORT_DATA_REG); +- outb(0, dev->iobase + PARPORT_CTRL_REG); +- + return 0; + } + +diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c +index a70df77f9b7d11..ced96d9e254ee4 100644 +--- a/drivers/cpufreq/cpufreq.c ++++ b/drivers/cpufreq/cpufreq.c +@@ -2584,6 +2584,9 @@ static void cpufreq_update_pressure(struct cpufreq_policy *policy) + + cpu = cpumask_first(policy->related_cpus); + max_freq = arch_scale_freq_ref(cpu); ++ if (!max_freq) ++ max_freq = policy->cpuinfo.max_freq; ++ + capped_freq = policy->max; + + /* +diff --git a/drivers/crypto/tegra/tegra-se-main.c b/drivers/crypto/tegra/tegra-se-main.c +index 2755f19ad05e92..77b923a6b7c18c 100644 +--- a/drivers/crypto/tegra/tegra-se-main.c ++++ b/drivers/crypto/tegra/tegra-se-main.c +@@ -52,7 +52,7 @@ tegra_se_cmdbuf_pin(struct device *dev, struct host1x_bo *bo, enum dma_data_dire + return ERR_PTR(-ENOMEM); + + kref_init(&map->ref); +- map->bo = host1x_bo_get(bo); ++ map->bo = bo; + map->direction = direction; + map->dev = dev; + +@@ -93,7 +93,6 @@ static void tegra_se_cmdbuf_unpin(struct host1x_bo_mapping *map) + dma_unmap_sgtable(map->dev, map->sgt, map->direction, 0); + sg_free_table(map->sgt); + kfree(map->sgt); +- host1x_bo_put(map->bo); + + kfree(map); + } +diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig +index 599e126a18eb72..4bdec46b2a6bbe 100644 +--- a/drivers/cxl/Kconfig ++++ b/drivers/cxl/Kconfig +@@ -234,4 +234,8 @@ config CXL_MCE + def_bool y + depends on X86_MCE && MEMORY_FAILURE + ++config CXL_RAS ++ def_bool y ++ depends on ACPI_APEI_GHES && PCIEAER && CXL_PCI ++ + endif +diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile +index 5ad8fef210b5c8..b2930cc54f8ba2 100644 +--- a/drivers/cxl/core/Makefile ++++ b/drivers/cxl/core/Makefile +@@ -14,9 +14,9 @@ cxl_core-y += pci.o + cxl_core-y += hdm.o + cxl_core-y += pmu.o + cxl_core-y += cdat.o +-cxl_core-y += ras.o + cxl_core-$(CONFIG_TRACING) += trace.o + cxl_core-$(CONFIG_CXL_REGION) += region.o + cxl_core-$(CONFIG_CXL_MCE) += mce.o + cxl_core-$(CONFIG_CXL_FEATURES) += features.o + cxl_core-$(CONFIG_CXL_EDAC_MEM_FEATURES) += edac.o ++cxl_core-$(CONFIG_CXL_RAS) += ras.o +diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h +index 1fb66132b77771..bc818de87ccccf 100644 +--- a/drivers/cxl/core/core.h ++++ b/drivers/cxl/core/core.h +@@ -144,8 +144,39 @@ int cxl_pci_get_bandwidth(struct pci_dev *pdev, struct access_coordinate *c); + int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port, + struct access_coordinate *c); + ++#ifdef CONFIG_CXL_RAS + int cxl_ras_init(void); + void cxl_ras_exit(void); ++bool cxl_handle_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base); ++void cxl_handle_cor_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base); ++#else ++static inline int cxl_ras_init(void) ++{ ++ return 0; ++} ++ ++static inline void cxl_ras_exit(void) ++{ ++} ++ ++static inline bool cxl_handle_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base) ++{ ++ return false; ++} ++static inline void cxl_handle_cor_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base) { } ++#endif /* CONFIG_CXL_RAS */ ++ ++/* Restricted CXL Host specific RAS functions */ ++#ifdef CONFIG_CXL_RAS ++void cxl_dport_map_rch_aer(struct cxl_dport *dport); ++void cxl_disable_rch_root_ints(struct cxl_dport *dport); ++void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds); ++#else ++static inline void cxl_dport_map_rch_aer(struct cxl_dport *dport) { } ++static inline void cxl_disable_rch_root_ints(struct cxl_dport *dport) { } ++static inline void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) { } ++#endif /* CONFIG_CXL_RAS */ ++ + int cxl_gpf_port_setup(struct cxl_dport *dport); + + struct cxl_hdm; +diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c +index 18825e1505d6ad..bd7d7e382d041b 100644 +--- a/drivers/cxl/core/pci.c ++++ b/drivers/cxl/core/pci.c +@@ -711,91 +711,8 @@ err: + } + EXPORT_SYMBOL_NS_GPL(read_cdat_data, "CXL"); + +-static void __cxl_handle_cor_ras(struct cxl_dev_state *cxlds, +- void __iomem *ras_base) +-{ +- void __iomem *addr; +- u32 status; +- +- if (!ras_base) +- return; +- +- addr = ras_base + CXL_RAS_CORRECTABLE_STATUS_OFFSET; +- status = readl(addr); +- if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) { +- writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr); +- trace_cxl_aer_correctable_error(cxlds->cxlmd, status); +- } +-} +- +-static void cxl_handle_endpoint_cor_ras(struct cxl_dev_state *cxlds) +-{ +- return __cxl_handle_cor_ras(cxlds, cxlds->regs.ras); +-} +- +-/* CXL spec rev3.0 8.2.4.16.1 */ +-static void header_log_copy(void __iomem *ras_base, u32 *log) +-{ +- void __iomem *addr; +- u32 *log_addr; +- int i, log_u32_size = CXL_HEADERLOG_SIZE / sizeof(u32); +- +- addr = ras_base + CXL_RAS_HEADER_LOG_OFFSET; +- log_addr = log; +- +- for (i = 0; i < log_u32_size; i++) { +- *log_addr = readl(addr); +- log_addr++; +- addr += sizeof(u32); +- } +-} +- +-/* +- * Log the state of the RAS status registers and prepare them to log the +- * next error status. Return 1 if reset needed. +- */ +-static bool __cxl_handle_ras(struct cxl_dev_state *cxlds, +- void __iomem *ras_base) +-{ +- u32 hl[CXL_HEADERLOG_SIZE_U32]; +- void __iomem *addr; +- u32 status; +- u32 fe; +- +- if (!ras_base) +- return false; +- +- addr = ras_base + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET; +- status = readl(addr); +- if (!(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK)) +- return false; +- +- /* If multiple errors, log header points to first error from ctrl reg */ +- if (hweight32(status) > 1) { +- void __iomem *rcc_addr = +- ras_base + CXL_RAS_CAP_CONTROL_OFFSET; +- +- fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK, +- readl(rcc_addr))); +- } else { +- fe = status; +- } +- +- header_log_copy(ras_base, hl); +- trace_cxl_aer_uncorrectable_error(cxlds->cxlmd, status, fe, hl); +- writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr); +- +- return true; +-} +- +-static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds) +-{ +- return __cxl_handle_ras(cxlds, cxlds->regs.ras); +-} +- +-#ifdef CONFIG_PCIEAER_CXL +- +-static void cxl_dport_map_rch_aer(struct cxl_dport *dport) ++#ifdef CONFIG_CXL_RAS ++void cxl_dport_map_rch_aer(struct cxl_dport *dport) + { + resource_size_t aer_phys; + struct device *host; +@@ -810,19 +727,7 @@ static void cxl_dport_map_rch_aer(struct cxl_dport *dport) + } + } + +-static void cxl_dport_map_ras(struct cxl_dport *dport) +-{ +- struct cxl_register_map *map = &dport->reg_map; +- struct device *dev = dport->dport_dev; +- +- if (!map->component_map.ras.valid) +- dev_dbg(dev, "RAS registers not found\n"); +- else if (cxl_map_component_regs(map, &dport->regs.component, +- BIT(CXL_CM_CAP_CAP_ID_RAS))) +- dev_dbg(dev, "Failed to map RAS capability.\n"); +-} +- +-static void cxl_disable_rch_root_ints(struct cxl_dport *dport) ++void cxl_disable_rch_root_ints(struct cxl_dport *dport) + { + void __iomem *aer_base = dport->regs.dport_aer; + u32 aer_cmd_mask, aer_cmd; +@@ -846,40 +751,6 @@ static void cxl_disable_rch_root_ints(struct cxl_dport *dport) + writel(aer_cmd, aer_base + PCI_ERR_ROOT_COMMAND); + } + +-/** +- * cxl_dport_init_ras_reporting - Setup CXL RAS report on this dport +- * @dport: the cxl_dport that needs to be initialized +- * @host: host device for devm operations +- */ +-void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host) +-{ +- dport->reg_map.host = host; +- cxl_dport_map_ras(dport); +- +- if (dport->rch) { +- struct pci_host_bridge *host_bridge = to_pci_host_bridge(dport->dport_dev); +- +- if (!host_bridge->native_aer) +- return; +- +- cxl_dport_map_rch_aer(dport); +- cxl_disable_rch_root_ints(dport); +- } +-} +-EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL"); +- +-static void cxl_handle_rdport_cor_ras(struct cxl_dev_state *cxlds, +- struct cxl_dport *dport) +-{ +- return __cxl_handle_cor_ras(cxlds, dport->regs.ras); +-} +- +-static bool cxl_handle_rdport_ras(struct cxl_dev_state *cxlds, +- struct cxl_dport *dport) +-{ +- return __cxl_handle_ras(cxlds, dport->regs.ras); +-} +- + /* + * Copy the AER capability registers using 32 bit read accesses. + * This is necessary because RCRB AER capability is MMIO mapped. Clear the +@@ -928,7 +799,7 @@ static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs, + return false; + } + +-static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) ++void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) + { + struct pci_dev *pdev = to_pci_dev(cxlds->dev); + struct aer_capability_regs aer_regs; +@@ -949,86 +820,12 @@ static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) + pci_print_aer(pdev, severity, &aer_regs); + + if (severity == AER_CORRECTABLE) +- cxl_handle_rdport_cor_ras(cxlds, dport); ++ cxl_handle_cor_ras(cxlds, dport->regs.ras); + else +- cxl_handle_rdport_ras(cxlds, dport); ++ cxl_handle_ras(cxlds, dport->regs.ras); + } +- +-#else +-static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) { } + #endif + +-void cxl_cor_error_detected(struct pci_dev *pdev) +-{ +- struct cxl_dev_state *cxlds = pci_get_drvdata(pdev); +- struct device *dev = &cxlds->cxlmd->dev; +- +- scoped_guard(device, dev) { +- if (!dev->driver) { +- dev_warn(&pdev->dev, +- "%s: memdev disabled, abort error handling\n", +- dev_name(dev)); +- return; +- } +- +- if (cxlds->rcd) +- cxl_handle_rdport_errors(cxlds); +- +- cxl_handle_endpoint_cor_ras(cxlds); +- } +-} +-EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL"); +- +-pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, +- pci_channel_state_t state) +-{ +- struct cxl_dev_state *cxlds = pci_get_drvdata(pdev); +- struct cxl_memdev *cxlmd = cxlds->cxlmd; +- struct device *dev = &cxlmd->dev; +- bool ue; +- +- scoped_guard(device, dev) { +- if (!dev->driver) { +- dev_warn(&pdev->dev, +- "%s: memdev disabled, abort error handling\n", +- dev_name(dev)); +- return PCI_ERS_RESULT_DISCONNECT; +- } +- +- if (cxlds->rcd) +- cxl_handle_rdport_errors(cxlds); +- /* +- * A frozen channel indicates an impending reset which is fatal to +- * CXL.mem operation, and will likely crash the system. On the off +- * chance the situation is recoverable dump the status of the RAS +- * capability registers and bounce the active state of the memdev. +- */ +- ue = cxl_handle_endpoint_ras(cxlds); +- } +- +- +- switch (state) { +- case pci_channel_io_normal: +- if (ue) { +- device_release_driver(dev); +- return PCI_ERS_RESULT_NEED_RESET; +- } +- return PCI_ERS_RESULT_CAN_RECOVER; +- case pci_channel_io_frozen: +- dev_warn(&pdev->dev, +- "%s: frozen state error detected, disable CXL.mem\n", +- dev_name(dev)); +- device_release_driver(dev); +- return PCI_ERS_RESULT_NEED_RESET; +- case pci_channel_io_perm_failure: +- dev_warn(&pdev->dev, +- "failure state error detected, request disconnect\n"); +- return PCI_ERS_RESULT_DISCONNECT; +- } +- return PCI_ERS_RESULT_NEED_RESET; +-} +-EXPORT_SYMBOL_NS_GPL(cxl_error_detected, "CXL"); +- + static int cxl_flit_size(struct pci_dev *pdev) + { + if (cxl_pci_flit_256(pdev)) +diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c +index 2731ba3a07993c..7056a79bff4d14 100644 +--- a/drivers/cxl/core/ras.c ++++ b/drivers/cxl/core/ras.c +@@ -5,8 +5,13 @@ + #include <linux/aer.h> + #include <cxl/event.h> + #include <cxlmem.h> ++#include <cxlpci.h> + #include "trace.h" + ++/* Check that UCE header definition is maintained to keep ABI intact */ ++static_assert(CXL_HEADERLOG_TRACE_SIZE_U32 == 128, ++ "rasdaemon ABI requires exactly 128 u32s"); ++ + static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev, + struct cxl_ras_capability_regs ras_cap) + { +@@ -18,6 +23,7 @@ static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev, + static void cxl_cper_trace_uncorr_port_prot_err(struct pci_dev *pdev, + struct cxl_ras_capability_regs ras_cap) + { ++ u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32] = {}; + u32 status = ras_cap.uncor_status & ~ras_cap.uncor_mask; + u32 fe; + +@@ -27,8 +33,8 @@ static void cxl_cper_trace_uncorr_port_prot_err(struct pci_dev *pdev, + else + fe = status; + +- trace_cxl_port_aer_uncorrectable_error(&pdev->dev, status, fe, +- ras_cap.header_log); ++ memcpy(hl, ras_cap.header_log, CXL_HEADERLOG_SIZE); ++ trace_cxl_port_aer_uncorrectable_error(&pdev->dev, status, fe, hl); + } + + static void cxl_cper_trace_corr_prot_err(struct cxl_memdev *cxlmd, +@@ -43,6 +49,7 @@ static void + cxl_cper_trace_uncorr_prot_err(struct cxl_memdev *cxlmd, + struct cxl_ras_capability_regs ras_cap) + { ++ u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32] = {}; + u32 status = ras_cap.uncor_status & ~ras_cap.uncor_mask; + u32 fe; + +@@ -52,8 +59,15 @@ cxl_cper_trace_uncorr_prot_err(struct cxl_memdev *cxlmd, + else + fe = status; + +- trace_cxl_aer_uncorrectable_error(cxlmd, status, fe, +- ras_cap.header_log); ++ /* ++ * ras_cap.header_log[] holds CXL_HEADERLOG_SIZE_U32 (16) hardware ++ * dwords. Copy them into the front of a zero-filled ++ * CXL_HEADERLOG_TRACE_SIZE_U32 (128) u32 staging buffer so the trace ++ * event memcpy sees a full 512-byte source and the userspace ABI ++ * (rasdaemon) is preserved. ++ */ ++ memcpy(hl, ras_cap.header_log, CXL_HEADERLOG_SIZE); ++ trace_cxl_aer_uncorrectable_error(cxlmd, status, fe, hl); + } + + static int match_memdev_by_parent(struct device *dev, const void *uport) +@@ -124,3 +138,178 @@ void cxl_ras_exit(void) + cxl_cper_unregister_prot_err_work(&cxl_cper_prot_err_work); + cancel_work_sync(&cxl_cper_prot_err_work); + } ++ ++static void cxl_dport_map_ras(struct cxl_dport *dport) ++{ ++ struct cxl_register_map *map = &dport->reg_map; ++ struct device *dev = dport->dport_dev; ++ ++ if (!map->component_map.ras.valid) ++ dev_dbg(dev, "RAS registers not found\n"); ++ else if (cxl_map_component_regs(map, &dport->regs.component, ++ BIT(CXL_CM_CAP_CAP_ID_RAS))) ++ dev_dbg(dev, "Failed to map RAS capability.\n"); ++} ++ ++/** ++ * cxl_dport_init_ras_reporting - Setup CXL RAS report on this dport ++ * @dport: the cxl_dport that needs to be initialized ++ * @host: host device for devm operations ++ */ ++void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host) ++{ ++ dport->reg_map.host = host; ++ cxl_dport_map_ras(dport); ++ ++ if (dport->rch) { ++ struct pci_host_bridge *host_bridge = to_pci_host_bridge(dport->dport_dev); ++ ++ if (!host_bridge->native_aer) ++ return; ++ ++ cxl_dport_map_rch_aer(dport); ++ cxl_disable_rch_root_ints(dport); ++ } ++} ++EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL"); ++ ++void cxl_handle_cor_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base) ++{ ++ void __iomem *addr; ++ u32 status; ++ ++ if (!ras_base) ++ return; ++ ++ addr = ras_base + CXL_RAS_CORRECTABLE_STATUS_OFFSET; ++ status = readl(addr); ++ if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) { ++ writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr); ++ trace_cxl_aer_correctable_error(cxlds->cxlmd, status); ++ } ++} ++ ++/* CXL spec rev3.0 8.2.4.16.1 */ ++static void header_log_copy(void __iomem *ras_base, u32 *log) ++{ ++ void __iomem *addr; ++ u32 *log_addr; ++ int i; ++ ++ addr = ras_base + CXL_RAS_HEADER_LOG_OFFSET; ++ log_addr = log; ++ ++ for (i = 0; i < CXL_HEADERLOG_SIZE_U32; i++) { ++ *log_addr = readl(addr); ++ log_addr++; ++ addr += sizeof(u32); ++ } ++} ++ ++/* ++ * Log the state of the RAS status registers and prepare them to log the ++ * next error status. Return 1 if reset needed. ++ */ ++bool cxl_handle_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base) ++{ ++ u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32] = {}; ++ void __iomem *addr; ++ u32 status; ++ u32 fe; ++ ++ if (!ras_base) ++ return false; ++ ++ addr = ras_base + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET; ++ status = readl(addr); ++ if (!(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK)) ++ return false; ++ ++ /* If multiple errors, log header points to first error from ctrl reg */ ++ if (hweight32(status) > 1) { ++ void __iomem *rcc_addr = ++ ras_base + CXL_RAS_CAP_CONTROL_OFFSET; ++ ++ fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK, ++ readl(rcc_addr))); ++ } else { ++ fe = status; ++ } ++ ++ header_log_copy(ras_base, hl); ++ trace_cxl_aer_uncorrectable_error(cxlds->cxlmd, status, fe, hl); ++ writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr); ++ ++ return true; ++} ++ ++void cxl_cor_error_detected(struct pci_dev *pdev) ++{ ++ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev); ++ struct device *dev = &cxlds->cxlmd->dev; ++ ++ scoped_guard(device, dev) { ++ if (!dev->driver) { ++ dev_warn(&pdev->dev, ++ "%s: memdev disabled, abort error handling\n", ++ dev_name(dev)); ++ return; ++ } ++ ++ if (cxlds->rcd) ++ cxl_handle_rdport_errors(cxlds); ++ ++ cxl_handle_cor_ras(cxlds, cxlds->regs.ras); ++ } ++} ++EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL"); ++ ++pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, ++ pci_channel_state_t state) ++{ ++ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev); ++ struct cxl_memdev *cxlmd = cxlds->cxlmd; ++ struct device *dev = &cxlmd->dev; ++ bool ue; ++ ++ scoped_guard(device, dev) { ++ if (!dev->driver) { ++ dev_warn(&pdev->dev, ++ "%s: memdev disabled, abort error handling\n", ++ dev_name(dev)); ++ return PCI_ERS_RESULT_DISCONNECT; ++ } ++ ++ if (cxlds->rcd) ++ cxl_handle_rdport_errors(cxlds); ++ /* ++ * A frozen channel indicates an impending reset which is fatal to ++ * CXL.mem operation, and will likely crash the system. On the off ++ * chance the situation is recoverable dump the status of the RAS ++ * capability registers and bounce the active state of the memdev. ++ */ ++ ue = cxl_handle_ras(cxlds, cxlds->regs.ras); ++ } ++ ++ ++ switch (state) { ++ case pci_channel_io_normal: ++ if (ue) { ++ device_release_driver(dev); ++ return PCI_ERS_RESULT_NEED_RESET; ++ } ++ return PCI_ERS_RESULT_CAN_RECOVER; ++ case pci_channel_io_frozen: ++ dev_warn(&pdev->dev, ++ "%s: frozen state error detected, disable CXL.mem\n", ++ dev_name(dev)); ++ device_release_driver(dev); ++ return PCI_ERS_RESULT_NEED_RESET; ++ case pci_channel_io_perm_failure: ++ dev_warn(&pdev->dev, ++ "failure state error detected, request disconnect\n"); ++ return PCI_ERS_RESULT_DISCONNECT; ++ } ++ return PCI_ERS_RESULT_NEED_RESET; ++} ++EXPORT_SYMBOL_NS_GPL(cxl_error_detected, "CXL"); +diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h +index a972e4ef193686..d37876096dd7cb 100644 +--- a/drivers/cxl/core/trace.h ++++ b/drivers/cxl/core/trace.h +@@ -56,7 +56,7 @@ TRACE_EVENT(cxl_port_aer_uncorrectable_error, + __string(host, dev_name(dev->parent)) + __field(u32, status) + __field(u32, first_error) +- __array(u32, header_log, CXL_HEADERLOG_SIZE_U32) ++ __array(u32, header_log, CXL_HEADERLOG_TRACE_SIZE_U32) + ), + TP_fast_assign( + __assign_str(device); +@@ -64,10 +64,14 @@ TRACE_EVENT(cxl_port_aer_uncorrectable_error, + __entry->status = status; + __entry->first_error = fe; + /* +- * Embed the 512B headerlog data for user app retrieval and +- * parsing, but no need to print this in the trace buffer. ++ * Embed headerlog data for user app retrieval and parsing, ++ * but no need to print in the trace buffer. Only ++ * CXL_HEADERLOG_SIZE_U32 (16) dwords are hardware data; ++ * the remaining entries preserve the 512-byte ABI layout ++ * rasdaemon depends on and are zero-filled by the caller. + */ +- memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE); ++ memcpy(__entry->header_log, hl, ++ CXL_HEADERLOG_TRACE_SIZE_U32 * sizeof(u32)); + ), + TP_printk("device=%s host=%s status: '%s' first_error: '%s'", + __get_str(device), __get_str(host), +@@ -85,7 +89,7 @@ TRACE_EVENT(cxl_aer_uncorrectable_error, + __field(u64, serial) + __field(u32, status) + __field(u32, first_error) +- __array(u32, header_log, CXL_HEADERLOG_SIZE_U32) ++ __array(u32, header_log, CXL_HEADERLOG_TRACE_SIZE_U32) + ), + TP_fast_assign( + __assign_str(memdev); +@@ -94,10 +98,14 @@ TRACE_EVENT(cxl_aer_uncorrectable_error, + __entry->status = status; + __entry->first_error = fe; + /* +- * Embed the 512B headerlog data for user app retrieval and +- * parsing, but no need to print this in the trace buffer. ++ * Embed headerlog data for user app retrieval and parsing, ++ * but no need to print in the trace buffer. Only ++ * CXL_HEADERLOG_SIZE_U32 (16) dwords are hardware data; ++ * the remaining entries preserve the 512-byte ABI layout ++ * rasdaemon depends on and are zero-filled by the caller. + */ +- memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE); ++ memcpy(__entry->header_log, hl, ++ CXL_HEADERLOG_TRACE_SIZE_U32 * sizeof(u32)); + ), + TP_printk("memdev=%s host=%s serial=%lld: status: '%s' first_error: '%s'", + __get_str(memdev), __get_str(host), __entry->serial, +diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h +index 3a794278cc7fef..a5b00c3b044477 100644 +--- a/drivers/cxl/cxl.h ++++ b/drivers/cxl/cxl.h +@@ -148,8 +148,18 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw) + #define CXL_RAS_CAP_CONTROL_FE_MASK GENMASK(5, 0) + #define CXL_RAS_HEADER_LOG_OFFSET 0x18 + #define CXL_RAS_CAPABILITY_LENGTH 0x58 +-#define CXL_HEADERLOG_SIZE SZ_512 +-#define CXL_HEADERLOG_SIZE_U32 SZ_512 / sizeof(u32) ++#define CXL_HEADERLOG_SIZE SZ_64 ++#define CXL_HEADERLOG_SIZE_U32 (CXL_HEADERLOG_SIZE / sizeof(u32)) ++ ++/* ++ * The RAS UCE trace event header array was originally sized at SZ_512/sizeof(u32) ++ * = 128 u32s due to a bug. Userspace tools (rasdaemon) have grown a dependency ++ * on that 512-byte layout. Keep the trace array at 128 u32s to preserve the ++ * ABI; only CXL_HEADERLOG_SIZE_U32 (16) dwords are valid hardware data, the ++ * remainder are zero-filled. ++ */ ++#define CXL_HEADERLOG_TRACE_SIZE SZ_512 ++#define CXL_HEADERLOG_TRACE_SIZE_U32 (CXL_HEADERLOG_TRACE_SIZE / sizeof(u32)) + + /* CXL 2.0 8.2.8.1 Device Capabilities Array Register */ + #define CXLDEV_CAP_ARRAY_OFFSET 0x0 +@@ -781,14 +791,6 @@ struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port, + struct device *dport_dev, int port_id, + resource_size_t rcrb); + +-#ifdef CONFIG_PCIEAER_CXL +-void cxl_setup_parent_dport(struct device *host, struct cxl_dport *dport); +-void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host); +-#else +-static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport, +- struct device *host) { } +-#endif +- + struct cxl_decoder *to_cxl_decoder(struct device *dev); + struct cxl_root_decoder *to_cxl_root_decoder(struct device *dev); + struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev); +diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h +index 7ae621e618e79a..970e84cf49e9ac 100644 +--- a/drivers/cxl/cxlpci.h ++++ b/drivers/cxl/cxlpci.h +@@ -130,7 +130,23 @@ static inline bool cxl_pci_flit_256(struct pci_dev *pdev) + int devm_cxl_port_enumerate_dports(struct cxl_port *port); + struct cxl_dev_state; + void read_cdat_data(struct cxl_port *port); ++ ++#ifdef CONFIG_CXL_RAS + void cxl_cor_error_detected(struct pci_dev *pdev); + pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, + pci_channel_state_t state); ++void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host); ++#else ++static inline void cxl_cor_error_detected(struct pci_dev *pdev) { } ++ ++static inline pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, ++ pci_channel_state_t state) ++{ ++ return PCI_ERS_RESULT_NONE; ++} ++ ++static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport, ++ struct device *host) { } ++#endif ++ + #endif /* __CXL_PCI_H__ */ +diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c +index be47d1ff6c508b..30b0f0c72e928c 100644 +--- a/drivers/dma-buf/udmabuf.c ++++ b/drivers/dma-buf/udmabuf.c +@@ -249,21 +249,22 @@ static int begin_cpu_udmabuf(struct dma_buf *buf, + { + struct udmabuf *ubuf = buf->priv; + struct device *dev = ubuf->device->this_device; +- int ret = 0; + + if (!ubuf->sg) { + ubuf->sg = get_sg_table(dev, buf, direction); + if (IS_ERR(ubuf->sg)) { ++ int ret; ++ + ret = PTR_ERR(ubuf->sg); + ubuf->sg = NULL; ++ return ret; + } else { + ubuf->sg_dir = direction; + } +- } else { +- dma_sync_sgtable_for_cpu(dev, ubuf->sg, direction); + } + +- return ret; ++ dma_sync_sgtable_for_cpu(dev, ubuf->sg, direction); ++ return 0; + } + + static int end_cpu_udmabuf(struct dma_buf *buf, +diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c +index 3371e0a76d3ca1..dc6ffb6941ade7 100644 +--- a/drivers/dma/dw-edma/dw-edma-pcie.c ++++ b/drivers/dma/dw-edma/dw-edma-pcie.c +@@ -161,13 +161,16 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *pid) + { + struct dw_edma_pcie_data *pdata = (void *)pid->driver_data; +- struct dw_edma_pcie_data *vsec_data __free(kfree) = NULL; + struct device *dev = &pdev->dev; + struct dw_edma_chip *chip; + int err, nr_irqs; + int i, mask; + +- vsec_data = kmalloc(sizeof(*vsec_data), GFP_KERNEL); ++ if (!pdata) ++ return -ENODEV; ++ ++ struct dw_edma_pcie_data *vsec_data __free(kfree) = ++ kmalloc(sizeof(*vsec_data), GFP_KERNEL); + if (!vsec_data) + return -ENOMEM; + +diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c +index 818d1ef6f0bf94..4db84b83177a6d 100644 +--- a/drivers/dma/sh/rz-dmac.c ++++ b/drivers/dma/sh/rz-dmac.c +@@ -811,27 +811,6 @@ static int rz_dmac_chan_probe(struct rz_dmac *dmac, + channel->index = index; + channel->mid_rid = -EINVAL; + +- /* Request the channel interrupt. */ +- scnprintf(pdev_irqname, sizeof(pdev_irqname), "ch%u", index); +- channel->irq = platform_get_irq_byname(pdev, pdev_irqname); +- if (channel->irq < 0) +- return channel->irq; +- +- irqname = devm_kasprintf(dmac->dev, GFP_KERNEL, "%s:%u", +- dev_name(dmac->dev), index); +- if (!irqname) +- return -ENOMEM; +- +- ret = devm_request_threaded_irq(dmac->dev, channel->irq, +- rz_dmac_irq_handler, +- rz_dmac_irq_handler_thread, 0, +- irqname, channel); +- if (ret) { +- dev_err(dmac->dev, "failed to request IRQ %u (%d)\n", +- channel->irq, ret); +- return ret; +- } +- + /* Set io base address for each channel */ + if (index < 8) { + channel->ch_base = dmac->base + CHANNEL_0_7_OFFSET + +@@ -844,9 +823,9 @@ static int rz_dmac_chan_probe(struct rz_dmac *dmac, + } + + /* Allocate descriptors */ +- lmdesc = dma_alloc_coherent(&pdev->dev, +- sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC, +- &channel->lmdesc.base_dma, GFP_KERNEL); ++ lmdesc = dmam_alloc_coherent(&pdev->dev, ++ sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC, ++ &channel->lmdesc.base_dma, GFP_KERNEL); + if (!lmdesc) { + dev_err(&pdev->dev, "Can't allocate memory (lmdesc)\n"); + return -ENOMEM; +@@ -862,7 +841,26 @@ static int rz_dmac_chan_probe(struct rz_dmac *dmac, + INIT_LIST_HEAD(&channel->ld_free); + INIT_LIST_HEAD(&channel->ld_active); + +- return 0; ++ /* Request the channel interrupt. */ ++ scnprintf(pdev_irqname, sizeof(pdev_irqname), "ch%u", index); ++ channel->irq = platform_get_irq_byname(pdev, pdev_irqname); ++ if (channel->irq < 0) ++ return channel->irq; ++ ++ irqname = devm_kasprintf(dmac->dev, GFP_KERNEL, "%s:%u", ++ dev_name(dmac->dev), index); ++ if (!irqname) ++ return -ENOMEM; ++ ++ ret = devm_request_threaded_irq(dmac->dev, channel->irq, ++ rz_dmac_irq_handler, ++ rz_dmac_irq_handler_thread, 0, ++ irqname, channel); ++ if (ret) ++ dev_err(dmac->dev, "failed to request IRQ %u (%d)\n", ++ channel->irq, ret); ++ ++ return ret; + } + + static void rz_dmac_put_device(void *_dev) +@@ -932,7 +930,6 @@ static int rz_dmac_probe(struct platform_device *pdev) + const char *irqname = "error"; + struct dma_device *engine; + struct rz_dmac *dmac; +- int channel_num; + int ret; + int irq; + u8 i; +@@ -964,19 +961,6 @@ static int rz_dmac_probe(struct platform_device *pdev) + return PTR_ERR(dmac->ext_base); + } + +- /* Register interrupt handler for error */ +- irq = platform_get_irq_byname(pdev, irqname); +- if (irq < 0) +- return irq; +- +- ret = devm_request_irq(&pdev->dev, irq, rz_dmac_irq_handler, 0, +- irqname, NULL); +- if (ret) { +- dev_err(&pdev->dev, "failed to request IRQ %u (%d)\n", +- irq, ret); +- return ret; +- } +- + /* Initialize the channels. */ + INIT_LIST_HEAD(&dmac->engine.channels); + +@@ -1002,6 +986,21 @@ static int rz_dmac_probe(struct platform_device *pdev) + goto err; + } + ++ /* Register interrupt handler for error */ ++ irq = platform_get_irq_byname(pdev, irqname); ++ if (irq < 0) { ++ ret = irq; ++ goto err; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, irq, rz_dmac_irq_handler, 0, ++ irqname, NULL); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to request IRQ %u (%d)\n", ++ irq, ret); ++ goto err; ++ } ++ + /* Register the DMAC as a DMA provider for DT. */ + ret = of_dma_controller_register(pdev->dev.of_node, rz_dmac_of_xlate, + NULL); +@@ -1040,16 +1039,6 @@ static int rz_dmac_probe(struct platform_device *pdev) + dma_register_err: + of_dma_controller_free(pdev->dev.of_node); + err: +- channel_num = i ? i - 1 : 0; +- for (i = 0; i < channel_num; i++) { +- struct rz_dmac_chan *channel = &dmac->channels[i]; +- +- dma_free_coherent(&pdev->dev, +- sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC, +- channel->lmdesc.base, +- channel->lmdesc.base_dma); +- } +- + reset_control_assert(dmac->rstc); + err_pm_runtime_put: + pm_runtime_put(&pdev->dev); +@@ -1062,18 +1051,9 @@ err_pm_disable: + static void rz_dmac_remove(struct platform_device *pdev) + { + struct rz_dmac *dmac = platform_get_drvdata(pdev); +- unsigned int i; + + dma_async_device_unregister(&dmac->engine); + of_dma_controller_free(pdev->dev.of_node); +- for (i = 0; i < dmac->n_channels; i++) { +- struct rz_dmac_chan *channel = &dmac->channels[i]; +- +- dma_free_coherent(&pdev->dev, +- sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC, +- channel->lmdesc.base, +- channel->lmdesc.base_dma); +- } + reset_control_assert(dmac->rstc); + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); +diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c +index de8b065280d15d..eb23ee401aaef8 100644 +--- a/drivers/dpll/dpll_netlink.c ++++ b/drivers/dpll/dpll_netlink.c +@@ -486,6 +486,9 @@ dpll_msg_add_pin_ref_sync(struct sk_buff *msg, struct dpll_pin *pin, + if (!dpll_pin_available(ref_sync_pin)) + continue; + ref_sync_pin_priv = dpll_pin_on_dpll_priv(dpll, ref_sync_pin); ++ /* Pin may have been unregistered from this dpll already */ ++ if (!ref_sync_pin_priv) ++ continue; + if (WARN_ON(!ops->ref_sync_get)) + return -EOPNOTSUPP; + ret = ops->ref_sync_get(pin, pin_priv, ref_sync_pin, +diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c +index e8294540895507..354c81409946a9 100644 +--- a/drivers/firewire/net.c ++++ b/drivers/firewire/net.c +@@ -298,31 +298,34 @@ static struct fwnet_fragment_info *fwnet_frag_new( + if (fi->offset + fi->len == offset) { + /* The new fragment can be tacked on to the end */ + /* Did the new fragment plug a hole? */ +- fi2 = list_entry(fi->fi_link.next, +- struct fwnet_fragment_info, fi_link); +- if (fi->offset + fi->len == fi2->offset) { +- /* glue fragments together */ +- fi->len += len + fi2->len; +- list_del(&fi2->fi_link); +- kfree(fi2); +- } else { +- fi->len += len; ++ if (!list_is_last(&fi->fi_link, &pd->fi_list)) { ++ fi2 = list_next_entry(fi, fi_link); ++ if (offset + len == fi2->offset) { ++ /* glue fragments together */ ++ fi->len += len + fi2->len; ++ list_del(&fi2->fi_link); ++ kfree(fi2); ++ ++ return fi; ++ } + } ++ fi->len += len; + + return fi; + } + if (offset + len == fi->offset) { + /* The new fragment can be tacked on to the beginning */ + /* Did the new fragment plug a hole? */ +- fi2 = list_entry(fi->fi_link.prev, +- struct fwnet_fragment_info, fi_link); +- if (fi2->offset + fi2->len == fi->offset) { +- /* glue fragments together */ +- fi2->len += fi->len + len; +- list_del(&fi->fi_link); +- kfree(fi); +- +- return fi2; ++ if (!list_is_first(&fi->fi_link, &pd->fi_list)) { ++ fi2 = list_prev_entry(fi, fi_link); ++ if (fi2->offset + fi2->len == offset) { ++ /* glue fragments together */ ++ fi2->len += fi->len + len; ++ list_del(&fi->fi_link); ++ kfree(fi); ++ ++ return fi2; ++ } + } + fi->offset = offset; + fi->len += len; +diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c +index 3fbc75caf0c506..1d0bd586da4d6f 100644 +--- a/drivers/firmware/arm_ffa/driver.c ++++ b/drivers/firmware/arm_ffa/driver.c +@@ -32,6 +32,7 @@ + #include <linux/interrupt.h> + #include <linux/io.h> + #include <linux/kernel.h> ++#include <linux/minmax.h> + #include <linux/module.h> + #include <linux/mm.h> + #include <linux/mutex.h> +@@ -55,7 +56,9 @@ + (FIELD_PREP(SENDER_ID_MASK, (s)) | FIELD_PREP(RECEIVER_ID_MASK, (r))) + + #define RXTX_MAP_MIN_BUFSZ_MASK GENMASK(1, 0) +-#define RXTX_MAP_MIN_BUFSZ(x) ((x) & RXTX_MAP_MIN_BUFSZ_MASK) ++#define RXTX_MAP_MAX_BUFSZ_MASK GENMASK(31, 16) ++#define RXTX_MAP_MIN_BUFSZ(x) (FIELD_GET(RXTX_MAP_MIN_BUFSZ_MASK, (x))) ++#define RXTX_MAP_MAX_BUFSZ(x) (FIELD_GET(RXTX_MAP_MAX_BUFSZ_MASK, (x))) + + #define FFA_MAX_NOTIFICATIONS 64 + +@@ -704,30 +707,39 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize, + struct ffa_composite_mem_region *composite; + struct ffa_mem_region_addr_range *constituents; + struct ffa_mem_region_attributes *ep_mem_access; +- u32 idx, frag_len, length, buf_sz = 0, num_entries = sg_nents(args->sg); ++ u32 idx, frag_len, length, buf_sz = 0, num_entries = sg_nents(args->sg), ep_offset; ++ u32 emad_end, emad_size = ffa_emad_size_get(drv_info->version); + + mem_region->tag = args->tag; + mem_region->flags = args->flags; + mem_region->sender_id = drv_info->vm_id; + mem_region->attributes = ffa_memory_attributes_get(func_id); ++ ++ ffa_mem_region_additional_setup(drv_info->version, mem_region); + composite_offset = ffa_mem_desc_offset(buffer, args->nattrs, + drv_info->version); ++ if (composite_offset + sizeof(*composite) > max_fragsize) ++ return -ENXIO; + + for (idx = 0; idx < args->nattrs; idx++) { +- ep_mem_access = buffer + +- ffa_mem_desc_offset(buffer, idx, drv_info->version); ++ ep_offset = ffa_mem_desc_offset(buffer, idx, drv_info->version); ++ if (check_add_overflow(ep_offset, emad_size, &emad_end)) ++ return -ENXIO; ++ ++ if (emad_end > max_fragsize) ++ return -ENXIO; ++ ++ ep_mem_access = buffer + ep_offset; ++ memset(ep_mem_access, 0, emad_size); + ep_mem_access->receiver = args->attrs[idx].receiver; + ep_mem_access->attrs = args->attrs[idx].attrs; + ep_mem_access->composite_off = composite_offset; +- ep_mem_access->flag = 0; +- ep_mem_access->reserved = 0; + ffa_emad_impdef_value_init(drv_info->version, + ep_mem_access->impdef_val, + args->attrs[idx].impdef_val); + } + mem_region->handle = 0; + mem_region->ep_count = args->nattrs; +- ffa_mem_region_additional_setup(drv_info->version, mem_region); + + composite = buffer + composite_offset; + composite->total_pg_cnt = ffa_get_num_pages_sg(args->sg); +@@ -760,7 +772,7 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize, + constituents = buffer; + } + +- if ((void *)constituents - buffer > max_fragsize) { ++ if ((void *)constituents + sizeof(*constituents) - buffer > max_fragsize) { + pr_err("Memory Region Fragment > Tx Buffer size\n"); + return -EFAULT; + } +@@ -769,7 +781,7 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize, + constituents->pg_cnt = args->sg->length / FFA_PAGE_SIZE; + constituents->reserved = 0; + constituents++; +- frag_len += sizeof(struct ffa_mem_region_addr_range); ++ frag_len += sizeof(*constituents); + } while ((args->sg = sg_next(args->sg))); + + return ffa_transmit_fragment(func_id, addr, buf_sz, frag_len, +@@ -1130,7 +1142,7 @@ static int ffa_partition_info_get(const char *uuid_str, + uuid_t uuid; + struct ffa_partition_info *pbuf; + +- if (uuid_parse(uuid_str, &uuid)) { ++ if (!uuid_str || uuid_parse(uuid_str, &uuid)) { + pr_err("invalid uuid (%s)\n", uuid_str); + return -ENODEV; + } +@@ -2088,7 +2100,7 @@ static int __init ffa_init(void) + { + int ret; + u32 buf_sz; +- size_t rxtx_bufsz = SZ_4K; ++ size_t rxtx_min_bufsz = SZ_4K, rxtx_max_bufsz = 0, rxtx_bufsz; + + ret = ffa_transport_init(&invoke_ffa_fn); + if (ret) +@@ -2111,15 +2123,18 @@ static int __init ffa_init(void) + ret = ffa_features(FFA_FN_NATIVE(RXTX_MAP), 0, &buf_sz, NULL); + if (!ret) { + if (RXTX_MAP_MIN_BUFSZ(buf_sz) == 1) +- rxtx_bufsz = SZ_64K; ++ rxtx_min_bufsz = SZ_64K; + else if (RXTX_MAP_MIN_BUFSZ(buf_sz) == 2) +- rxtx_bufsz = SZ_16K; ++ rxtx_min_bufsz = SZ_16K; + else +- rxtx_bufsz = SZ_4K; ++ rxtx_min_bufsz = SZ_4K; ++ ++ rxtx_max_bufsz = RXTX_MAP_MAX_BUFSZ(buf_sz) * SZ_4K; ++ if (rxtx_max_bufsz != 0 && rxtx_max_bufsz < rxtx_min_bufsz) ++ rxtx_max_bufsz = rxtx_min_bufsz; + } + +- rxtx_bufsz = PAGE_ALIGN(rxtx_bufsz); +- drv_info->rxtx_bufsz = rxtx_bufsz; ++ rxtx_bufsz = min_not_zero(PAGE_ALIGN(rxtx_min_bufsz), rxtx_max_bufsz); + drv_info->rx_buffer = alloc_pages_exact(rxtx_bufsz, GFP_KERNEL); + if (!drv_info->rx_buffer) { + ret = -ENOMEM; +@@ -2135,10 +2150,17 @@ static int __init ffa_init(void) + ret = ffa_rxtx_map(virt_to_phys(drv_info->tx_buffer), + virt_to_phys(drv_info->rx_buffer), + rxtx_bufsz / FFA_PAGE_SIZE); ++ if (ret == -EINVAL && !rxtx_max_bufsz && rxtx_min_bufsz < rxtx_bufsz) { ++ rxtx_bufsz = rxtx_min_bufsz; ++ ret = ffa_rxtx_map(virt_to_phys(drv_info->tx_buffer), ++ virt_to_phys(drv_info->rx_buffer), ++ rxtx_bufsz / FFA_PAGE_SIZE); ++ } + if (ret) { + pr_err("failed to register FFA RxTx buffers\n"); + goto free_pages; + } ++ drv_info->rxtx_bufsz = rxtx_bufsz; + + mutex_init(&drv_info->rx_lock); + mutex_init(&drv_info->tx_lock); +diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c +index 2047edbdc5f6b1..9bf7f43ab868c8 100644 +--- a/drivers/firmware/arm_scmi/notify.c ++++ b/drivers/firmware/arm_scmi/notify.c +@@ -600,9 +600,9 @@ int scmi_notify(const struct scmi_handle *handle, u8 proto_id, u8 evt_id, + return -EINVAL; + } + if (kfifo_avail(&r_evt->proto->equeue.kfifo) < sizeof(eh) + len) { +- dev_warn(handle->dev, +- "queue full, dropping proto_id:%d evt_id:%d ts:%lld\n", +- proto_id, evt_id, ktime_to_ns(ts)); ++ dev_warn_ratelimited(handle->dev, ++ "queue full, dropping proto_id:%d evt_id:%d ts:%lld\n", ++ proto_id, evt_id, ktime_to_ns(ts)); + return -ENOMEM; + } + +diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c +index 1d24e82f3d09d8..ba715c6eb32bf8 100644 +--- a/drivers/firmware/stratix10-svc.c ++++ b/drivers/firmware/stratix10-svc.c +@@ -1080,14 +1080,16 @@ void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan, + struct gen_pool *genpool = chan->ctrl->genpool; + size_t s = roundup(size, 1 << genpool->min_alloc_order); + +- pmem = devm_kzalloc(chan->ctrl->dev, sizeof(*pmem), GFP_KERNEL); ++ pmem = kzalloc_obj(*pmem); + if (!pmem) + return ERR_PTR(-ENOMEM); + + guard(mutex)(&svc_mem_lock); + va = gen_pool_alloc(genpool, s); +- if (!va) ++ if (!va) { ++ kfree(pmem); + return ERR_PTR(-ENOMEM); ++ } + + memset((void *)va, 0, s); + pa = gen_pool_virt_to_phys(genpool, va); +@@ -1113,6 +1115,7 @@ EXPORT_SYMBOL_GPL(stratix10_svc_allocate_memory); + void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr) + { + struct stratix10_svc_data_mem *pmem; ++ + guard(mutex)(&svc_mem_lock); + + list_for_each_entry(pmem, &svc_data_mem, node) +@@ -1121,10 +1124,9 @@ void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr) + (unsigned long)kaddr, pmem->size); + pmem->vaddr = NULL; + list_del(&pmem->node); ++ kfree(pmem); + return; + } +- +- list_del(&svc_data_mem); + } + EXPORT_SYMBOL_GPL(stratix10_svc_free_memory); + +diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c +index 02da3e48bc8f35..dc9c5d32108d57 100644 +--- a/drivers/firmware/xilinx/zynqmp.c ++++ b/drivers/firmware/xilinx/zynqmp.c +@@ -461,6 +461,7 @@ int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 *ret_payload, u32 num_args, ...) + return do_fw_call(ret_payload, 8, smc_arg[0], smc_arg[1], smc_arg[2], smc_arg[3], + smc_arg[4], smc_arg[5], smc_arg[6], smc_arg[7]); + } ++EXPORT_SYMBOL_GPL(zynqmp_pm_invoke_fn); + + static u32 pm_api_version; + static u32 pm_tz_version; +diff --git a/drivers/gpu/Kconfig b/drivers/gpu/Kconfig +new file mode 100644 +index 00000000000000..ebb2ad4b7ea0bb +--- /dev/null ++++ b/drivers/gpu/Kconfig +@@ -0,0 +1,13 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++config GPU_BUDDY ++ bool ++ help ++ A page based buddy allocator for GPU memory. ++ ++config GPU_BUDDY_KUNIT_TEST ++ tristate "KUnit tests for GPU buddy allocator" if !KUNIT_ALL_TESTS ++ depends on GPU_BUDDY && KUNIT ++ default KUNIT_ALL_TESTS ++ help ++ KUnit tests for the GPU buddy allocator. +diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile +index 36a54d45663030..b4e5e338efa239 100644 +--- a/drivers/gpu/Makefile ++++ b/drivers/gpu/Makefile +@@ -2,7 +2,9 @@ + # drm/tegra depends on host1x, so if both drivers are built-in care must be + # taken to initialize them in the correct order. Link order is the only way + # to ensure this currently. +-obj-y += host1x/ drm/ vga/ ++# Similarly, buddy must come first since it is used by other drivers. ++obj-$(CONFIG_GPU_BUDDY) += buddy.o ++obj-y += host1x/ drm/ vga/ tests/ + obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/ + obj-$(CONFIG_TRACE_GPU_MEM) += trace/ + obj-$(CONFIG_NOVA_CORE) += nova-core/ +diff --git a/drivers/gpu/buddy.c b/drivers/gpu/buddy.c +new file mode 100644 +index 00000000000000..bf5920bd225803 +--- /dev/null ++++ b/drivers/gpu/buddy.c +@@ -0,0 +1,1347 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * Copyright © 2021 Intel Corporation ++ */ ++ ++#include <kunit/test-bug.h> ++ ++#include <linux/export.h> ++#include <linux/kmemleak.h> ++#include <linux/module.h> ++#include <linux/sizes.h> ++ ++#include <linux/gpu_buddy.h> ++ ++static struct kmem_cache *slab_blocks; ++ ++static struct gpu_buddy_block *gpu_block_alloc(struct gpu_buddy *mm, ++ struct gpu_buddy_block *parent, ++ unsigned int order, ++ u64 offset) ++{ ++ struct gpu_buddy_block *block; ++ ++ BUG_ON(order > GPU_BUDDY_MAX_ORDER); ++ ++ block = kmem_cache_zalloc(slab_blocks, GFP_KERNEL); ++ if (!block) ++ return NULL; ++ ++ block->header = offset; ++ block->header |= order; ++ block->parent = parent; ++ ++ RB_CLEAR_NODE(&block->rb); ++ ++ BUG_ON(block->header & GPU_BUDDY_HEADER_UNUSED); ++ return block; ++} ++ ++static void gpu_block_free(struct gpu_buddy *mm, ++ struct gpu_buddy_block *block) ++{ ++ kmem_cache_free(slab_blocks, block); ++} ++ ++static enum gpu_buddy_free_tree ++get_block_tree(struct gpu_buddy_block *block) ++{ ++ return gpu_buddy_block_is_clear(block) ? ++ GPU_BUDDY_CLEAR_TREE : GPU_BUDDY_DIRTY_TREE; ++} ++ ++static struct gpu_buddy_block * ++rbtree_get_free_block(const struct rb_node *node) ++{ ++ return node ? rb_entry(node, struct gpu_buddy_block, rb) : NULL; ++} ++ ++static struct gpu_buddy_block * ++rbtree_last_free_block(struct rb_root *root) ++{ ++ return rbtree_get_free_block(rb_last(root)); ++} ++ ++static bool rbtree_is_empty(struct rb_root *root) ++{ ++ return RB_EMPTY_ROOT(root); ++} ++ ++static bool gpu_buddy_block_offset_less(const struct gpu_buddy_block *block, ++ const struct gpu_buddy_block *node) ++{ ++ return gpu_buddy_block_offset(block) < gpu_buddy_block_offset(node); ++} ++ ++static bool rbtree_block_offset_less(struct rb_node *block, ++ const struct rb_node *node) ++{ ++ return gpu_buddy_block_offset_less(rbtree_get_free_block(block), ++ rbtree_get_free_block(node)); ++} ++ ++static void rbtree_insert(struct gpu_buddy *mm, ++ struct gpu_buddy_block *block, ++ enum gpu_buddy_free_tree tree) ++{ ++ rb_add(&block->rb, ++ &mm->free_trees[tree][gpu_buddy_block_order(block)], ++ rbtree_block_offset_less); ++} ++ ++static void rbtree_remove(struct gpu_buddy *mm, ++ struct gpu_buddy_block *block) ++{ ++ unsigned int order = gpu_buddy_block_order(block); ++ enum gpu_buddy_free_tree tree; ++ struct rb_root *root; ++ ++ tree = get_block_tree(block); ++ root = &mm->free_trees[tree][order]; ++ ++ rb_erase(&block->rb, root); ++ RB_CLEAR_NODE(&block->rb); ++} ++ ++static void clear_reset(struct gpu_buddy_block *block) ++{ ++ block->header &= ~GPU_BUDDY_HEADER_CLEAR; ++} ++ ++static void mark_cleared(struct gpu_buddy_block *block) ++{ ++ block->header |= GPU_BUDDY_HEADER_CLEAR; ++} ++ ++static void mark_allocated(struct gpu_buddy *mm, ++ struct gpu_buddy_block *block) ++{ ++ block->header &= ~GPU_BUDDY_HEADER_STATE; ++ block->header |= GPU_BUDDY_ALLOCATED; ++ ++ rbtree_remove(mm, block); ++} ++ ++static void mark_free(struct gpu_buddy *mm, ++ struct gpu_buddy_block *block) ++{ ++ enum gpu_buddy_free_tree tree; ++ ++ block->header &= ~GPU_BUDDY_HEADER_STATE; ++ block->header |= GPU_BUDDY_FREE; ++ ++ tree = get_block_tree(block); ++ rbtree_insert(mm, block, tree); ++} ++ ++static void mark_split(struct gpu_buddy *mm, ++ struct gpu_buddy_block *block) ++{ ++ block->header &= ~GPU_BUDDY_HEADER_STATE; ++ block->header |= GPU_BUDDY_SPLIT; ++ ++ rbtree_remove(mm, block); ++} ++ ++static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2) ++{ ++ return s1 <= e2 && e1 >= s2; ++} ++ ++static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2) ++{ ++ return s1 <= s2 && e1 >= e2; ++} ++ ++static struct gpu_buddy_block * ++__get_buddy(struct gpu_buddy_block *block) ++{ ++ struct gpu_buddy_block *parent; ++ ++ parent = block->parent; ++ if (!parent) ++ return NULL; ++ ++ if (parent->left == block) ++ return parent->right; ++ ++ return parent->left; ++} ++ ++static unsigned int __gpu_buddy_free(struct gpu_buddy *mm, ++ struct gpu_buddy_block *block, ++ bool force_merge) ++{ ++ struct gpu_buddy_block *parent; ++ unsigned int order; ++ ++ while ((parent = block->parent)) { ++ struct gpu_buddy_block *buddy; ++ ++ buddy = __get_buddy(block); ++ ++ if (!gpu_buddy_block_is_free(buddy)) ++ break; ++ ++ if (!force_merge) { ++ /* ++ * Check the block and its buddy clear state and exit ++ * the loop if they both have the dissimilar state. ++ */ ++ if (gpu_buddy_block_is_clear(block) != ++ gpu_buddy_block_is_clear(buddy)) ++ break; ++ ++ if (gpu_buddy_block_is_clear(block)) ++ mark_cleared(parent); ++ } ++ ++ rbtree_remove(mm, buddy); ++ if (force_merge && gpu_buddy_block_is_clear(buddy)) ++ mm->clear_avail -= gpu_buddy_block_size(mm, buddy); ++ ++ gpu_block_free(mm, block); ++ gpu_block_free(mm, buddy); ++ ++ block = parent; ++ } ++ ++ order = gpu_buddy_block_order(block); ++ mark_free(mm, block); ++ ++ return order; ++} ++ ++static int __force_merge(struct gpu_buddy *mm, ++ u64 start, ++ u64 end, ++ unsigned int min_order) ++{ ++ unsigned int tree, order; ++ int i; ++ ++ if (!min_order) ++ return -ENOMEM; ++ ++ if (min_order > mm->max_order) ++ return -EINVAL; ++ ++ for_each_free_tree(tree) { ++ for (i = min_order - 1; i >= 0; i--) { ++ struct rb_node *iter = rb_last(&mm->free_trees[tree][i]); ++ ++ while (iter) { ++ struct gpu_buddy_block *block, *buddy; ++ u64 block_start, block_end; ++ ++ block = rbtree_get_free_block(iter); ++ iter = rb_prev(iter); ++ ++ if (!block || !block->parent) ++ continue; ++ ++ block_start = gpu_buddy_block_offset(block); ++ block_end = block_start + gpu_buddy_block_size(mm, block) - 1; ++ ++ if (!contains(start, end, block_start, block_end)) ++ continue; ++ ++ buddy = __get_buddy(block); ++ if (!gpu_buddy_block_is_free(buddy)) ++ continue; ++ ++ WARN_ON(gpu_buddy_block_is_clear(block) == ++ gpu_buddy_block_is_clear(buddy)); ++ ++ /* ++ * Advance to the next node when the current node is the buddy, ++ * as freeing the block will also remove its buddy from the tree. ++ */ ++ if (iter == &buddy->rb) ++ iter = rb_prev(iter); ++ ++ rbtree_remove(mm, block); ++ if (gpu_buddy_block_is_clear(block)) ++ mm->clear_avail -= gpu_buddy_block_size(mm, block); ++ ++ order = __gpu_buddy_free(mm, block, true); ++ if (order >= min_order) ++ return 0; ++ } ++ } ++ } ++ ++ return -ENOMEM; ++} ++ ++/** ++ * gpu_buddy_init - init memory manager ++ * ++ * @mm: GPU buddy manager to initialize ++ * @size: size in bytes to manage ++ * @chunk_size: minimum page size in bytes for our allocations ++ * ++ * Initializes the memory manager and its resources. ++ * ++ * Returns: ++ * 0 on success, error code on failure. ++ */ ++int gpu_buddy_init(struct gpu_buddy *mm, u64 size, u64 chunk_size) ++{ ++ unsigned int i, j, root_count = 0; ++ u64 offset = 0; ++ ++ if (size < chunk_size) ++ return -EINVAL; ++ ++ if (chunk_size < SZ_4K) ++ return -EINVAL; ++ ++ if (!is_power_of_2(chunk_size)) ++ return -EINVAL; ++ ++ size = round_down(size, chunk_size); ++ ++ mm->size = size; ++ mm->avail = size; ++ mm->clear_avail = 0; ++ mm->chunk_size = chunk_size; ++ mm->max_order = ilog2(size) - ilog2(chunk_size); ++ ++ BUG_ON(mm->max_order > GPU_BUDDY_MAX_ORDER); ++ ++ mm->free_trees = kmalloc_array(GPU_BUDDY_MAX_FREE_TREES, ++ sizeof(*mm->free_trees), ++ GFP_KERNEL); ++ if (!mm->free_trees) ++ return -ENOMEM; ++ ++ for_each_free_tree(i) { ++ mm->free_trees[i] = kmalloc_array(mm->max_order + 1, ++ sizeof(struct rb_root), ++ GFP_KERNEL); ++ if (!mm->free_trees[i]) ++ goto out_free_tree; ++ ++ for (j = 0; j <= mm->max_order; ++j) ++ mm->free_trees[i][j] = RB_ROOT; ++ } ++ ++ mm->n_roots = hweight64(size); ++ ++ mm->roots = kmalloc_array(mm->n_roots, ++ sizeof(struct gpu_buddy_block *), ++ GFP_KERNEL); ++ if (!mm->roots) ++ goto out_free_tree; ++ ++ /* ++ * Split into power-of-two blocks, in case we are given a size that is ++ * not itself a power-of-two. ++ */ ++ do { ++ struct gpu_buddy_block *root; ++ unsigned int order; ++ u64 root_size; ++ ++ order = ilog2(size) - ilog2(chunk_size); ++ root_size = chunk_size << order; ++ ++ root = gpu_block_alloc(mm, NULL, order, offset); ++ if (!root) ++ goto out_free_roots; ++ ++ mark_free(mm, root); ++ ++ BUG_ON(root_count > mm->max_order); ++ BUG_ON(gpu_buddy_block_size(mm, root) < chunk_size); ++ ++ mm->roots[root_count] = root; ++ ++ offset += root_size; ++ size -= root_size; ++ root_count++; ++ } while (size); ++ ++ return 0; ++ ++out_free_roots: ++ while (root_count--) ++ gpu_block_free(mm, mm->roots[root_count]); ++ kfree(mm->roots); ++out_free_tree: ++ while (i--) ++ kfree(mm->free_trees[i]); ++ kfree(mm->free_trees); ++ return -ENOMEM; ++} ++EXPORT_SYMBOL(gpu_buddy_init); ++ ++/** ++ * gpu_buddy_fini - tear down the memory manager ++ * ++ * @mm: GPU buddy manager to free ++ * ++ * Cleanup memory manager resources and the freetree ++ */ ++void gpu_buddy_fini(struct gpu_buddy *mm) ++{ ++ u64 root_size, size, start; ++ unsigned int order; ++ int i; ++ ++ size = mm->size; ++ ++ for (i = 0; i < mm->n_roots; ++i) { ++ order = ilog2(size) - ilog2(mm->chunk_size); ++ start = gpu_buddy_block_offset(mm->roots[i]); ++ __force_merge(mm, start, start + size, order); ++ ++ if (WARN_ON(!gpu_buddy_block_is_free(mm->roots[i]))) ++ kunit_fail_current_test("buddy_fini() root"); ++ ++ gpu_block_free(mm, mm->roots[i]); ++ ++ root_size = mm->chunk_size << order; ++ size -= root_size; ++ } ++ ++ WARN_ON(mm->avail != mm->size); ++ ++ for_each_free_tree(i) ++ kfree(mm->free_trees[i]); ++ kfree(mm->free_trees); ++ kfree(mm->roots); ++} ++EXPORT_SYMBOL(gpu_buddy_fini); ++ ++static int split_block(struct gpu_buddy *mm, ++ struct gpu_buddy_block *block) ++{ ++ unsigned int block_order = gpu_buddy_block_order(block) - 1; ++ u64 offset = gpu_buddy_block_offset(block); ++ ++ BUG_ON(!gpu_buddy_block_is_free(block)); ++ BUG_ON(!gpu_buddy_block_order(block)); ++ ++ block->left = gpu_block_alloc(mm, block, block_order, offset); ++ if (!block->left) ++ return -ENOMEM; ++ ++ block->right = gpu_block_alloc(mm, block, block_order, ++ offset + (mm->chunk_size << block_order)); ++ if (!block->right) { ++ gpu_block_free(mm, block->left); ++ return -ENOMEM; ++ } ++ ++ mark_split(mm, block); ++ ++ if (gpu_buddy_block_is_clear(block)) { ++ mark_cleared(block->left); ++ mark_cleared(block->right); ++ clear_reset(block); ++ } ++ ++ mark_free(mm, block->left); ++ mark_free(mm, block->right); ++ ++ return 0; ++} ++ ++/** ++ * gpu_get_buddy - get buddy address ++ * ++ * @block: GPU buddy block ++ * ++ * Returns the corresponding buddy block for @block, or NULL ++ * if this is a root block and can't be merged further. ++ * Requires some kind of locking to protect against ++ * any concurrent allocate and free operations. ++ */ ++struct gpu_buddy_block * ++gpu_get_buddy(struct gpu_buddy_block *block) ++{ ++ return __get_buddy(block); ++} ++EXPORT_SYMBOL(gpu_get_buddy); ++ ++/** ++ * gpu_buddy_reset_clear - reset blocks clear state ++ * ++ * @mm: GPU buddy manager ++ * @is_clear: blocks clear state ++ * ++ * Reset the clear state based on @is_clear value for each block ++ * in the freetree. ++ */ ++void gpu_buddy_reset_clear(struct gpu_buddy *mm, bool is_clear) ++{ ++ enum gpu_buddy_free_tree src_tree, dst_tree; ++ u64 root_size, size, start; ++ unsigned int order; ++ int i; ++ ++ size = mm->size; ++ for (i = 0; i < mm->n_roots; ++i) { ++ order = ilog2(size) - ilog2(mm->chunk_size); ++ start = gpu_buddy_block_offset(mm->roots[i]); ++ __force_merge(mm, start, start + size, order); ++ ++ root_size = mm->chunk_size << order; ++ size -= root_size; ++ } ++ ++ src_tree = is_clear ? GPU_BUDDY_DIRTY_TREE : GPU_BUDDY_CLEAR_TREE; ++ dst_tree = is_clear ? GPU_BUDDY_CLEAR_TREE : GPU_BUDDY_DIRTY_TREE; ++ ++ for (i = 0; i <= mm->max_order; ++i) { ++ struct rb_root *root = &mm->free_trees[src_tree][i]; ++ struct gpu_buddy_block *block, *tmp; ++ ++ rbtree_postorder_for_each_entry_safe(block, tmp, root, rb) { ++ rbtree_remove(mm, block); ++ if (is_clear) { ++ mark_cleared(block); ++ mm->clear_avail += gpu_buddy_block_size(mm, block); ++ } else { ++ clear_reset(block); ++ mm->clear_avail -= gpu_buddy_block_size(mm, block); ++ } ++ ++ rbtree_insert(mm, block, dst_tree); ++ } ++ } ++} ++EXPORT_SYMBOL(gpu_buddy_reset_clear); ++ ++/** ++ * gpu_buddy_free_block - free a block ++ * ++ * @mm: GPU buddy manager ++ * @block: block to be freed ++ */ ++void gpu_buddy_free_block(struct gpu_buddy *mm, ++ struct gpu_buddy_block *block) ++{ ++ BUG_ON(!gpu_buddy_block_is_allocated(block)); ++ mm->avail += gpu_buddy_block_size(mm, block); ++ if (gpu_buddy_block_is_clear(block)) ++ mm->clear_avail += gpu_buddy_block_size(mm, block); ++ ++ __gpu_buddy_free(mm, block, false); ++} ++EXPORT_SYMBOL(gpu_buddy_free_block); ++ ++static void __gpu_buddy_free_list(struct gpu_buddy *mm, ++ struct list_head *objects, ++ bool mark_clear, ++ bool mark_dirty) ++{ ++ struct gpu_buddy_block *block, *on; ++ ++ WARN_ON(mark_dirty && mark_clear); ++ ++ list_for_each_entry_safe(block, on, objects, link) { ++ if (mark_clear) ++ mark_cleared(block); ++ else if (mark_dirty) ++ clear_reset(block); ++ gpu_buddy_free_block(mm, block); ++ cond_resched(); ++ } ++ INIT_LIST_HEAD(objects); ++} ++ ++static void gpu_buddy_free_list_internal(struct gpu_buddy *mm, ++ struct list_head *objects) ++{ ++ /* ++ * Don't touch the clear/dirty bit, since allocation is still internal ++ * at this point. For example we might have just failed part of the ++ * allocation. ++ */ ++ __gpu_buddy_free_list(mm, objects, false, false); ++} ++ ++/** ++ * gpu_buddy_free_list - free blocks ++ * ++ * @mm: GPU buddy manager ++ * @objects: input list head to free blocks ++ * @flags: optional flags like GPU_BUDDY_CLEARED ++ */ ++void gpu_buddy_free_list(struct gpu_buddy *mm, ++ struct list_head *objects, ++ unsigned int flags) ++{ ++ bool mark_clear = flags & GPU_BUDDY_CLEARED; ++ ++ __gpu_buddy_free_list(mm, objects, mark_clear, !mark_clear); ++} ++EXPORT_SYMBOL(gpu_buddy_free_list); ++ ++static bool block_incompatible(struct gpu_buddy_block *block, unsigned int flags) ++{ ++ bool needs_clear = flags & GPU_BUDDY_CLEAR_ALLOCATION; ++ ++ return needs_clear != gpu_buddy_block_is_clear(block); ++} ++ ++static struct gpu_buddy_block * ++__alloc_range_bias(struct gpu_buddy *mm, ++ u64 start, u64 end, ++ unsigned int order, ++ unsigned long flags, ++ bool fallback) ++{ ++ u64 req_size = mm->chunk_size << order; ++ struct gpu_buddy_block *block; ++ struct gpu_buddy_block *buddy; ++ LIST_HEAD(dfs); ++ int err; ++ int i; ++ ++ end = end - 1; ++ ++ for (i = 0; i < mm->n_roots; ++i) ++ list_add_tail(&mm->roots[i]->tmp_link, &dfs); ++ ++ do { ++ u64 block_start; ++ u64 block_end; ++ ++ block = list_first_entry_or_null(&dfs, ++ struct gpu_buddy_block, ++ tmp_link); ++ if (!block) ++ break; ++ ++ list_del(&block->tmp_link); ++ ++ if (gpu_buddy_block_order(block) < order) ++ continue; ++ ++ block_start = gpu_buddy_block_offset(block); ++ block_end = block_start + gpu_buddy_block_size(mm, block) - 1; ++ ++ if (!overlaps(start, end, block_start, block_end)) ++ continue; ++ ++ if (gpu_buddy_block_is_allocated(block)) ++ continue; ++ ++ if (block_start < start || block_end > end) { ++ u64 adjusted_start = max(block_start, start); ++ u64 adjusted_end = min(block_end, end); ++ ++ if (round_down(adjusted_end + 1, req_size) <= ++ round_up(adjusted_start, req_size)) ++ continue; ++ } ++ ++ if (!fallback && block_incompatible(block, flags)) ++ continue; ++ ++ if (contains(start, end, block_start, block_end) && ++ order == gpu_buddy_block_order(block)) { ++ /* ++ * Find the free block within the range. ++ */ ++ if (gpu_buddy_block_is_free(block)) ++ return block; ++ ++ continue; ++ } ++ ++ if (!gpu_buddy_block_is_split(block)) { ++ err = split_block(mm, block); ++ if (unlikely(err)) ++ goto err_undo; ++ } ++ ++ list_add(&block->right->tmp_link, &dfs); ++ list_add(&block->left->tmp_link, &dfs); ++ } while (1); ++ ++ return ERR_PTR(-ENOSPC); ++ ++err_undo: ++ /* ++ * We really don't want to leave around a bunch of split blocks, since ++ * bigger is better, so make sure we merge everything back before we ++ * free the allocated blocks. ++ */ ++ buddy = __get_buddy(block); ++ if (buddy && ++ (gpu_buddy_block_is_free(block) && ++ gpu_buddy_block_is_free(buddy))) ++ __gpu_buddy_free(mm, block, false); ++ return ERR_PTR(err); ++} ++ ++static struct gpu_buddy_block * ++__gpu_buddy_alloc_range_bias(struct gpu_buddy *mm, ++ u64 start, u64 end, ++ unsigned int order, ++ unsigned long flags) ++{ ++ struct gpu_buddy_block *block; ++ bool fallback = false; ++ ++ block = __alloc_range_bias(mm, start, end, order, ++ flags, fallback); ++ if (IS_ERR(block)) ++ return __alloc_range_bias(mm, start, end, order, ++ flags, !fallback); ++ ++ return block; ++} ++ ++static struct gpu_buddy_block * ++get_maxblock(struct gpu_buddy *mm, ++ unsigned int order, ++ enum gpu_buddy_free_tree tree) ++{ ++ struct gpu_buddy_block *max_block = NULL, *block = NULL; ++ struct rb_root *root; ++ unsigned int i; ++ ++ for (i = order; i <= mm->max_order; ++i) { ++ root = &mm->free_trees[tree][i]; ++ block = rbtree_last_free_block(root); ++ if (!block) ++ continue; ++ ++ if (!max_block) { ++ max_block = block; ++ continue; ++ } ++ ++ if (gpu_buddy_block_offset(block) > ++ gpu_buddy_block_offset(max_block)) { ++ max_block = block; ++ } ++ } ++ ++ return max_block; ++} ++ ++static struct gpu_buddy_block * ++alloc_from_freetree(struct gpu_buddy *mm, ++ unsigned int order, ++ unsigned long flags) ++{ ++ struct gpu_buddy_block *block = NULL; ++ struct rb_root *root; ++ enum gpu_buddy_free_tree tree; ++ unsigned int tmp; ++ int err; ++ ++ tree = (flags & GPU_BUDDY_CLEAR_ALLOCATION) ? ++ GPU_BUDDY_CLEAR_TREE : GPU_BUDDY_DIRTY_TREE; ++ ++ if (flags & GPU_BUDDY_TOPDOWN_ALLOCATION) { ++ block = get_maxblock(mm, order, tree); ++ if (block) ++ /* Store the obtained block order */ ++ tmp = gpu_buddy_block_order(block); ++ } else { ++ for (tmp = order; tmp <= mm->max_order; ++tmp) { ++ /* Get RB tree root for this order and tree */ ++ root = &mm->free_trees[tree][tmp]; ++ block = rbtree_last_free_block(root); ++ if (block) ++ break; ++ } ++ } ++ ++ if (!block) { ++ /* Try allocating from the other tree */ ++ tree = (tree == GPU_BUDDY_CLEAR_TREE) ? ++ GPU_BUDDY_DIRTY_TREE : GPU_BUDDY_CLEAR_TREE; ++ ++ for (tmp = order; tmp <= mm->max_order; ++tmp) { ++ root = &mm->free_trees[tree][tmp]; ++ block = rbtree_last_free_block(root); ++ if (block) ++ break; ++ } ++ ++ if (!block) ++ return ERR_PTR(-ENOSPC); ++ } ++ ++ BUG_ON(!gpu_buddy_block_is_free(block)); ++ ++ while (tmp != order) { ++ err = split_block(mm, block); ++ if (unlikely(err)) ++ goto err_undo; ++ ++ block = block->right; ++ tmp--; ++ } ++ return block; ++ ++err_undo: ++ if (tmp != order) ++ __gpu_buddy_free(mm, block, false); ++ return ERR_PTR(err); ++} ++ ++static int __alloc_range(struct gpu_buddy *mm, ++ struct list_head *dfs, ++ u64 start, u64 size, ++ struct list_head *blocks, ++ u64 *total_allocated_on_err) ++{ ++ struct gpu_buddy_block *block; ++ struct gpu_buddy_block *buddy; ++ u64 total_allocated = 0; ++ LIST_HEAD(allocated); ++ u64 end; ++ int err; ++ ++ end = start + size - 1; ++ ++ do { ++ u64 block_start; ++ u64 block_end; ++ ++ block = list_first_entry_or_null(dfs, ++ struct gpu_buddy_block, ++ tmp_link); ++ if (!block) ++ break; ++ ++ list_del(&block->tmp_link); ++ ++ block_start = gpu_buddy_block_offset(block); ++ block_end = block_start + gpu_buddy_block_size(mm, block) - 1; ++ ++ if (!overlaps(start, end, block_start, block_end)) ++ continue; ++ ++ if (gpu_buddy_block_is_allocated(block)) { ++ err = -ENOSPC; ++ goto err_free; ++ } ++ ++ if (contains(start, end, block_start, block_end)) { ++ if (gpu_buddy_block_is_free(block)) { ++ mark_allocated(mm, block); ++ total_allocated += gpu_buddy_block_size(mm, block); ++ mm->avail -= gpu_buddy_block_size(mm, block); ++ if (gpu_buddy_block_is_clear(block)) ++ mm->clear_avail -= gpu_buddy_block_size(mm, block); ++ list_add_tail(&block->link, &allocated); ++ continue; ++ } else if (!mm->clear_avail) { ++ err = -ENOSPC; ++ goto err_free; ++ } ++ } ++ ++ if (!gpu_buddy_block_is_split(block)) { ++ err = split_block(mm, block); ++ if (unlikely(err)) ++ goto err_undo; ++ } ++ ++ list_add(&block->right->tmp_link, dfs); ++ list_add(&block->left->tmp_link, dfs); ++ } while (1); ++ ++ if (total_allocated < size) { ++ err = -ENOSPC; ++ goto err_free; ++ } ++ ++ list_splice_tail(&allocated, blocks); ++ ++ return 0; ++ ++err_undo: ++ /* ++ * We really don't want to leave around a bunch of split blocks, since ++ * bigger is better, so make sure we merge everything back before we ++ * free the allocated blocks. ++ */ ++ buddy = __get_buddy(block); ++ if (buddy && ++ (gpu_buddy_block_is_free(block) && ++ gpu_buddy_block_is_free(buddy))) ++ __gpu_buddy_free(mm, block, false); ++ ++err_free: ++ if (err == -ENOSPC && total_allocated_on_err) { ++ list_splice_tail(&allocated, blocks); ++ *total_allocated_on_err = total_allocated; ++ } else { ++ gpu_buddy_free_list_internal(mm, &allocated); ++ } ++ ++ return err; ++} ++ ++static int __gpu_buddy_alloc_range(struct gpu_buddy *mm, ++ u64 start, ++ u64 size, ++ u64 *total_allocated_on_err, ++ struct list_head *blocks) ++{ ++ LIST_HEAD(dfs); ++ int i; ++ ++ for (i = 0; i < mm->n_roots; ++i) ++ list_add_tail(&mm->roots[i]->tmp_link, &dfs); ++ ++ return __alloc_range(mm, &dfs, start, size, ++ blocks, total_allocated_on_err); ++} ++ ++static int __alloc_contig_aligned_retry(struct gpu_buddy *mm, ++ u64 unaligned_offset, ++ u64 size, ++ u64 min_block_size, ++ struct list_head *blocks) ++{ ++ u64 aligned_offset = round_down(unaligned_offset, min_block_size); ++ ++ return __gpu_buddy_alloc_range(mm, aligned_offset, size, NULL, blocks); ++} ++ ++static int __alloc_contig_try_harder(struct gpu_buddy *mm, ++ u64 size, ++ u64 min_block_size, ++ struct list_head *blocks) ++{ ++ u64 rhs_offset, lhs_offset, filled; ++ struct gpu_buddy_block *block; ++ unsigned int tree, order; ++ u64 modify_size; ++ int err; ++ ++ modify_size = rounddown_pow_of_two(size); ++ order = ilog2(modify_size) - ilog2(mm->chunk_size); ++ if (order == 0) ++ return -ENOSPC; ++ ++ for_each_free_tree(tree) { ++ struct rb_root *root; ++ struct rb_node *iter; ++ ++ root = &mm->free_trees[tree][order]; ++ if (rbtree_is_empty(root)) ++ continue; ++ ++ iter = rb_last(root); ++ while (iter) { ++ block = rbtree_get_free_block(iter); ++ ++ rhs_offset = gpu_buddy_block_offset(block); ++ ++ /* Allocate blocks traversing RHS */ ++ err = __gpu_buddy_alloc_range(mm, rhs_offset, size, ++ &filled, blocks); ++ if (err && err != -ENOSPC) ++ return err; ++ if (!err && IS_ALIGNED(rhs_offset, min_block_size)) ++ return 0; ++ if (!err) { ++ /* Allocate the unaligned RHS offset using round_down */ ++ gpu_buddy_free_list_internal(mm, blocks); ++ err = __alloc_contig_aligned_retry(mm, rhs_offset, ++ size, ++ min_block_size, ++ blocks); ++ if (!err) ++ return 0; ++ if (err != -ENOSPC) { ++ gpu_buddy_free_list_internal(mm, blocks); ++ return err; ++ } ++ goto next; ++ } ++ ++ if (size - filled > rhs_offset) ++ goto next; ++ ++ lhs_offset = rhs_offset - (size - filled); ++ ++ /* Allocate the unaligned LHS offset using round_down */ ++ gpu_buddy_free_list_internal(mm, blocks); ++ err = __alloc_contig_aligned_retry(mm, lhs_offset, size, ++ min_block_size, blocks); ++ if (!err) ++ return 0; ++ if (err != -ENOSPC) { ++ gpu_buddy_free_list_internal(mm, blocks); ++ return err; ++ } ++next: ++ gpu_buddy_free_list_internal(mm, blocks); ++ iter = rb_prev(iter); ++ } ++ } ++ ++ return -ENOSPC; ++} ++ ++/** ++ * gpu_buddy_block_trim - free unused pages ++ * ++ * @mm: GPU buddy manager ++ * @start: start address to begin the trimming. ++ * @new_size: original size requested ++ * @blocks: Input and output list of allocated blocks. ++ * MUST contain single block as input to be trimmed. ++ * On success will contain the newly allocated blocks ++ * making up the @new_size. Blocks always appear in ++ * ascending order ++ * ++ * For contiguous allocation, we round up the size to the nearest ++ * power of two value, drivers consume *actual* size, so remaining ++ * portions are unused and can be optionally freed with this function ++ * ++ * Returns: ++ * 0 on success, error code on failure. ++ */ ++int gpu_buddy_block_trim(struct gpu_buddy *mm, ++ u64 *start, ++ u64 new_size, ++ struct list_head *blocks) ++{ ++ struct gpu_buddy_block *parent; ++ struct gpu_buddy_block *block; ++ u64 block_start, block_end; ++ LIST_HEAD(dfs); ++ u64 new_start; ++ int err; ++ ++ if (!list_is_singular(blocks)) ++ return -EINVAL; ++ ++ block = list_first_entry(blocks, ++ struct gpu_buddy_block, ++ link); ++ ++ block_start = gpu_buddy_block_offset(block); ++ block_end = block_start + gpu_buddy_block_size(mm, block); ++ ++ if (WARN_ON(!gpu_buddy_block_is_allocated(block))) ++ return -EINVAL; ++ ++ if (new_size > gpu_buddy_block_size(mm, block)) ++ return -EINVAL; ++ ++ if (!new_size || !IS_ALIGNED(new_size, mm->chunk_size)) ++ return -EINVAL; ++ ++ if (new_size == gpu_buddy_block_size(mm, block)) ++ return 0; ++ ++ new_start = block_start; ++ if (start) { ++ new_start = *start; ++ ++ if (new_start < block_start) ++ return -EINVAL; ++ ++ if (!IS_ALIGNED(new_start, mm->chunk_size)) ++ return -EINVAL; ++ ++ if (range_overflows(new_start, new_size, block_end)) ++ return -EINVAL; ++ } ++ ++ list_del(&block->link); ++ mark_free(mm, block); ++ mm->avail += gpu_buddy_block_size(mm, block); ++ if (gpu_buddy_block_is_clear(block)) ++ mm->clear_avail += gpu_buddy_block_size(mm, block); ++ ++ /* Prevent recursively freeing this node */ ++ parent = block->parent; ++ block->parent = NULL; ++ ++ list_add(&block->tmp_link, &dfs); ++ err = __alloc_range(mm, &dfs, new_start, new_size, blocks, NULL); ++ if (err) { ++ mark_allocated(mm, block); ++ mm->avail -= gpu_buddy_block_size(mm, block); ++ if (gpu_buddy_block_is_clear(block)) ++ mm->clear_avail -= gpu_buddy_block_size(mm, block); ++ list_add(&block->link, blocks); ++ } ++ ++ block->parent = parent; ++ return err; ++} ++EXPORT_SYMBOL(gpu_buddy_block_trim); ++ ++static struct gpu_buddy_block * ++__gpu_buddy_alloc_blocks(struct gpu_buddy *mm, ++ u64 start, u64 end, ++ unsigned int order, ++ unsigned long flags) ++{ ++ if (flags & GPU_BUDDY_RANGE_ALLOCATION) ++ /* Allocate traversing within the range */ ++ return __gpu_buddy_alloc_range_bias(mm, start, end, ++ order, flags); ++ else ++ /* Allocate from freetree */ ++ return alloc_from_freetree(mm, order, flags); ++} ++ ++/** ++ * gpu_buddy_alloc_blocks - allocate power-of-two blocks ++ * ++ * @mm: GPU buddy manager to allocate from ++ * @start: start of the allowed range for this block ++ * @end: end of the allowed range for this block ++ * @size: size of the allocation in bytes ++ * @min_block_size: alignment of the allocation ++ * @blocks: output list head to add allocated blocks ++ * @flags: GPU_BUDDY_*_ALLOCATION flags ++ * ++ * alloc_range_bias() called on range limitations, which traverses ++ * the tree and returns the desired block. ++ * ++ * alloc_from_freetree() called when *no* range restrictions ++ * are enforced, which picks the block from the freetree. ++ * ++ * Returns: ++ * 0 on success, error code on failure. ++ */ ++int gpu_buddy_alloc_blocks(struct gpu_buddy *mm, ++ u64 start, u64 end, u64 size, ++ u64 min_block_size, ++ struct list_head *blocks, ++ unsigned long flags) ++{ ++ struct gpu_buddy_block *block = NULL; ++ u64 original_size, original_min_size; ++ unsigned int min_order, order; ++ LIST_HEAD(allocated); ++ unsigned long pages; ++ int err; ++ ++ if (size < mm->chunk_size) ++ return -EINVAL; ++ ++ if (min_block_size < mm->chunk_size) ++ return -EINVAL; ++ ++ if (!is_power_of_2(min_block_size)) ++ return -EINVAL; ++ ++ if (!IS_ALIGNED(start | end | size, mm->chunk_size)) ++ return -EINVAL; ++ ++ if (end > mm->size) ++ return -EINVAL; ++ ++ if (range_overflows(start, size, mm->size)) ++ return -EINVAL; ++ ++ /* Actual range allocation */ ++ if (start + size == end) { ++ if (!IS_ALIGNED(start | end, min_block_size)) ++ return -EINVAL; ++ ++ return __gpu_buddy_alloc_range(mm, start, size, NULL, blocks); ++ } ++ ++ original_size = size; ++ original_min_size = min_block_size; ++ ++ /* Roundup the size to power of 2 */ ++ if (flags & GPU_BUDDY_CONTIGUOUS_ALLOCATION) { ++ size = roundup_pow_of_two(size); ++ min_block_size = size; ++ /* Align size value to min_block_size */ ++ } else if (!IS_ALIGNED(size, min_block_size)) { ++ size = round_up(size, min_block_size); ++ } ++ ++ pages = size >> ilog2(mm->chunk_size); ++ order = fls(pages) - 1; ++ min_order = ilog2(min_block_size) - ilog2(mm->chunk_size); ++ ++ if (order > mm->max_order || size > mm->size) { ++ if ((flags & GPU_BUDDY_CONTIGUOUS_ALLOCATION) && ++ !(flags & GPU_BUDDY_RANGE_ALLOCATION)) ++ return __alloc_contig_try_harder(mm, original_size, ++ original_min_size, blocks); ++ ++ return -EINVAL; ++ } ++ ++ do { ++ order = min(order, (unsigned int)fls(pages) - 1); ++ BUG_ON(order > mm->max_order); ++ BUG_ON(order < min_order); ++ ++ do { ++ block = __gpu_buddy_alloc_blocks(mm, start, ++ end, ++ order, ++ flags); ++ if (!IS_ERR(block)) ++ break; ++ ++ if (order-- == min_order) { ++ /* Try allocation through force merge method */ ++ if (mm->clear_avail && ++ !__force_merge(mm, start, end, min_order)) { ++ block = __gpu_buddy_alloc_blocks(mm, start, ++ end, ++ min_order, ++ flags); ++ if (!IS_ERR(block)) { ++ order = min_order; ++ break; ++ } ++ } ++ ++ /* ++ * Try contiguous block allocation through ++ * try harder method. ++ */ ++ if (flags & GPU_BUDDY_CONTIGUOUS_ALLOCATION && ++ !(flags & GPU_BUDDY_RANGE_ALLOCATION)) ++ return __alloc_contig_try_harder(mm, ++ original_size, ++ original_min_size, ++ blocks); ++ err = -ENOSPC; ++ goto err_free; ++ } ++ } while (1); ++ ++ mark_allocated(mm, block); ++ mm->avail -= gpu_buddy_block_size(mm, block); ++ if (gpu_buddy_block_is_clear(block)) ++ mm->clear_avail -= gpu_buddy_block_size(mm, block); ++ kmemleak_update_trace(block); ++ list_add_tail(&block->link, &allocated); ++ ++ pages -= BIT(order); ++ ++ if (!pages) ++ break; ++ } while (1); ++ ++ /* Trim the allocated block to the required size */ ++ if (!(flags & GPU_BUDDY_TRIM_DISABLE) && ++ original_size != size) { ++ struct list_head *trim_list; ++ LIST_HEAD(temp); ++ u64 trim_size; ++ ++ trim_list = &allocated; ++ trim_size = original_size; ++ ++ if (!list_is_singular(&allocated)) { ++ block = list_last_entry(&allocated, typeof(*block), link); ++ list_move(&block->link, &temp); ++ trim_list = &temp; ++ trim_size = gpu_buddy_block_size(mm, block) - ++ (size - original_size); ++ } ++ ++ gpu_buddy_block_trim(mm, ++ NULL, ++ trim_size, ++ trim_list); ++ ++ if (!list_empty(&temp)) ++ list_splice_tail(trim_list, &allocated); ++ } ++ ++ list_splice_tail(&allocated, blocks); ++ return 0; ++ ++err_free: ++ gpu_buddy_free_list_internal(mm, &allocated); ++ return err; ++} ++EXPORT_SYMBOL(gpu_buddy_alloc_blocks); ++ ++/** ++ * gpu_buddy_block_print - print block information ++ * ++ * @mm: GPU buddy manager ++ * @block: GPU buddy block ++ */ ++void gpu_buddy_block_print(struct gpu_buddy *mm, ++ struct gpu_buddy_block *block) ++{ ++ u64 start = gpu_buddy_block_offset(block); ++ u64 size = gpu_buddy_block_size(mm, block); ++ ++ pr_info("%#018llx-%#018llx: %llu\n", start, start + size, size); ++} ++EXPORT_SYMBOL(gpu_buddy_block_print); ++ ++/** ++ * gpu_buddy_print - print allocator state ++ * ++ * @mm: GPU buddy manager ++ * @p: GPU printer to use ++ */ ++void gpu_buddy_print(struct gpu_buddy *mm) ++{ ++ int order; ++ ++ pr_info("chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB, clear_free: %lluMiB\n", ++ mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20, mm->clear_avail >> 20); ++ ++ for (order = mm->max_order; order >= 0; order--) { ++ struct gpu_buddy_block *block, *tmp; ++ struct rb_root *root; ++ u64 count = 0, free; ++ unsigned int tree; ++ ++ for_each_free_tree(tree) { ++ root = &mm->free_trees[tree][order]; ++ ++ rbtree_postorder_for_each_entry_safe(block, tmp, root, rb) { ++ BUG_ON(!gpu_buddy_block_is_free(block)); ++ count++; ++ } ++ } ++ ++ free = count * (mm->chunk_size << order); ++ if (free < SZ_1M) ++ pr_info("order-%2d free: %8llu KiB, blocks: %llu\n", ++ order, free >> 10, count); ++ else ++ pr_info("order-%2d free: %8llu MiB, blocks: %llu\n", ++ order, free >> 20, count); ++ } ++} ++EXPORT_SYMBOL(gpu_buddy_print); ++ ++static void gpu_buddy_module_exit(void) ++{ ++ kmem_cache_destroy(slab_blocks); ++} ++ ++static int __init gpu_buddy_module_init(void) ++{ ++ slab_blocks = KMEM_CACHE(gpu_buddy_block, 0); ++ if (!slab_blocks) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++module_init(gpu_buddy_module_init); ++module_exit(gpu_buddy_module_exit); ++ ++MODULE_DESCRIPTION("GPU Buddy Allocator"); ++MODULE_LICENSE("Dual MIT/GPL"); +diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig +index ed85d0ceee3ba5..4b0228c88f496a 100644 +--- a/drivers/gpu/drm/Kconfig ++++ b/drivers/gpu/drm/Kconfig +@@ -220,6 +220,7 @@ config DRM_GPUSVM + config DRM_BUDDY + tristate + depends on DRM ++ select GPU_BUDDY + help + A page based buddy allocator + +@@ -416,10 +417,6 @@ config DRM_HYPERV + config DRM_PANEL_BACKLIGHT_QUIRKS + tristate + +-config DRM_LIB_RANDOM +- bool +- default n +- + config DRM_PRIVACY_SCREEN + bool + default n +diff --git a/drivers/gpu/drm/Kconfig.debug b/drivers/gpu/drm/Kconfig.debug +index 05dc43c0b8c5af..3b7886865335a3 100644 +--- a/drivers/gpu/drm/Kconfig.debug ++++ b/drivers/gpu/drm/Kconfig.debug +@@ -69,7 +69,6 @@ config DRM_KUNIT_TEST + select DRM_EXPORT_FOR_TESTS if m + select DRM_GEM_SHMEM_HELPER + select DRM_KUNIT_TEST_HELPERS +- select DRM_LIB_RANDOM + select DRM_SYSFB_HELPER + select PRIME_NUMBERS + default KUNIT_ALL_TESTS +diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile +index b248e64587ed40..1b3a7ab6df5855 100644 +--- a/drivers/gpu/drm/Makefile ++++ b/drivers/gpu/drm/Makefile +@@ -77,7 +77,6 @@ drm-$(CONFIG_DRM_CLIENT) += \ + drm_client.o \ + drm_client_event.o \ + drm_client_modeset.o +-drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o + drm-$(CONFIG_COMPAT) += drm_ioc32.o + drm-$(CONFIG_DRM_PANEL) += drm_panel.o + drm-$(CONFIG_OF) += drm_of.o +@@ -239,7 +238,7 @@ obj-$(CONFIG_DRM_POWERVR) += imagination/ + # Ensure drm headers are self-contained and pass kernel-doc + hdrtest-files := \ + $(shell cd $(src) && find . -maxdepth 1 -name 'drm_*.h') \ +- $(shell cd $(src) && find display lib -name '*.h') ++ $(shell cd $(src) && find display -name '*.h') + + always-$(CONFIG_DRM_HEADER_TEST) += \ + $(patsubst %.h,%.hdrtest, $(hdrtest-files)) +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +index 4926996f94da08..fe39b150ee5335 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +@@ -505,6 +505,7 @@ static int acp_hw_fini(struct amdgpu_ip_block *ip_block) + u32 val = 0; + u32 count = 0; + struct amdgpu_device *adev = ip_block->adev; ++ int ret = 0; + + /* return early if no ACP */ + if (!adev->acp.acp_genpd) { +@@ -526,7 +527,8 @@ static int acp_hw_fini(struct amdgpu_ip_block *ip_block) + break; + if (--count == 0) { + dev_err(&adev->pdev->dev, "Failed to reset ACP\n"); +- return -ETIMEDOUT; ++ ret = -ETIMEDOUT; ++ goto out; + } + udelay(100); + } +@@ -543,20 +545,23 @@ static int acp_hw_fini(struct amdgpu_ip_block *ip_block) + break; + if (--count == 0) { + dev_err(&adev->pdev->dev, "Failed to reset ACP\n"); +- return -ETIMEDOUT; ++ ret = -ETIMEDOUT; ++ goto out; + } + udelay(100); + } +- ++out: + device_for_each_child(adev->acp.parent, NULL, + acp_genpd_remove_device); + + mfd_remove_devices(adev->acp.parent); + kfree(adev->acp.acp_res); ++ pm_genpd_remove(&adev->acp.acp_genpd->gpd); + kfree(adev->acp.acp_genpd); ++ adev->acp.acp_genpd = NULL; + kfree(adev->acp.acp_cell); + +- return 0; ++ return ret; + } + + static int acp_suspend(struct amdgpu_ip_block *ip_block) +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +index 00e96419fcdad8..4e60753e16e900 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +@@ -355,19 +355,59 @@ static bool amdgpu_read_disabled_bios(struct amdgpu_device *adev) + } + + #ifdef CONFIG_ACPI ++/** ++ * amdgpu_acpi_vfct_match() - Check if a VFCT entry matches the device ++ * @adev: AMDGPU device ++ * @vhdr: VFCT image header to check ++ * ++ * VFCT entries contain the PCI bus number as recorded during BIOS POST. ++ * On systems where the kernel renumbers PCI buses (e.g. pci=realloc or ++ * resource conflicts), the runtime bus number may differ from the POST ++ * value. Match by device identity (vendor + device + function) and use ++ * the bus number as a preference: exact bus match is preferred, but when ++ * the bus numbers disagree we accept the entry if the device identity ++ * matches. ++ * ++ * Returns: 0 on match, -ENODEV on no match ++ */ ++static int amdgpu_acpi_vfct_match(struct amdgpu_device *adev, ++ VFCT_IMAGE_HEADER *vhdr) ++{ ++ /* Vendor and device IDs must always match */ ++ if (vhdr->VendorID != adev->pdev->vendor || ++ vhdr->DeviceID != adev->pdev->device) ++ return -ENODEV; ++ ++ if (vhdr->PCIDevice != PCI_SLOT(adev->pdev->devfn) || ++ vhdr->PCIFunction != PCI_FUNC(adev->pdev->devfn)) ++ return -ENODEV; ++ ++ /* Exact bus number match - preferred */ ++ if (vhdr->PCIBus == adev->pdev->bus->number) ++ return 0; ++ ++ /* Bus mismatch but device identity matches (PCI renumbering case) */ ++ dev_notice(adev->dev, ++ "VFCT bus number mismatch: table %u != runtime %u, matching by device identity (vendor 0x%04x device 0x%04x)\n", ++ vhdr->PCIBus, adev->pdev->bus->number, ++ adev->pdev->vendor, adev->pdev->device); ++ return 0; ++} ++ + static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) + { + struct acpi_table_header *hdr; + acpi_size tbl_size; + UEFI_ACPI_VFCT *vfct; + unsigned int offset; ++ bool r = false; + + if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr))) + return false; + tbl_size = hdr->length; + if (tbl_size < sizeof(UEFI_ACPI_VFCT)) { + dev_info(adev->dev, "ACPI VFCT table present but broken (too short #1),skipping\n"); +- return false; ++ goto out; + } + + vfct = (UEFI_ACPI_VFCT *)hdr; +@@ -380,36 +420,36 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) + offset += sizeof(VFCT_IMAGE_HEADER); + if (offset > tbl_size) { + dev_info(adev->dev, "ACPI VFCT image header truncated,skipping\n"); +- return false; ++ goto out; + } + + offset += vhdr->ImageLength; + if (offset > tbl_size) { + dev_info(adev->dev, "ACPI VFCT image truncated,skipping\n"); +- return false; ++ goto out; + } + + if (vhdr->ImageLength && +- vhdr->PCIBus == adev->pdev->bus->number && +- vhdr->PCIDevice == PCI_SLOT(adev->pdev->devfn) && +- vhdr->PCIFunction == PCI_FUNC(adev->pdev->devfn) && +- vhdr->VendorID == adev->pdev->vendor && +- vhdr->DeviceID == adev->pdev->device) { ++ !amdgpu_acpi_vfct_match(adev, vhdr)) { + adev->bios = kmemdup(&vbios->VbiosContent, + vhdr->ImageLength, + GFP_KERNEL); + + if (!check_atom_bios(adev, vhdr->ImageLength)) { + amdgpu_bios_release(adev); +- return false; ++ goto out; + } + adev->bios_size = vhdr->ImageLength; +- return true; ++ r = true; ++ goto out; + } + } + + dev_info(adev->dev, "ACPI VFCT table present but broken (too short #2),skipping\n"); +- return false; ++ ++out: ++ acpi_put_table(hdr); ++ return r; + } + #else + static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +index 8669e2fd6eff61..4b449b58d90733 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +@@ -260,13 +260,17 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p, + goto free_partial_kdata; + break; + ++ case AMDGPU_CHUNK_ID_CP_GFX_SHADOW: ++ if (size < sizeof(struct drm_amdgpu_cs_chunk_cp_gfx_shadow)) ++ goto free_partial_kdata; ++ break; ++ + case AMDGPU_CHUNK_ID_DEPENDENCIES: + case AMDGPU_CHUNK_ID_SYNCOBJ_IN: + case AMDGPU_CHUNK_ID_SYNCOBJ_OUT: + case AMDGPU_CHUNK_ID_SCHEDULED_DEPENDENCIES: + case AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_WAIT: + case AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_SIGNAL: +- case AMDGPU_CHUNK_ID_CP_GFX_SHADOW: + break; + + default: +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index d0cb300cd382bd..2c55925895f92e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -1878,6 +1878,15 @@ static bool amdgpu_device_pcie_dynamic_switching_supported(struct amdgpu_device + + if (c->x86_vendor == X86_VENDOR_INTEL) + return false; ++ ++ /* ++ * AMD Ryzen Pinnacle Ridge (Zen+, family 0x17 model 0x08) CPUs don't ++ * support PCIe dynamic speed switching. ++ * https://gitlab.freedesktop.org/drm/amd/-/work_items/5436 ++ */ ++ if (c->x86_vendor == X86_VENDOR_AMD && c->x86 == 0x17 && ++ c->x86_model == 0x08) ++ return false; + #endif + return true; + } +@@ -1888,7 +1897,8 @@ static bool amdgpu_device_aspm_support_quirk(struct amdgpu_device *adev) + * It's unclear if this is a platform-specific or GPU-specific issue. + * Disable ASPM on SI for the time being. + */ +- if (adev->family == AMDGPU_FAMILY_SI) ++ if (adev->family == AMDGPU_FAMILY_SI || ++ (!(adev->pm.pp_feature & PP_PCIE_DPM_MASK) && adev->family == AMDGPU_FAMILY_VI)) + return true; + + #if IS_ENABLED(CONFIG_X86) +@@ -4936,8 +4946,6 @@ static void amdgpu_device_unmap_mmio(struct amdgpu_device *adev) + + iounmap(adev->rmmio); + adev->rmmio = NULL; +- if (adev->mman.aper_base_kaddr) +- iounmap(adev->mman.aper_base_kaddr); + adev->mman.aper_base_kaddr = NULL; + + /* Memory manager related */ +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +index cd52ddd27c58b3..5fc9a6b1ec7228 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +@@ -523,6 +523,7 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data, + bo = gem_to_amdgpu_bo(gobj); + bo->preferred_domains = AMDGPU_GEM_DOMAIN_GTT; + bo->allowed_domains = AMDGPU_GEM_DOMAIN_GTT; ++ bo->parent = amdgpu_bo_ref(fpriv->vm.root.bo); + r = amdgpu_ttm_tt_set_userptr(&bo->tbo, args->addr, args->flags); + if (r) + goto release_object; +@@ -1075,6 +1076,11 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data, + * If that number is larger than the size of the array, the ioctl must + * be retried. + */ ++ if (!bo_va) { ++ r = -ENOENT; ++ goto out_exec; ++ } ++ + if (args->num_entries > INT_MAX / sizeof(*vm_entries)) { + r = -EINVAL; + goto out_exec; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +index ebe2b4c68b0f36..40e7482980692e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +@@ -1456,12 +1456,13 @@ static int amdgpu_gfx_run_cleaner_shader_job(struct amdgpu_ring *ring) + struct amdgpu_device *adev = ring->adev; + struct drm_gpu_scheduler *sched = &ring->sched; + struct drm_sched_entity entity; ++ unsigned int ib_size_dw = 16; + static atomic_t counter; + struct dma_fence *f; + struct amdgpu_job *job; + struct amdgpu_ib *ib; + void *owner; +- int i, r; ++ int r; + + /* Initialize the scheduler entity */ + r = drm_sched_entity_init(&entity, DRM_SCHED_PRIORITY_NORMAL, +@@ -1479,7 +1480,7 @@ static int amdgpu_gfx_run_cleaner_shader_job(struct amdgpu_ring *ring) + owner = (void *)(unsigned long)atomic_inc_return(&counter); + + r = amdgpu_job_alloc_with_ib(ring->adev, &entity, owner, +- 64, 0, &job, ++ ib_size_dw * sizeof(uint32_t), 0, &job, + AMDGPU_KERNEL_JOB_ID_CLEANER_SHADER); + if (r) + goto err; +@@ -1489,9 +1490,8 @@ static int amdgpu_gfx_run_cleaner_shader_job(struct amdgpu_ring *ring) + job->run_cleaner_shader = true; + + ib = &job->ibs[0]; +- for (i = 0; i <= ring->funcs->align_mask; ++i) +- ib->ptr[i] = ring->funcs->nop; +- ib->length_dw = ring->funcs->align_mask + 1; ++ memset32(ib->ptr, ring->funcs->nop, ib_size_dw); ++ ib->length_dw = ib_size_dw; + + f = amdgpu_job_submit(job); + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c +index ccda3b58a4558d..f60f26470af036 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c +@@ -69,7 +69,6 @@ static bool amdgpu_hmm_invalidate_gfx(struct mmu_interval_notifier *mni, + { + struct amdgpu_bo *bo = container_of(mni, struct amdgpu_bo, notifier); + struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); +- struct amdgpu_bo *vm_root = bo->vm_bo->vm->root.bo; + long r; + + if (!mmu_notifier_range_blockable(range)) +@@ -80,7 +79,7 @@ static bool amdgpu_hmm_invalidate_gfx(struct mmu_interval_notifier *mni, + mmu_interval_set_seq(mni, cur_seq); + + amdgpu_vm_bo_invalidate(bo, false); +- r = dma_resv_wait_timeout(vm_root->tbo.base.resv, ++ r = dma_resv_wait_timeout(bo->parent->tbo.base.resv, + DMA_RESV_USAGE_BOOKKEEP, false, + MAX_SCHEDULE_TIMEOUT); + mutex_unlock(&adev->notifier_lock); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +index e08f58de4b17f2..cdab2c098cfab7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +@@ -284,10 +284,12 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev, + goto error_free; + } + +- r = amdgpu_bo_pin(*bo_ptr, domain); +- if (r) { +- dev_err(adev->dev, "(%d) kernel bo pin failed\n", r); +- goto error_unreserve; ++ if (free) { ++ r = amdgpu_bo_pin(*bo_ptr, domain); ++ if (r) { ++ dev_err(adev->dev, "(%d) kernel bo pin failed\n", r); ++ goto error_unreserve; ++ } + } + + r = amdgpu_ttm_alloc_gart(&(*bo_ptr)->tbo); +@@ -310,7 +312,8 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev, + return 0; + + error_unpin: +- amdgpu_bo_unpin(*bo_ptr); ++ if (free) ++ amdgpu_bo_unpin(*bo_ptr); + error_unreserve: + amdgpu_bo_unreserve(*bo_ptr); + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +index e9ed1a3b135cc4..9df691364a18c2 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +@@ -5416,7 +5416,7 @@ int amdgpu_ras_add_critical_region(struct amdgpu_device *adev, + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + struct amdgpu_vram_mgr_resource *vres; + struct ras_critical_region *region; +- struct drm_buddy_block *block; ++ struct gpu_buddy_block *block; + int ret = 0; + + if (!bo || !bo->tbo.resource) +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h +index be2e56ce1355ec..8908d9e08a3043 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h +@@ -55,7 +55,7 @@ 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 gpu_buddy_block *block; + struct list_head *head, *next; + struct drm_mm_node *node; + +@@ -71,7 +71,7 @@ static inline void amdgpu_res_first(struct ttm_resource *res, + head = &to_amdgpu_vram_mgr_resource(res)->blocks; + + block = list_first_entry_or_null(head, +- struct drm_buddy_block, ++ struct gpu_buddy_block, + link); + if (!block) + goto fallback; +@@ -81,7 +81,7 @@ static inline void amdgpu_res_first(struct ttm_resource *res, + + next = block->link.next; + if (next != head) +- block = list_entry(next, struct drm_buddy_block, link); ++ block = list_entry(next, struct gpu_buddy_block, link); + } + + cur->start = amdgpu_vram_mgr_block_start(block) + start; +@@ -125,7 +125,7 @@ fallback: + */ + static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size) + { +- struct drm_buddy_block *block; ++ struct gpu_buddy_block *block; + struct drm_mm_node *node; + struct list_head *next; + +@@ -146,7 +146,7 @@ static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size) + block = cur->node; + + next = block->link.next; +- block = list_entry(next, struct drm_buddy_block, link); ++ block = list_entry(next, struct gpu_buddy_block, link); + + cur->node = block; + cur->start = amdgpu_vram_mgr_block_start(block); +@@ -175,7 +175,7 @@ static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size) + */ + static inline bool amdgpu_res_cleared(struct amdgpu_res_cursor *cur) + { +- struct drm_buddy_block *block; ++ struct gpu_buddy_block *block; + + switch (cur->mem_type) { + case TTM_PL_VRAM: +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +index d629c5f73bf598..a4b5fe35c3cda8 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +@@ -505,6 +505,15 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict, + + if (new_mem->mem_type == TTM_PL_TT || + new_mem->mem_type == AMDGPU_PL_PREEMPT) { ++ if (old_mem && (old_mem->mem_type == TTM_PL_TT || ++ old_mem->mem_type == AMDGPU_PL_PREEMPT)) { ++ r = ttm_bo_wait_ctx(bo, ctx); ++ if (r) ++ return r; ++ ++ amdgpu_ttm_backend_unbind(bo->bdev, bo->ttm); ++ } ++ + r = amdgpu_ttm_backend_bind(bo->bdev, bo->ttm, new_mem); + if (r) + return r; +@@ -539,6 +548,15 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict, + ttm_bo_assign_mem(bo, new_mem); + return 0; + } ++ if ((old_mem->mem_type == TTM_PL_TT || ++ old_mem->mem_type == AMDGPU_PL_PREEMPT) && ++ (new_mem->mem_type == TTM_PL_TT || ++ new_mem->mem_type == AMDGPU_PL_PREEMPT)) { ++ amdgpu_bo_move_notify(bo, evict, new_mem); ++ ttm_resource_free(bo, &bo->resource); ++ ttm_bo_assign_mem(bo, new_mem); ++ return 0; ++ } + + if (old_mem->mem_type == AMDGPU_PL_GDS || + old_mem->mem_type == AMDGPU_PL_GWS || +@@ -1962,18 +1980,23 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) + /* Change the size here instead of the init above so only lpfn is affected */ + amdgpu_ttm_set_buffer_funcs_status(adev, false); + #ifdef CONFIG_64BIT +-#ifdef CONFIG_X86 +- if (adev->gmc.xgmi.connected_to_cpu) +- adev->mman.aper_base_kaddr = ioremap_cache(adev->gmc.aper_base, +- adev->gmc.visible_vram_size); +- +- else if (adev->gmc.is_app_apu) ++ if (adev->gmc.xgmi.connected_to_cpu) { ++ void *kaddr = devm_memremap(adev->dev, adev->gmc.aper_base, ++ adev->gmc.visible_vram_size, ++ MEMREMAP_WB); ++ if (IS_ERR(kaddr)) ++ return PTR_ERR(kaddr); ++ adev->mman.aper_base_kaddr = (__force void __iomem *)kaddr; ++ } else if (adev->gmc.is_app_apu) { + DRM_DEBUG_DRIVER( + "No need to ioremap when real vram size is 0\n"); +- else +-#endif +- adev->mman.aper_base_kaddr = ioremap_wc(adev->gmc.aper_base, +- adev->gmc.visible_vram_size); ++ } else { ++ adev->mman.aper_base_kaddr = devm_ioremap_wc(adev->dev, ++ adev->gmc.aper_base, ++ adev->gmc.visible_vram_size); ++ if (!adev->mman.aper_base_kaddr) ++ return -ENOMEM; ++ } + #endif + + /* +@@ -2134,8 +2157,6 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) + */ + void amdgpu_ttm_fini(struct amdgpu_device *adev) + { +- int idx; +- + if (!adev->mman.initialized) + return; + +@@ -2162,14 +2183,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) + amdgpu_ttm_fw_reserve_vram_fini(adev); + amdgpu_ttm_drv_reserve_vram_fini(adev); + +- if (drm_dev_enter(adev_to_drm(adev), &idx)) { +- +- if (adev->mman.aper_base_kaddr) +- iounmap(adev->mman.aper_base_kaddr); +- adev->mman.aper_base_kaddr = NULL; +- +- drm_dev_exit(idx); +- } ++ adev->mman.aper_base_kaddr = NULL; + + if (!adev->gmc.is_app_apu) + amdgpu_vram_mgr_fini(adev); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +index 5c38f0d30c87ab..5f1199b592b063 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +@@ -135,7 +135,7 @@ MODULE_FIRMWARE(FIRMWARE_VEGA12); + MODULE_FIRMWARE(FIRMWARE_VEGA20); + + static void amdgpu_uvd_idle_work_handler(struct work_struct *work); +-static void amdgpu_uvd_force_into_uvd_segment(struct amdgpu_bo *abo); ++static void amdgpu_uvd_force_into_vcpu_segment(struct amdgpu_bo *abo); + + static int amdgpu_uvd_create_msg_bo_helper(struct amdgpu_device *adev, + uint32_t size, +@@ -158,7 +158,7 @@ static int amdgpu_uvd_create_msg_bo_helper(struct amdgpu_device *adev, + amdgpu_bo_kunmap(bo); + amdgpu_bo_unpin(bo); + amdgpu_bo_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_VRAM); +- amdgpu_uvd_force_into_uvd_segment(bo); ++ amdgpu_uvd_force_into_vcpu_segment(bo); + r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); + if (r) + goto err; +@@ -188,6 +188,7 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) + const struct common_firmware_header *hdr; + unsigned int family_id; + int i, j, r; ++ u32 vcpu_bo_domain; + + INIT_DELAYED_WORK(&adev->uvd.idle_work, amdgpu_uvd_idle_work_handler); + +@@ -319,12 +320,20 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) + if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) + bo_size += AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8); + ++ /* UVD 5.0 and newer HW can use 64 bit addressing. */ ++ adev->uvd.address_64_bit = ++ !amdgpu_device_ip_block_version_cmp(adev, AMD_IP_BLOCK_TYPE_UVD, 5, 0); ++ ++ vcpu_bo_domain = AMDGPU_GEM_DOMAIN_VRAM; ++ if (adev->uvd.address_64_bit) ++ vcpu_bo_domain |= AMDGPU_GEM_DOMAIN_GTT; ++ + for (j = 0; j < adev->uvd.num_uvd_inst; j++) { + if (adev->uvd.harvest_config & (1 << j)) + continue; ++ + r = amdgpu_bo_create_kernel(adev, bo_size, PAGE_SIZE, +- AMDGPU_GEM_DOMAIN_VRAM | +- AMDGPU_GEM_DOMAIN_GTT, ++ vcpu_bo_domain, + &adev->uvd.inst[j].vcpu_bo, + &adev->uvd.inst[j].gpu_addr, + &adev->uvd.inst[j].cpu_addr); +@@ -339,10 +348,6 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) + adev->uvd.filp[i] = NULL; + } + +- /* from uvd v5.0 HW addressing capacity increased to 64 bits */ +- if (!amdgpu_device_ip_block_version_cmp(adev, AMD_IP_BLOCK_TYPE_UVD, 5, 0)) +- adev->uvd.address_64_bit = true; +- + r = amdgpu_uvd_create_msg_bo_helper(adev, 128 << 10, &adev->uvd.ib_bo); + if (r) + return r; +@@ -544,6 +549,24 @@ void amdgpu_uvd_free_handles(struct amdgpu_device *adev, struct drm_file *filp) + } + } + ++static void amdgpu_uvd_force_into_vcpu_segment(struct amdgpu_bo *bo) ++{ ++ struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); ++ struct amdgpu_bo *vcpu_bo = adev->uvd.inst[0].vcpu_bo; ++ struct amdgpu_res_cursor vcpu_cur; ++ ++ amdgpu_res_first(vcpu_bo->tbo.resource, 0, ++ amdgpu_bo_size(vcpu_bo), &vcpu_cur); ++ ++ bo->placement.num_placement = 1; ++ bo->placement.placement = &bo->placements[0]; ++ bo->placements[0].fpfn = ALIGN_DOWN(vcpu_cur.start, SZ_256M) >> PAGE_SHIFT; ++ bo->placements[0].lpfn = bo->placements[0].fpfn + (SZ_256M >> PAGE_SHIFT); ++ bo->placements[0].mem_type = vcpu_bo->tbo.resource->mem_type; ++ if (bo->placements[0].mem_type == TTM_PL_VRAM) ++ bo->placements[0].flags |= TTM_PL_FLAG_CONTIGUOUS; ++} ++ + static void amdgpu_uvd_force_into_uvd_segment(struct amdgpu_bo *abo) + { + int i; +@@ -594,13 +617,10 @@ static int amdgpu_uvd_cs_pass1(struct amdgpu_uvd_cs_ctx *ctx) + if (!ctx->parser->adev->uvd.address_64_bit) { + /* check if it's a message or feedback command */ + cmd = amdgpu_ib_get_value(ctx->ib, ctx->idx) >> 1; +- if (cmd == 0x0 || cmd == 0x3) { +- /* yes, force it into VRAM */ +- uint32_t domain = AMDGPU_GEM_DOMAIN_VRAM; +- +- amdgpu_bo_placement_from_domain(bo, domain); +- } +- amdgpu_uvd_force_into_uvd_segment(bo); ++ if (cmd == 0x0 || cmd == 0x3) ++ amdgpu_uvd_force_into_vcpu_segment(bo); ++ else ++ amdgpu_uvd_force_into_uvd_segment(bo); + + r = ttm_bo_validate(&bo->tbo, &bo->placement, &tctx); + } +@@ -634,6 +654,14 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg, + unsigned int image_size, tmp, min_dpb_size, num_dpb_buffer; + unsigned int min_ctx_size = ~0; + ++ /* Reject invalid dimensions to prevent division by zero */ ++ if (width < 16 || height < 16) { ++ dev_WARN_ONCE(adev->dev, 1, ++ "Invalid UVD decoding dimensions (%dx%d)!\n", ++ width, height); ++ return -EINVAL; ++ } ++ + image_size = width * height; + image_size += image_size / 2; + image_size = ALIGN(image_size, 1024); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +index 3b9a9010ed3549..3dc2b7f91e288a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +@@ -853,9 +853,20 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, + goto out; + } + +- *size = amdgpu_ib_get_value(ib, idx + 8) * +- amdgpu_ib_get_value(ib, idx + 10) * +- 8 * 3 / 2; ++ uint32_t width, height; ++ width = amdgpu_ib_get_value(ib, idx + 8); ++ height = amdgpu_ib_get_value(ib, idx + 10); ++ ++ if (width == 0 || height == 0 || ++ width > 4096 || height > 2304) { ++ DRM_ERROR("invalid VCE image size: %ux%u\n", ++ width, height); ++ r = -EINVAL; ++ goto out; ++ } ++ ++ *size = width * height * 8 * 3 / 2; ++ + break; + + case 0x04000001: /* config extension */ +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +index ffbae605caaa5a..fd80571a1aceab 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +@@ -2453,19 +2453,6 @@ static void amdgpu_vm_destroy_task_info(struct kref *kref) + kfree(ti); + } + +-static inline struct amdgpu_vm * +-amdgpu_vm_get_vm_from_pasid(struct amdgpu_device *adev, u32 pasid) +-{ +- struct amdgpu_vm *vm; +- unsigned long flags; +- +- xa_lock_irqsave(&adev->vm_manager.pasids, flags); +- vm = xa_load(&adev->vm_manager.pasids, pasid); +- xa_unlock_irqrestore(&adev->vm_manager.pasids, flags); +- +- return vm; +-} +- + /** + * amdgpu_vm_put_task_info - reference down the vm task_info ptr + * +@@ -2512,8 +2499,16 @@ amdgpu_vm_get_task_info_vm(struct amdgpu_vm *vm) + struct amdgpu_task_info * + amdgpu_vm_get_task_info_pasid(struct amdgpu_device *adev, u32 pasid) + { +- return amdgpu_vm_get_task_info_vm( +- amdgpu_vm_get_vm_from_pasid(adev, pasid)); ++ struct amdgpu_task_info *ti; ++ struct amdgpu_vm *vm; ++ unsigned long flags; ++ ++ xa_lock_irqsave(&adev->vm_manager.pasids, flags); ++ vm = xa_load(&adev->vm_manager.pasids, pasid); ++ ti = amdgpu_vm_get_task_info_vm(vm); ++ xa_unlock_irqrestore(&adev->vm_manager.pasids, flags); ++ ++ return ti; + } + + static int amdgpu_vm_create_task_info(struct amdgpu_vm *vm) +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +index 9d934c07fa6b8b..cd94f6efb7cb37 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +@@ -25,6 +25,7 @@ + #include <linux/dma-mapping.h> + #include <drm/ttm/ttm_range_manager.h> + #include <drm/drm_drv.h> ++#include <drm/drm_buddy.h> + + #include "amdgpu.h" + #include "amdgpu_vm.h" +@@ -52,15 +53,15 @@ to_amdgpu_device(struct amdgpu_vram_mgr *mgr) + return container_of(mgr, struct amdgpu_device, mman.vram_mgr); + } + +-static inline struct drm_buddy_block * ++static inline struct gpu_buddy_block * + amdgpu_vram_mgr_first_block(struct list_head *list) + { +- return list_first_entry_or_null(list, struct drm_buddy_block, link); ++ return list_first_entry_or_null(list, struct gpu_buddy_block, link); + } + + static inline bool amdgpu_is_vram_mgr_blocks_contiguous(struct list_head *head) + { +- struct drm_buddy_block *block; ++ struct gpu_buddy_block *block; + u64 start, size; + + block = amdgpu_vram_mgr_first_block(head); +@@ -71,7 +72,7 @@ static inline bool amdgpu_is_vram_mgr_blocks_contiguous(struct list_head *head) + 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); ++ block = list_entry(block->link.next, struct gpu_buddy_block, link); + if (start + size != amdgpu_vram_mgr_block_start(block)) + return false; + } +@@ -81,7 +82,7 @@ static inline bool amdgpu_is_vram_mgr_blocks_contiguous(struct list_head *head) + + static inline u64 amdgpu_vram_mgr_blocks_size(struct list_head *head) + { +- struct drm_buddy_block *block; ++ struct gpu_buddy_block *block; + u64 size = 0; + + list_for_each_entry(block, head, link) +@@ -254,7 +255,7 @@ const struct attribute_group amdgpu_vram_mgr_attr_group = { + * Calculate how many bytes of the DRM BUDDY block are inside visible VRAM + */ + static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev, +- struct drm_buddy_block *block) ++ struct gpu_buddy_block *block) + { + u64 start = amdgpu_vram_mgr_block_start(block); + u64 end = start + amdgpu_vram_mgr_block_size(block); +@@ -279,7 +280,7 @@ 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; ++ struct gpu_buddy_block *block; + u64 usage = 0; + + if (amdgpu_gmc_vram_full_visible(&adev->gmc)) +@@ -299,15 +300,15 @@ 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 gpu_buddy *mm = &mgr->mm; + struct amdgpu_vram_reservation *rsv, *temp; +- struct drm_buddy_block *block; ++ struct gpu_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, ++ if (gpu_buddy_alloc_blocks(mm, rsv->start, rsv->start + rsv->size, + rsv->size, mm->chunk_size, &rsv->allocated, +- DRM_BUDDY_RANGE_ALLOCATION)) ++ GPU_BUDDY_RANGE_ALLOCATION)) + continue; + + block = amdgpu_vram_mgr_first_block(&rsv->allocated); +@@ -403,7 +404,7 @@ int amdgpu_vram_mgr_query_address_block_info(struct amdgpu_vram_mgr *mgr, + uint64_t address, struct amdgpu_vram_block_info *info) + { + struct amdgpu_vram_mgr_resource *vres; +- struct drm_buddy_block *block; ++ struct gpu_buddy_block *block; + u64 start, size; + int ret = -ENOENT; + +@@ -450,8 +451,8 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, + struct amdgpu_vram_mgr_resource *vres; + u64 size, remaining_size, lpfn, fpfn; + unsigned int adjust_dcc_size = 0; +- struct drm_buddy *mm = &mgr->mm; +- struct drm_buddy_block *block; ++ struct gpu_buddy *mm = &mgr->mm; ++ struct gpu_buddy_block *block; + unsigned long pages_per_block; + int r; + +@@ -493,17 +494,17 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, + INIT_LIST_HEAD(&vres->blocks); + + if (place->flags & TTM_PL_FLAG_TOPDOWN) +- vres->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION; ++ vres->flags |= GPU_BUDDY_TOPDOWN_ALLOCATION; + + if (bo->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS) +- vres->flags |= DRM_BUDDY_CONTIGUOUS_ALLOCATION; ++ vres->flags |= GPU_BUDDY_CONTIGUOUS_ALLOCATION; + + if (bo->flags & AMDGPU_GEM_CREATE_VRAM_CLEARED) +- vres->flags |= DRM_BUDDY_CLEAR_ALLOCATION; ++ vres->flags |= GPU_BUDDY_CLEAR_ALLOCATION; + + if (fpfn || lpfn != mgr->mm.size) + /* Allocate blocks in desired range */ +- vres->flags |= DRM_BUDDY_RANGE_ALLOCATION; ++ vres->flags |= GPU_BUDDY_RANGE_ALLOCATION; + + if (bo->flags & AMDGPU_GEM_CREATE_GFX12_DCC && + adev->gmc.gmc_funcs->get_dcc_alignment) +@@ -516,7 +517,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, + dcc_size = roundup_pow_of_two(vres->base.size + adjust_dcc_size); + remaining_size = (u64)dcc_size; + +- vres->flags |= DRM_BUDDY_TRIM_DISABLE; ++ vres->flags |= GPU_BUDDY_TRIM_DISABLE; + } + + mutex_lock(&mgr->lock); +@@ -536,7 +537,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, + + BUG_ON(min_block_size < mm->chunk_size); + +- r = drm_buddy_alloc_blocks(mm, fpfn, ++ r = gpu_buddy_alloc_blocks(mm, fpfn, + lpfn, + size, + min_block_size, +@@ -545,7 +546,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, + + if (unlikely(r == -ENOSPC) && pages_per_block == ~0ul && + !(place->flags & TTM_PL_FLAG_CONTIGUOUS)) { +- vres->flags &= ~DRM_BUDDY_CONTIGUOUS_ALLOCATION; ++ vres->flags &= ~GPU_BUDDY_CONTIGUOUS_ALLOCATION; + pages_per_block = max_t(u32, 2UL << (20UL - PAGE_SHIFT), + tbo->page_alignment); + +@@ -566,7 +567,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, + list_add_tail(&vres->vres_node, &mgr->allocated_vres_list); + + if (bo->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS && adjust_dcc_size) { +- struct drm_buddy_block *dcc_block; ++ struct gpu_buddy_block *dcc_block; + unsigned long dcc_start; + u64 trim_start; + +@@ -576,7 +577,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, + roundup((unsigned long)amdgpu_vram_mgr_block_start(dcc_block), + adjust_dcc_size); + trim_start = (u64)dcc_start; +- drm_buddy_block_trim(mm, &trim_start, ++ gpu_buddy_block_trim(mm, &trim_start, + (u64)vres->base.size, + &vres->blocks); + } +@@ -614,7 +615,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, + return 0; + + error_free_blocks: +- drm_buddy_free_list(mm, &vres->blocks, 0); ++ gpu_buddy_free_list(mm, &vres->blocks, 0); + mutex_unlock(&mgr->lock); + error_fini: + ttm_resource_fini(man, &vres->base); +@@ -637,8 +638,8 @@ static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man, + struct amdgpu_vram_mgr_resource *vres = to_amdgpu_vram_mgr_resource(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; ++ struct gpu_buddy *mm = &mgr->mm; ++ struct gpu_buddy_block *block; + uint64_t vis_usage = 0; + + mutex_lock(&mgr->lock); +@@ -649,7 +650,7 @@ static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man, + list_for_each_entry(block, &vres->blocks, link) + vis_usage += amdgpu_vram_mgr_vis_size(adev, block); + +- drm_buddy_free_list(mm, &vres->blocks, vres->flags); ++ gpu_buddy_free_list(mm, &vres->blocks, vres->flags); + amdgpu_vram_mgr_do_reserve(man); + mutex_unlock(&mgr->lock); + +@@ -688,7 +689,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 GPU_BUDDY blocks to export */ + amdgpu_res_first(res, offset, length, &cursor); + while (cursor.remaining) { + num_entries++; +@@ -704,10 +705,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 GPU_BUDDY blocks to populate scatterlist nodes ++ * @note: Use iterator api to get first the GPU_BUDDY block + * and the number of bytes from it. Access the following +- * DRM_BUDDY block(s) if more buffer needs to exported ++ * GPU_BUDDY block(s) if more buffer needs to exported + */ + amdgpu_res_first(res, offset, length, &cursor); + for_each_sgtable_sg((*sgt), sg, i) { +@@ -792,10 +793,10 @@ uint64_t amdgpu_vram_mgr_vis_usage(struct amdgpu_vram_mgr *mgr) + void amdgpu_vram_mgr_clear_reset_blocks(struct amdgpu_device *adev) + { + struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr; +- struct drm_buddy *mm = &mgr->mm; ++ struct gpu_buddy *mm = &mgr->mm; + + mutex_lock(&mgr->lock); +- drm_buddy_reset_clear(mm, false); ++ gpu_buddy_reset_clear(mm, false); + mutex_unlock(&mgr->lock); + } + +@@ -815,7 +816,7 @@ static bool amdgpu_vram_mgr_intersects(struct ttm_resource_manager *man, + size_t size) + { + struct amdgpu_vram_mgr_resource *mgr = to_amdgpu_vram_mgr_resource(res); +- struct drm_buddy_block *block; ++ struct gpu_buddy_block *block; + + /* Check each drm buddy block individually */ + list_for_each_entry(block, &mgr->blocks, link) { +@@ -848,7 +849,7 @@ static bool amdgpu_vram_mgr_compatible(struct ttm_resource_manager *man, + size_t size) + { + struct amdgpu_vram_mgr_resource *mgr = to_amdgpu_vram_mgr_resource(res); +- struct drm_buddy_block *block; ++ struct gpu_buddy_block *block; + + /* Check each drm buddy block individually */ + list_for_each_entry(block, &mgr->blocks, link) { +@@ -877,7 +878,7 @@ 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 gpu_buddy *mm = &mgr->mm; + struct amdgpu_vram_reservation *rsv; + + drm_printf(printer, " vis usage:%llu\n", +@@ -930,7 +931,7 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev) + mgr->default_page_size = PAGE_SIZE; + + man->func = &amdgpu_vram_mgr_func; +- err = drm_buddy_init(&mgr->mm, man->size, PAGE_SIZE); ++ err = gpu_buddy_init(&mgr->mm, man->size, PAGE_SIZE); + if (err) + return err; + +@@ -965,11 +966,11 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev) + kfree(rsv); + + list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, blocks) { +- drm_buddy_free_list(&mgr->mm, &rsv->allocated, 0); ++ gpu_buddy_free_list(&mgr->mm, &rsv->allocated, 0); + kfree(rsv); + } + if (!adev->gmc.is_app_apu) +- drm_buddy_fini(&mgr->mm); ++ gpu_buddy_fini(&mgr->mm); + mutex_unlock(&mgr->lock); + + ttm_resource_manager_cleanup(man); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h +index 5f5fd9a911c268..429a21a2e9b236 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h +@@ -24,11 +24,11 @@ + #ifndef __AMDGPU_VRAM_MGR_H__ + #define __AMDGPU_VRAM_MGR_H__ + +-#include <drm/drm_buddy.h> ++#include <linux/gpu_buddy.h> + + struct amdgpu_vram_mgr { + struct ttm_resource_manager manager; +- struct drm_buddy mm; ++ struct gpu_buddy mm; + /* protects access to buffer objects */ + struct mutex lock; + struct list_head reservations_pending; +@@ -57,19 +57,19 @@ struct amdgpu_vram_mgr_resource { + struct amdgpu_vres_task task; + }; + +-static inline u64 amdgpu_vram_mgr_block_start(struct drm_buddy_block *block) ++static inline u64 amdgpu_vram_mgr_block_start(struct gpu_buddy_block *block) + { +- return drm_buddy_block_offset(block); ++ return gpu_buddy_block_offset(block); + } + +-static inline u64 amdgpu_vram_mgr_block_size(struct drm_buddy_block *block) ++static inline u64 amdgpu_vram_mgr_block_size(struct gpu_buddy_block *block) + { +- return (u64)PAGE_SIZE << drm_buddy_block_order(block); ++ return (u64)PAGE_SIZE << gpu_buddy_block_order(block); + } + +-static inline bool amdgpu_vram_mgr_is_cleared(struct drm_buddy_block *block) ++static inline bool amdgpu_vram_mgr_is_cleared(struct gpu_buddy_block *block) + { +- return drm_buddy_block_is_clear(block); ++ return gpu_buddy_block_is_clear(block); + } + + static inline struct amdgpu_vram_mgr_resource * +@@ -82,8 +82,8 @@ static inline void amdgpu_vram_mgr_set_cleared(struct ttm_resource *res) + { + struct amdgpu_vram_mgr_resource *ares = to_amdgpu_vram_mgr_resource(res); + +- WARN_ON(ares->flags & DRM_BUDDY_CLEARED); +- ares->flags |= DRM_BUDDY_CLEARED; ++ WARN_ON(ares->flags & GPU_BUDDY_CLEARED); ++ ares->flags |= GPU_BUDDY_CLEARED; + } + + int amdgpu_vram_mgr_query_address_block_info(struct amdgpu_vram_mgr *mgr, +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +index 234753a10361fd..b8cc213b347cc9 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +@@ -4022,7 +4022,7 @@ static void gfx_v10_0_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel, + WAIT_REG_MEM_ENGINE(eng_sel))); + + if (mem_space) +- BUG_ON(addr0 & 0x3); /* Dword align */ ++ WARN_ON(addr0 & 0x3); /* Dword align */ + amdgpu_ring_write(ring, addr0); + amdgpu_ring_write(ring, addr1); + amdgpu_ring_write(ring, ref); +@@ -5349,6 +5349,15 @@ static void gfx_v10_0_constants_init(struct amdgpu_device *adev) + gfx_v10_0_get_tcc_info(adev); + adev->gfx.config.pa_sc_tile_steering_override = + gfx_v10_0_init_pa_sc_tile_steering_override(adev); ++ /* Program DB_RING_CONTROL for multiple GFX pipes ++ * Default power up value is 1. ++ * Possible values: ++ * 0 - split occlusion counters between gfx pipes ++ * 1 - all occlusion counters to pipe 0 ++ * 2 - all occlusion counters to pipe 1 ++ */ ++ WREG32_FIELD15(GC, 0, DB_RING_CONTROL, COUNTER_CONTROL, ++ (adev->gfx.me.num_pipe_per_me > 1) ? 0 : 1); + + /* XXX SH_MEM regs */ + /* where to put LDS, scratch, GPUVM in FSA64 space */ +@@ -8665,7 +8674,7 @@ static void gfx_v10_0_ring_emit_ib_gfx(struct amdgpu_ring *ring, + } + + amdgpu_ring_write(ring, header); +- BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ ++ WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ + amdgpu_ring_write(ring, + #ifdef __BIG_ENDIAN + (2 << 0) | +@@ -8700,7 +8709,7 @@ static void gfx_v10_0_ring_emit_ib_compute(struct amdgpu_ring *ring, + } + + amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); +- BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ ++ WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ + amdgpu_ring_write(ring, + #ifdef __BIG_ENDIAN + (2 << 0) | +@@ -8733,9 +8742,9 @@ static void gfx_v10_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, + * aligned if only send 32bit data low (discard data high) + */ + if (write64bit) +- BUG_ON(addr & 0x7); ++ WARN_ON(addr & 0x7); + else +- BUG_ON(addr & 0x3); ++ WARN_ON(addr & 0x3); + amdgpu_ring_write(ring, lower_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + amdgpu_ring_write(ring, lower_32_bits(seq)); +@@ -8783,9 +8792,6 @@ static void gfx_v10_0_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr, + { + struct amdgpu_device *adev = ring->adev; + +- /* we only allocate 32bit for each seq wb address */ +- BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT); +- + /* write fence seq to the "addr" */ + amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); + amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +index cf23b5da6dbbb1..f428b652db3384 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +@@ -537,7 +537,7 @@ static void gfx_v11_0_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel, + WAIT_REG_MEM_ENGINE(eng_sel))); + + if (mem_space) +- BUG_ON(addr0 & 0x3); /* Dword align */ ++ WARN_ON(addr0 & 0x3); /* Dword align */ + amdgpu_ring_write(ring, addr0); + amdgpu_ring_write(ring, addr1); + amdgpu_ring_write(ring, ref); +@@ -5901,7 +5901,7 @@ static void gfx_v11_0_ring_emit_ib_gfx(struct amdgpu_ring *ring, + } + + amdgpu_ring_write(ring, header); +- BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ ++ WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ + amdgpu_ring_write(ring, + #ifdef __BIG_ENDIAN + (2 << 0) | +@@ -5936,7 +5936,7 @@ static void gfx_v11_0_ring_emit_ib_compute(struct amdgpu_ring *ring, + } + + amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); +- BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ ++ WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ + amdgpu_ring_write(ring, + #ifdef __BIG_ENDIAN + (2 << 0) | +@@ -5969,9 +5969,9 @@ static void gfx_v11_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, + * aligned if only send 32bit data low (discard data high) + */ + if (write64bit) +- BUG_ON(addr & 0x7); ++ WARN_ON(addr & 0x7); + else +- BUG_ON(addr & 0x3); ++ WARN_ON(addr & 0x3); + amdgpu_ring_write(ring, lower_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + amdgpu_ring_write(ring, lower_32_bits(seq)); +@@ -6025,9 +6025,6 @@ static void gfx_v11_0_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr, + { + struct amdgpu_device *adev = ring->adev; + +- /* we only allocate 32bit for each seq wb address */ +- BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT); +- + /* write fence seq to the "addr" */ + amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); + amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +index 50e39b9d9df6f8..b91e8127687788 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +@@ -439,7 +439,7 @@ static void gfx_v12_0_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel, + WAIT_REG_MEM_ENGINE(eng_sel))); + + if (mem_space) +- BUG_ON(addr0 & 0x3); /* Dword align */ ++ WARN_ON(addr0 & 0x3); /* Dword align */ + amdgpu_ring_write(ring, addr0); + amdgpu_ring_write(ring, addr1); + amdgpu_ring_write(ring, ref); +@@ -4424,7 +4424,7 @@ static void gfx_v12_0_ring_emit_ib_gfx(struct amdgpu_ring *ring, + control |= ib->length_dw | (vmid << 24); + + amdgpu_ring_write(ring, header); +- BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ ++ WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ + amdgpu_ring_write(ring, + #ifdef __BIG_ENDIAN + (2 << 0) | +@@ -4443,7 +4443,7 @@ static void gfx_v12_0_ring_emit_ib_compute(struct amdgpu_ring *ring, + u32 control = INDIRECT_BUFFER_VALID | ib->length_dw | (vmid << 24); + + amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); +- BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ ++ WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ + amdgpu_ring_write(ring, + #ifdef __BIG_ENDIAN + (2 << 0) | +@@ -4474,9 +4474,9 @@ static void gfx_v12_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, + * aligned if only send 32bit data low (discard data high) + */ + if (write64bit) +- BUG_ON(addr & 0x7); ++ WARN_ON(addr & 0x7); + else +- BUG_ON(addr & 0x3); ++ WARN_ON(addr & 0x3); + amdgpu_ring_write(ring, lower_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + amdgpu_ring_write(ring, lower_32_bits(seq)); +@@ -4524,9 +4524,6 @@ static void gfx_v12_0_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr, + { + struct amdgpu_device *adev = ring->adev; + +- /* we only allocate 32bit for each seq wb address */ +- BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT); +- + /* write fence seq to the "addr" */ + amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); + amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +index 8a81713d97aac2..690128ad3094a3 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +@@ -6226,9 +6226,6 @@ static void gfx_v8_0_ring_emit_fence_compute(struct amdgpu_ring *ring, + static void gfx_v8_0_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr, + u64 seq, unsigned int flags) + { +- /* we only allocate 32bit for each seq wb address */ +- BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT); +- + /* write fence seq to the "addr" */ + amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); + amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +index f589457f601875..c5549a5abcd438 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +@@ -1183,7 +1183,7 @@ static void gfx_v9_0_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel, + WAIT_REG_MEM_ENGINE(eng_sel))); + + if (mem_space) +- BUG_ON(addr0 & 0x3); /* Dword align */ ++ WARN_ON(addr0 & 0x3); /* Dword align */ + amdgpu_ring_write(ring, addr0); + amdgpu_ring_write(ring, addr1); + amdgpu_ring_write(ring, ref); +@@ -4045,6 +4045,41 @@ static int gfx_v9_0_hw_init(struct amdgpu_ip_block *ip_block) + return r; + } + ++static void gfx_v9_0_deactivate_kcq_hqd(struct amdgpu_device *adev) ++{ ++ amdgpu_gfx_rlc_enter_safe_mode(adev, 0); ++ for (int i = 0; i < adev->gfx.num_compute_rings; i++) { ++ u32 tmp; ++ struct amdgpu_ring *ring = &adev->gfx.compute_ring[i]; ++ ++ mutex_lock(&adev->srbm_mutex); ++ soc15_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0, 0); ++ tmp = RREG32_SOC15(GC, 0, mmCP_HQD_ACTIVE); ++ /* disable the queue if it's active */ ++ if (tmp & CP_HQD_ACTIVE__ACTIVE_MASK) { ++ int j; ++ ++ WREG32_SOC15(GC, 0, mmCP_HQD_DEQUEUE_REQUEST, 1); ++ for (j = 0; j < adev->usec_timeout; j++) { ++ tmp = RREG32_SOC15(GC, 0, mmCP_HQD_ACTIVE); ++ if (!(tmp & CP_HQD_ACTIVE__ACTIVE_MASK)) ++ break; ++ udelay(1); ++ } ++ if (j == AMDGPU_MAX_USEC_TIMEOUT) { ++ DRM_DEBUG("comp_%u_%u_%u dequeue request failed.\n", ++ ring->me, ring->pipe, ring->queue); ++ /* Manual disable if dequeue request times out */ ++ WREG32_SOC15(GC, 0, mmCP_HQD_ACTIVE, 0); ++ } ++ WREG32_SOC15(GC, 0, mmCP_HQD_DEQUEUE_REQUEST, 0); ++ } ++ soc15_grbm_select(adev, 0, 0, 0, 0, 0); ++ mutex_unlock(&adev->srbm_mutex); ++ } ++ amdgpu_gfx_rlc_exit_safe_mode(adev, 0); ++} ++ + static int gfx_v9_0_hw_fini(struct amdgpu_ip_block *ip_block) + { + struct amdgpu_device *adev = ip_block->adev; +@@ -4071,6 +4106,10 @@ static int gfx_v9_0_hw_fini(struct amdgpu_ip_block *ip_block) + return 0; + } + ++ if ((adev->flags & AMD_IS_APU) && amdgpu_in_reset(adev) && ++ amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_MODE2) ++ gfx_v9_0_deactivate_kcq_hqd(adev); ++ + /* Use deinitialize sequence from CAIL when unbinding device from driver, + * otherwise KIQ is hanging when binding back + */ +@@ -5434,7 +5473,7 @@ static void gfx_v9_0_ring_emit_ib_gfx(struct amdgpu_ring *ring, + } + + amdgpu_ring_write(ring, header); +- BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ ++ WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ + amdgpu_ring_write(ring, + #ifdef __BIG_ENDIAN + (2 << 0) | +@@ -5530,7 +5569,7 @@ static void gfx_v9_0_ring_emit_ib_compute(struct amdgpu_ring *ring, + } + + amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); +- BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ ++ WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ + amdgpu_ring_write(ring, + #ifdef __BIG_ENDIAN + (2 << 0) | +@@ -5571,9 +5610,9 @@ static void gfx_v9_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, + * aligned if only send 32bit data low (discard data high) + */ + if (write64bit) +- BUG_ON(addr & 0x7); ++ WARN_ON(addr & 0x7); + else +- BUG_ON(addr & 0x3); ++ WARN_ON(addr & 0x3); + amdgpu_ring_write(ring, lower_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + amdgpu_ring_write(ring, lower_32_bits(seq)); +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +index a4ebb6c5af5574..314916bd2368ff 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +@@ -405,7 +405,7 @@ static void gfx_v9_4_3_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel, + WAIT_REG_MEM_ENGINE(eng_sel))); + + if (mem_space) +- BUG_ON(addr0 & 0x3); /* Dword align */ ++ WARN_ON(addr0 & 0x3); /* Dword align */ + amdgpu_ring_write(ring, addr0); + amdgpu_ring_write(ring, addr1); + amdgpu_ring_write(ring, ref); +@@ -2871,7 +2871,7 @@ static void gfx_v9_4_3_ring_emit_ib_compute(struct amdgpu_ring *ring, + } + + amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); +- BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ ++ WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ + amdgpu_ring_write(ring, + #ifdef __BIG_ENDIAN + (2 << 0) | +@@ -2905,9 +2905,9 @@ static void gfx_v9_4_3_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, + * aligned if only send 32bit data low (discard data high) + */ + if (write64bit) +- BUG_ON(addr & 0x7); ++ WARN_ON(addr & 0x7); + else +- BUG_ON(addr & 0x3); ++ WARN_ON(addr & 0x3); + amdgpu_ring_write(ring, lower_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + amdgpu_ring_write(ring, lower_32_bits(seq)); +@@ -2967,9 +2967,6 @@ static void gfx_v9_4_3_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr, + { + struct amdgpu_device *adev = ring->adev; + +- /* we only allocate 32bit for each seq wb address */ +- BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT); +- + /* write fence seq to the "addr" */ + amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); + amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +index 99e6dabc36ee8b..4521465506682a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +@@ -1010,7 +1010,7 @@ void jpeg_v4_0_3_dec_ring_nop(struct amdgpu_ring *ring, uint32_t count) + static bool jpeg_v4_0_3_is_idle(struct amdgpu_ip_block *ip_block) + { + struct amdgpu_device *adev = ip_block->adev; +- bool ret = false; ++ bool ret = true; + int i, j; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { +diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c +index 1fb2386352ccb2..de9ca229479e82 100644 +--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c ++++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c +@@ -657,7 +657,7 @@ static void jpeg_v5_0_1_dec_ring_set_wptr(struct amdgpu_ring *ring) + static bool jpeg_v5_0_1_is_idle(struct amdgpu_ip_block *ip_block) + { + struct amdgpu_device *adev = ip_block->adev; +- bool ret = false; ++ bool ret = true; + int i, j; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +index a1443990d5c60d..c8b4fda590168b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +@@ -458,7 +458,7 @@ static void sdma_v4_4_2_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 + /* write the fence */ + amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE)); + /* zero in first two bits */ +- BUG_ON(addr & 0x3); ++ WARN_ON(addr & 0x3); + amdgpu_ring_write(ring, lower_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + amdgpu_ring_write(ring, lower_32_bits(seq)); +@@ -468,7 +468,7 @@ static void sdma_v4_4_2_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 + addr += 4; + amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE)); + /* zero in first two bits */ +- BUG_ON(addr & 0x3); ++ WARN_ON(addr & 0x3); + amdgpu_ring_write(ring, lower_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(seq)); +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c +index 45e2933214a802..e1d9cea98a2d6f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c +@@ -528,7 +528,7 @@ static void sdma_v5_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se + amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE) | + SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); /* Ucached(UC) */ + /* zero in first two bits */ +- BUG_ON(addr & 0x3); ++ WARN_ON(addr & 0x3); + amdgpu_ring_write(ring, lower_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + amdgpu_ring_write(ring, lower_32_bits(seq)); +@@ -539,7 +539,7 @@ static void sdma_v5_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se + amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE) | + SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); + /* zero in first two bits */ +- BUG_ON(addr & 0x3); ++ WARN_ON(addr & 0x3); + amdgpu_ring_write(ring, lower_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(seq)); +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +index 5b982cc91af391..48c672c1b74d18 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +@@ -378,7 +378,7 @@ static void sdma_v5_2_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se + amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE) | + SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); /* Ucached(UC) */ + /* zero in first two bits */ +- BUG_ON(addr & 0x3); ++ WARN_ON(addr & 0x3); + amdgpu_ring_write(ring, lower_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + amdgpu_ring_write(ring, lower_32_bits(seq)); +@@ -389,7 +389,7 @@ static void sdma_v5_2_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se + amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE) | + SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); + /* zero in first two bits */ +- BUG_ON(addr & 0x3); ++ WARN_ON(addr & 0x3); + amdgpu_ring_write(ring, lower_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(seq)); +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +index 6809c6d4be5b1b..ef411bd02237ff 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +@@ -360,7 +360,7 @@ static void sdma_v6_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se + amdgpu_ring_write(ring, SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_FENCE) | + SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); /* Ucached(UC) */ + /* zero in first two bits */ +- BUG_ON(addr & 0x3); ++ WARN_ON(addr & 0x3); + amdgpu_ring_write(ring, lower_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + amdgpu_ring_write(ring, lower_32_bits(seq)); +@@ -371,7 +371,7 @@ static void sdma_v6_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se + amdgpu_ring_write(ring, SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_FENCE) | + SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); + /* zero in first two bits */ +- BUG_ON(addr & 0x3); ++ WARN_ON(addr & 0x3); + amdgpu_ring_write(ring, lower_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(seq)); +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c +index 2b81344dcd668a..d1318fb8060f9b 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c +@@ -364,7 +364,7 @@ static void sdma_v7_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se + amdgpu_ring_write(ring, SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_FENCE) | + SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); /* Ucached(UC) */ + /* zero in first two bits */ +- BUG_ON(addr & 0x3); ++ WARN_ON(addr & 0x3); + amdgpu_ring_write(ring, lower_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + amdgpu_ring_write(ring, lower_32_bits(seq)); +@@ -375,7 +375,7 @@ static void sdma_v7_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se + amdgpu_ring_write(ring, SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_FENCE) | + SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); + /* zero in first two bits */ +- BUG_ON(addr & 0x3); ++ WARN_ON(addr & 0x3); + amdgpu_ring_write(ring, lower_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(addr)); + amdgpu_ring_write(ring, upper_32_bits(seq)); +diff --git a/drivers/gpu/drm/amd/amdgpu/soc24.c b/drivers/gpu/drm/amd/amdgpu/soc24.c +index 972b449ab89faa..999d9da6756dbd 100644 +--- a/drivers/gpu/drm/amd/amdgpu/soc24.c ++++ b/drivers/gpu/drm/amd/amdgpu/soc24.c +@@ -526,8 +526,36 @@ static int soc24_common_suspend(struct amdgpu_ip_block *ip_block) + return soc24_common_hw_fini(ip_block); + } + ++static bool soc24_need_reset_on_resume(struct amdgpu_device *adev) ++{ ++ u32 sol_reg1, sol_reg2; ++ ++ /* Will reset for the following suspend abort cases. ++ * 1) Only reset dGPU side. ++ * 2) S3 suspend got aborted and TOS is active. ++ * As for dGPU suspend abort cases the SOL value ++ * will be kept as zero at this resume point. ++ */ ++ if (!(adev->flags & AMD_IS_APU) && adev->in_s3) { ++ sol_reg1 = RREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_81); ++ msleep(100); ++ sol_reg2 = RREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_81); ++ ++ return (sol_reg1 != sol_reg2); ++ } ++ ++ return false; ++} ++ + static int soc24_common_resume(struct amdgpu_ip_block *ip_block) + { ++ struct amdgpu_device *adev = ip_block->adev; ++ ++ if (soc24_need_reset_on_resume(adev)) { ++ dev_info(adev->dev, "S3 suspend aborted, resetting..."); ++ soc24_asic_reset(adev); ++ } ++ + return soc24_common_hw_init(ip_block); + } + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +index 21e40eb2078d17..ad74edc1bbfc33 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +@@ -1926,14 +1926,17 @@ out: + #define RENCODE_IB_PARAM_SESSION_INIT 0x00000003 + + /* return the offset in ib if id is found, -1 otherwise */ +-static int vcn_v4_0_enc_find_ib_param(struct amdgpu_ib *ib, uint32_t id, int start) ++static int vcn_v4_0_enc_find_ib_param(struct amdgpu_ib *ib, uint32_t id, int start, uint32_t *length) + { + int i; + uint32_t len; + + for (i = start; (len = amdgpu_ib_get_value(ib, i)) >= 8; i += len / 4) { +- if (amdgpu_ib_get_value(ib, i + 1) == id) ++ if (amdgpu_ib_get_value(ib, i + 1) == id) { ++ if (length) ++ *length = len; + return i; ++ } + } + return -1; + } +@@ -1943,14 +1946,14 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, + struct amdgpu_ib *ib) + { + struct amdgpu_ring *ring = amdgpu_job_ring(job); +- uint32_t val; ++ uint32_t val, len; + int idx = 0, sidx; + + /* The first instance can decode anything */ + if (!ring->me) + return 0; + +- while ((idx = vcn_v4_0_enc_find_ib_param(ib, RADEON_VCN_ENGINE_INFO, idx)) >= 0) { ++ while ((idx = vcn_v4_0_enc_find_ib_param(ib, RADEON_VCN_ENGINE_INFO, idx, &len)) >= 0) { + val = amdgpu_ib_get_value(ib, idx + 2); /* RADEON_VCN_ENGINE_TYPE */ + if (val == RADEON_VCN_ENGINE_TYPE_DECODE) { + uint32_t valid_buf_flag = amdgpu_ib_get_value(ib, idx + 6); +@@ -1963,12 +1966,12 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, + amdgpu_ib_get_value(ib, idx + 8); + return vcn_v4_0_dec_msg(p, job, msg_buffer_addr); + } else if (val == RADEON_VCN_ENGINE_TYPE_ENCODE) { +- sidx = vcn_v4_0_enc_find_ib_param(ib, RENCODE_IB_PARAM_SESSION_INIT, idx); ++ sidx = vcn_v4_0_enc_find_ib_param(ib, RENCODE_IB_PARAM_SESSION_INIT, idx, NULL); + if (sidx >= 0 && + amdgpu_ib_get_value(ib, sidx + 2) == RENCODE_ENCODE_STANDARD_AV1) + return vcn_v4_0_limit_sched(p, job); + } +- idx += amdgpu_ib_get_value(ib, idx) / 4; ++ idx += len / 4; + } + return 0; + } +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +index c2100fd78b522b..c4fd83ae17620e 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +@@ -1790,13 +1790,13 @@ static int criu_checkpoint_devices(struct kfd_process *p, + struct kfd_criu_device_bucket *device_buckets = NULL; + int ret = 0, i; + +- device_buckets = kvzalloc(num_devices * sizeof(*device_buckets), GFP_KERNEL); ++ device_buckets = kvcalloc(num_devices, sizeof(*device_buckets), GFP_KERNEL); + if (!device_buckets) { + ret = -ENOMEM; + goto exit; + } + +- device_priv = kvzalloc(num_devices * sizeof(*device_priv), GFP_KERNEL); ++ device_priv = kvcalloc(num_devices, sizeof(*device_priv), GFP_KERNEL); + if (!device_priv) { + ret = -ENOMEM; + goto exit; +@@ -1916,17 +1916,17 @@ static int criu_checkpoint_bos(struct kfd_process *p, + int ret = 0, pdd_index, bo_index = 0, id; + void *mem; + +- bo_buckets = kvzalloc(num_bos * sizeof(*bo_buckets), GFP_KERNEL); ++ bo_buckets = kvcalloc(num_bos, sizeof(*bo_buckets), GFP_KERNEL); + if (!bo_buckets) + return -ENOMEM; + +- bo_privs = kvzalloc(num_bos * sizeof(*bo_privs), GFP_KERNEL); ++ bo_privs = kvcalloc(num_bos, sizeof(*bo_privs), GFP_KERNEL); + if (!bo_privs) { + ret = -ENOMEM; + goto exit; + } + +- files = kvzalloc(num_bos * sizeof(struct file *), GFP_KERNEL); ++ files = kvcalloc(num_bos, sizeof(struct file *), GFP_KERNEL); + if (!files) { + ret = -ENOMEM; + goto exit; +@@ -2463,7 +2463,7 @@ static int criu_restore_bos(struct kfd_process *p, + if (!bo_buckets) + return -ENOMEM; + +- files = kvzalloc(args->num_bos * sizeof(struct file *), GFP_KERNEL); ++ files = kvcalloc(args->num_bos, sizeof(struct file *), GFP_KERNEL); + if (!files) { + ret = -ENOMEM; + goto exit; +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +index 18d03f33c62027..c650ffc3e66e86 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +@@ -3628,6 +3628,12 @@ out: + dqm_unlock(dqm); + return r; + } ++ ++size_t mqd_size_from_queue_type(struct device_queue_manager *dqm, enum kfd_queue_type type) ++{ ++ return dqm->mqd_mgrs[get_mqd_type_from_queue_type(type)]->mqd_size; ++} ++ + #if defined(CONFIG_DEBUG_FS) + + static void seq_reg_dump(struct seq_file *m, +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +index 74a61b5b2f0b4f..46c6849df13f42 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +@@ -327,6 +327,8 @@ int debug_refresh_runlist(struct device_queue_manager *dqm); + bool kfd_dqm_is_queue_in_process(struct device_queue_manager *dqm, + struct qcm_process_device *qpd, + int doorbell_off, u32 *queue_format); ++size_t mqd_size_from_queue_type(struct device_queue_manager *dqm, ++ enum kfd_queue_type type); + + static inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd) + { +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c +index 63039035b19412..2fdee34ae54326 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c +@@ -107,6 +107,9 @@ static int allocate_event_notification_slot(struct kfd_process *p, + } + + if (restore_id) { ++ if (*restore_id >= KFD_SIGNAL_EVENT_LIMIT) ++ return -EINVAL; ++ + id = idr_alloc(&p->event_idr, ev, *restore_id, *restore_id + 1, + GFP_KERNEL); + } else { +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +index 24e85440473a1a..d7e91504024285 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +@@ -436,7 +436,8 @@ enum kfd_queue_type { + KFD_QUEUE_TYPE_HIQ, + KFD_QUEUE_TYPE_DIQ, + KFD_QUEUE_TYPE_SDMA_XGMI, +- KFD_QUEUE_TYPE_SDMA_BY_ENG_ID ++ KFD_QUEUE_TYPE_SDMA_BY_ENG_ID, ++ KFD_QUEUE_TYPE_MAX, + }; + + enum kfd_queue_format { +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +index 7bf712032c52c0..0bfe64cdabe6ae 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +@@ -1015,6 +1015,23 @@ int kfd_criu_restore_queue(struct kfd_process *p, + goto exit; + } + ++ pdd = kfd_process_device_data_by_id(p, q_data->gpu_id); ++ if (!pdd) { ++ pr_err("Failed to get pdd\n"); ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (q_data->type >= KFD_QUEUE_TYPE_MAX) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (q_data->mqd_size != mqd_size_from_queue_type(pdd->dev->dqm, q_data->type)) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ + *priv_data_offset += sizeof(*q_data); + q_extra_data_size = (uint64_t)q_data->ctl_stack_size + q_data->mqd_size; + +@@ -1037,13 +1054,6 @@ int kfd_criu_restore_queue(struct kfd_process *p, + + *priv_data_offset += q_extra_data_size; + +- pdd = kfd_process_device_data_by_id(p, q_data->gpu_id); +- if (!pdd) { +- pr_err("Failed to get pdd\n"); +- ret = -EINVAL; +- goto exit; +- } +- + /* + * data stored in this order: + * mqd[xcc0], mqd[xcc1],..., ctl_stack[xcc0], ctl_stack[xcc1]... +diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c +index b97f4a51db6e37..8e74e2bae59025 100644 +--- a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c ++++ b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c +@@ -23,6 +23,7 @@ + */ + + #include <linux/slab.h> ++#include <linux/overflow.h> + #include "kfd_priv.h" + #include "kfd_topology.h" + #include "kfd_svm.h" +@@ -235,7 +236,7 @@ int kfd_queue_acquire_buffers(struct kfd_process_device *pdd, struct queue_prope + struct kfd_topology_device *topo_dev; + u64 expected_queue_size; + struct amdgpu_vm *vm; +- u32 total_cwsr_size; ++ u64 total_cwsr_size; + int err; + + topo_dev = kfd_topology_device_by_id(pdd->dev->id); +@@ -305,8 +306,14 @@ int kfd_queue_acquire_buffers(struct kfd_process_device *pdd, struct queue_prope + goto out_err_unreserve; + } + +- total_cwsr_size = (properties->ctx_save_restore_area_size + +- topo_dev->node_props.debug_memory_size) * NUM_XCC(pdd->dev->xcc_mask); ++ total_cwsr_size = (u64)properties->ctx_save_restore_area_size + ++ topo_dev->node_props.debug_memory_size; ++ if (check_mul_overflow(total_cwsr_size, ++ NUM_XCC(pdd->dev->xcc_mask), ++ &total_cwsr_size)) { ++ err = -EINVAL; ++ goto out_err_unreserve; ++ } + total_cwsr_size = ALIGN(total_cwsr_size, PAGE_SIZE); + + err = kfd_queue_buffer_get(vm, (void *)properties->ctx_save_restore_area_address, +@@ -341,7 +348,7 @@ out_err_release: + int kfd_queue_release_buffers(struct kfd_process_device *pdd, struct queue_properties *properties) + { + struct kfd_topology_device *topo_dev; +- u32 total_cwsr_size; ++ u64 total_cwsr_size; + + kfd_queue_buffer_put(&properties->wptr_bo); + kfd_queue_buffer_put(&properties->rptr_bo); +@@ -352,8 +359,12 @@ int kfd_queue_release_buffers(struct kfd_process_device *pdd, struct queue_prope + topo_dev = kfd_topology_device_by_id(pdd->dev->id); + if (!topo_dev) + return -EINVAL; +- total_cwsr_size = (properties->ctx_save_restore_area_size + +- topo_dev->node_props.debug_memory_size) * NUM_XCC(pdd->dev->xcc_mask); ++ total_cwsr_size = (u64)properties->ctx_save_restore_area_size + ++ topo_dev->node_props.debug_memory_size; ++ if (check_mul_overflow(total_cwsr_size, ++ NUM_XCC(pdd->dev->xcc_mask), ++ &total_cwsr_size)) ++ return -EINVAL; + total_cwsr_size = ALIGN(total_cwsr_size, PAGE_SIZE); + + kfd_queue_buffer_svm_put(pdd, properties->ctx_save_restore_area_address, total_cwsr_size); +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index a2ca1de6b43cfc..99759559cc0f6c 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -575,89 +575,25 @@ static void schedule_dc_vmin_vmax(struct amdgpu_device *adev, + queue_work(system_wq, &offload_work->work); + } + +-static void dm_vupdate_high_irq(void *interrupt_params) +-{ +- struct common_irq_params *irq_params = interrupt_params; +- struct amdgpu_device *adev = irq_params->adev; +- struct amdgpu_crtc *acrtc; +- struct drm_device *drm_dev; +- struct drm_vblank_crtc *vblank; +- ktime_t frame_duration_ns, previous_timestamp; +- unsigned long flags; +- int vrr_active; +- +- acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VUPDATE); +- +- if (acrtc) { +- vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc); +- drm_dev = acrtc->base.dev; +- vblank = drm_crtc_vblank_crtc(&acrtc->base); +- previous_timestamp = atomic64_read(&irq_params->previous_timestamp); +- frame_duration_ns = vblank->time - previous_timestamp; +- +- if (frame_duration_ns > 0) { +- trace_amdgpu_refresh_rate_track(acrtc->base.index, +- frame_duration_ns, +- ktime_divns(NSEC_PER_SEC, frame_duration_ns)); +- atomic64_set(&irq_params->previous_timestamp, vblank->time); +- } +- +- drm_dbg_vbl(drm_dev, +- "crtc:%d, vupdate-vrr:%d\n", acrtc->crtc_id, +- vrr_active); +- +- /* Core vblank handling is done here after end of front-porch in +- * vrr mode, as vblank timestamping will give valid results +- * while now done after front-porch. This will also deliver +- * page-flip completion events that have been queued to us +- * if a pageflip happened inside front-porch. +- */ +- if (vrr_active && acrtc->dm_irq_params.stream) { +- bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled; +- bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled; +- bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state +- == VRR_STATE_ACTIVE_VARIABLE; +- +- amdgpu_dm_crtc_handle_vblank(acrtc); +- +- /* BTR processing for pre-DCE12 ASICs */ +- if (adev->family < AMDGPU_FAMILY_AI) { +- spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); +- mod_freesync_handle_v_update( +- adev->dm.freesync_module, +- acrtc->dm_irq_params.stream, +- &acrtc->dm_irq_params.vrr_params); +- +- if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) { +- schedule_dc_vmin_vmax(adev, +- acrtc->dm_irq_params.stream, +- &acrtc->dm_irq_params.vrr_params.adjust); +- } +- spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); +- } +- } +- } +-} +- + /** +- * dm_crtc_high_irq() - Handles CRTC interrupt +- * @interrupt_params: used for determining the CRTC instance ++ * dm_crtc_high_irq_handler() - Common OTG vblank/flip event handling ++ * @adev: amdgpu device ++ * @acrtc: the CRTC to service + * +- * Handles the CRTC/VSYNC interrupt by notfying DRM's VBLANK +- * event handler. ++ * Performs writeback completion, vblank event handling, CRC processing, VRR BTR ++ * updates and pageflip completion delivery. ++ * ++ * On DCN this is driven by VUPDATE_NO_LOCK (the register latch point) from ++ * dm_vupdate_high_irq(); on DCE it is driven by VLINE0 at the start of vblank ++ * from dm_crtc_high_irq(). + */ +-static void dm_crtc_high_irq(void *interrupt_params) ++static void dm_crtc_high_irq_handler(struct amdgpu_device *adev, ++ struct amdgpu_crtc *acrtc) + { +- struct common_irq_params *irq_params = interrupt_params; +- struct amdgpu_device *adev = irq_params->adev; + struct drm_writeback_job *job; +- struct amdgpu_crtc *acrtc; + unsigned long flags; + int vrr_active; +- +- acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK); +- if (!acrtc) +- return; ++ bool is_dcn = amdgpu_ip_version(adev, DCE_HWIP, 0) != 0; + + if (acrtc->wb_conn) { + spin_lock_irqsave(&acrtc->wb_conn->job_lock, flags); +@@ -694,12 +630,17 @@ static void dm_crtc_high_irq(void *interrupt_params) + vrr_active, acrtc->dm_irq_params.active_planes); + + /** +- * Core vblank handling at start of front-porch is only possible +- * in non-vrr mode, as only there vblank timestamping will give +- * valid results while done in front-porch. Otherwise defer it +- * to dm_vupdate_high_irq after end of front-porch. ++ * Core vblank handling. ++ * ++ * On DCN this handler runs at VUPDATE_NO_LOCK, the register latch ++ * point, which is the correct place to timestamp both VRR and non-VRR ++ * vblanks. ++ * ++ * On DCE this handler runs at the start of front-porch, where only ++ * non-VRR timestamping is valid; VRR vblank is deferred to ++ * dm_vupdate_high_irq() after end of front-porch. + */ +- if (!vrr_active) ++ if (is_dcn || !vrr_active) + amdgpu_dm_crtc_handle_vblank(acrtc); + + /** +@@ -732,18 +673,16 @@ static void dm_crtc_high_irq(void *interrupt_params) + } + + /* +- * If there aren't any active_planes then DCH HUBP may be clock-gated. +- * In that case, pageflip completion interrupts won't fire and pageflip +- * completion events won't get delivered. Prevent this by sending +- * pending pageflip events from here if a flip is still pending. ++ * Deliver pageflip completion events (DCN only). + * +- * If any planes are enabled, use dm_pflip_high_irq() instead, to +- * avoid race conditions between flip programming and completion, +- * which could cause too early flip completion events. ++ * Since GRPH_PFLIP is not used, VUPDATE_NO_LOCK is the flip latch ++ * point. Deliver any pending pageflip completion event from here. ++ * ++ * NOTE: This can deliver an event for a flip that was armed but not yet ++ * programmed into HW; that race is closed in a follow-up change by ++ * checking the programmed flip status. + */ +- if (adev->family >= AMDGPU_FAMILY_RV && +- acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED && +- acrtc->dm_irq_params.active_planes == 0) { ++ if (is_dcn && acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED) { + if (acrtc->event) { + drm_crtc_send_vblank_event(&acrtc->base, acrtc->event); + acrtc->event = NULL; +@@ -755,6 +694,104 @@ static void dm_crtc_high_irq(void *interrupt_params) + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); + } + ++static void dm_vupdate_high_irq(void *interrupt_params) ++{ ++ struct common_irq_params *irq_params = interrupt_params; ++ struct amdgpu_device *adev = irq_params->adev; ++ struct amdgpu_crtc *acrtc; ++ struct drm_device *drm_dev; ++ struct drm_vblank_crtc *vblank; ++ ktime_t frame_duration_ns, previous_timestamp; ++ unsigned long flags; ++ int vrr_active; ++ ++ acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VUPDATE); ++ if (!acrtc) ++ return; ++ ++ vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc); ++ drm_dev = acrtc->base.dev; ++ vblank = drm_crtc_vblank_crtc(&acrtc->base); ++ previous_timestamp = atomic64_read(&irq_params->previous_timestamp); ++ frame_duration_ns = vblank->time - previous_timestamp; ++ ++ if (frame_duration_ns > 0) { ++ trace_amdgpu_refresh_rate_track(acrtc->base.index, ++ frame_duration_ns, ++ ktime_divns(NSEC_PER_SEC, frame_duration_ns)); ++ atomic64_set(&irq_params->previous_timestamp, vblank->time); ++ } ++ ++ drm_dbg_vbl(drm_dev, ++ "crtc:%d, vupdate-vrr:%d\n", acrtc->crtc_id, ++ vrr_active); ++ ++ /* ++ * On DCN, VUPDATE_NO_LOCK is the single OTG interrupt used to deliver ++ * vblank and pageflip completion events; VSTARTUP and GRPH_PFLIP are ++ * not used. Run the full handler here. ++ */ ++ if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0) { ++ dm_crtc_high_irq_handler(adev, acrtc); ++ return; ++ } ++ ++ /* DCE only below. */ ++ ++ /* Core vblank handling is done here after end of front-porch in ++ * vrr mode, as vblank timestamping will give valid results ++ * while now done after front-porch. This will also deliver ++ * page-flip completion events that have been queued to us ++ * if a pageflip happened inside front-porch. ++ */ ++ if (vrr_active && acrtc->dm_irq_params.stream) { ++ bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled; ++ bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled; ++ bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state ++ == VRR_STATE_ACTIVE_VARIABLE; ++ ++ amdgpu_dm_crtc_handle_vblank(acrtc); ++ ++ /* BTR processing for pre-DCE12 ASICs */ ++ if (adev->family < AMDGPU_FAMILY_AI) { ++ spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); ++ mod_freesync_handle_v_update( ++ adev->dm.freesync_module, ++ acrtc->dm_irq_params.stream, ++ &acrtc->dm_irq_params.vrr_params); ++ ++ if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) { ++ schedule_dc_vmin_vmax(adev, ++ acrtc->dm_irq_params.stream, ++ &acrtc->dm_irq_params.vrr_params.adjust); ++ } ++ spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); ++ } ++ } ++} ++ ++/** ++ * dm_crtc_high_irq() - Handles CRTC interrupt ++ * @interrupt_params: used for determining the CRTC instance ++ * ++ * Handles the CRTC/VSYNC interrupt by notifying DRM's VBLANK event handler. ++ * ++ * Used on DCE (VLINE0, set to vblank start). On DCN the equivalent handling is ++ * driven by VUPDATE_NO_LOCK in dm_vupdate_high_irq(). ++ */ ++static void dm_crtc_high_irq(void *interrupt_params) ++{ ++ struct common_irq_params *irq_params = interrupt_params; ++ struct amdgpu_device *adev = irq_params->adev; ++ struct amdgpu_crtc *acrtc; ++ ++ acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK); ++ if (!acrtc) ++ return; ++ ++ dm_crtc_high_irq_handler(adev, acrtc); ++} ++ + #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) + /** + * dm_dcn_vertical_interrupt0_high_irq() - Handles OTG Vertical interrupt0 for +@@ -3031,7 +3068,8 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev, + acrtc = get_crtc_by_otg_inst( + adev, state->stream_status[i].primary_otg_inst); + +- if (acrtc && state->stream_status[i].plane_count != 0) { ++ if (acrtc && state->stream_status[i].plane_count != 0 && ++ amdgpu_ip_version(adev, DCE_HWIP, 0) == 0) { + irq_source = IRQ_TYPE_PFLIP + acrtc->otg_inst; + rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY; + if (rc) +@@ -3059,6 +3097,13 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev, + */ + if (!dc_interrupt_set(adev->dm.dc, irq_source, enable)) + drm_warn(adev_to_drm(adev), "Failed to %sable vblank interrupt\n", enable ? "en" : "dis"); ++ ++ } else if (acrtc && state->stream_status[i].plane_count != 0) { ++ /* DCN only needs to toggle VUPDATE_NO_LOCK */ ++ rc = amdgpu_dm_crtc_set_vupdate_irq(&acrtc->base, enable); ++ if (rc) ++ drm_warn(adev_to_drm(adev), "Failed to %sable vupdate interrupt\n", ++ enable ? "en" : "dis"); + } + } + +@@ -3680,6 +3725,8 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector) + caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps; + caps->aux_support = false; + ++ panel_backlight_quirk = drm_get_panel_backlight_quirk(aconnector->drm_edid); ++ + if (caps->ext_caps->bits.oled == 1 + /* + * || +@@ -3692,6 +3739,9 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector) + caps->aux_support = false; + else if (amdgpu_backlight == 1) + caps->aux_support = true; ++ else if (!IS_ERR_OR_NULL(panel_backlight_quirk) && ++ panel_backlight_quirk->force_pwm) ++ caps->aux_support = false; + if (caps->aux_support) + aconnector->dc_link->backlight_control_type = BACKLIGHT_CONTROL_AMD_AUX; + +@@ -3707,8 +3757,6 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector) + else + caps->aux_min_input_signal = 1; + +- panel_backlight_quirk = +- drm_get_panel_backlight_quirk(aconnector->drm_edid); + if (!IS_ERR_OR_NULL(panel_backlight_quirk)) { + if (panel_backlight_quirk->min_brightness) { + caps->min_input_signal = +@@ -4558,38 +4606,6 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) + * for acknowledging and handling. + */ + +- /* Use VSTARTUP interrupt */ +- for (i = DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP; +- i <= DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP + adev->mode_info.num_crtc - 1; +- i++) { +- r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->crtc_irq); +- +- if (r) { +- drm_err(adev_to_drm(adev), "Failed to add crtc irq id!\n"); +- return r; +- } +- +- int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; +- int_params.irq_source = +- dc_interrupt_to_irq_source(dc, i, 0); +- +- if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || +- int_params.irq_source < DC_IRQ_SOURCE_VBLANK1 || +- int_params.irq_source > DC_IRQ_SOURCE_VBLANK6) { +- drm_err(adev_to_drm(adev), "Failed to register vblank irq!\n"); +- return -EINVAL; +- } +- +- c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1]; +- +- c_irq_params->adev = adev; +- c_irq_params->irq_src = int_params.irq_source; +- +- if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, +- dm_crtc_high_irq, c_irq_params)) +- return -ENOMEM; +- } +- + /* Use otg vertical line interrupt */ + #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) + for (i = 0; i <= adev->mode_info.num_crtc - 1; i++) { +@@ -4661,37 +4677,6 @@ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) + return -ENOMEM; + } + +- /* Use GRPH_PFLIP interrupt */ +- for (i = DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT; +- i <= DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT + dc->caps.max_otg_num - 1; +- i++) { +- r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->pageflip_irq); +- if (r) { +- drm_err(adev_to_drm(adev), "Failed to add page flip irq id!\n"); +- return r; +- } +- +- int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; +- int_params.irq_source = +- dc_interrupt_to_irq_source(dc, i, 0); +- +- if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || +- int_params.irq_source < DC_IRQ_SOURCE_PFLIP_FIRST || +- int_params.irq_source > DC_IRQ_SOURCE_PFLIP_LAST) { +- drm_err(adev_to_drm(adev), "Failed to register pflip irq!\n"); +- return -EINVAL; +- } +- +- c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST]; +- +- c_irq_params->adev = adev; +- c_irq_params->irq_src = int_params.irq_source; +- +- if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, +- dm_pflip_high_irq, c_irq_params)) +- return -ENOMEM; +- } +- + /* HPD */ + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT, + &adev->hpd_irq); +@@ -5220,11 +5205,11 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) + caps = &dm->backlight_caps[aconnector->bl_idx]; + if (get_brightness_range(caps, &min, &max)) { + if (power_supply_is_system_supplied() > 0) +- props.brightness = DIV_ROUND_CLOSEST((max - min) * caps->ac_level, 100); ++ props.brightness = DIV_ROUND_CLOSEST(max * caps->ac_level, 100); + else +- props.brightness = DIV_ROUND_CLOSEST((max - min) * caps->dc_level, 100); ++ props.brightness = DIV_ROUND_CLOSEST(max * caps->dc_level, 100); + /* min is zero, so max needs to be adjusted */ +- props.max_brightness = max - min; ++ props.max_brightness = max; + drm_dbg(drm, "Backlight caps: min: %d, max: %d, ac %d, dc %d\n", min, max, + caps->ac_level, caps->dc_level); + } else +@@ -6240,8 +6225,8 @@ static void fill_dc_dirty_rects(struct drm_plane *plane, + { + struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state); + struct rect *dirty_rects = flip_addrs->dirty_rects; +- u32 num_clips; +- struct drm_mode_rect *clips; ++ u32 num_clips = 0; ++ struct drm_mode_rect *clips = NULL; + bool bb_changed; + bool fb_changed; + u32 i = 0; +@@ -6257,8 +6242,10 @@ static void fill_dc_dirty_rects(struct drm_plane *plane, + if (new_plane_state->rotation != DRM_MODE_ROTATE_0) + goto ffu; + +- num_clips = drm_plane_get_damage_clips_count(new_plane_state); +- clips = drm_plane_get_damage_clips(new_plane_state); ++ if (!new_plane_state->ignore_damage_clips) { ++ num_clips = drm_plane_get_damage_clips_count(new_plane_state); ++ clips = drm_plane_get_damage_clips(new_plane_state); ++ } + + if (num_clips && (!amdgpu_damage_clips || (amdgpu_damage_clips < 0 && + is_psr_su))) +@@ -9116,14 +9103,22 @@ static void manage_dm_interrupts(struct amdgpu_device *adev, + + drm_crtc_vblank_on_config(&acrtc->base, + &config); +- /* Allow RX6xxx, RX7700, RX7800 GPUs to call amdgpu_irq_get.*/ ++ /* ++ * Since pflip_high_irq is no longer registered for DCN, grab an ++ * extra reference to vupdate irq instead to workaround this ++ * issue: ++ * https://gitlab.freedesktop.org/drm/amd/-/work_items/3936 ++ * ++ * The callbacks to drm_vblank_on/off should really take care of ++ * this though. ++ */ + switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { + case IP_VERSION(3, 0, 0): + case IP_VERSION(3, 0, 2): + case IP_VERSION(3, 0, 3): + case IP_VERSION(3, 2, 0): +- if (amdgpu_irq_get(adev, &adev->pageflip_irq, irq_type)) +- drm_err(dev, "DM_IRQ: Cannot get pageflip irq!\n"); ++ if (amdgpu_irq_get(adev, &adev->vupdate_irq, irq_type)) ++ drm_err(dev, "DM_IRQ: Cannot get vupdate irq!\n"); + #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) + if (amdgpu_irq_get(adev, &adev->vline0_irq, irq_type)) + drm_err(dev, "DM_IRQ: Cannot get vline0 irq!\n"); +@@ -9141,8 +9136,8 @@ static void manage_dm_interrupts(struct amdgpu_device *adev, + if (amdgpu_irq_put(adev, &adev->vline0_irq, irq_type)) + drm_err(dev, "DM_IRQ: Cannot put vline0 irq!\n"); + #endif +- if (amdgpu_irq_put(adev, &adev->pageflip_irq, irq_type)) +- drm_err(dev, "DM_IRQ: Cannot put pageflip irq!\n"); ++ if (amdgpu_irq_put(adev, &adev->vupdate_irq, irq_type)) ++ drm_err(dev, "DM_IRQ: Cannot put vupdate irq!\n"); + } + + drm_crtc_vblank_off(&acrtc->base); +@@ -9155,6 +9150,10 @@ static void dm_update_pflip_irq_state(struct amdgpu_device *adev, + int irq_type = + amdgpu_display_crtc_idx_to_irq_type(adev, acrtc->crtc_id); + ++ /* GRPH_PFLIP is not used on DCN; nothing to reapply. */ ++ if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0) ++ return; ++ + /** + * This reads the current state for the IRQ and force reapplies + * the setting to hardware. +@@ -9486,9 +9485,13 @@ static void update_stream_irq_parameters( + static void amdgpu_dm_handle_vrr_transition(struct dm_crtc_state *old_state, + struct dm_crtc_state *new_state) + { ++ struct amdgpu_device *adev = drm_to_adev(new_state->base.crtc->dev); + bool old_vrr_active = amdgpu_dm_crtc_vrr_active(old_state); + bool new_vrr_active = amdgpu_dm_crtc_vrr_active(new_state); + ++ /* Only DCE gates vupdate on VRR, keep it enabled for DCN */ ++ bool vrr_gates_vupdate = amdgpu_ip_version(adev, DCE_HWIP, 0) == 0; ++ + if (!old_vrr_active && new_vrr_active) { + /* Transition VRR inactive -> active: + * While VRR is active, we must not disable vblank irq, as a +@@ -9498,7 +9501,8 @@ static void amdgpu_dm_handle_vrr_transition(struct dm_crtc_state *old_state, + * We also need vupdate irq for the actual core vblank handling + * at end of vblank. + */ +- WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, true) != 0); ++ if (vrr_gates_vupdate) ++ WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, true) != 0); + WARN_ON(drm_crtc_vblank_get(new_state->base.crtc) != 0); + drm_dbg_driver(new_state->base.crtc->dev, "%s: crtc=%u VRR off->on: Get vblank ref\n", + __func__, new_state->base.crtc->base.id); +@@ -9506,7 +9510,8 @@ static void amdgpu_dm_handle_vrr_transition(struct dm_crtc_state *old_state, + /* Transition VRR active -> inactive: + * Allow vblank irq disable again for fixed refresh rate. + */ +- WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, false) != 0); ++ if (vrr_gates_vupdate) ++ WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, false) != 0); + drm_crtc_vblank_put(new_state->base.crtc); + drm_dbg_driver(new_state->base.crtc->dev, "%s: crtc=%u VRR on->off: Drop vblank ref\n", + __func__, new_state->base.crtc->base.id); +@@ -9681,6 +9686,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, + bool vrr_active = amdgpu_dm_crtc_vrr_active(acrtc_state); + bool cursor_update = false; + bool pflip_present = false; ++ bool immediate_flip = false; + bool dirty_rects_changed = false; + bool updated_planes_and_streams = false; + struct { +@@ -9846,6 +9852,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, + acrtc_state->update_type == UPDATE_TYPE_FAST && + get_mem_type(old_plane_state->fb) == get_mem_type(fb); + ++ immediate_flip |= bundle->flip_addrs[planes_count].flip_immediate; ++ + timestamp_ns = ktime_get_ns(); + bundle->flip_addrs[planes_count].flip_timestamp_in_us = div_u64(timestamp_ns, 1000); + bundle->surface_updates[planes_count].flip_addr = &bundle->flip_addrs[planes_count]; +@@ -10047,6 +10055,29 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, + acrtc_state->cursor_mode == DM_CURSOR_NATIVE_MODE) + amdgpu_dm_commit_cursors(state); + ++ /* ++ * On DCN, flip completion is normally delivered from VUPDATE_NO_LOCK. ++ * However, an immediate (tearing / async) flip is latched by HW right ++ * away and does not wait for the next vupdate, so deliver its ++ * completion event here after programming. ++ * ++ * On DCE, GRPH_PFLIP already fires immediately for immediate flips, so ++ * this is DCN-only. ++ */ ++ if (immediate_flip && amdgpu_ip_version(dm->adev, DCE_HWIP, 0) != 0) { ++ spin_lock_irqsave(&pcrtc->dev->event_lock, flags); ++ if (acrtc_attach->pflip_status == AMDGPU_FLIP_SUBMITTED && ++ acrtc_attach->event) { ++ drm_crtc_accurate_vblank_count(&acrtc_attach->base); ++ drm_crtc_send_vblank_event(&acrtc_attach->base, ++ acrtc_attach->event); ++ acrtc_attach->event = NULL; ++ drm_crtc_vblank_put(&acrtc_attach->base); ++ acrtc_attach->pflip_status = AMDGPU_FLIP_NONE; ++ } ++ spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags); ++ } ++ + cleanup: + kfree(bundle); + } +@@ -11381,6 +11412,7 @@ skip_modeset: + /* Release extra reference */ + if (new_stream) + dc_stream_release(new_stream); ++ new_stream = NULL; + + /* + * We want to do dc stream updates that do not require a +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +index 2e7ee77c010e18..cc23d45815c368 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +@@ -327,9 +327,25 @@ static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable) + drm_crtc_vblank_restore(crtc); + } + +- if (dc_supports_vrr(dm->dc->ctx->dce_version)) { ++ /* ++ * On DCN, VUPDATE_NO_LOCK is the single OTG interrupt used to deliver ++ * vblank and pageflip completion events, so enable it whenever vblank ++ * is enabled. On DCE, vupdate is only needed in VRR mode. ++ */ ++ if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0) { + if (enable) { +- /* vblank irq on -> Only need vupdate irq in vrr mode */ ++ rc = amdgpu_irq_get(adev, &adev->vupdate_irq, irq_type); ++ drm_dbg_vbl(crtc->dev, "Get vupdate_irq ret=%d\n", rc); ++ } else { ++ rc = amdgpu_irq_put(adev, &adev->vupdate_irq, irq_type); ++ drm_dbg_vbl(crtc->dev, "Put vupdate_irq ret=%d\n", rc); ++ } ++ } else if (dc_supports_vrr(dm->dc->ctx->dce_version)) { ++ if (enable) { ++ /* vblank irq on -> Only need vupdate irq in vrr mode ++ * Not ref-counted since we need explicit enable/disable ++ * for DCE VRR handling ++ */ + if (amdgpu_dm_crtc_vrr_active(acrtc_state)) + rc = amdgpu_dm_crtc_set_vupdate_irq(crtc, true); + } else { +@@ -338,39 +354,46 @@ static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable) + } + } + +- if (rc) +- return rc; +- +- /* crtc vblank or vstartup interrupt */ +- if (enable) { +- rc = amdgpu_irq_get(adev, &adev->crtc_irq, irq_type); +- drm_dbg_vbl(crtc->dev, "Get crtc_irq ret=%d\n", rc); +- } else { +- rc = amdgpu_irq_put(adev, &adev->crtc_irq, irq_type); +- drm_dbg_vbl(crtc->dev, "Put crtc_irq ret=%d\n", rc); +- } +- + if (rc) + return rc; + + /* +- * hubp surface flip interrupt +- * +- * We have no guarantee that the frontend index maps to the same +- * backend index - some even map to more than one. +- * +- * TODO: Use a different interrupt or check DC itself for the mapping. ++ * VLINE0 (crtc_irq) and GRPH_PFLIP (pageflip_irq) are only used on ++ * DCE. On DCN, vblank and pageflip completion are delivered from ++ * VUPDATE_NO_LOCK (enabled above), so don't touch them here. + */ +- if (enable) { +- rc = amdgpu_irq_get(adev, &adev->pageflip_irq, irq_type); +- drm_dbg_vbl(crtc->dev, "Get pageflip_irq ret=%d\n", rc); +- } else { +- rc = amdgpu_irq_put(adev, &adev->pageflip_irq, irq_type); +- drm_dbg_vbl(crtc->dev, "Put pageflip_irq ret=%d\n", rc); +- } ++ if (amdgpu_ip_version(adev, DCE_HWIP, 0) == 0) { ++ /* crtc vblank or vstartup interrupt */ ++ if (enable) { ++ rc = amdgpu_irq_get(adev, &adev->crtc_irq, irq_type); ++ drm_dbg_vbl(crtc->dev, "Get crtc_irq ret=%d\n", rc); ++ } else { ++ rc = amdgpu_irq_put(adev, &adev->crtc_irq, irq_type); ++ drm_dbg_vbl(crtc->dev, "Put crtc_irq ret=%d\n", rc); ++ } + +- if (rc) +- return rc; ++ if (rc) ++ return rc; ++ ++ /* ++ * hubp surface flip interrupt ++ * ++ * We have no guarantee that the frontend index maps to the same ++ * backend index - some even map to more than one. ++ * ++ * TODO: Use a different interrupt or check DC itself for the mapping. ++ */ ++ if (enable) { ++ rc = amdgpu_irq_get(adev, &adev->pageflip_irq, irq_type); ++ drm_dbg_vbl(crtc->dev, "Get pageflip_irq ret=%d\n", rc); ++ } else { ++ rc = amdgpu_irq_put(adev, &adev->pageflip_irq, irq_type); ++ drm_dbg_vbl(crtc->dev, "Put pageflip_irq ret=%d\n", rc); ++ } ++ ++ if (rc) ++ return rc; ++ } + + #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) + /* crtc vline0 interrupt, only available on DCN+ */ +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +index 7da7b41bd09256..b98d946a8d2ee6 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +@@ -276,13 +276,20 @@ static void dcn32_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr, + struct dtbclk_dto_params dto_params = {0}; + + /* use mask to program DTO once per tg */ +- if (pipe_ctx->stream_res.tg && ++ if (pipe_ctx->stream && pipe_ctx->stream_res.tg && + !(tg_mask & (1 << pipe_ctx->stream_res.tg->inst))) { + tg_mask |= (1 << pipe_ctx->stream_res.tg->inst); + + dto_params.otg_inst = pipe_ctx->stream_res.tg->inst; + dto_params.ref_dtbclk_khz = ref_dtbclk_khz; + ++ if (dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) ++ dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10; ++ ++ if (dc_is_hdmi_signal(pipe_ctx->stream->signal) || ++ dc_is_dvi_signal(pipe_ctx->stream->signal)) ++ dto_params.is_hdmi = true; ++ + dccg->funcs->set_dtbclk_dto(clk_mgr->dccg, &dto_params); + //dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params); + } +diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +index 817a0253d10e52..d1785a5c7f85fd 100644 +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +@@ -264,13 +264,20 @@ static void dcn35_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr, + struct dtbclk_dto_params dto_params = {0}; + + /* use mask to program DTO once per tg */ +- if (pipe_ctx->stream_res.tg && ++ if (pipe_ctx->stream && pipe_ctx->stream_res.tg && + !(tg_mask & (1 << pipe_ctx->stream_res.tg->inst))) { + tg_mask |= (1 << pipe_ctx->stream_res.tg->inst); + + dto_params.otg_inst = pipe_ctx->stream_res.tg->inst; + dto_params.ref_dtbclk_khz = ref_dtbclk_khz; + ++ if (dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) ++ dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10; ++ ++ if (dc_is_hdmi_signal(pipe_ctx->stream->signal) || ++ dc_is_dvi_signal(pipe_ctx->stream->signal)) ++ dto_params.is_hdmi = true; ++ + dccg->funcs->set_dtbclk_dto(clk_mgr->dccg, &dto_params); + //dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params); + } +diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c +index 31b404e9b9ae07..37ca3bb734c388 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c ++++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c +@@ -979,8 +979,11 @@ static bool detect_link_and_local_sink(struct dc_link *link, + link->link_enc->features.flags.bits.DP_IS_USB_C == 1) { + + /* if alt mode times out, return false */ +- if (!wait_for_entering_dp_alt_mode(link)) ++ if (!wait_for_entering_dp_alt_mode(link)) { ++ if (prev_sink) ++ dc_sink_release(prev_sink); + return false; ++ } + } + + if (!detect_dp(link, &sink_caps, reason)) { +diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c +index ef146f253577aa..91fd73f4a96cf4 100644 +--- a/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c +@@ -957,6 +957,11 @@ struct stream_encoder *dce100_find_first_free_match_stream_enc_for_link( + for (i = 0; i < pool->stream_enc_count; i++) { + if (!res_ctx->is_stream_enc_acquired[i] && + pool->stream_enc[i]) { ++ /* DP/MST needs a digital encoder; skip analog/no-DP encoders */ ++ if (dc_is_dp_signal(stream->signal) && ++ (!pool->stream_enc[i]->funcs || ++ !pool->stream_enc[i]->funcs->dp_set_stream_attribute)) ++ continue; + /* Store first available for MST second display + * in daisy chain use case + */ +@@ -980,7 +985,7 @@ struct stream_encoder *dce100_find_first_free_match_stream_enc_for_link( + * required for non DP connectors. + */ + +- if (j >= 0 && link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT) ++ if (j >= 0 && dc_is_dp_signal(stream->signal)) + return pool->stream_enc[j]; + + return NULL; +diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c +index ae858a43c35f4a..b3d55cac35694b 100644 +--- a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c ++++ b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c +@@ -447,8 +447,6 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream, + * + * @stream: contains data we may need to construct VSIF (i.e. timing_3d_format, etc.) + * @info_packet: output structure where to store VSIF +- * @ALLMEnabled: indicates whether ALLM HF-VSIF should be generated +- * @ALLMValue: ALLM bit value to advertise in HF-VSIF + */ + void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream, + struct dc_info_packet *info_packet) +diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c +index 0d72118a12b4cc..7c9e2003e2a04e 100644 +--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c ++++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c +@@ -40,6 +40,8 @@ + + #define DEVICE_ATTR_IS(_name) (attr_id == device_attr_id__##_name) + ++#define power_2_mwatt(power) (((power) >> 8) * 1000 + ((power) & 0xff)) ++ + struct od_attribute { + struct kobj_attribute attribute; + struct list_head entry; +@@ -2617,6 +2619,11 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ + gc_ver != IP_VERSION(9, 4, 3)) || + gc_ver < IP_VERSION(9, 0, 0)) + *states = ATTR_STATE_UNSUPPORTED; ++ ++ if (adev->scpm_enabled) { ++ dev_attr->attr.mode &= ~S_IWUGO; ++ dev_attr->store = NULL; ++ } + } else if (DEVICE_ATTR_IS(gpu_metrics)) { + if (gc_ver < IP_VERSION(9, 1, 0)) + *states = ATTR_STATE_UNSUPPORTED; +@@ -3261,7 +3268,6 @@ static int amdgpu_hwmon_get_power(struct device *dev, + enum amd_pp_sensors sensor) + { + struct amdgpu_device *adev = dev_get_drvdata(dev); +- unsigned int uw; + u32 query = 0; + int r; + +@@ -3270,9 +3276,7 @@ static int amdgpu_hwmon_get_power(struct device *dev, + return r; + + /* convert to microwatts */ +- uw = (query >> 8) * 1000000 + (query & 0xff) * 1000; +- +- return uw; ++ return power_2_mwatt(query) * 1000; + } + + static ssize_t amdgpu_hwmon_show_power_avg(struct device *dev, +@@ -4804,7 +4808,7 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a + { + uint32_t mp1_ver = amdgpu_ip_version(adev, MP1_HWIP, 0); + uint32_t gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0); +- uint32_t value; ++ uint32_t value, mwatt, centiwatt; + uint64_t value64 = 0; + uint32_t query = 0; + int size; +@@ -4829,17 +4833,21 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a + seq_printf(m, "\t%u mV (VDDNB)\n", value); + size = sizeof(uint32_t); + if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *)&query, &size)) { ++ mwatt = power_2_mwatt(query); ++ centiwatt = DIV_ROUND_CLOSEST(mwatt, 10); + if (adev->flags & AMD_IS_APU) +- seq_printf(m, "\t%u.%02u W (average SoC including CPU)\n", query >> 8, query & 0xff); ++ seq_printf(m, "\t%u.%02u W (average SoC including CPU)\n", centiwatt / 100, centiwatt % 100); + else +- seq_printf(m, "\t%u.%02u W (average SoC)\n", query >> 8, query & 0xff); ++ seq_printf(m, "\t%u.%02u W (average SoC)\n", centiwatt / 100, centiwatt % 100); + } + size = sizeof(uint32_t); + if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER, (void *)&query, &size)) { ++ mwatt = power_2_mwatt(query); ++ centiwatt = DIV_ROUND_CLOSEST(mwatt, 10); + if (adev->flags & AMD_IS_APU) +- seq_printf(m, "\t%u.%02u W (current SoC including CPU)\n", query >> 8, query & 0xff); ++ seq_printf(m, "\t%u.%02u W (current SoC including CPU)\n", centiwatt / 100, centiwatt % 100); + else +- seq_printf(m, "\t%u.%02u W (current SoC)\n", query >> 8, query & 0xff); ++ seq_printf(m, "\t%u.%02u W (current SoC)\n", centiwatt / 100, centiwatt % 100); + } + size = sizeof(value); + seq_printf(m, "\n"); +diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +index 1d6e30269d5679..4d553be56396f3 100644 +--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c +@@ -106,11 +106,8 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr) + hwmgr->od_enabled = false; + switch (hwmgr->chip_id) { + case CHIP_BONAIRE: +- /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM +- * R7 260X cards with old MC ucode: MCLK DPM is unstable +- */ +- if (adev->pdev->subsystem_vendor == 0x106B || +- adev->pdev->device == 0x6658) { ++ /* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM */ ++ if (adev->pdev->subsystem_vendor == 0x106B) { + dev_info(adev->dev, "disabling MCLK DPM on quirky ASIC"); + adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK; + hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK; +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +index 96a2b5ab87d850..f5c20f2320621b 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +@@ -2481,11 +2481,14 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu, + uint32_t pp_limit = smu->adev->pm.ac_power ? + skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] : + skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0]; +- uint32_t power_limit = 0, od_percent_upper = 0, od_percent_lower = 0; ++ uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; ++ uint32_t min_limit = min_t(uint32_t, pp_limit, msg_limit); ++ uint32_t max_limit = max_t(uint32_t, pp_limit, msg_limit); ++ uint32_t od_percent_upper = 0, od_percent_lower = 0; + int ret; + + if (current_power_limit) { +- ret = smu_v13_0_get_current_power_limit(smu, &power_limit); ++ ret = smu_v13_0_get_current_power_limit(smu, current_power_limit); + if (ret) + *current_power_limit = pp_limit; + } +@@ -2508,12 +2511,12 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu, + od_percent_upper, od_percent_lower, pp_limit); + + if (max_power_limit) { +- *max_power_limit = pp_limit * (100 + od_percent_upper); ++ *max_power_limit = max_limit * (100 + od_percent_upper); + *max_power_limit /= 100; + } + + if (min_power_limit) { +- *min_power_limit = pp_limit * (100 - od_percent_lower); ++ *min_power_limit = min_limit * (100 - od_percent_lower); + *min_power_limit /= 100; + } + +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +index 0843fa0f5e2aed..427f3569f1d392 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +@@ -2442,15 +2442,16 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu, + uint32_t pp_limit = smu->adev->pm.ac_power ? + skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] : + skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0]; +- uint32_t power_limit = 0, od_percent_upper = 0, od_percent_lower = 0; ++ uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; ++ uint32_t min_limit = min_t(uint32_t, pp_limit, msg_limit); ++ uint32_t max_limit = max_t(uint32_t, pp_limit, msg_limit); ++ uint32_t od_percent_upper = 0, od_percent_lower = 0; + int ret; + + if (current_power_limit) { +- ret = smu_v13_0_get_current_power_limit(smu, &power_limit); ++ ret = smu_v13_0_get_current_power_limit(smu, current_power_limit); + if (ret) +- power_limit = pp_limit; +- +- *current_power_limit = power_limit; ++ *current_power_limit = pp_limit; + } + + if (default_power_limit) +@@ -2471,12 +2472,12 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu, + od_percent_upper, od_percent_lower, pp_limit); + + if (max_power_limit) { +- *max_power_limit = pp_limit * (100 + od_percent_upper); ++ *max_power_limit = max_limit * (100 + od_percent_upper); + *max_power_limit /= 100; + } + + if (min_power_limit) { +- *min_power_limit = pp_limit * (100 - od_percent_lower); ++ *min_power_limit = min_limit * (100 - od_percent_lower); + *min_power_limit /= 100; + } + +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +index 969be5ad068190..9e42cc8dd133e6 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +@@ -1701,19 +1701,23 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu, + table_context->power_play_table; + PPTable_t *pptable = table_context->driver_pptable; + CustomSkuTable_t *skutable = &pptable->CustomSkuTable; +- int16_t od_percent_upper = 0, od_percent_lower = 0; ++ uint32_t pp_limit = smu->adev->pm.ac_power ? ++ skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] : ++ skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0]; + uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; +- uint32_t power_limit; ++ uint32_t min_limit = min_t(uint32_t, pp_limit, msg_limit); ++ uint32_t max_limit = max_t(uint32_t, pp_limit, msg_limit); ++ int16_t od_percent_upper = 0, od_percent_lower = 0; ++ int ret; + +- if (smu_v14_0_get_current_power_limit(smu, &power_limit)) +- power_limit = smu->adev->pm.ac_power ? +- skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] : +- skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0]; ++ if (current_power_limit) { ++ ret = smu_v14_0_get_current_power_limit(smu, current_power_limit); ++ if (ret) ++ *current_power_limit = pp_limit; ++ } + +- if (current_power_limit) +- *current_power_limit = power_limit; + if (default_power_limit) +- *default_power_limit = power_limit; ++ *default_power_limit = pp_limit; + + if (powerplay_table) { + if (smu->od_enabled && +@@ -1727,15 +1731,15 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu, + } + + dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n", +- od_percent_upper, od_percent_lower, power_limit); ++ od_percent_upper, od_percent_lower, pp_limit); + + if (max_power_limit) { +- *max_power_limit = msg_limit * (100 + od_percent_upper); ++ *max_power_limit = max_limit * (100 + od_percent_upper); + *max_power_limit /= 100; + } + + if (min_power_limit) { +- *min_power_limit = power_limit * (100 + od_percent_lower); ++ *min_power_limit = min_limit * (100 + od_percent_lower); + *min_power_limit /= 100; + } + +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c +index 09b289f0fcbf59..de2a32112913e8 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c +@@ -1230,7 +1230,7 @@ static const struct mipi_dsi_host_ops cdns_dsi_ops = { + .transfer = cdns_dsi_transfer, + }; + +-static int __maybe_unused cdns_dsi_resume(struct device *dev) ++static int cdns_dsi_resume(struct device *dev) + { + struct cdns_dsi *dsi = dev_get_drvdata(dev); + +@@ -1241,7 +1241,7 @@ static int __maybe_unused cdns_dsi_resume(struct device *dev) + return 0; + } + +-static int __maybe_unused cdns_dsi_suspend(struct device *dev) ++static int cdns_dsi_suspend(struct device *dev) + { + struct cdns_dsi *dsi = dev_get_drvdata(dev); + +@@ -1251,8 +1251,9 @@ static int __maybe_unused cdns_dsi_suspend(struct device *dev) + return 0; + } + +-static UNIVERSAL_DEV_PM_OPS(cdns_dsi_pm_ops, cdns_dsi_suspend, cdns_dsi_resume, +- NULL); ++static const struct dev_pm_ops cdns_dsi_pm_ops = { ++ RUNTIME_PM_OPS(cdns_dsi_suspend, cdns_dsi_resume, NULL) ++}; + + static int cdns_dsi_drm_probe(struct platform_device *pdev) + { +@@ -1399,7 +1400,7 @@ static struct platform_driver cdns_dsi_platform_driver = { + .driver = { + .name = "cdns-dsi", + .of_match_table = cdns_dsi_of_match, +- .pm = &cdns_dsi_pm_ops, ++ .pm = pm_ptr(&cdns_dsi_pm_ops), + }, + }; + module_platform_driver(cdns_dsi_platform_driver); +diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c +index be749dcad3b585..383cfd99f955e1 100644 +--- a/drivers/gpu/drm/display/drm_dp_mst_topology.c ++++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c +@@ -789,6 +789,12 @@ static bool drm_dp_sideband_append_payload(struct drm_dp_sideband_msg_rx *msg, + { + u8 crc4; + ++ /* curchunk_len must be >= 1 (min 1 CRC byte) and fit in chunk[] */ ++ if (!msg->curchunk_len || ++ msg->curchunk_len > ARRAY_SIZE(msg->chunk) || ++ msg->curchunk_idx + replybuflen > ARRAY_SIZE(msg->chunk)) ++ return false; ++ + memcpy(&msg->chunk[msg->curchunk_idx], replybuf, replybuflen); + msg->curchunk_idx += replybuflen; + +@@ -799,6 +805,9 @@ static bool drm_dp_sideband_append_payload(struct drm_dp_sideband_msg_rx *msg, + print_hex_dump(KERN_DEBUG, "wrong crc", + DUMP_PREFIX_NONE, 16, 1, + msg->chunk, msg->curchunk_len, false); ++ /* Guard against accumulated msg[] overflow */ ++ if (msg->curlen + msg->curchunk_len - 1 > ARRAY_SIZE(msg->msg)) ++ return false; + /* copy chunk into bigger msg */ + memcpy(&msg->msg[msg->curlen], msg->chunk, msg->curchunk_len - 1); + msg->curlen += msg->curchunk_len - 1; +@@ -871,7 +880,7 @@ static bool drm_dp_sideband_parse_remote_dpcd_read(struct drm_dp_sideband_msg_rx + goto fail_len; + repmsg->u.remote_dpcd_read_ack.num_bytes = raw->msg[idx]; + idx++; +- if (idx > raw->curlen) ++ if (idx + repmsg->u.remote_dpcd_read_ack.num_bytes > raw->curlen) + goto fail_len; + + memcpy(repmsg->u.remote_dpcd_read_ack.bytes, &raw->msg[idx], repmsg->u.remote_dpcd_read_ack.num_bytes); +@@ -907,7 +916,9 @@ static bool drm_dp_sideband_parse_remote_i2c_read_ack(struct drm_dp_sideband_msg + goto fail_len; + repmsg->u.remote_i2c_read_ack.num_bytes = raw->msg[idx]; + idx++; +- /* TODO check */ ++ if (idx + repmsg->u.remote_i2c_read_ack.num_bytes > raw->curlen) ++ goto fail_len; ++ + memcpy(repmsg->u.remote_i2c_read_ack.bytes, &raw->msg[idx], repmsg->u.remote_i2c_read_ack.num_bytes); + return true; + fail_len: +@@ -923,16 +934,13 @@ static bool drm_dp_sideband_parse_enum_path_resources_ack(struct drm_dp_sideband + repmsg->u.path_resources.port_number = (raw->msg[idx] >> 4) & 0xf; + repmsg->u.path_resources.fec_capable = raw->msg[idx] & 0x1; + idx++; +- if (idx > raw->curlen) ++ if (idx + 2 > raw->curlen) + goto fail_len; + repmsg->u.path_resources.full_payload_bw_number = (raw->msg[idx] << 8) | (raw->msg[idx+1]); + idx += 2; +- if (idx > raw->curlen) ++ if (idx + 2 > raw->curlen) + goto fail_len; + repmsg->u.path_resources.avail_payload_bw_number = (raw->msg[idx] << 8) | (raw->msg[idx+1]); +- idx += 2; +- if (idx > raw->curlen) +- goto fail_len; + return true; + fail_len: + DRM_DEBUG_KMS("enum resource parse length fail %d %d\n", idx, raw->curlen); +@@ -950,12 +958,9 @@ static bool drm_dp_sideband_parse_allocate_payload_ack(struct drm_dp_sideband_ms + goto fail_len; + repmsg->u.allocate_payload.vcpi = raw->msg[idx]; + idx++; +- if (idx > raw->curlen) ++ if (idx + 2 > raw->curlen) + goto fail_len; + repmsg->u.allocate_payload.allocated_pbn = (raw->msg[idx] << 8) | (raw->msg[idx+1]); +- idx += 2; +- if (idx > raw->curlen) +- goto fail_len; + return true; + fail_len: + DRM_DEBUG_KMS("allocate payload parse length fail %d %d\n", idx, raw->curlen); +@@ -969,12 +974,9 @@ static bool drm_dp_sideband_parse_query_payload_ack(struct drm_dp_sideband_msg_r + + repmsg->u.query_payload.port_number = (raw->msg[idx] >> 4) & 0xf; + idx++; +- if (idx > raw->curlen) ++ if (idx + 2 > raw->curlen) + goto fail_len; + repmsg->u.query_payload.allocated_pbn = (raw->msg[idx] << 8) | (raw->msg[idx + 1]); +- idx += 2; +- if (idx > raw->curlen) +- goto fail_len; + return true; + fail_len: + DRM_DEBUG_KMS("query payload parse length fail %d %d\n", idx, raw->curlen); +@@ -3738,8 +3740,10 @@ void drm_dp_mst_topology_queue_probe(struct drm_dp_mst_topology_mgr *mgr) + { + mutex_lock(&mgr->lock); + +- if (drm_WARN_ON(mgr->dev, !mgr->mst_state || !mgr->mst_primary)) ++ if (!mgr->mst_state || !mgr->mst_primary) { ++ drm_dbg_kms(mgr->dev, "queue_probe skipped: topology torn down\n"); + goto out_unlock; ++ } + + drm_dp_mst_topology_mgr_invalidate_mstb(mgr->mst_primary); + drm_dp_mst_queue_probe_work(mgr); +diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c +index 640d93070bb7c4..841f3de5f307a0 100644 +--- a/drivers/gpu/drm/drm_buddy.c ++++ b/drivers/gpu/drm/drm_buddy.c +@@ -10,1250 +10,9 @@ + #include <linux/module.h> + #include <linux/sizes.h> + ++#include <linux/gpu_buddy.h> + #include <drm/drm_buddy.h> +- +-enum drm_buddy_free_tree { +- DRM_BUDDY_CLEAR_TREE = 0, +- DRM_BUDDY_DIRTY_TREE, +- DRM_BUDDY_MAX_FREE_TREES, +-}; +- +-static struct kmem_cache *slab_blocks; +- +-#define for_each_free_tree(tree) \ +- for ((tree) = 0; (tree) < DRM_BUDDY_MAX_FREE_TREES; (tree)++) +- +-static struct drm_buddy_block *drm_block_alloc(struct drm_buddy *mm, +- struct drm_buddy_block *parent, +- unsigned int order, +- u64 offset) +-{ +- struct drm_buddy_block *block; +- +- BUG_ON(order > DRM_BUDDY_MAX_ORDER); +- +- block = kmem_cache_zalloc(slab_blocks, GFP_KERNEL); +- if (!block) +- return NULL; +- +- block->header = offset; +- block->header |= order; +- block->parent = parent; +- +- RB_CLEAR_NODE(&block->rb); +- +- BUG_ON(block->header & DRM_BUDDY_HEADER_UNUSED); +- return block; +-} +- +-static void drm_block_free(struct drm_buddy *mm, +- struct drm_buddy_block *block) +-{ +- kmem_cache_free(slab_blocks, block); +-} +- +-static enum drm_buddy_free_tree +-get_block_tree(struct drm_buddy_block *block) +-{ +- return drm_buddy_block_is_clear(block) ? +- DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE; +-} +- +-static struct drm_buddy_block * +-rbtree_get_free_block(const struct rb_node *node) +-{ +- return node ? rb_entry(node, struct drm_buddy_block, rb) : NULL; +-} +- +-static struct drm_buddy_block * +-rbtree_last_free_block(struct rb_root *root) +-{ +- return rbtree_get_free_block(rb_last(root)); +-} +- +-static bool rbtree_is_empty(struct rb_root *root) +-{ +- return RB_EMPTY_ROOT(root); +-} +- +-static bool drm_buddy_block_offset_less(const struct drm_buddy_block *block, +- const struct drm_buddy_block *node) +-{ +- return drm_buddy_block_offset(block) < drm_buddy_block_offset(node); +-} +- +-static bool rbtree_block_offset_less(struct rb_node *block, +- const struct rb_node *node) +-{ +- return drm_buddy_block_offset_less(rbtree_get_free_block(block), +- rbtree_get_free_block(node)); +-} +- +-static void rbtree_insert(struct drm_buddy *mm, +- struct drm_buddy_block *block, +- enum drm_buddy_free_tree tree) +-{ +- rb_add(&block->rb, +- &mm->free_trees[tree][drm_buddy_block_order(block)], +- rbtree_block_offset_less); +-} +- +-static void rbtree_remove(struct drm_buddy *mm, +- struct drm_buddy_block *block) +-{ +- unsigned int order = drm_buddy_block_order(block); +- enum drm_buddy_free_tree tree; +- struct rb_root *root; +- +- tree = get_block_tree(block); +- root = &mm->free_trees[tree][order]; +- +- rb_erase(&block->rb, root); +- RB_CLEAR_NODE(&block->rb); +-} +- +-static void clear_reset(struct drm_buddy_block *block) +-{ +- block->header &= ~DRM_BUDDY_HEADER_CLEAR; +-} +- +-static void mark_cleared(struct drm_buddy_block *block) +-{ +- block->header |= DRM_BUDDY_HEADER_CLEAR; +-} +- +-static void mark_allocated(struct drm_buddy *mm, +- struct drm_buddy_block *block) +-{ +- block->header &= ~DRM_BUDDY_HEADER_STATE; +- block->header |= DRM_BUDDY_ALLOCATED; +- +- rbtree_remove(mm, block); +-} +- +-static void mark_free(struct drm_buddy *mm, +- struct drm_buddy_block *block) +-{ +- enum drm_buddy_free_tree tree; +- +- block->header &= ~DRM_BUDDY_HEADER_STATE; +- block->header |= DRM_BUDDY_FREE; +- +- tree = get_block_tree(block); +- rbtree_insert(mm, block, tree); +-} +- +-static void mark_split(struct drm_buddy *mm, +- struct drm_buddy_block *block) +-{ +- block->header &= ~DRM_BUDDY_HEADER_STATE; +- block->header |= DRM_BUDDY_SPLIT; +- +- rbtree_remove(mm, block); +-} +- +-static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2) +-{ +- return s1 <= e2 && e1 >= s2; +-} +- +-static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2) +-{ +- return s1 <= s2 && e1 >= e2; +-} +- +-static struct drm_buddy_block * +-__get_buddy(struct drm_buddy_block *block) +-{ +- struct drm_buddy_block *parent; +- +- parent = block->parent; +- if (!parent) +- return NULL; +- +- if (parent->left == block) +- return parent->right; +- +- return parent->left; +-} +- +-static unsigned int __drm_buddy_free(struct drm_buddy *mm, +- struct drm_buddy_block *block, +- bool force_merge) +-{ +- struct drm_buddy_block *parent; +- unsigned int order; +- +- while ((parent = block->parent)) { +- struct drm_buddy_block *buddy; +- +- buddy = __get_buddy(block); +- +- if (!drm_buddy_block_is_free(buddy)) +- break; +- +- if (!force_merge) { +- /* +- * Check the block and its buddy clear state and exit +- * the loop if they both have the dissimilar state. +- */ +- if (drm_buddy_block_is_clear(block) != +- drm_buddy_block_is_clear(buddy)) +- break; +- +- if (drm_buddy_block_is_clear(block)) +- mark_cleared(parent); +- } +- +- rbtree_remove(mm, buddy); +- if (force_merge && drm_buddy_block_is_clear(buddy)) +- mm->clear_avail -= drm_buddy_block_size(mm, buddy); +- +- drm_block_free(mm, block); +- drm_block_free(mm, buddy); +- +- block = parent; +- } +- +- order = drm_buddy_block_order(block); +- mark_free(mm, block); +- +- return order; +-} +- +-static int __force_merge(struct drm_buddy *mm, +- u64 start, +- u64 end, +- unsigned int min_order) +-{ +- unsigned int tree, order; +- int i; +- +- if (!min_order) +- return -ENOMEM; +- +- if (min_order > mm->max_order) +- return -EINVAL; +- +- for_each_free_tree(tree) { +- for (i = min_order - 1; i >= 0; i--) { +- struct rb_node *iter = rb_last(&mm->free_trees[tree][i]); +- +- while (iter) { +- struct drm_buddy_block *block, *buddy; +- u64 block_start, block_end; +- +- block = rbtree_get_free_block(iter); +- iter = rb_prev(iter); +- +- if (!block || !block->parent) +- continue; +- +- block_start = drm_buddy_block_offset(block); +- block_end = block_start + drm_buddy_block_size(mm, block) - 1; +- +- if (!contains(start, end, block_start, block_end)) +- continue; +- +- buddy = __get_buddy(block); +- if (!drm_buddy_block_is_free(buddy)) +- continue; +- +- WARN_ON(drm_buddy_block_is_clear(block) == +- drm_buddy_block_is_clear(buddy)); +- +- /* +- * Advance to the next node when the current node is the buddy, +- * as freeing the block will also remove its buddy from the tree. +- */ +- if (iter == &buddy->rb) +- iter = rb_prev(iter); +- +- rbtree_remove(mm, block); +- if (drm_buddy_block_is_clear(block)) +- mm->clear_avail -= drm_buddy_block_size(mm, block); +- +- order = __drm_buddy_free(mm, block, true); +- if (order >= min_order) +- return 0; +- } +- } +- } +- +- return -ENOMEM; +-} +- +-/** +- * drm_buddy_init - init memory manager +- * +- * @mm: DRM buddy manager to initialize +- * @size: size in bytes to manage +- * @chunk_size: minimum page size in bytes for our allocations +- * +- * Initializes the memory manager and its resources. +- * +- * Returns: +- * 0 on success, error code on failure. +- */ +-int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size) +-{ +- unsigned int i, j, root_count = 0; +- u64 offset = 0; +- +- if (size < chunk_size) +- return -EINVAL; +- +- if (chunk_size < SZ_4K) +- return -EINVAL; +- +- if (!is_power_of_2(chunk_size)) +- return -EINVAL; +- +- size = round_down(size, chunk_size); +- +- mm->size = size; +- mm->avail = size; +- mm->clear_avail = 0; +- mm->chunk_size = chunk_size; +- mm->max_order = ilog2(size) - ilog2(chunk_size); +- +- BUG_ON(mm->max_order > DRM_BUDDY_MAX_ORDER); +- +- mm->free_trees = kmalloc_array(DRM_BUDDY_MAX_FREE_TREES, +- sizeof(*mm->free_trees), +- GFP_KERNEL); +- if (!mm->free_trees) +- return -ENOMEM; +- +- for_each_free_tree(i) { +- mm->free_trees[i] = kmalloc_array(mm->max_order + 1, +- sizeof(struct rb_root), +- GFP_KERNEL); +- if (!mm->free_trees[i]) +- goto out_free_tree; +- +- for (j = 0; j <= mm->max_order; ++j) +- mm->free_trees[i][j] = RB_ROOT; +- } +- +- mm->n_roots = hweight64(size); +- +- mm->roots = kmalloc_array(mm->n_roots, +- sizeof(struct drm_buddy_block *), +- GFP_KERNEL); +- if (!mm->roots) +- goto out_free_tree; +- +- /* +- * Split into power-of-two blocks, in case we are given a size that is +- * not itself a power-of-two. +- */ +- do { +- struct drm_buddy_block *root; +- unsigned int order; +- u64 root_size; +- +- order = ilog2(size) - ilog2(chunk_size); +- root_size = chunk_size << order; +- +- root = drm_block_alloc(mm, NULL, order, offset); +- if (!root) +- goto out_free_roots; +- +- mark_free(mm, root); +- +- BUG_ON(root_count > mm->max_order); +- BUG_ON(drm_buddy_block_size(mm, root) < chunk_size); +- +- mm->roots[root_count] = root; +- +- offset += root_size; +- size -= root_size; +- root_count++; +- } while (size); +- +- return 0; +- +-out_free_roots: +- while (root_count--) +- drm_block_free(mm, mm->roots[root_count]); +- kfree(mm->roots); +-out_free_tree: +- while (i--) +- kfree(mm->free_trees[i]); +- kfree(mm->free_trees); +- return -ENOMEM; +-} +-EXPORT_SYMBOL(drm_buddy_init); +- +-/** +- * drm_buddy_fini - tear down the memory manager +- * +- * @mm: DRM buddy manager to free +- * +- * Cleanup memory manager resources and the freetree +- */ +-void drm_buddy_fini(struct drm_buddy *mm) +-{ +- u64 root_size, size, start; +- unsigned int order; +- int i; +- +- size = mm->size; +- +- for (i = 0; i < mm->n_roots; ++i) { +- order = ilog2(size) - ilog2(mm->chunk_size); +- start = drm_buddy_block_offset(mm->roots[i]); +- __force_merge(mm, start, start + size, order); +- +- if (WARN_ON(!drm_buddy_block_is_free(mm->roots[i]))) +- kunit_fail_current_test("buddy_fini() root"); +- +- drm_block_free(mm, mm->roots[i]); +- +- root_size = mm->chunk_size << order; +- size -= root_size; +- } +- +- WARN_ON(mm->avail != mm->size); +- +- for_each_free_tree(i) +- kfree(mm->free_trees[i]); +- kfree(mm->free_trees); +- kfree(mm->roots); +-} +-EXPORT_SYMBOL(drm_buddy_fini); +- +-static int split_block(struct drm_buddy *mm, +- struct drm_buddy_block *block) +-{ +- unsigned int block_order = drm_buddy_block_order(block) - 1; +- u64 offset = drm_buddy_block_offset(block); +- +- BUG_ON(!drm_buddy_block_is_free(block)); +- BUG_ON(!drm_buddy_block_order(block)); +- +- block->left = drm_block_alloc(mm, block, block_order, offset); +- if (!block->left) +- return -ENOMEM; +- +- block->right = drm_block_alloc(mm, block, block_order, +- offset + (mm->chunk_size << block_order)); +- if (!block->right) { +- drm_block_free(mm, block->left); +- return -ENOMEM; +- } +- +- mark_split(mm, block); +- +- if (drm_buddy_block_is_clear(block)) { +- mark_cleared(block->left); +- mark_cleared(block->right); +- clear_reset(block); +- } +- +- mark_free(mm, block->left); +- mark_free(mm, block->right); +- +- return 0; +-} +- +-/** +- * drm_get_buddy - get buddy address +- * +- * @block: DRM buddy block +- * +- * Returns the corresponding buddy block for @block, or NULL +- * if this is a root block and can't be merged further. +- * Requires some kind of locking to protect against +- * any concurrent allocate and free operations. +- */ +-struct drm_buddy_block * +-drm_get_buddy(struct drm_buddy_block *block) +-{ +- return __get_buddy(block); +-} +-EXPORT_SYMBOL(drm_get_buddy); +- +-/** +- * drm_buddy_reset_clear - reset blocks clear state +- * +- * @mm: DRM buddy manager +- * @is_clear: blocks clear state +- * +- * Reset the clear state based on @is_clear value for each block +- * in the freetree. +- */ +-void drm_buddy_reset_clear(struct drm_buddy *mm, bool is_clear) +-{ +- enum drm_buddy_free_tree src_tree, dst_tree; +- u64 root_size, size, start; +- unsigned int order; +- int i; +- +- size = mm->size; +- for (i = 0; i < mm->n_roots; ++i) { +- order = ilog2(size) - ilog2(mm->chunk_size); +- start = drm_buddy_block_offset(mm->roots[i]); +- __force_merge(mm, start, start + size, order); +- +- root_size = mm->chunk_size << order; +- size -= root_size; +- } +- +- src_tree = is_clear ? DRM_BUDDY_DIRTY_TREE : DRM_BUDDY_CLEAR_TREE; +- dst_tree = is_clear ? DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE; +- +- for (i = 0; i <= mm->max_order; ++i) { +- struct rb_root *root = &mm->free_trees[src_tree][i]; +- struct drm_buddy_block *block, *tmp; +- +- rbtree_postorder_for_each_entry_safe(block, tmp, root, rb) { +- rbtree_remove(mm, block); +- if (is_clear) { +- mark_cleared(block); +- mm->clear_avail += drm_buddy_block_size(mm, block); +- } else { +- clear_reset(block); +- mm->clear_avail -= drm_buddy_block_size(mm, block); +- } +- +- rbtree_insert(mm, block, dst_tree); +- } +- } +-} +-EXPORT_SYMBOL(drm_buddy_reset_clear); +- +-/** +- * drm_buddy_free_block - free a block +- * +- * @mm: DRM buddy manager +- * @block: block to be freed +- */ +-void drm_buddy_free_block(struct drm_buddy *mm, +- struct drm_buddy_block *block) +-{ +- BUG_ON(!drm_buddy_block_is_allocated(block)); +- mm->avail += drm_buddy_block_size(mm, block); +- if (drm_buddy_block_is_clear(block)) +- mm->clear_avail += drm_buddy_block_size(mm, block); +- +- __drm_buddy_free(mm, block, false); +-} +-EXPORT_SYMBOL(drm_buddy_free_block); +- +-static void __drm_buddy_free_list(struct drm_buddy *mm, +- struct list_head *objects, +- bool mark_clear, +- bool mark_dirty) +-{ +- struct drm_buddy_block *block, *on; +- +- WARN_ON(mark_dirty && mark_clear); +- +- list_for_each_entry_safe(block, on, objects, link) { +- if (mark_clear) +- mark_cleared(block); +- else if (mark_dirty) +- clear_reset(block); +- drm_buddy_free_block(mm, block); +- cond_resched(); +- } +- INIT_LIST_HEAD(objects); +-} +- +-static void drm_buddy_free_list_internal(struct drm_buddy *mm, +- struct list_head *objects) +-{ +- /* +- * Don't touch the clear/dirty bit, since allocation is still internal +- * at this point. For example we might have just failed part of the +- * allocation. +- */ +- __drm_buddy_free_list(mm, objects, false, false); +-} +- +-/** +- * drm_buddy_free_list - free blocks +- * +- * @mm: DRM buddy manager +- * @objects: input list head to free blocks +- * @flags: optional flags like DRM_BUDDY_CLEARED +- */ +-void drm_buddy_free_list(struct drm_buddy *mm, +- struct list_head *objects, +- unsigned int flags) +-{ +- bool mark_clear = flags & DRM_BUDDY_CLEARED; +- +- __drm_buddy_free_list(mm, objects, mark_clear, !mark_clear); +-} +-EXPORT_SYMBOL(drm_buddy_free_list); +- +-static bool block_incompatible(struct drm_buddy_block *block, unsigned int flags) +-{ +- bool needs_clear = flags & DRM_BUDDY_CLEAR_ALLOCATION; +- +- return needs_clear != drm_buddy_block_is_clear(block); +-} +- +-static struct drm_buddy_block * +-__alloc_range_bias(struct drm_buddy *mm, +- u64 start, u64 end, +- unsigned int order, +- unsigned long flags, +- bool fallback) +-{ +- u64 req_size = mm->chunk_size << order; +- struct drm_buddy_block *block; +- struct drm_buddy_block *buddy; +- LIST_HEAD(dfs); +- int err; +- int i; +- +- end = end - 1; +- +- for (i = 0; i < mm->n_roots; ++i) +- list_add_tail(&mm->roots[i]->tmp_link, &dfs); +- +- do { +- u64 block_start; +- u64 block_end; +- +- block = list_first_entry_or_null(&dfs, +- struct drm_buddy_block, +- tmp_link); +- if (!block) +- break; +- +- list_del(&block->tmp_link); +- +- if (drm_buddy_block_order(block) < order) +- continue; +- +- block_start = drm_buddy_block_offset(block); +- block_end = block_start + drm_buddy_block_size(mm, block) - 1; +- +- if (!overlaps(start, end, block_start, block_end)) +- continue; +- +- if (drm_buddy_block_is_allocated(block)) +- continue; +- +- if (block_start < start || block_end > end) { +- u64 adjusted_start = max(block_start, start); +- u64 adjusted_end = min(block_end, end); +- +- if (round_down(adjusted_end + 1, req_size) <= +- round_up(adjusted_start, req_size)) +- continue; +- } +- +- if (!fallback && block_incompatible(block, flags)) +- continue; +- +- if (contains(start, end, block_start, block_end) && +- order == drm_buddy_block_order(block)) { +- /* +- * Find the free block within the range. +- */ +- if (drm_buddy_block_is_free(block)) +- return block; +- +- continue; +- } +- +- if (!drm_buddy_block_is_split(block)) { +- err = split_block(mm, block); +- if (unlikely(err)) +- goto err_undo; +- } +- +- list_add(&block->right->tmp_link, &dfs); +- list_add(&block->left->tmp_link, &dfs); +- } while (1); +- +- return ERR_PTR(-ENOSPC); +- +-err_undo: +- /* +- * We really don't want to leave around a bunch of split blocks, since +- * bigger is better, so make sure we merge everything back before we +- * free the allocated blocks. +- */ +- buddy = __get_buddy(block); +- if (buddy && +- (drm_buddy_block_is_free(block) && +- drm_buddy_block_is_free(buddy))) +- __drm_buddy_free(mm, block, false); +- return ERR_PTR(err); +-} +- +-static struct drm_buddy_block * +-__drm_buddy_alloc_range_bias(struct drm_buddy *mm, +- u64 start, u64 end, +- unsigned int order, +- unsigned long flags) +-{ +- struct drm_buddy_block *block; +- bool fallback = false; +- +- block = __alloc_range_bias(mm, start, end, order, +- flags, fallback); +- if (IS_ERR(block)) +- return __alloc_range_bias(mm, start, end, order, +- flags, !fallback); +- +- return block; +-} +- +-static struct drm_buddy_block * +-get_maxblock(struct drm_buddy *mm, +- unsigned int order, +- enum drm_buddy_free_tree tree) +-{ +- struct drm_buddy_block *max_block = NULL, *block = NULL; +- struct rb_root *root; +- unsigned int i; +- +- for (i = order; i <= mm->max_order; ++i) { +- root = &mm->free_trees[tree][i]; +- block = rbtree_last_free_block(root); +- if (!block) +- continue; +- +- if (!max_block) { +- max_block = block; +- continue; +- } +- +- if (drm_buddy_block_offset(block) > +- drm_buddy_block_offset(max_block)) { +- max_block = block; +- } +- } +- +- return max_block; +-} +- +-static struct drm_buddy_block * +-alloc_from_freetree(struct drm_buddy *mm, +- unsigned int order, +- unsigned long flags) +-{ +- struct drm_buddy_block *block = NULL; +- struct rb_root *root; +- enum drm_buddy_free_tree tree; +- unsigned int tmp; +- int err; +- +- tree = (flags & DRM_BUDDY_CLEAR_ALLOCATION) ? +- DRM_BUDDY_CLEAR_TREE : DRM_BUDDY_DIRTY_TREE; +- +- if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) { +- block = get_maxblock(mm, order, tree); +- if (block) +- /* Store the obtained block order */ +- tmp = drm_buddy_block_order(block); +- } else { +- for (tmp = order; tmp <= mm->max_order; ++tmp) { +- /* Get RB tree root for this order and tree */ +- root = &mm->free_trees[tree][tmp]; +- block = rbtree_last_free_block(root); +- if (block) +- break; +- } +- } +- +- if (!block) { +- /* Try allocating from the other tree */ +- tree = (tree == DRM_BUDDY_CLEAR_TREE) ? +- DRM_BUDDY_DIRTY_TREE : DRM_BUDDY_CLEAR_TREE; +- +- for (tmp = order; tmp <= mm->max_order; ++tmp) { +- root = &mm->free_trees[tree][tmp]; +- block = rbtree_last_free_block(root); +- if (block) +- break; +- } +- +- if (!block) +- return ERR_PTR(-ENOSPC); +- } +- +- BUG_ON(!drm_buddy_block_is_free(block)); +- +- while (tmp != order) { +- err = split_block(mm, block); +- if (unlikely(err)) +- goto err_undo; +- +- block = block->right; +- tmp--; +- } +- return block; +- +-err_undo: +- if (tmp != order) +- __drm_buddy_free(mm, block, false); +- return ERR_PTR(err); +-} +- +-static int __alloc_range(struct drm_buddy *mm, +- struct list_head *dfs, +- u64 start, u64 size, +- struct list_head *blocks, +- u64 *total_allocated_on_err) +-{ +- struct drm_buddy_block *block; +- struct drm_buddy_block *buddy; +- u64 total_allocated = 0; +- LIST_HEAD(allocated); +- u64 end; +- int err; +- +- end = start + size - 1; +- +- do { +- u64 block_start; +- u64 block_end; +- +- block = list_first_entry_or_null(dfs, +- struct drm_buddy_block, +- tmp_link); +- if (!block) +- break; +- +- list_del(&block->tmp_link); +- +- block_start = drm_buddy_block_offset(block); +- block_end = block_start + drm_buddy_block_size(mm, block) - 1; +- +- if (!overlaps(start, end, block_start, block_end)) +- continue; +- +- if (drm_buddy_block_is_allocated(block)) { +- err = -ENOSPC; +- goto err_free; +- } +- +- if (contains(start, end, block_start, block_end)) { +- if (drm_buddy_block_is_free(block)) { +- mark_allocated(mm, block); +- total_allocated += drm_buddy_block_size(mm, block); +- mm->avail -= drm_buddy_block_size(mm, block); +- if (drm_buddy_block_is_clear(block)) +- mm->clear_avail -= drm_buddy_block_size(mm, block); +- list_add_tail(&block->link, &allocated); +- continue; +- } else if (!mm->clear_avail) { +- err = -ENOSPC; +- goto err_free; +- } +- } +- +- if (!drm_buddy_block_is_split(block)) { +- err = split_block(mm, block); +- if (unlikely(err)) +- goto err_undo; +- } +- +- list_add(&block->right->tmp_link, dfs); +- list_add(&block->left->tmp_link, dfs); +- } while (1); +- +- if (total_allocated < size) { +- err = -ENOSPC; +- goto err_free; +- } +- +- list_splice_tail(&allocated, blocks); +- +- return 0; +- +-err_undo: +- /* +- * We really don't want to leave around a bunch of split blocks, since +- * bigger is better, so make sure we merge everything back before we +- * free the allocated blocks. +- */ +- buddy = __get_buddy(block); +- if (buddy && +- (drm_buddy_block_is_free(block) && +- drm_buddy_block_is_free(buddy))) +- __drm_buddy_free(mm, block, false); +- +-err_free: +- if (err == -ENOSPC && total_allocated_on_err) { +- list_splice_tail(&allocated, blocks); +- *total_allocated_on_err = total_allocated; +- } else { +- drm_buddy_free_list_internal(mm, &allocated); +- } +- +- return err; +-} +- +-static int __drm_buddy_alloc_range(struct drm_buddy *mm, +- u64 start, +- u64 size, +- u64 *total_allocated_on_err, +- struct list_head *blocks) +-{ +- LIST_HEAD(dfs); +- int i; +- +- for (i = 0; i < mm->n_roots; ++i) +- list_add_tail(&mm->roots[i]->tmp_link, &dfs); +- +- return __alloc_range(mm, &dfs, start, size, +- blocks, total_allocated_on_err); +-} +- +-static int __alloc_contig_try_harder(struct drm_buddy *mm, +- u64 size, +- u64 min_block_size, +- struct list_head *blocks) +-{ +- u64 rhs_offset, lhs_offset, lhs_size, filled; +- struct drm_buddy_block *block; +- unsigned int tree, order; +- LIST_HEAD(blocks_lhs); +- unsigned long pages; +- u64 modify_size; +- int err; +- +- modify_size = rounddown_pow_of_two(size); +- pages = modify_size >> ilog2(mm->chunk_size); +- order = fls(pages) - 1; +- if (order == 0) +- return -ENOSPC; +- +- for_each_free_tree(tree) { +- struct rb_root *root; +- struct rb_node *iter; +- +- root = &mm->free_trees[tree][order]; +- if (rbtree_is_empty(root)) +- continue; +- +- iter = rb_last(root); +- while (iter) { +- block = rbtree_get_free_block(iter); +- +- /* Allocate blocks traversing RHS */ +- rhs_offset = drm_buddy_block_offset(block); +- err = __drm_buddy_alloc_range(mm, rhs_offset, size, +- &filled, blocks); +- if (!err || err != -ENOSPC) +- return err; +- +- lhs_size = max((size - filled), min_block_size); +- if (!IS_ALIGNED(lhs_size, min_block_size)) +- lhs_size = round_up(lhs_size, min_block_size); +- +- /* Allocate blocks traversing LHS */ +- lhs_offset = drm_buddy_block_offset(block) - lhs_size; +- err = __drm_buddy_alloc_range(mm, lhs_offset, lhs_size, +- NULL, &blocks_lhs); +- if (!err) { +- list_splice(&blocks_lhs, blocks); +- return 0; +- } else if (err != -ENOSPC) { +- drm_buddy_free_list_internal(mm, blocks); +- return err; +- } +- /* Free blocks for the next iteration */ +- drm_buddy_free_list_internal(mm, blocks); +- +- iter = rb_prev(iter); +- } +- } +- +- return -ENOSPC; +-} +- +-/** +- * drm_buddy_block_trim - free unused pages +- * +- * @mm: DRM buddy manager +- * @start: start address to begin the trimming. +- * @new_size: original size requested +- * @blocks: Input and output list of allocated blocks. +- * MUST contain single block as input to be trimmed. +- * On success will contain the newly allocated blocks +- * making up the @new_size. Blocks always appear in +- * ascending order +- * +- * For contiguous allocation, we round up the size to the nearest +- * power of two value, drivers consume *actual* size, so remaining +- * portions are unused and can be optionally freed with this function +- * +- * Returns: +- * 0 on success, error code on failure. +- */ +-int drm_buddy_block_trim(struct drm_buddy *mm, +- u64 *start, +- u64 new_size, +- struct list_head *blocks) +-{ +- struct drm_buddy_block *parent; +- struct drm_buddy_block *block; +- u64 block_start, block_end; +- LIST_HEAD(dfs); +- u64 new_start; +- int err; +- +- if (!list_is_singular(blocks)) +- return -EINVAL; +- +- block = list_first_entry(blocks, +- struct drm_buddy_block, +- link); +- +- block_start = drm_buddy_block_offset(block); +- block_end = block_start + drm_buddy_block_size(mm, block); +- +- if (WARN_ON(!drm_buddy_block_is_allocated(block))) +- return -EINVAL; +- +- if (new_size > drm_buddy_block_size(mm, block)) +- return -EINVAL; +- +- if (!new_size || !IS_ALIGNED(new_size, mm->chunk_size)) +- return -EINVAL; +- +- if (new_size == drm_buddy_block_size(mm, block)) +- return 0; +- +- new_start = block_start; +- if (start) { +- new_start = *start; +- +- if (new_start < block_start) +- return -EINVAL; +- +- if (!IS_ALIGNED(new_start, mm->chunk_size)) +- return -EINVAL; +- +- if (range_overflows(new_start, new_size, block_end)) +- return -EINVAL; +- } +- +- list_del(&block->link); +- mark_free(mm, block); +- mm->avail += drm_buddy_block_size(mm, block); +- if (drm_buddy_block_is_clear(block)) +- mm->clear_avail += drm_buddy_block_size(mm, block); +- +- /* Prevent recursively freeing this node */ +- parent = block->parent; +- block->parent = NULL; +- +- list_add(&block->tmp_link, &dfs); +- err = __alloc_range(mm, &dfs, new_start, new_size, blocks, NULL); +- if (err) { +- mark_allocated(mm, block); +- mm->avail -= drm_buddy_block_size(mm, block); +- if (drm_buddy_block_is_clear(block)) +- mm->clear_avail -= drm_buddy_block_size(mm, block); +- list_add(&block->link, blocks); +- } +- +- block->parent = parent; +- return err; +-} +-EXPORT_SYMBOL(drm_buddy_block_trim); +- +-static struct drm_buddy_block * +-__drm_buddy_alloc_blocks(struct drm_buddy *mm, +- u64 start, u64 end, +- unsigned int order, +- unsigned long flags) +-{ +- if (flags & DRM_BUDDY_RANGE_ALLOCATION) +- /* Allocate traversing within the range */ +- return __drm_buddy_alloc_range_bias(mm, start, end, +- order, flags); +- else +- /* Allocate from freetree */ +- return alloc_from_freetree(mm, order, flags); +-} +- +-/** +- * drm_buddy_alloc_blocks - allocate power-of-two blocks +- * +- * @mm: DRM buddy manager to allocate from +- * @start: start of the allowed range for this block +- * @end: end of the allowed range for this block +- * @size: size of the allocation in bytes +- * @min_block_size: alignment of the allocation +- * @blocks: output list head to add allocated blocks +- * @flags: DRM_BUDDY_*_ALLOCATION flags +- * +- * alloc_range_bias() called on range limitations, which traverses +- * the tree and returns the desired block. +- * +- * alloc_from_freetree() called when *no* range restrictions +- * are enforced, which picks the block from the freetree. +- * +- * Returns: +- * 0 on success, error code on failure. +- */ +-int drm_buddy_alloc_blocks(struct drm_buddy *mm, +- u64 start, u64 end, u64 size, +- u64 min_block_size, +- struct list_head *blocks, +- unsigned long flags) +-{ +- struct drm_buddy_block *block = NULL; +- u64 original_size, original_min_size; +- unsigned int min_order, order; +- LIST_HEAD(allocated); +- unsigned long pages; +- int err; +- +- if (size < mm->chunk_size) +- return -EINVAL; +- +- if (min_block_size < mm->chunk_size) +- return -EINVAL; +- +- if (!is_power_of_2(min_block_size)) +- return -EINVAL; +- +- if (!IS_ALIGNED(start | end | size, mm->chunk_size)) +- return -EINVAL; +- +- if (end > mm->size) +- return -EINVAL; +- +- if (range_overflows(start, size, mm->size)) +- return -EINVAL; +- +- /* Actual range allocation */ +- if (start + size == end) { +- if (!IS_ALIGNED(start | end, min_block_size)) +- return -EINVAL; +- +- return __drm_buddy_alloc_range(mm, start, size, NULL, blocks); +- } +- +- original_size = size; +- original_min_size = min_block_size; +- +- /* Roundup the size to power of 2 */ +- if (flags & DRM_BUDDY_CONTIGUOUS_ALLOCATION) { +- size = roundup_pow_of_two(size); +- min_block_size = size; +- /* Align size value to min_block_size */ +- } else if (!IS_ALIGNED(size, min_block_size)) { +- size = round_up(size, min_block_size); +- } +- +- pages = size >> ilog2(mm->chunk_size); +- order = fls(pages) - 1; +- min_order = ilog2(min_block_size) - ilog2(mm->chunk_size); +- +- if (order > mm->max_order || size > mm->size) { +- if ((flags & DRM_BUDDY_CONTIGUOUS_ALLOCATION) && +- !(flags & DRM_BUDDY_RANGE_ALLOCATION)) +- return __alloc_contig_try_harder(mm, original_size, +- original_min_size, blocks); +- +- return -EINVAL; +- } +- +- do { +- order = min(order, (unsigned int)fls(pages) - 1); +- BUG_ON(order > mm->max_order); +- BUG_ON(order < min_order); +- +- do { +- block = __drm_buddy_alloc_blocks(mm, start, +- end, +- order, +- flags); +- if (!IS_ERR(block)) +- break; +- +- if (order-- == min_order) { +- /* Try allocation through force merge method */ +- if (mm->clear_avail && +- !__force_merge(mm, start, end, min_order)) { +- block = __drm_buddy_alloc_blocks(mm, start, +- end, +- min_order, +- flags); +- if (!IS_ERR(block)) { +- order = min_order; +- break; +- } +- } +- +- /* +- * Try contiguous block allocation through +- * try harder method. +- */ +- if (flags & DRM_BUDDY_CONTIGUOUS_ALLOCATION && +- !(flags & DRM_BUDDY_RANGE_ALLOCATION)) +- return __alloc_contig_try_harder(mm, +- original_size, +- original_min_size, +- blocks); +- err = -ENOSPC; +- goto err_free; +- } +- } while (1); +- +- mark_allocated(mm, block); +- mm->avail -= drm_buddy_block_size(mm, block); +- if (drm_buddy_block_is_clear(block)) +- mm->clear_avail -= drm_buddy_block_size(mm, block); +- kmemleak_update_trace(block); +- list_add_tail(&block->link, &allocated); +- +- pages -= BIT(order); +- +- if (!pages) +- break; +- } while (1); +- +- /* Trim the allocated block to the required size */ +- if (!(flags & DRM_BUDDY_TRIM_DISABLE) && +- original_size != size) { +- struct list_head *trim_list; +- LIST_HEAD(temp); +- u64 trim_size; +- +- trim_list = &allocated; +- trim_size = original_size; +- +- if (!list_is_singular(&allocated)) { +- block = list_last_entry(&allocated, typeof(*block), link); +- list_move(&block->link, &temp); +- trim_list = &temp; +- trim_size = drm_buddy_block_size(mm, block) - +- (size - original_size); +- } +- +- drm_buddy_block_trim(mm, +- NULL, +- trim_size, +- trim_list); +- +- if (!list_empty(&temp)) +- list_splice_tail(trim_list, &allocated); +- } +- +- list_splice_tail(&allocated, blocks); +- return 0; +- +-err_free: +- drm_buddy_free_list_internal(mm, &allocated); +- return err; +-} +-EXPORT_SYMBOL(drm_buddy_alloc_blocks); ++#include <drm/drm_print.h> + + /** + * drm_buddy_block_print - print block information +@@ -1262,12 +21,12 @@ EXPORT_SYMBOL(drm_buddy_alloc_blocks); + * @block: DRM buddy block + * @p: DRM printer to use + */ +-void drm_buddy_block_print(struct drm_buddy *mm, +- struct drm_buddy_block *block, ++void drm_buddy_block_print(struct gpu_buddy *mm, ++ struct gpu_buddy_block *block, + struct drm_printer *p) + { +- u64 start = drm_buddy_block_offset(block); +- u64 size = drm_buddy_block_size(mm, block); ++ u64 start = gpu_buddy_block_offset(block); ++ u64 size = gpu_buddy_block_size(mm, block); + + drm_printf(p, "%#018llx-%#018llx: %llu\n", start, start + size, size); + } +@@ -1279,7 +38,7 @@ EXPORT_SYMBOL(drm_buddy_block_print); + * @mm: DRM buddy manager + * @p: DRM printer to use + */ +-void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p) ++void drm_buddy_print(struct gpu_buddy *mm, struct drm_printer *p) + { + int order; + +@@ -1287,7 +46,7 @@ void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p) + mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20, mm->clear_avail >> 20); + + for (order = mm->max_order; order >= 0; order--) { +- struct drm_buddy_block *block, *tmp; ++ struct gpu_buddy_block *block, *tmp; + struct rb_root *root; + u64 count = 0, free; + unsigned int tree; +@@ -1296,7 +55,7 @@ void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p) + root = &mm->free_trees[tree][order]; + + rbtree_postorder_for_each_entry_safe(block, tmp, root, rb) { +- BUG_ON(!drm_buddy_block_is_free(block)); ++ BUG_ON(!gpu_buddy_block_is_free(block)); + count++; + } + } +@@ -1314,22 +73,5 @@ void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p) + } + EXPORT_SYMBOL(drm_buddy_print); + +-static void drm_buddy_module_exit(void) +-{ +- kmem_cache_destroy(slab_blocks); +-} +- +-static int __init drm_buddy_module_init(void) +-{ +- slab_blocks = KMEM_CACHE(drm_buddy_block, 0); +- if (!slab_blocks) +- return -ENOMEM; +- +- return 0; +-} +- +-module_init(drm_buddy_module_init); +-module_exit(drm_buddy_module_exit); +- +-MODULE_DESCRIPTION("DRM Buddy Allocator"); ++MODULE_DESCRIPTION("DRM-specific GPU Buddy Allocator Print Helpers"); + MODULE_LICENSE("Dual MIT/GPL"); +diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c +index 272d6254ea4784..0326b9adb5f12c 100644 +--- a/drivers/gpu/drm/drm_connector.c ++++ b/drivers/gpu/drm/drm_connector.c +@@ -3554,7 +3554,7 @@ EXPORT_SYMBOL(drm_mode_put_tile_group); + /** + * drm_mode_get_tile_group - get a reference to an existing tile group + * @dev: DRM device +- * @topology: 8-bytes unique per monitor. ++ * @topology_id: 9-byte unique ID per monitor. + * + * Use the unique bytes to get a reference to an existing tile group. + * +@@ -3562,14 +3562,14 @@ EXPORT_SYMBOL(drm_mode_put_tile_group); + * tile group or NULL if not found. + */ + struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, +- const char topology[8]) ++ const char topology_id[9]) + { + struct drm_tile_group *tg; + int id; + + mutex_lock(&dev->mode_config.idr_mutex); + idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { +- if (!memcmp(tg->group_data, topology, 8)) { ++ if (!memcmp(tg->group_data, topology_id, sizeof(tg->group_data))) { + if (!kref_get_unless_zero(&tg->refcount)) + tg = NULL; + mutex_unlock(&dev->mode_config.idr_mutex); +@@ -3584,7 +3584,7 @@ EXPORT_SYMBOL(drm_mode_get_tile_group); + /** + * drm_mode_create_tile_group - create a tile group from a displayid description + * @dev: DRM device +- * @topology: 8-bytes unique per monitor. ++ * @topology_id: 9-byte unique ID per monitor. + * + * Create a tile group for the unique monitor, and get a unique + * identifier for the tile group. +@@ -3593,7 +3593,7 @@ EXPORT_SYMBOL(drm_mode_get_tile_group); + * new tile group or NULL. + */ + struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, +- const char topology[8]) ++ const char topology_id[9]) + { + struct drm_tile_group *tg; + int ret; +@@ -3603,7 +3603,7 @@ struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, + return NULL; + + kref_init(&tg->refcount); +- memcpy(tg->group_data, topology, 8); ++ memcpy(tg->group_data, topology_id, sizeof(tg->group_data)); + tg->dev = dev; + + mutex_lock(&dev->mode_config.idr_mutex); +diff --git a/drivers/gpu/drm/drm_displayid_internal.h b/drivers/gpu/drm/drm_displayid_internal.h +index 5b1b32f7351662..4590d6a3d82152 100644 +--- a/drivers/gpu/drm/drm_displayid_internal.h ++++ b/drivers/gpu/drm/drm_displayid_internal.h +@@ -109,7 +109,7 @@ struct displayid_tiled_block { + u8 topo[3]; + u8 tile_size[4]; + u8 tile_pixel_bezel[5]; +- u8 topology_id[8]; ++ u8 topology_id[9]; + } __packed; + + struct displayid_detailed_timings_1 { +diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c +index 4cde5bf4aedd86..781cd4e5b704f1 100644 +--- a/drivers/gpu/drm/drm_gpusvm.c ++++ b/drivers/gpu/drm/drm_gpusvm.c +@@ -1566,8 +1566,10 @@ int drm_gpusvm_range_evict(struct drm_gpusvm *gpusvm, + return -EFAULT; + + pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL); +- if (!pfns) ++ if (!pfns) { ++ mmput(mm); + return -ENOMEM; ++ } + + hmm_range.hmm_pfns = pfns; + while (!time_after(jiffies, timeout)) { +diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c +index 537dc6dd053439..2d0238382ebd59 100644 +--- a/drivers/gpu/drm/drm_panel_backlight_quirks.c ++++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c +@@ -21,6 +21,15 @@ struct drm_get_panel_backlight_quirk { + }; + + static const struct drm_get_panel_backlight_quirk drm_panel_min_backlight_quirks[] = { ++ /* Lenovo Legion 5 15ARH05, AUX backlight non-functional, force PWM */ ++ { ++ .dmi_match.field = DMI_SYS_VENDOR, ++ .dmi_match.value = "LENOVO", ++ .dmi_match_other.field = DMI_PRODUCT_VERSION, ++ .dmi_match_other.value = "Lenovo Legion 5 15ARH05", ++ .ident.panel_id = drm_edid_encode_panel_id('B', 'O', 'E', 0x08df), ++ .quirk = { .force_pwm = true, }, ++ }, + /* 13 inch matte panel */ + { + .dmi_match.field = DMI_BOARD_VENDOR, +diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c +index 3596dce84c2863..a2b6f40b4b0c0b 100644 +--- a/drivers/gpu/drm/i915/display/intel_bios.c ++++ b/drivers/gpu/drm/i915/display/intel_bios.c +@@ -624,6 +624,21 @@ get_lfp_data_tail(const struct bdb_lfp_data *data, + return NULL; + } + ++static bool is_panel_type_valid(int panel_type) ++{ ++ return panel_type >= 0 && panel_type < 16; ++} ++ ++static bool is_panel_type_pnp(int panel_type) ++{ ++ return panel_type == 0xff; ++} ++ ++static bool is_panel_type_valid_or_pnp(int panel_type) ++{ ++ return is_panel_type_valid(panel_type) || is_panel_type_pnp(panel_type); ++} ++ + static int opregion_get_panel_type(struct intel_display *display, + const struct intel_bios_encoder_data *devdata, + const struct drm_edid *drm_edid, bool use_fallback) +@@ -641,15 +656,21 @@ static int vbt_get_panel_type(struct intel_display *display, + if (!lfp_options) + return -1; + +- if (lfp_options->panel_type > 0xf && +- lfp_options->panel_type != 0xff) { ++ if (!is_panel_type_valid_or_pnp(lfp_options->panel_type)) { + drm_dbg_kms(display->drm, "Invalid VBT panel type 0x%x\n", + lfp_options->panel_type); + return -1; + } + +- if (devdata && devdata->child.handle == DEVICE_HANDLE_LFP2) ++ if (devdata && devdata->child.handle == DEVICE_HANDLE_LFP2) { ++ if (!is_panel_type_valid_or_pnp(lfp_options->panel_type2)) { ++ drm_dbg_kms(display->drm, "Invalid VBT panel type 2 0x%x\n", ++ lfp_options->panel_type2); ++ return -1; ++ } ++ + return lfp_options->panel_type2; ++ } + + drm_WARN_ON(display->drm, + devdata && devdata->child.handle != DEVICE_HANDLE_LFP1); +@@ -763,13 +784,12 @@ static int get_panel_type(struct intel_display *display, + panel_types[i].name, panel_types[i].panel_type); + } + +- if (panel_types[PANEL_TYPE_OPREGION].panel_type >= 0) ++ if (is_panel_type_valid(panel_types[PANEL_TYPE_OPREGION].panel_type)) + i = PANEL_TYPE_OPREGION; +- else if (panel_types[PANEL_TYPE_VBT].panel_type == 0xff && +- panel_types[PANEL_TYPE_PNPID].panel_type >= 0) ++ else if (is_panel_type_pnp(panel_types[PANEL_TYPE_VBT].panel_type) && ++ is_panel_type_valid(panel_types[PANEL_TYPE_PNPID].panel_type)) + i = PANEL_TYPE_PNPID; +- else if (panel_types[PANEL_TYPE_VBT].panel_type != 0xff && +- panel_types[PANEL_TYPE_VBT].panel_type >= 0) ++ else if (is_panel_type_valid(panel_types[PANEL_TYPE_VBT].panel_type)) + i = PANEL_TYPE_VBT; + else + i = PANEL_TYPE_FALLBACK; +diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c +index c7886b36477067..2a0750acf20537 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp.c ++++ b/drivers/gpu/drm/i915/display/intel_dp.c +@@ -5203,8 +5203,9 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp) + struct intel_encoder *encoder = &dig_port->base; + bool link_ok = true; + bool reprobe_needed = false; ++ int tries = 33; + +- for (;;) { ++ while (--tries) { + u8 esi[4] = {}; + u8 ack[4] = {}; + +@@ -5247,6 +5248,11 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp) + if (!link_ok || intel_dp->link.force_retrain) + intel_encoder_link_check_queue_work(encoder, 0); + ++ if (!tries) { ++ drm_dbg_kms(display->drm, "DPRX ESI not clearing, device may be stuck\n"); ++ reprobe_needed = true; ++ } ++ + return !reprobe_needed; + } + +diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c +index 531ee122bf8222..68503a3f945e09 100644 +--- a/drivers/gpu/drm/i915/display/intel_hdcp.c ++++ b/drivers/gpu/drm/i915/display/intel_hdcp.c +@@ -140,6 +140,9 @@ intel_hdcp_required_content_stream(struct intel_atomic_state *state, + if (conn_dig_port != dig_port) + continue; + ++ if (drm_WARN_ON(display->drm, data->k >= INTEL_NUM_PIPES(display))) ++ return -EINVAL; ++ + data->streams[data->k].stream_id = + intel_conn_to_vcpi(state, connector); + data->k++; +@@ -150,7 +153,7 @@ intel_hdcp_required_content_stream(struct intel_atomic_state *state, + } + drm_connector_list_iter_end(&conn_iter); + +- if (drm_WARN_ON(display->drm, data->k > INTEL_NUM_PIPES(display) || data->k == 0)) ++ if (drm_WARN_ON(display->drm, !data->k)) + return -EINVAL; + + /* +@@ -1794,9 +1797,10 @@ int hdcp2_authenticate_repeater_topology(struct intel_connector *connector) + return -EINVAL; + } + +- if (seq_num_v < hdcp->seq_num_v) { +- /* Roll over of the seq_num_v from repeater. Reauthenticate. */ +- drm_dbg_kms(display->drm, "Seq_num_v roll over.\n"); ++ if (hdcp->hdcp2_encrypted && seq_num_v <= hdcp->seq_num_v) { ++ /* Reauthenticate on Seq_num_v repeat or rollover */ ++ drm_dbg_kms(display->drm, "Seq_num_v %s\n", ++ seq_num_v == hdcp->seq_num_v ? "repeat" : "rollover"); + return -EINVAL; + } + +diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c +index a5862998bf1447..eb54fffc698864 100644 +--- a/drivers/gpu/drm/i915/display/skl_watermark.c ++++ b/drivers/gpu/drm/i915/display/skl_watermark.c +@@ -3815,7 +3815,7 @@ void skl_wm_plane_disable_noatomic(struct intel_crtc *crtc, + return; + + skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb[plane->id], 0, 0); +- skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb[plane->id], 0, 0); ++ skl_ddb_entry_init(&crtc_state->wm.skl.plane_ddb_y[plane->id], 0, 0); + + crtc_state->wm.skl.plane_min_ddb[plane->id] = 0; + crtc_state->wm.skl.plane_interim_ddb[plane->id] = 0; +diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c +index ed6599694835f2..ae5194625508f9 100644 +--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c ++++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c +@@ -612,6 +612,7 @@ set_proto_ctx_engines_parallel_submit(struct i915_user_extension __user *base, + return -EINVAL; + } + ++ slot = array_index_nospec(slot, set->num_engines); + if (set->engines[slot].type != I915_GEM_ENGINE_TYPE_INVALID) { + drm_dbg(&i915->drm, + "Invalid placement[%d], already occupied\n", slot); +@@ -769,8 +770,8 @@ static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv, + struct intel_engine_cs *engine; + + if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) { +- kfree(set.engines); +- return -EFAULT; ++ err = -EFAULT; ++ goto err; + } + + memset(&set.engines[n], 0, sizeof(set.engines[n])); +@@ -786,8 +787,8 @@ static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv, + drm_dbg(&i915->drm, + "Invalid engine[%d]: { class:%d, instance:%d }\n", + n, ci.engine_class, ci.engine_instance); +- kfree(set.engines); +- return -ENOENT; ++ err = -ENOENT; ++ goto err; + } + + set.engines[n].type = I915_GEM_ENGINE_TYPE_PHYSICAL; +@@ -800,15 +801,21 @@ static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv, + set_proto_ctx_engines_extensions, + ARRAY_SIZE(set_proto_ctx_engines_extensions), + &set); +- if (err) { +- kfree(set.engines); +- return err; +- } ++ if (err) ++ goto err_extensions; + + pc->num_user_engines = set.num_engines; + pc->user_engines = set.engines; + + return 0; ++ ++err_extensions: ++ for (n = 0; n < set.num_engines; n++) ++ kfree(set.engines[n].siblings); ++err: ++ kfree(set.engines); ++ ++ return err; + } + + static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv, +@@ -850,7 +857,7 @@ static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv, + pe = &pc->user_engines[idx]; + + /* Only render engine supports RPCS configuration. */ +- if (pe->engine->class != RENDER_CLASS) ++ if (!pe->engine || pe->engine->class != RENDER_CLASS) + return -EINVAL; + + sseu = &pe->sseu; +diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +index 3d53c54eb48fe0..d17695ae0a31c9 100644 +--- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c ++++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +@@ -5,9 +5,10 @@ + + #include <linux/shmem_fs.h> + ++#include <linux/gpu_buddy.h> ++#include <drm/drm_print.h> + #include <drm/ttm/ttm_placement.h> + #include <drm/ttm/ttm_tt.h> +-#include <drm/drm_buddy.h> + + #include "i915_drv.h" + #include "i915_ttm_buddy_manager.h" +diff --git a/drivers/gpu/drm/i915/gt/intel_engine_user.c b/drivers/gpu/drm/i915/gt/intel_engine_user.c +index 833987015b8bbc..ed42b9d05a07d5 100644 +--- a/drivers/gpu/drm/i915/gt/intel_engine_user.c ++++ b/drivers/gpu/drm/i915/gt/intel_engine_user.c +@@ -257,7 +257,7 @@ void intel_engines_driver_register(struct drm_i915_private *i915) + p = &prev->rb_right; + } + +- if (IS_ENABLED(CONFIG_DRM_I915_SELFTESTS) && ++ if (IS_ENABLED(CONFIG_DRM_I915_SELFTEST) && + IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) { + struct intel_engine_cs *engine; + unsigned int isolation; +diff --git a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c +index 33351deeea4f0b..07eaf71955c447 100644 +--- a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c ++++ b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c +@@ -16,9 +16,9 @@ static int cmp_u64(const void *A, const void *B) + { + const u64 *a = A, *b = B; + +- if (a < b) ++ if (*a < *b) + return -1; +- else if (a > b) ++ else if (*a > *b) + return 1; + else + return 0; +@@ -28,9 +28,9 @@ static int cmp_u32(const void *A, const void *B) + { + const u32 *a = A, *b = B; + +- if (a < b) ++ if (*a < *b) + return -1; +- else if (a > b) ++ else if (*a > *b) + return 1; + else + return 0; +diff --git a/drivers/gpu/drm/i915/i915_active.c b/drivers/gpu/drm/i915/i915_active.c +index 6b0c1162505ac2..bbcfdf23c0a7d8 100644 +--- a/drivers/gpu/drm/i915/i915_active.c ++++ b/drivers/gpu/drm/i915/i915_active.c +@@ -318,7 +318,7 @@ active_instance(struct i915_active *ref, u64 idx) + */ + node = kmem_cache_alloc(slab_cache, GFP_ATOMIC); + if (!node) +- goto out; ++ goto err; + + __i915_active_fence_init(&node->base, NULL, node_retire); + node->ref = ref; +@@ -332,6 +332,11 @@ out: + spin_unlock_irq(&ref->tree_lock); + + return &node->base; ++ ++err: ++ spin_unlock_irq(&ref->tree_lock); ++ ++ return NULL; + } + + void __i915_active_init(struct i915_active *ref, +diff --git a/drivers/gpu/drm/i915/i915_scatterlist.c b/drivers/gpu/drm/i915/i915_scatterlist.c +index 4d830740946da3..6a34dae13769e8 100644 +--- a/drivers/gpu/drm/i915/i915_scatterlist.c ++++ b/drivers/gpu/drm/i915/i915_scatterlist.c +@@ -7,7 +7,7 @@ + #include "i915_scatterlist.h" + #include "i915_ttm_buddy_manager.h" + +-#include <drm/drm_buddy.h> ++#include <linux/gpu_buddy.h> + #include <drm/drm_mm.h> + + #include <linux/slab.h> +@@ -167,9 +167,9 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res, + struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res); + const u64 size = res->size; + const u32 max_segment = round_down(UINT_MAX, page_alignment); +- struct drm_buddy *mm = bman_res->mm; ++ struct gpu_buddy *mm = bman_res->mm; + struct list_head *blocks = &bman_res->blocks; +- struct drm_buddy_block *block; ++ struct gpu_buddy_block *block; + struct i915_refct_sgt *rsgt; + struct scatterlist *sg; + struct sg_table *st; +@@ -202,8 +202,8 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res, + list_for_each_entry(block, blocks, link) { + u64 block_size, offset; + +- block_size = min_t(u64, size, drm_buddy_block_size(mm, block)); +- offset = drm_buddy_block_offset(block); ++ block_size = min_t(u64, size, gpu_buddy_block_size(mm, block)); ++ offset = gpu_buddy_block_offset(block); + + while (block_size) { + u64 len; +diff --git a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c +index 942345548bc323..c5ca90088705a5 100644 +--- a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c ++++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c +@@ -5,18 +5,19 @@ + + #include <linux/slab.h> + ++#include <linux/gpu_buddy.h> ++#include <drm/drm_buddy.h> ++#include <drm/drm_print.h> + #include <drm/ttm/ttm_placement.h> + #include <drm/ttm/ttm_bo.h> + +-#include <drm/drm_buddy.h> +- + #include "i915_ttm_buddy_manager.h" + + #include "i915_gem.h" + + struct i915_ttm_buddy_manager { + struct ttm_resource_manager manager; +- struct drm_buddy mm; ++ struct gpu_buddy mm; + struct list_head reserved; + struct mutex lock; + unsigned long visible_size; +@@ -38,7 +39,7 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, + { + struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); + struct i915_ttm_buddy_resource *bman_res; +- struct drm_buddy *mm = &bman->mm; ++ struct gpu_buddy *mm = &bman->mm; + unsigned long n_pages, lpfn; + u64 min_page_size; + u64 size; +@@ -57,13 +58,13 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, + bman_res->mm = mm; + + if (place->flags & TTM_PL_FLAG_TOPDOWN) +- bman_res->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION; ++ bman_res->flags |= GPU_BUDDY_TOPDOWN_ALLOCATION; + + if (place->flags & TTM_PL_FLAG_CONTIGUOUS) +- bman_res->flags |= DRM_BUDDY_CONTIGUOUS_ALLOCATION; ++ bman_res->flags |= GPU_BUDDY_CONTIGUOUS_ALLOCATION; + + if (place->fpfn || lpfn != man->size) +- bman_res->flags |= DRM_BUDDY_RANGE_ALLOCATION; ++ bman_res->flags |= GPU_BUDDY_RANGE_ALLOCATION; + + GEM_BUG_ON(!bman_res->base.size); + size = bman_res->base.size; +@@ -89,7 +90,7 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, + goto err_free_res; + } + +- err = drm_buddy_alloc_blocks(mm, (u64)place->fpfn << PAGE_SHIFT, ++ err = gpu_buddy_alloc_blocks(mm, (u64)place->fpfn << PAGE_SHIFT, + (u64)lpfn << PAGE_SHIFT, + (u64)n_pages << PAGE_SHIFT, + min_page_size, +@@ -101,15 +102,15 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, + if (lpfn <= bman->visible_size) { + bman_res->used_visible_size = PFN_UP(bman_res->base.size); + } else { +- struct drm_buddy_block *block; ++ struct gpu_buddy_block *block; + + list_for_each_entry(block, &bman_res->blocks, link) { + unsigned long start = +- drm_buddy_block_offset(block) >> PAGE_SHIFT; ++ gpu_buddy_block_offset(block) >> PAGE_SHIFT; + + if (start < bman->visible_size) { + unsigned long end = start + +- (drm_buddy_block_size(mm, block) >> PAGE_SHIFT); ++ (gpu_buddy_block_size(mm, block) >> PAGE_SHIFT); + + bman_res->used_visible_size += + min(end, bman->visible_size) - start; +@@ -126,7 +127,7 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, + return 0; + + err_free_blocks: +- drm_buddy_free_list(mm, &bman_res->blocks, 0); ++ gpu_buddy_free_list(mm, &bman_res->blocks, 0); + mutex_unlock(&bman->lock); + err_free_res: + ttm_resource_fini(man, &bman_res->base); +@@ -141,7 +142,7 @@ static void i915_ttm_buddy_man_free(struct ttm_resource_manager *man, + struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); + + mutex_lock(&bman->lock); +- drm_buddy_free_list(&bman->mm, &bman_res->blocks, 0); ++ gpu_buddy_free_list(&bman->mm, &bman_res->blocks, 0); + bman->visible_avail += bman_res->used_visible_size; + mutex_unlock(&bman->lock); + +@@ -156,8 +157,8 @@ static bool i915_ttm_buddy_man_intersects(struct ttm_resource_manager *man, + { + struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res); + struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); +- struct drm_buddy *mm = &bman->mm; +- struct drm_buddy_block *block; ++ struct gpu_buddy *mm = &bman->mm; ++ struct gpu_buddy_block *block; + + if (!place->fpfn && !place->lpfn) + return true; +@@ -176,9 +177,9 @@ static bool i915_ttm_buddy_man_intersects(struct ttm_resource_manager *man, + /* Check each drm buddy block individually */ + list_for_each_entry(block, &bman_res->blocks, link) { + unsigned long fpfn = +- drm_buddy_block_offset(block) >> PAGE_SHIFT; ++ gpu_buddy_block_offset(block) >> PAGE_SHIFT; + unsigned long lpfn = fpfn + +- (drm_buddy_block_size(mm, block) >> PAGE_SHIFT); ++ (gpu_buddy_block_size(mm, block) >> PAGE_SHIFT); + + if (place->fpfn < lpfn && place->lpfn > fpfn) + return true; +@@ -194,8 +195,8 @@ static bool i915_ttm_buddy_man_compatible(struct ttm_resource_manager *man, + { + struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res); + struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); +- struct drm_buddy *mm = &bman->mm; +- struct drm_buddy_block *block; ++ struct gpu_buddy *mm = &bman->mm; ++ struct gpu_buddy_block *block; + + if (!place->fpfn && !place->lpfn) + return true; +@@ -209,9 +210,9 @@ static bool i915_ttm_buddy_man_compatible(struct ttm_resource_manager *man, + /* Check each drm buddy block individually */ + list_for_each_entry(block, &bman_res->blocks, link) { + unsigned long fpfn = +- drm_buddy_block_offset(block) >> PAGE_SHIFT; ++ gpu_buddy_block_offset(block) >> PAGE_SHIFT; + unsigned long lpfn = fpfn + +- (drm_buddy_block_size(mm, block) >> PAGE_SHIFT); ++ (gpu_buddy_block_size(mm, block) >> PAGE_SHIFT); + + if (fpfn < place->fpfn || lpfn > place->lpfn) + return false; +@@ -224,7 +225,7 @@ static void i915_ttm_buddy_man_debug(struct ttm_resource_manager *man, + struct drm_printer *printer) + { + struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); +- struct drm_buddy_block *block; ++ struct gpu_buddy_block *block; + + mutex_lock(&bman->lock); + drm_printf(printer, "default_page_size: %lluKiB\n", +@@ -293,7 +294,7 @@ int i915_ttm_buddy_man_init(struct ttm_device *bdev, + if (!bman) + return -ENOMEM; + +- err = drm_buddy_init(&bman->mm, size, chunk_size); ++ err = gpu_buddy_init(&bman->mm, size, chunk_size); + if (err) + goto err_free_bman; + +@@ -333,7 +334,7 @@ int i915_ttm_buddy_man_fini(struct ttm_device *bdev, unsigned int type) + { + struct ttm_resource_manager *man = ttm_manager_type(bdev, type); + struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); +- struct drm_buddy *mm = &bman->mm; ++ struct gpu_buddy *mm = &bman->mm; + int ret; + + ttm_resource_manager_set_used(man, false); +@@ -345,8 +346,8 @@ int i915_ttm_buddy_man_fini(struct ttm_device *bdev, unsigned int type) + ttm_set_driver_manager(bdev, type, NULL); + + mutex_lock(&bman->lock); +- drm_buddy_free_list(mm, &bman->reserved, 0); +- drm_buddy_fini(mm); ++ gpu_buddy_free_list(mm, &bman->reserved, 0); ++ gpu_buddy_fini(mm); + bman->visible_avail += bman->visible_reserved; + WARN_ON_ONCE(bman->visible_avail != bman->visible_size); + mutex_unlock(&bman->lock); +@@ -371,15 +372,15 @@ int i915_ttm_buddy_man_reserve(struct ttm_resource_manager *man, + u64 start, u64 size) + { + struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); +- struct drm_buddy *mm = &bman->mm; ++ struct gpu_buddy *mm = &bman->mm; + unsigned long fpfn = start >> PAGE_SHIFT; + unsigned long flags = 0; + int ret; + +- flags |= DRM_BUDDY_RANGE_ALLOCATION; ++ flags |= GPU_BUDDY_RANGE_ALLOCATION; + + mutex_lock(&bman->lock); +- ret = drm_buddy_alloc_blocks(mm, start, ++ ret = gpu_buddy_alloc_blocks(mm, start, + start + size, + size, mm->chunk_size, + &bman->reserved, +diff --git a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.h b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.h +index d6462071283039..1cff018c1689af 100644 +--- a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.h ++++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.h +@@ -13,7 +13,7 @@ + + struct ttm_device; + struct ttm_resource_manager; +-struct drm_buddy; ++struct gpu_buddy; + + /** + * struct i915_ttm_buddy_resource +@@ -33,7 +33,7 @@ struct i915_ttm_buddy_resource { + struct list_head blocks; + unsigned long flags; + unsigned long used_visible_size; +- struct drm_buddy *mm; ++ struct gpu_buddy *mm; + }; + + /** +diff --git a/drivers/gpu/drm/i915/selftests/intel_memory_region.c b/drivers/gpu/drm/i915/selftests/intel_memory_region.c +index 7b856b5090f9a3..8307390943a2f3 100644 +--- a/drivers/gpu/drm/i915/selftests/intel_memory_region.c ++++ b/drivers/gpu/drm/i915/selftests/intel_memory_region.c +@@ -6,7 +6,7 @@ + #include <linux/prime_numbers.h> + #include <linux/sort.h> + +-#include <drm/drm_buddy.h> ++#include <linux/gpu_buddy.h> + + #include "../i915_selftest.h" + +@@ -371,7 +371,7 @@ static int igt_mock_splintered_region(void *arg) + struct drm_i915_private *i915 = mem->i915; + struct i915_ttm_buddy_resource *res; + struct drm_i915_gem_object *obj; +- struct drm_buddy *mm; ++ struct gpu_buddy *mm; + unsigned int expected_order; + LIST_HEAD(objects); + u64 size; +@@ -447,8 +447,8 @@ static int igt_mock_max_segment(void *arg) + struct drm_i915_private *i915 = mem->i915; + struct i915_ttm_buddy_resource *res; + struct drm_i915_gem_object *obj; +- struct drm_buddy_block *block; +- struct drm_buddy *mm; ++ struct gpu_buddy_block *block; ++ struct gpu_buddy *mm; + struct list_head *blocks; + struct scatterlist *sg; + I915_RND_STATE(prng); +@@ -487,8 +487,8 @@ static int igt_mock_max_segment(void *arg) + mm = res->mm; + size = 0; + list_for_each_entry(block, blocks, link) { +- if (drm_buddy_block_size(mm, block) > size) +- size = drm_buddy_block_size(mm, block); ++ if (gpu_buddy_block_size(mm, block) > size) ++ size = gpu_buddy_block_size(mm, block); + } + if (size < max_segment) { + pr_err("%s: Failed to create a huge contiguous block [> %u], largest block %lld\n", +@@ -527,14 +527,14 @@ static u64 igt_object_mappable_total(struct drm_i915_gem_object *obj) + struct intel_memory_region *mr = obj->mm.region; + struct i915_ttm_buddy_resource *bman_res = + to_ttm_buddy_resource(obj->mm.res); +- struct drm_buddy *mm = bman_res->mm; +- struct drm_buddy_block *block; ++ struct gpu_buddy *mm = bman_res->mm; ++ struct gpu_buddy_block *block; + u64 total; + + total = 0; + list_for_each_entry(block, &bman_res->blocks, link) { +- u64 start = drm_buddy_block_offset(block); +- u64 end = start + drm_buddy_block_size(mm, block); ++ u64 start = gpu_buddy_block_offset(block); ++ u64 end = start + gpu_buddy_block_size(mm, block); + + if (start < resource_size(&mr->io)) + total += min_t(u64, end, resource_size(&mr->io)) - start; +diff --git a/drivers/gpu/drm/imagination/pvr_context.c b/drivers/gpu/drm/imagination/pvr_context.c +index 5edc3c01af72bd..d9066a4fefcf3d 100644 +--- a/drivers/gpu/drm/imagination/pvr_context.c ++++ b/drivers/gpu/drm/imagination/pvr_context.c +@@ -161,22 +161,24 @@ ctx_fw_data_init(void *cpu_ptr, void *priv) + /** + * pvr_context_destroy_queues() - Destroy all queues attached to a context. + * @ctx: Context to destroy queues on. ++ * @cleanup_queue_entity: Whether to cleanup the queue entity e.g. context ++ * creation failure path. + * + * Should be called when the last reference to a context object is dropped. + * It releases all resources attached to the queues bound to this context. + */ +-static void pvr_context_destroy_queues(struct pvr_context *ctx) ++static void pvr_context_destroy_queues(struct pvr_context *ctx, bool cleanup_queue_entity) + { + switch (ctx->type) { + case DRM_PVR_CTX_TYPE_RENDER: +- pvr_queue_destroy(ctx->queues.fragment); +- pvr_queue_destroy(ctx->queues.geometry); ++ pvr_queue_destroy(ctx->queues.fragment, cleanup_queue_entity); ++ pvr_queue_destroy(ctx->queues.geometry, cleanup_queue_entity); + break; + case DRM_PVR_CTX_TYPE_COMPUTE: +- pvr_queue_destroy(ctx->queues.compute); ++ pvr_queue_destroy(ctx->queues.compute, cleanup_queue_entity); + break; + case DRM_PVR_CTX_TYPE_TRANSFER_FRAG: +- pvr_queue_destroy(ctx->queues.transfer); ++ pvr_queue_destroy(ctx->queues.transfer, cleanup_queue_entity); + break; + } + } +@@ -240,7 +242,7 @@ static int pvr_context_create_queues(struct pvr_context *ctx, + return -EINVAL; + + err_destroy_queues: +- pvr_context_destroy_queues(ctx); ++ pvr_context_destroy_queues(ctx, true); + return err; + } + +@@ -307,8 +309,8 @@ int pvr_context_create(struct pvr_file *pvr_file, struct drm_pvr_ioctl_create_co + goto err_free_ctx; + + ctx->vm_ctx = pvr_vm_context_lookup(pvr_file, args->vm_context_handle); +- if (IS_ERR(ctx->vm_ctx)) { +- err = PTR_ERR(ctx->vm_ctx); ++ if (!ctx->vm_ctx) { ++ err = -EINVAL; + goto err_free_ctx; + } + +@@ -356,7 +358,7 @@ err_destroy_fw_obj: + pvr_fw_object_destroy(ctx->fw_obj); + + err_destroy_queues: +- pvr_context_destroy_queues(ctx); ++ pvr_context_destroy_queues(ctx, true); + + err_free_ctx_data: + kfree(ctx->data); +@@ -382,7 +384,7 @@ pvr_context_release(struct kref *ref_count) + spin_unlock(&pvr_dev->ctx_list_lock); + + xa_erase(&pvr_dev->ctx_ids, ctx->ctx_id); +- pvr_context_destroy_queues(ctx); ++ pvr_context_destroy_queues(ctx, false); + pvr_fw_object_destroy(ctx->fw_obj); + kfree(ctx->data); + pvr_vm_context_put(ctx->vm_ctx); +diff --git a/drivers/gpu/drm/imagination/pvr_drv.c b/drivers/gpu/drm/imagination/pvr_drv.c +index 916b40ced7eb04..e403411cf9639e 100644 +--- a/drivers/gpu/drm/imagination/pvr_drv.c ++++ b/drivers/gpu/drm/imagination/pvr_drv.c +@@ -1252,14 +1252,13 @@ pvr_set_uobj_array(const struct drm_pvr_obj_array *out, u32 min_stride, u32 obj_ + if (copy_to_user(out_ptr, in_ptr, cpy_elem_size)) + return -EFAULT; + +- out_ptr += obj_size; +- in_ptr += out->stride; +- } ++ if (out->stride > obj_size && ++ clear_user(out_ptr + cpy_elem_size, out->stride - obj_size)) { ++ return -EFAULT; ++ } + +- if (out->stride > obj_size && +- clear_user(u64_to_user_ptr(out->array + obj_size), +- out->stride - obj_size)) { +- return -EFAULT; ++ out_ptr += out->stride; ++ in_ptr += obj_size; + } + } + +diff --git a/drivers/gpu/drm/imagination/pvr_queue.c b/drivers/gpu/drm/imagination/pvr_queue.c +index fc415dd0d7a736..bb5835ede66607 100644 +--- a/drivers/gpu/drm/imagination/pvr_queue.c ++++ b/drivers/gpu/drm/imagination/pvr_queue.c +@@ -179,7 +179,7 @@ static const struct dma_fence_ops pvr_queue_job_fence_ops = { + + /** + * to_pvr_queue_job_fence() - Return a pvr_queue_fence object if the fence is +- * backed by a UFO. ++ * already backed by a UFO. + * @f: The dma_fence to turn into a pvr_queue_fence. + * + * Return: +@@ -356,6 +356,15 @@ static u32 job_cmds_size(struct pvr_job *job, u32 ufo_wait_count) + pvr_cccb_get_size_of_cmd_with_hdr(job->cmd_len); + } + ++static bool ++is_paired_job_fence(struct dma_fence *fence, struct pvr_job *job) ++{ ++ /* This assumes "fence" is one of "job"'s drm_sched_job::dependencies */ ++ return job->type == DRM_PVR_JOB_TYPE_FRAGMENT && ++ job->paired_job && ++ &job->paired_job->base.s_fence->scheduled == fence; ++} ++ + /** + * job_count_remaining_native_deps() - Count the number of non-signaled native dependencies. + * @job: Job to operate on. +@@ -371,6 +380,17 @@ static unsigned long job_count_remaining_native_deps(struct pvr_job *job) + xa_for_each(&job->base.dependencies, index, fence) { + struct pvr_queue_fence *jfence; + ++ if (is_paired_job_fence(fence, job)) { ++ /* ++ * A fence between paired jobs won't resolve to a pvr_queue_fence (i.e. ++ * be backed by a UFO) until the jobs have been submitted, together. ++ * The submitting code will insert a partial render fence command for this. ++ */ ++ WARN_ON(dma_fence_is_signaled(fence)); ++ remaining_count++; ++ continue; ++ } ++ + jfence = to_pvr_queue_job_fence(fence); + if (!jfence) + continue; +@@ -468,10 +488,11 @@ pvr_queue_get_job_kccb_fence(struct pvr_queue *queue, struct pvr_job *job) + } + + static struct dma_fence * +-pvr_queue_get_paired_frag_job_dep(struct pvr_queue *queue, struct pvr_job *job) ++pvr_queue_get_paired_frag_job_dep(struct pvr_job *job) + { + struct pvr_job *frag_job = job->type == DRM_PVR_JOB_TYPE_GEOMETRY ? + job->paired_job : NULL; ++ struct pvr_queue *frag_queue = frag_job ? frag_job->ctx->queues.fragment : NULL; + struct dma_fence *f; + unsigned long index; + +@@ -490,7 +511,10 @@ pvr_queue_get_paired_frag_job_dep(struct pvr_queue *queue, struct pvr_job *job) + return dma_fence_get(f); + } + +- return frag_job->base.sched->ops->prepare_job(&frag_job->base, &queue->entity); ++ /* Initialize the paired fragment job's done_fence, so we can signal it. */ ++ pvr_queue_job_fence_init(frag_job->done_fence, frag_queue); ++ ++ return pvr_queue_get_job_cccb_fence(frag_queue, frag_job); + } + + /** +@@ -509,11 +533,6 @@ pvr_queue_prepare_job(struct drm_sched_job *sched_job, + struct pvr_queue *queue = container_of(s_entity, struct pvr_queue, entity); + struct dma_fence *internal_dep = NULL; + +- /* +- * Initialize the done_fence, so we can signal it. This must be done +- * here because otherwise by the time of run_job() the job will end up +- * in the pending list without a valid fence. +- */ + if (job->type == DRM_PVR_JOB_TYPE_FRAGMENT && job->paired_job) { + /* + * This will be called on a paired fragment job after being +@@ -523,18 +542,15 @@ pvr_queue_prepare_job(struct drm_sched_job *sched_job, + */ + if (job->paired_job->has_pm_ref) + return NULL; +- +- /* +- * In this case we need to use the job's own ctx to initialise +- * the done_fence. The other steps are done in the ctx of the +- * paired geometry job. +- */ +- pvr_queue_job_fence_init(job->done_fence, +- job->ctx->queues.fragment); +- } else { +- pvr_queue_job_fence_init(job->done_fence, queue); + } + ++ /* ++ * Initialize the done_fence, so we can signal it. This must be done ++ * here because otherwise by the time of run_job() the job will end up ++ * in the pending list without a valid fence. ++ */ ++ pvr_queue_job_fence_init(job->done_fence, queue); ++ + /* CCCB fence is used to make sure we have enough space in the CCCB to + * submit our commands. + */ +@@ -555,7 +571,7 @@ pvr_queue_prepare_job(struct drm_sched_job *sched_job, + + /* The paired job fence should come last, when everything else is ready. */ + if (!internal_dep) +- internal_dep = pvr_queue_get_paired_frag_job_dep(queue, job); ++ internal_dep = pvr_queue_get_paired_frag_job_dep(job); + + return internal_dep; + } +@@ -630,9 +646,8 @@ static void pvr_queue_submit_job_to_cccb(struct pvr_job *job) + if (!jfence) + continue; + +- /* Skip the partial render fence, we will place it at the end. */ +- if (job->type == DRM_PVR_JOB_TYPE_FRAGMENT && job->paired_job && +- &job->paired_job->base.s_fence->scheduled == fence) ++ /* This fence will be placed last, as partial render fence. */ ++ if (is_paired_job_fence(fence, job)) + continue; + + if (dma_fence_is_signaled(&jfence->base)) +@@ -1386,11 +1401,12 @@ void pvr_queue_kill(struct pvr_queue *queue) + /** + * pvr_queue_destroy() - Destroy a queue. + * @queue: The queue to destroy. ++ * @cleanup_queue_entity: Whether to cleanup the queue entity. + * + * Cleanup the queue and free the resources attached to it. Should be + * called from the context release function. + */ +-void pvr_queue_destroy(struct pvr_queue *queue) ++void pvr_queue_destroy(struct pvr_queue *queue, bool cleanup_queue_entity) + { + if (!queue) + return; +@@ -1400,7 +1416,8 @@ void pvr_queue_destroy(struct pvr_queue *queue) + mutex_unlock(&queue->ctx->pvr_dev->queues.lock); + + drm_sched_fini(&queue->scheduler); +- drm_sched_entity_fini(&queue->entity); ++ if (cleanup_queue_entity) ++ drm_sched_entity_fini(&queue->entity); + + if (WARN_ON(queue->last_queued_job_scheduled_fence)) + dma_fence_put(queue->last_queued_job_scheduled_fence); +diff --git a/drivers/gpu/drm/imagination/pvr_queue.h b/drivers/gpu/drm/imagination/pvr_queue.h +index fc1986d73fc88e..a205e29437f4ed 100644 +--- a/drivers/gpu/drm/imagination/pvr_queue.h ++++ b/drivers/gpu/drm/imagination/pvr_queue.h +@@ -158,7 +158,7 @@ struct pvr_queue *pvr_queue_create(struct pvr_context *ctx, + + void pvr_queue_kill(struct pvr_queue *queue); + +-void pvr_queue_destroy(struct pvr_queue *queue); ++void pvr_queue_destroy(struct pvr_queue *queue, bool cleanup_queue_entity); + + void pvr_queue_process(struct pvr_queue *queue); + +diff --git a/drivers/gpu/drm/imagination/pvr_vm.c b/drivers/gpu/drm/imagination/pvr_vm.c +index 3d97990170bf6b..b2f8e89dafb70c 100644 +--- a/drivers/gpu/drm/imagination/pvr_vm.c ++++ b/drivers/gpu/drm/imagination/pvr_vm.c +@@ -746,6 +746,7 @@ pvr_vm_map(struct pvr_vm_context *vm_ctx, struct pvr_gem_object *pvr_obj, + + pvr_gem_object_get(pvr_obj); + ++ mutex_lock(&vm_ctx->lock); + err = drm_gpuvm_exec_lock(&vm_exec); + if (err) + goto err_cleanup; +@@ -755,6 +756,7 @@ pvr_vm_map(struct pvr_vm_context *vm_ctx, struct pvr_gem_object *pvr_obj, + drm_gpuvm_exec_unlock(&vm_exec); + + err_cleanup: ++ mutex_unlock(&vm_ctx->lock); + pvr_vm_bind_op_fini(&bind_op); + + return err; +diff --git a/drivers/gpu/drm/lib/drm_random.c b/drivers/gpu/drm/lib/drm_random.c +deleted file mode 100644 +index 0e9dba1ef4af51..00000000000000 +--- a/drivers/gpu/drm/lib/drm_random.c ++++ /dev/null +@@ -1,44 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-#include <linux/bitops.h> +-#include <linux/export.h> +-#include <linux/kernel.h> +-#include <linux/random.h> +-#include <linux/slab.h> +-#include <linux/types.h> +- +-#include "drm_random.h" +- +-u32 drm_prandom_u32_max_state(u32 ep_ro, struct rnd_state *state) +-{ +- return upper_32_bits((u64)prandom_u32_state(state) * ep_ro); +-} +-EXPORT_SYMBOL(drm_prandom_u32_max_state); +- +-void drm_random_reorder(unsigned int *order, unsigned int count, +- struct rnd_state *state) +-{ +- unsigned int i, j; +- +- for (i = 0; i < count; ++i) { +- BUILD_BUG_ON(sizeof(unsigned int) > sizeof(u32)); +- j = drm_prandom_u32_max_state(count, state); +- swap(order[i], order[j]); +- } +-} +-EXPORT_SYMBOL(drm_random_reorder); +- +-unsigned int *drm_random_order(unsigned int count, struct rnd_state *state) +-{ +- unsigned int *order, i; +- +- order = kmalloc_array(count, sizeof(*order), GFP_KERNEL); +- if (!order) +- return order; +- +- for (i = 0; i < count; i++) +- order[i] = i; +- +- drm_random_reorder(order, count, state); +- return order; +-} +-EXPORT_SYMBOL(drm_random_order); +diff --git a/drivers/gpu/drm/lib/drm_random.h b/drivers/gpu/drm/lib/drm_random.h +deleted file mode 100644 +index 9f827260a89db9..00000000000000 +--- a/drivers/gpu/drm/lib/drm_random.h ++++ /dev/null +@@ -1,28 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-#ifndef __DRM_RANDOM_H__ +-#define __DRM_RANDOM_H__ +- +-/* This is a temporary home for a couple of utility functions that should +- * be transposed to lib/ at the earliest convenience. +- */ +- +-#include <linux/prandom.h> +- +-#define DRM_RND_STATE_INITIALIZER(seed__) ({ \ +- struct rnd_state state__; \ +- prandom_seed_state(&state__, (seed__)); \ +- state__; \ +-}) +- +-#define DRM_RND_STATE(name__, seed__) \ +- struct rnd_state name__ = DRM_RND_STATE_INITIALIZER(seed__) +- +-unsigned int *drm_random_order(unsigned int count, +- struct rnd_state *state); +-void drm_random_reorder(unsigned int *order, +- unsigned int count, +- struct rnd_state *state); +-u32 drm_prandom_u32_max_state(u32 ep_ro, +- struct rnd_state *state); +- +-#endif /* !__DRM_RANDOM_H__ */ +diff --git a/drivers/gpu/drm/nouveau/nouveau_exec.c b/drivers/gpu/drm/nouveau/nouveau_exec.c +index c4949e815eb365..6c31093be1c784 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_exec.c ++++ b/drivers/gpu/drm/nouveau/nouveau_exec.c +@@ -331,10 +331,10 @@ nouveau_exec_ucopy(struct nouveau_exec_job_args *args, + + return 0; + +-err_free_pushs: +- u_free(args->push.s); + err_free_ins: + u_free(args->in_sync.s); ++err_free_pushs: ++ u_free(args->push.s); + return ret; + } + +diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c +index 79eefdfd08a267..fd518e3f1809dd 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c ++++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c +@@ -1711,10 +1711,10 @@ nouveau_uvmm_vm_bind_ucopy(struct nouveau_uvmm_bind_job_args *args, + + return 0; + +-err_free_ops: +- u_free(args->op.s); + err_free_ins: + u_free(args->in_sync.s); ++err_free_ops: ++ u_free(args->op.s); + return ret; + } + +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c +index 13d829593180c6..8b6274b945b0d4 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c +@@ -315,6 +315,7 @@ nvkm_acr_oneinit(struct nvkm_subdev *subdev) + i, us, fw); + } + } ++ nvkm_done(acr->wpr); + return -EINVAL; + } + nvkm_done(acr->wpr); +diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig +index 1516c6fa265db7..7354dc85a6aa70 100644 +--- a/drivers/gpu/drm/panel/Kconfig ++++ b/drivers/gpu/drm/panel/Kconfig +@@ -814,6 +814,7 @@ config DRM_PANEL_SAMSUNG_S6E3HA8 + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE ++ select DRM_DISPLAY_HELPER + select DRM_DISPLAY_DSC_HELPER + help + Say Y or M here if you want to enable support for the +diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c +index 962a10e00848ef..cdf82d83de7abe 100644 +--- a/drivers/gpu/drm/panthor/panthor_device.c ++++ b/drivers/gpu/drm/panthor/panthor_device.c +@@ -182,7 +182,10 @@ int panthor_device_init(struct panthor_device *ptdev) + return ret; + + #ifdef CONFIG_DEBUG_FS +- drmm_mutex_init(&ptdev->base, &ptdev->gems.lock); ++ ret = drmm_mutex_init(&ptdev->base, &ptdev->gems.lock); ++ if (ret) ++ return ret; ++ + INIT_LIST_HEAD(&ptdev->gems.node); + #endif + +diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c +index df767e82148afc..a8a5a8e2602427 100644 +--- a/drivers/gpu/drm/panthor/panthor_fw.c ++++ b/drivers/gpu/drm/panthor/panthor_fw.c +@@ -777,6 +777,7 @@ static int panthor_fw_load(struct panthor_device *ptdev) + } + + if (hdr.size > iter.size) { ++ ret = -EINVAL; + drm_err(&ptdev->base, "Firmware image is truncated\n"); + goto out; + } +diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c +index 07a9c523a17afb..59ea0b94932da9 100644 +--- a/drivers/gpu/drm/radeon/r100.c ++++ b/drivers/gpu/drm/radeon/r100.c +@@ -906,6 +906,7 @@ struct radeon_fence *r100_copy_blit(struct radeon_device *rdev, + { + struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; + struct radeon_fence *fence; ++ uint64_t cur_src_offset, cur_dst_offset; + uint32_t cur_pages; + uint32_t stride_bytes = RADEON_GPU_PAGE_SIZE; + uint32_t pitch; +@@ -934,6 +935,10 @@ struct radeon_fence *r100_copy_blit(struct radeon_device *rdev, + cur_pages = 8191; + } + num_gpu_pages -= cur_pages; ++ cur_src_offset = src_offset + ++ (uint64_t)num_gpu_pages * RADEON_GPU_PAGE_SIZE; ++ cur_dst_offset = dst_offset + ++ (uint64_t)num_gpu_pages * RADEON_GPU_PAGE_SIZE; + + /* pages are in Y direction - height + page width in X direction - width */ +@@ -950,13 +955,13 @@ struct radeon_fence *r100_copy_blit(struct radeon_device *rdev, + RADEON_DP_SRC_SOURCE_MEMORY | + RADEON_GMC_CLR_CMP_CNTL_DIS | + RADEON_GMC_WR_MSK_DIS); +- radeon_ring_write(ring, (pitch << 22) | (src_offset >> 10)); +- radeon_ring_write(ring, (pitch << 22) | (dst_offset >> 10)); ++ radeon_ring_write(ring, (pitch << 22) | (cur_src_offset >> 10)); ++ radeon_ring_write(ring, (pitch << 22) | (cur_dst_offset >> 10)); + radeon_ring_write(ring, (0x1fff) | (0x1fff << 16)); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, (0x1fff) | (0x1fff << 16)); +- radeon_ring_write(ring, num_gpu_pages); +- radeon_ring_write(ring, num_gpu_pages); ++ radeon_ring_write(ring, 0); ++ radeon_ring_write(ring, 0); + radeon_ring_write(ring, cur_pages | (stride_pixels << 16)); + } + radeon_ring_write(ring, PACKET0(RADEON_DSTCACHE_CTLSTAT, 0)); +diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c +index cbd898a182b564..04a24ff9dde150 100644 +--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c ++++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c +@@ -272,7 +272,7 @@ static int rzg2l_mipi_dsi_dphy_init(struct rzg2l_mipi_dsi *dsi, + if (ret < 0) + return ret; + +- udelay(1); ++ fsleep(1000); + + return 0; + } +@@ -604,29 +604,33 @@ static void rzg2l_mipi_dsi_atomic_pre_enable(struct drm_bridge *bridge, + const struct drm_display_mode *mode; + struct drm_connector *connector; + struct drm_crtc *crtc; +- int ret; + + connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); + crtc = drm_atomic_get_new_connector_state(state, connector)->crtc; + mode = &drm_atomic_get_new_crtc_state(state, crtc)->adjusted_mode; + +- ret = rzg2l_mipi_dsi_startup(dsi, mode); +- if (ret < 0) +- return; +- +- rzg2l_mipi_dsi_set_display_timing(dsi, mode); ++ rzg2l_mipi_dsi_startup(dsi, mode); + } + + static void rzg2l_mipi_dsi_atomic_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state) + { + struct rzg2l_mipi_dsi *dsi = bridge_to_rzg2l_mipi_dsi(bridge); ++ const struct drm_display_mode *mode; ++ struct drm_connector *connector; ++ struct drm_crtc *crtc; + int ret; + + ret = rzg2l_mipi_dsi_start_hs_clock(dsi); + if (ret < 0) + goto err_stop; + ++ connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); ++ crtc = drm_atomic_get_new_connector_state(state, connector)->crtc; ++ mode = &drm_atomic_get_new_crtc_state(state, crtc)->adjusted_mode; ++ ++ rzg2l_mipi_dsi_set_display_timing(dsi, mode); ++ + ret = rzg2l_mipi_dsi_start_video(dsi); + if (ret < 0) + goto err_stop_clock; +diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +index d30f0983a53a6d..b905e28afa0742 100644 +--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c ++++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +@@ -469,6 +469,8 @@ static int rockchip_dp_probe(struct platform_device *pdev) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -EINVAL; + + i = 0; + while (dp_data[i].reg) { +diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c +index 924fb1d3ece28c..c0866ca1054354 100644 +--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c ++++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c +@@ -683,6 +683,8 @@ int cdn_dp_config_video(struct cdn_dp_device *dp) + val = div_u64(8 * (symbol + 1), bit_per_pix) - val; + val += 2; + ret = cdn_dp_reg_write(dp, DP_VC_TABLE(15), val); ++ if (ret) ++ goto err_config_video; + + switch (video->color_depth) { + case 6: +diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h +index 265a1b8a934932..6caf87ab1f1547 100644 +--- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h ++++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h +@@ -39,7 +39,7 @@ struct resource *drm_sysfb_get_memory_si(struct drm_device *dev, + int drm_sysfb_get_stride_si(struct drm_device *dev, const struct screen_info *si, + const struct drm_format_info *format, + unsigned int width, unsigned int height, u64 size); +-u64 drm_sysfb_get_visible_size_si(struct drm_device *dev, const struct screen_info *si, ++s64 drm_sysfb_get_visible_size_si(struct drm_device *dev, const struct screen_info *si, + unsigned int height, unsigned int stride, u64 size); + const struct drm_format_info *drm_sysfb_get_format_si(struct drm_device *dev, + const struct drm_sysfb_format *formats, +diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_screen_info.c b/drivers/gpu/drm/sysfb/drm_sysfb_screen_info.c +index 885864168c54fa..a250bea7b19cab 100644 +--- a/drivers/gpu/drm/sysfb/drm_sysfb_screen_info.c ++++ b/drivers/gpu/drm/sysfb/drm_sysfb_screen_info.c +@@ -2,6 +2,7 @@ + + #include <linux/export.h> + #include <linux/limits.h> ++#include <linux/math64.h> + #include <linux/minmax.h> + #include <linux/screen_info.h> + +@@ -56,18 +57,24 @@ int drm_sysfb_get_stride_si(struct drm_device *dev, const struct screen_info *si + unsigned int width, unsigned int height, u64 size) + { + u64 lfb_linelength = si->lfb_linelength; ++ s64 stride; + + if (!lfb_linelength) + lfb_linelength = drm_format_info_min_pitch(format, 0, width); + +- return drm_sysfb_get_validated_int0(dev, "stride", lfb_linelength, div64_u64(size, height)); ++ stride = drm_sysfb_get_validated_size0(dev, "stride", lfb_linelength, ++ div64_u64(size, height)); ++ if (stride < INT_MIN || stride > INT_MAX) ++ return -EINVAL; ++ ++ return (int)stride; /* stride or negative errno code */ + } + EXPORT_SYMBOL(drm_sysfb_get_stride_si); + +-u64 drm_sysfb_get_visible_size_si(struct drm_device *dev, const struct screen_info *si, ++s64 drm_sysfb_get_visible_size_si(struct drm_device *dev, const struct screen_info *si, + unsigned int height, unsigned int stride, u64 size) + { +- u64 vsize = PAGE_ALIGN(height * stride); ++ u64 vsize = mul_u32_u32(height, stride); + + return drm_sysfb_get_validated_size0(dev, "visible size", vsize, size); + } +diff --git a/drivers/gpu/drm/sysfb/efidrm.c b/drivers/gpu/drm/sysfb/efidrm.c +index 97a3711e79337d..844d1e8b0ab3cd 100644 +--- a/drivers/gpu/drm/sysfb/efidrm.c ++++ b/drivers/gpu/drm/sysfb/efidrm.c +@@ -143,7 +143,8 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv, + const struct screen_info *si; + const struct drm_format_info *format; + int width, height, stride; +- u64 vsize, mem_flags; ++ s64 vsize; ++ u64 mem_flags; + struct resource resbuf; + struct resource *res; + struct efidrm_device *efi; +@@ -195,8 +196,8 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv, + if (stride < 0) + return ERR_PTR(stride); + vsize = drm_sysfb_get_visible_size_si(dev, si, height, stride, resource_size(res)); +- if (!vsize) +- return ERR_PTR(-EINVAL); ++ if (vsize < 0) ++ return ERR_PTR(vsize); + + drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d bytes\n", + &format->format, width, height, stride); +diff --git a/drivers/gpu/drm/sysfb/vesadrm.c b/drivers/gpu/drm/sysfb/vesadrm.c +index 16a4b52d45c6cb..37123976e1fbf6 100644 +--- a/drivers/gpu/drm/sysfb/vesadrm.c ++++ b/drivers/gpu/drm/sysfb/vesadrm.c +@@ -392,7 +392,7 @@ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv, + const struct screen_info *si; + const struct drm_format_info *format; + int width, height, stride; +- u64 vsize; ++ s64 vsize; + struct resource resbuf; + struct resource *res; + struct vesadrm_device *vesa; +@@ -445,8 +445,8 @@ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv, + if (stride < 0) + return ERR_PTR(stride); + vsize = drm_sysfb_get_visible_size_si(dev, si, height, stride, resource_size(res)); +- if (!vsize) +- return ERR_PTR(-EINVAL); ++ if (vsize < 0) ++ return ERR_PTR(vsize); + + drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d bytes\n", + &format->format, width, height, stride); +diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile +index c0e952293ad021..524310241e16d3 100644 +--- a/drivers/gpu/drm/tests/Makefile ++++ b/drivers/gpu/drm/tests/Makefile +@@ -7,7 +7,6 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \ + drm_atomic_test.o \ + drm_atomic_state_test.o \ + drm_bridge_test.o \ +- drm_buddy_test.o \ + drm_cmdline_parser_test.o \ + drm_connector_test.o \ + drm_damage_helper_test.o \ +diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c b/drivers/gpu/drm/tests/drm_buddy_test.c +deleted file mode 100644 +index 7a0e523651f054..00000000000000 +--- a/drivers/gpu/drm/tests/drm_buddy_test.c ++++ /dev/null +@@ -1,788 +0,0 @@ +-// SPDX-License-Identifier: MIT +-/* +- * Copyright © 2019 Intel Corporation +- * Copyright © 2022 Maíra Canal <[email protected]> +- */ +- +-#include <kunit/test.h> +- +-#include <linux/prime_numbers.h> +-#include <linux/sched/signal.h> +-#include <linux/sizes.h> +- +-#include <drm/drm_buddy.h> +- +-#include "../lib/drm_random.h" +- +-static unsigned int random_seed; +- +-static inline u64 get_size(int order, u64 chunk_size) +-{ +- return (1 << order) * chunk_size; +-} +- +-static void drm_test_buddy_alloc_range_bias(struct kunit *test) +-{ +- u32 mm_size, size, ps, bias_size, bias_start, bias_end, bias_rem; +- DRM_RND_STATE(prng, random_seed); +- unsigned int i, count, *order; +- struct drm_buddy_block *block; +- unsigned long flags; +- struct drm_buddy mm; +- LIST_HEAD(allocated); +- +- bias_size = SZ_1M; +- ps = roundup_pow_of_two(prandom_u32_state(&prng) % bias_size); +- ps = max(SZ_4K, ps); +- mm_size = (SZ_8M-1) & ~(ps-1); /* Multiple roots */ +- +- kunit_info(test, "mm_size=%u, ps=%u\n", mm_size, ps); +- +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, ps), +- "buddy_init failed\n"); +- +- count = mm_size / bias_size; +- order = drm_random_order(count, &prng); +- KUNIT_EXPECT_TRUE(test, order); +- +- /* +- * Idea is to split the address space into uniform bias ranges, and then +- * in some random order allocate within each bias, using various +- * patterns within. This should detect if allocations leak out from a +- * given bias, for example. +- */ +- +- for (i = 0; i < count; i++) { +- LIST_HEAD(tmp); +- u32 size; +- +- bias_start = order[i] * bias_size; +- bias_end = bias_start + bias_size; +- bias_rem = bias_size; +- +- /* internal round_up too big */ +- KUNIT_ASSERT_TRUE_MSG(test, +- drm_buddy_alloc_blocks(&mm, bias_start, +- bias_end, bias_size + ps, bias_size, +- &allocated, +- DRM_BUDDY_RANGE_ALLOCATION), +- "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", +- bias_start, bias_end, bias_size, bias_size); +- +- /* size too big */ +- KUNIT_ASSERT_TRUE_MSG(test, +- drm_buddy_alloc_blocks(&mm, bias_start, +- bias_end, bias_size + ps, ps, +- &allocated, +- DRM_BUDDY_RANGE_ALLOCATION), +- "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n", +- bias_start, bias_end, bias_size + ps, ps); +- +- /* bias range too small for size */ +- KUNIT_ASSERT_TRUE_MSG(test, +- drm_buddy_alloc_blocks(&mm, bias_start + ps, +- bias_end, bias_size, ps, +- &allocated, +- DRM_BUDDY_RANGE_ALLOCATION), +- "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n", +- bias_start + ps, bias_end, bias_size, ps); +- +- /* bias misaligned */ +- KUNIT_ASSERT_TRUE_MSG(test, +- drm_buddy_alloc_blocks(&mm, bias_start + ps, +- bias_end - ps, +- bias_size >> 1, bias_size >> 1, +- &allocated, +- DRM_BUDDY_RANGE_ALLOCATION), +- "buddy_alloc h didn't fail with bias(%x-%x), size=%u, ps=%u\n", +- bias_start + ps, bias_end - ps, bias_size >> 1, bias_size >> 1); +- +- /* single big page */ +- KUNIT_ASSERT_FALSE_MSG(test, +- drm_buddy_alloc_blocks(&mm, bias_start, +- bias_end, bias_size, bias_size, +- &tmp, +- DRM_BUDDY_RANGE_ALLOCATION), +- "buddy_alloc i failed with bias(%x-%x), size=%u, ps=%u\n", +- bias_start, bias_end, bias_size, bias_size); +- drm_buddy_free_list(&mm, &tmp, 0); +- +- /* single page with internal round_up */ +- KUNIT_ASSERT_FALSE_MSG(test, +- drm_buddy_alloc_blocks(&mm, bias_start, +- bias_end, ps, bias_size, +- &tmp, +- DRM_BUDDY_RANGE_ALLOCATION), +- "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", +- bias_start, bias_end, ps, bias_size); +- drm_buddy_free_list(&mm, &tmp, 0); +- +- /* random size within */ +- size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps); +- if (size) +- KUNIT_ASSERT_FALSE_MSG(test, +- drm_buddy_alloc_blocks(&mm, bias_start, +- bias_end, size, ps, +- &tmp, +- DRM_BUDDY_RANGE_ALLOCATION), +- "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", +- bias_start, bias_end, size, ps); +- +- bias_rem -= size; +- /* too big for current avail */ +- KUNIT_ASSERT_TRUE_MSG(test, +- drm_buddy_alloc_blocks(&mm, bias_start, +- bias_end, bias_rem + ps, ps, +- &allocated, +- DRM_BUDDY_RANGE_ALLOCATION), +- "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n", +- bias_start, bias_end, bias_rem + ps, ps); +- +- if (bias_rem) { +- /* random fill of the remainder */ +- size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps); +- size = max(size, ps); +- +- KUNIT_ASSERT_FALSE_MSG(test, +- drm_buddy_alloc_blocks(&mm, bias_start, +- bias_end, size, ps, +- &allocated, +- DRM_BUDDY_RANGE_ALLOCATION), +- "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", +- bias_start, bias_end, size, ps); +- /* +- * Intentionally allow some space to be left +- * unallocated, and ideally not always on the bias +- * boundaries. +- */ +- drm_buddy_free_list(&mm, &tmp, 0); +- } else { +- list_splice_tail(&tmp, &allocated); +- } +- } +- +- kfree(order); +- drm_buddy_free_list(&mm, &allocated, 0); +- drm_buddy_fini(&mm); +- +- /* +- * Something more free-form. Idea is to pick a random starting bias +- * range within the address space and then start filling it up. Also +- * randomly grow the bias range in both directions as we go along. This +- * should give us bias start/end which is not always uniform like above, +- * and in some cases will require the allocator to jump over already +- * allocated nodes in the middle of the address space. +- */ +- +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, ps), +- "buddy_init failed\n"); +- +- bias_start = round_up(prandom_u32_state(&prng) % (mm_size - ps), ps); +- bias_end = round_up(bias_start + prandom_u32_state(&prng) % (mm_size - bias_start), ps); +- bias_end = max(bias_end, bias_start + ps); +- bias_rem = bias_end - bias_start; +- +- do { +- u32 size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps); +- +- KUNIT_ASSERT_FALSE_MSG(test, +- drm_buddy_alloc_blocks(&mm, bias_start, +- bias_end, size, ps, +- &allocated, +- DRM_BUDDY_RANGE_ALLOCATION), +- "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", +- bias_start, bias_end, size, ps); +- bias_rem -= size; +- +- /* +- * Try to randomly grow the bias range in both directions, or +- * only one, or perhaps don't grow at all. +- */ +- do { +- u32 old_bias_start = bias_start; +- u32 old_bias_end = bias_end; +- +- if (bias_start) +- bias_start -= round_up(prandom_u32_state(&prng) % bias_start, ps); +- if (bias_end != mm_size) +- bias_end += round_up(prandom_u32_state(&prng) % (mm_size - bias_end), ps); +- +- bias_rem += old_bias_start - bias_start; +- bias_rem += bias_end - old_bias_end; +- } while (!bias_rem && (bias_start || bias_end != mm_size)); +- } while (bias_rem); +- +- KUNIT_ASSERT_EQ(test, bias_start, 0); +- KUNIT_ASSERT_EQ(test, bias_end, mm_size); +- KUNIT_ASSERT_TRUE_MSG(test, +- drm_buddy_alloc_blocks(&mm, bias_start, bias_end, +- ps, ps, +- &allocated, +- DRM_BUDDY_RANGE_ALLOCATION), +- "buddy_alloc passed with bias(%x-%x), size=%u\n", +- bias_start, bias_end, ps); +- +- drm_buddy_free_list(&mm, &allocated, 0); +- drm_buddy_fini(&mm); +- +- /* +- * Allocate cleared blocks in the bias range when the DRM buddy's clear avail is +- * zero. This will validate the bias range allocation in scenarios like system boot +- * when no cleared blocks are available and exercise the fallback path too. The resulting +- * blocks should always be dirty. +- */ +- +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, ps), +- "buddy_init failed\n"); +- +- bias_start = round_up(prandom_u32_state(&prng) % (mm_size - ps), ps); +- bias_end = round_up(bias_start + prandom_u32_state(&prng) % (mm_size - bias_start), ps); +- bias_end = max(bias_end, bias_start + ps); +- bias_rem = bias_end - bias_start; +- +- flags = DRM_BUDDY_CLEAR_ALLOCATION | DRM_BUDDY_RANGE_ALLOCATION; +- size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps); +- +- KUNIT_ASSERT_FALSE_MSG(test, +- drm_buddy_alloc_blocks(&mm, bias_start, +- bias_end, size, ps, +- &allocated, +- flags), +- "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", +- bias_start, bias_end, size, ps); +- +- list_for_each_entry(block, &allocated, link) +- KUNIT_EXPECT_EQ(test, drm_buddy_block_is_clear(block), false); +- +- drm_buddy_free_list(&mm, &allocated, 0); +- drm_buddy_fini(&mm); +-} +- +-static void drm_test_buddy_alloc_clear(struct kunit *test) +-{ +- unsigned long n_pages, total, i = 0; +- const unsigned long ps = SZ_4K; +- struct drm_buddy_block *block; +- const int max_order = 12; +- LIST_HEAD(allocated); +- struct drm_buddy mm; +- unsigned int order; +- u32 mm_size, size; +- LIST_HEAD(dirty); +- LIST_HEAD(clean); +- +- mm_size = SZ_4K << max_order; +- KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps)); +- +- KUNIT_EXPECT_EQ(test, mm.max_order, max_order); +- +- /* +- * Idea is to allocate and free some random portion of the address space, +- * returning those pages as non-dirty and randomly alternate between +- * requesting dirty and non-dirty pages (not going over the limit +- * we freed as non-dirty), putting that into two separate lists. +- * Loop over both lists at the end checking that the dirty list +- * is indeed all dirty pages and vice versa. Free it all again, +- * keeping the dirty/clear status. +- */ +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, +- 5 * ps, ps, &allocated, +- DRM_BUDDY_TOPDOWN_ALLOCATION), +- "buddy_alloc hit an error size=%lu\n", 5 * ps); +- drm_buddy_free_list(&mm, &allocated, DRM_BUDDY_CLEARED); +- +- n_pages = 10; +- do { +- unsigned long flags; +- struct list_head *list; +- int slot = i % 2; +- +- if (slot == 0) { +- list = &dirty; +- flags = 0; +- } else { +- list = &clean; +- flags = DRM_BUDDY_CLEAR_ALLOCATION; +- } +- +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, +- ps, ps, list, +- flags), +- "buddy_alloc hit an error size=%lu\n", ps); +- } while (++i < n_pages); +- +- list_for_each_entry(block, &clean, link) +- KUNIT_EXPECT_EQ(test, drm_buddy_block_is_clear(block), true); +- +- list_for_each_entry(block, &dirty, link) +- KUNIT_EXPECT_EQ(test, drm_buddy_block_is_clear(block), false); +- +- drm_buddy_free_list(&mm, &clean, DRM_BUDDY_CLEARED); +- +- /* +- * Trying to go over the clear limit for some allocation. +- * The allocation should never fail with reasonable page-size. +- */ +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, +- 10 * ps, ps, &clean, +- DRM_BUDDY_CLEAR_ALLOCATION), +- "buddy_alloc hit an error size=%lu\n", 10 * ps); +- +- drm_buddy_free_list(&mm, &clean, DRM_BUDDY_CLEARED); +- drm_buddy_free_list(&mm, &dirty, 0); +- drm_buddy_fini(&mm); +- +- KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps)); +- +- /* +- * Create a new mm. Intentionally fragment the address space by creating +- * two alternating lists. Free both lists, one as dirty the other as clean. +- * Try to allocate double the previous size with matching min_page_size. The +- * allocation should never fail as it calls the force_merge. Also check that +- * the page is always dirty after force_merge. Free the page as dirty, then +- * repeat the whole thing, increment the order until we hit the max_order. +- */ +- +- i = 0; +- n_pages = mm_size / ps; +- do { +- struct list_head *list; +- int slot = i % 2; +- +- if (slot == 0) +- list = &dirty; +- else +- list = &clean; +- +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, +- ps, ps, list, 0), +- "buddy_alloc hit an error size=%lu\n", ps); +- } while (++i < n_pages); +- +- drm_buddy_free_list(&mm, &clean, DRM_BUDDY_CLEARED); +- drm_buddy_free_list(&mm, &dirty, 0); +- +- order = 1; +- do { +- size = SZ_4K << order; +- +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, +- size, size, &allocated, +- DRM_BUDDY_CLEAR_ALLOCATION), +- "buddy_alloc hit an error size=%u\n", size); +- total = 0; +- list_for_each_entry(block, &allocated, link) { +- if (size != mm_size) +- KUNIT_EXPECT_EQ(test, drm_buddy_block_is_clear(block), false); +- total += drm_buddy_block_size(&mm, block); +- } +- KUNIT_EXPECT_EQ(test, total, size); +- +- drm_buddy_free_list(&mm, &allocated, 0); +- } while (++order <= max_order); +- +- drm_buddy_fini(&mm); +- +- /* +- * Create a new mm with a non power-of-two size. Allocate a random size from each +- * root, free as cleared and then call fini. This will ensure the multi-root +- * force merge during fini. +- */ +- mm_size = (SZ_4K << max_order) + (SZ_4K << (max_order - 2)); +- +- KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps)); +- KUNIT_EXPECT_EQ(test, mm.max_order, max_order); +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, SZ_4K << max_order, +- 4 * ps, ps, &allocated, +- DRM_BUDDY_RANGE_ALLOCATION), +- "buddy_alloc hit an error size=%lu\n", 4 * ps); +- drm_buddy_free_list(&mm, &allocated, DRM_BUDDY_CLEARED); +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, SZ_4K << max_order, +- 2 * ps, ps, &allocated, +- DRM_BUDDY_CLEAR_ALLOCATION), +- "buddy_alloc hit an error size=%lu\n", 2 * ps); +- drm_buddy_free_list(&mm, &allocated, DRM_BUDDY_CLEARED); +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, SZ_4K << max_order, mm_size, +- ps, ps, &allocated, +- DRM_BUDDY_RANGE_ALLOCATION), +- "buddy_alloc hit an error size=%lu\n", ps); +- drm_buddy_free_list(&mm, &allocated, DRM_BUDDY_CLEARED); +- drm_buddy_fini(&mm); +-} +- +-static void drm_test_buddy_alloc_contiguous(struct kunit *test) +-{ +- const unsigned long ps = SZ_4K, mm_size = 16 * 3 * SZ_4K; +- unsigned long i, n_pages, total; +- struct drm_buddy_block *block; +- struct drm_buddy mm; +- LIST_HEAD(left); +- LIST_HEAD(middle); +- LIST_HEAD(right); +- LIST_HEAD(allocated); +- +- KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps)); +- +- /* +- * Idea is to fragment the address space by alternating block +- * allocations between three different lists; one for left, middle and +- * right. We can then free a list to simulate fragmentation. In +- * particular we want to exercise the DRM_BUDDY_CONTIGUOUS_ALLOCATION, +- * including the try_harder path. +- */ +- +- i = 0; +- n_pages = mm_size / ps; +- do { +- struct list_head *list; +- int slot = i % 3; +- +- if (slot == 0) +- list = &left; +- else if (slot == 1) +- list = &middle; +- else +- list = &right; +- KUNIT_ASSERT_FALSE_MSG(test, +- drm_buddy_alloc_blocks(&mm, 0, mm_size, +- ps, ps, list, 0), +- "buddy_alloc hit an error size=%lu\n", +- ps); +- } while (++i < n_pages); +- +- KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, +- 3 * ps, ps, &allocated, +- DRM_BUDDY_CONTIGUOUS_ALLOCATION), +- "buddy_alloc didn't error size=%lu\n", 3 * ps); +- +- drm_buddy_free_list(&mm, &middle, 0); +- KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, +- 3 * ps, ps, &allocated, +- DRM_BUDDY_CONTIGUOUS_ALLOCATION), +- "buddy_alloc didn't error size=%lu\n", 3 * ps); +- KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, +- 2 * ps, ps, &allocated, +- DRM_BUDDY_CONTIGUOUS_ALLOCATION), +- "buddy_alloc didn't error size=%lu\n", 2 * ps); +- +- drm_buddy_free_list(&mm, &right, 0); +- KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, +- 3 * ps, ps, &allocated, +- DRM_BUDDY_CONTIGUOUS_ALLOCATION), +- "buddy_alloc didn't error size=%lu\n", 3 * ps); +- /* +- * At this point we should have enough contiguous space for 2 blocks, +- * however they are never buddies (since we freed middle and right) so +- * will require the try_harder logic to find them. +- */ +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, +- 2 * ps, ps, &allocated, +- DRM_BUDDY_CONTIGUOUS_ALLOCATION), +- "buddy_alloc hit an error size=%lu\n", 2 * ps); +- +- drm_buddy_free_list(&mm, &left, 0); +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, +- 3 * ps, ps, &allocated, +- DRM_BUDDY_CONTIGUOUS_ALLOCATION), +- "buddy_alloc hit an error size=%lu\n", 3 * ps); +- +- total = 0; +- list_for_each_entry(block, &allocated, link) +- total += drm_buddy_block_size(&mm, block); +- +- KUNIT_ASSERT_EQ(test, total, ps * 2 + ps * 3); +- +- drm_buddy_free_list(&mm, &allocated, 0); +- drm_buddy_fini(&mm); +-} +- +-static void drm_test_buddy_alloc_pathological(struct kunit *test) +-{ +- u64 mm_size, size, start = 0; +- struct drm_buddy_block *block; +- const int max_order = 3; +- unsigned long flags = 0; +- int order, top; +- struct drm_buddy mm; +- LIST_HEAD(blocks); +- LIST_HEAD(holes); +- LIST_HEAD(tmp); +- +- /* +- * Create a pot-sized mm, then allocate one of each possible +- * order within. This should leave the mm with exactly one +- * page left. Free the largest block, then whittle down again. +- * Eventually we will have a fully 50% fragmented mm. +- */ +- +- mm_size = SZ_4K << max_order; +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, SZ_4K), +- "buddy_init failed\n"); +- +- KUNIT_EXPECT_EQ(test, mm.max_order, max_order); +- +- for (top = max_order; top; top--) { +- /* Make room by freeing the largest allocated block */ +- block = list_first_entry_or_null(&blocks, typeof(*block), link); +- if (block) { +- list_del(&block->link); +- drm_buddy_free_block(&mm, block); +- } +- +- for (order = top; order--;) { +- size = get_size(order, mm.chunk_size); +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, +- mm_size, size, size, +- &tmp, flags), +- "buddy_alloc hit -ENOMEM with order=%d, top=%d\n", +- order, top); +- +- block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); +- KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); +- +- list_move_tail(&block->link, &blocks); +- } +- +- /* There should be one final page for this sub-allocation */ +- size = get_size(0, mm.chunk_size); +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, +- size, size, &tmp, flags), +- "buddy_alloc hit -ENOMEM for hole\n"); +- +- block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); +- KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); +- +- list_move_tail(&block->link, &holes); +- +- size = get_size(top, mm.chunk_size); +- KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, +- size, size, &tmp, flags), +- "buddy_alloc unexpectedly succeeded at top-order %d/%d, it should be full!", +- top, max_order); +- } +- +- drm_buddy_free_list(&mm, &holes, 0); +- +- /* Nothing larger than blocks of chunk_size now available */ +- for (order = 1; order <= max_order; order++) { +- size = get_size(order, mm.chunk_size); +- KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, +- size, size, &tmp, flags), +- "buddy_alloc unexpectedly succeeded at order %d, it should be full!", +- order); +- } +- +- list_splice_tail(&holes, &blocks); +- drm_buddy_free_list(&mm, &blocks, 0); +- drm_buddy_fini(&mm); +-} +- +-static void drm_test_buddy_alloc_pessimistic(struct kunit *test) +-{ +- u64 mm_size, size, start = 0; +- struct drm_buddy_block *block, *bn; +- const unsigned int max_order = 16; +- unsigned long flags = 0; +- struct drm_buddy mm; +- unsigned int order; +- LIST_HEAD(blocks); +- LIST_HEAD(tmp); +- +- /* +- * Create a pot-sized mm, then allocate one of each possible +- * order within. This should leave the mm with exactly one +- * page left. +- */ +- +- mm_size = SZ_4K << max_order; +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, SZ_4K), +- "buddy_init failed\n"); +- +- KUNIT_EXPECT_EQ(test, mm.max_order, max_order); +- +- for (order = 0; order < max_order; order++) { +- size = get_size(order, mm.chunk_size); +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, +- size, size, &tmp, flags), +- "buddy_alloc hit -ENOMEM with order=%d\n", +- order); +- +- block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); +- KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); +- +- list_move_tail(&block->link, &blocks); +- } +- +- /* And now the last remaining block available */ +- size = get_size(0, mm.chunk_size); +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, +- size, size, &tmp, flags), +- "buddy_alloc hit -ENOMEM on final alloc\n"); +- +- block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); +- KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); +- +- list_move_tail(&block->link, &blocks); +- +- /* Should be completely full! */ +- for (order = max_order; order--;) { +- size = get_size(order, mm.chunk_size); +- KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, +- size, size, &tmp, flags), +- "buddy_alloc unexpectedly succeeded, it should be full!"); +- } +- +- block = list_last_entry(&blocks, typeof(*block), link); +- list_del(&block->link); +- drm_buddy_free_block(&mm, block); +- +- /* As we free in increasing size, we make available larger blocks */ +- order = 1; +- list_for_each_entry_safe(block, bn, &blocks, link) { +- list_del(&block->link); +- drm_buddy_free_block(&mm, block); +- +- size = get_size(order, mm.chunk_size); +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, +- size, size, &tmp, flags), +- "buddy_alloc hit -ENOMEM with order=%d\n", +- order); +- +- block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); +- KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); +- +- list_del(&block->link); +- drm_buddy_free_block(&mm, block); +- order++; +- } +- +- /* To confirm, now the whole mm should be available */ +- size = get_size(max_order, mm.chunk_size); +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, +- size, size, &tmp, flags), +- "buddy_alloc (realloc) hit -ENOMEM with order=%d\n", +- max_order); +- +- block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); +- KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); +- +- list_del(&block->link); +- drm_buddy_free_block(&mm, block); +- drm_buddy_free_list(&mm, &blocks, 0); +- drm_buddy_fini(&mm); +-} +- +-static void drm_test_buddy_alloc_optimistic(struct kunit *test) +-{ +- u64 mm_size, size, start = 0; +- struct drm_buddy_block *block; +- unsigned long flags = 0; +- const int max_order = 16; +- struct drm_buddy mm; +- LIST_HEAD(blocks); +- LIST_HEAD(tmp); +- int order; +- +- /* +- * Create a mm with one block of each order available, and +- * try to allocate them all. +- */ +- +- mm_size = SZ_4K * ((1 << (max_order + 1)) - 1); +- +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_init(&mm, mm_size, SZ_4K), +- "buddy_init failed\n"); +- +- KUNIT_EXPECT_EQ(test, mm.max_order, max_order); +- +- for (order = 0; order <= max_order; order++) { +- size = get_size(order, mm.chunk_size); +- KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, +- size, size, &tmp, flags), +- "buddy_alloc hit -ENOMEM with order=%d\n", +- order); +- +- block = list_first_entry_or_null(&tmp, struct drm_buddy_block, link); +- KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); +- +- list_move_tail(&block->link, &blocks); +- } +- +- /* Should be completely full! */ +- size = get_size(0, mm.chunk_size); +- KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, start, mm_size, +- size, size, &tmp, flags), +- "buddy_alloc unexpectedly succeeded, it should be full!"); +- +- drm_buddy_free_list(&mm, &blocks, 0); +- drm_buddy_fini(&mm); +-} +- +-static void drm_test_buddy_alloc_limit(struct kunit *test) +-{ +- u64 size = U64_MAX, start = 0; +- struct drm_buddy_block *block; +- unsigned long flags = 0; +- LIST_HEAD(allocated); +- struct drm_buddy mm; +- +- KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, size, SZ_4K)); +- +- KUNIT_EXPECT_EQ_MSG(test, mm.max_order, DRM_BUDDY_MAX_ORDER, +- "mm.max_order(%d) != %d\n", mm.max_order, +- DRM_BUDDY_MAX_ORDER); +- +- size = mm.chunk_size << mm.max_order; +- KUNIT_EXPECT_FALSE(test, drm_buddy_alloc_blocks(&mm, start, size, size, +- mm.chunk_size, &allocated, flags)); +- +- block = list_first_entry_or_null(&allocated, struct drm_buddy_block, link); +- KUNIT_EXPECT_TRUE(test, block); +- +- KUNIT_EXPECT_EQ_MSG(test, drm_buddy_block_order(block), mm.max_order, +- "block order(%d) != %d\n", +- drm_buddy_block_order(block), mm.max_order); +- +- KUNIT_EXPECT_EQ_MSG(test, drm_buddy_block_size(&mm, block), +- BIT_ULL(mm.max_order) * mm.chunk_size, +- "block size(%llu) != %llu\n", +- drm_buddy_block_size(&mm, block), +- BIT_ULL(mm.max_order) * mm.chunk_size); +- +- drm_buddy_free_list(&mm, &allocated, 0); +- drm_buddy_fini(&mm); +-} +- +-static int drm_buddy_suite_init(struct kunit_suite *suite) +-{ +- while (!random_seed) +- random_seed = get_random_u32(); +- +- kunit_info(suite, "Testing DRM buddy manager, with random_seed=0x%x\n", +- random_seed); +- +- return 0; +-} +- +-static struct kunit_case drm_buddy_tests[] = { +- KUNIT_CASE(drm_test_buddy_alloc_limit), +- KUNIT_CASE(drm_test_buddy_alloc_optimistic), +- KUNIT_CASE(drm_test_buddy_alloc_pessimistic), +- KUNIT_CASE(drm_test_buddy_alloc_pathological), +- KUNIT_CASE(drm_test_buddy_alloc_contiguous), +- KUNIT_CASE(drm_test_buddy_alloc_clear), +- KUNIT_CASE(drm_test_buddy_alloc_range_bias), +- {} +-}; +- +-static struct kunit_suite drm_buddy_test_suite = { +- .name = "drm_buddy", +- .suite_init = drm_buddy_suite_init, +- .test_cases = drm_buddy_tests, +-}; +- +-kunit_test_suite(drm_buddy_test_suite); +- +-MODULE_AUTHOR("Intel Corporation"); +-MODULE_DESCRIPTION("Kunit test for drm_buddy functions"); +-MODULE_LICENSE("GPL"); +diff --git a/drivers/gpu/drm/tests/drm_exec_test.c b/drivers/gpu/drm/tests/drm_exec_test.c +index 3a20c788c51f89..2fc47f3b463b7e 100644 +--- a/drivers/gpu/drm/tests/drm_exec_test.c ++++ b/drivers/gpu/drm/tests/drm_exec_test.c +@@ -16,8 +16,6 @@ + #include <drm/drm_gem.h> + #include <drm/drm_kunit_helpers.h> + +-#include "../lib/drm_random.h" +- + struct drm_exec_priv { + struct device *dev; + struct drm_device *drm; +diff --git a/drivers/gpu/drm/tests/drm_gem_shmem_test.c b/drivers/gpu/drm/tests/drm_gem_shmem_test.c +index 4b459f21acfd95..b1fa287892fb81 100644 +--- a/drivers/gpu/drm/tests/drm_gem_shmem_test.c ++++ b/drivers/gpu/drm/tests/drm_gem_shmem_test.c +@@ -95,13 +95,9 @@ static void drm_gem_shmem_test_obj_create_private(struct kunit *test) + sg_init_one(sgt->sgl, buf, TEST_SIZE); + + /* +- * Set the DMA mask to 64-bits and map the sgtables +- * otherwise drm_gem_shmem_free will cause a warning +- * on debug kernels. ++ * Map the sgtables otherwise drm_gem_shmem_free will cause a warning on ++ * debug kernels. + */ +- ret = dma_set_mask(drm_dev->dev, DMA_BIT_MASK(64)); +- KUNIT_ASSERT_EQ(test, ret, 0); +- + ret = dma_map_sgtable(drm_dev->dev, sgt, DMA_BIDIRECTIONAL, 0); + KUNIT_ASSERT_EQ(test, ret, 0); + +@@ -352,11 +348,19 @@ static int drm_gem_shmem_test_init(struct kunit *test) + { + struct device *dev; + struct drm_device *drm_dev; ++ int ret; + + /* Allocate a parent device */ + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + ++ /* ++ * Set the DMA mask to 64-bits to avoid intermittent failures calling ++ * drm_gem_shmem_get_pages_sgt(). ++ */ ++ ret = dma_set_mask(dev, DMA_BIT_MASK(64)); ++ KUNIT_ASSERT_EQ(test, ret, 0); ++ + /* + * The DRM core will automatically initialize the GEM core and create + * a DRM Memory Manager object which provides an address space pool +diff --git a/drivers/gpu/drm/tests/drm_mm_test.c b/drivers/gpu/drm/tests/drm_mm_test.c +index 6174d092902082..99744322ed1a25 100644 +--- a/drivers/gpu/drm/tests/drm_mm_test.c ++++ b/drivers/gpu/drm/tests/drm_mm_test.c +@@ -15,8 +15,6 @@ + + #include <drm/drm_mm.h> + +-#include "../lib/drm_random.h" +- + enum { + BEST, + BOTTOMUP, +diff --git a/drivers/gpu/drm/tidss/tidss_encoder.c b/drivers/gpu/drm/tidss/tidss_encoder.c +index 81a04f7677701b..db467bbcdb7762 100644 +--- a/drivers/gpu/drm/tidss/tidss_encoder.c ++++ b/drivers/gpu/drm/tidss/tidss_encoder.c +@@ -106,6 +106,8 @@ int tidss_encoder_create(struct tidss_device *tidss, + enc = &t_enc->encoder; + enc->possible_crtcs = possible_crtcs; + ++ devm_drm_bridge_add(tidss->dev, &t_enc->bridge); ++ + /* Attaching first bridge to the encoder */ + ret = drm_bridge_attach(enc, &t_enc->bridge, NULL, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); +diff --git a/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c b/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c +index 1bcc67977f4879..3cbdc8101b7c6b 100644 +--- a/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c ++++ b/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c +@@ -251,7 +251,7 @@ static void ttm_bo_validate_basic(struct kunit *test) + NULL, &dummy_ttm_bo_destroy); + KUNIT_EXPECT_EQ(test, err, 0); + +- snd_place = ttm_place_kunit_init(test, snd_mem, DRM_BUDDY_TOPDOWN_ALLOCATION); ++ snd_place = ttm_place_kunit_init(test, snd_mem, GPU_BUDDY_TOPDOWN_ALLOCATION); + snd_placement = ttm_placement_kunit_init(test, snd_place, 1); + + err = ttm_bo_validate(bo, snd_placement, &ctx_val); +@@ -263,7 +263,7 @@ static void ttm_bo_validate_basic(struct kunit *test) + KUNIT_EXPECT_TRUE(test, ttm_tt_is_populated(bo->ttm)); + KUNIT_EXPECT_EQ(test, bo->resource->mem_type, snd_mem); + KUNIT_EXPECT_EQ(test, bo->resource->placement, +- DRM_BUDDY_TOPDOWN_ALLOCATION); ++ GPU_BUDDY_TOPDOWN_ALLOCATION); + + ttm_bo_put(bo); + ttm_mock_manager_fini(priv->ttm_dev, snd_mem); +diff --git a/drivers/gpu/drm/ttm/tests/ttm_mock_manager.c b/drivers/gpu/drm/ttm/tests/ttm_mock_manager.c +index d7eb6471f2edad..a9c233f982f676 100644 +--- a/drivers/gpu/drm/ttm/tests/ttm_mock_manager.c ++++ b/drivers/gpu/drm/ttm/tests/ttm_mock_manager.c +@@ -30,7 +30,7 @@ static int ttm_mock_manager_alloc(struct ttm_resource_manager *man, + { + struct ttm_mock_manager *manager = to_mock_mgr(man); + struct ttm_mock_resource *mock_res; +- struct drm_buddy *mm = &manager->mm; ++ struct gpu_buddy *mm = &manager->mm; + u64 lpfn, fpfn, alloc_size; + int err; + +@@ -46,14 +46,14 @@ static int ttm_mock_manager_alloc(struct ttm_resource_manager *man, + INIT_LIST_HEAD(&mock_res->blocks); + + if (place->flags & TTM_PL_FLAG_TOPDOWN) +- mock_res->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION; ++ mock_res->flags |= GPU_BUDDY_TOPDOWN_ALLOCATION; + + if (place->flags & TTM_PL_FLAG_CONTIGUOUS) +- mock_res->flags |= DRM_BUDDY_CONTIGUOUS_ALLOCATION; ++ mock_res->flags |= GPU_BUDDY_CONTIGUOUS_ALLOCATION; + + alloc_size = (uint64_t)mock_res->base.size; + mutex_lock(&manager->lock); +- err = drm_buddy_alloc_blocks(mm, fpfn, lpfn, alloc_size, ++ err = gpu_buddy_alloc_blocks(mm, fpfn, lpfn, alloc_size, + manager->default_page_size, + &mock_res->blocks, + mock_res->flags); +@@ -66,7 +66,7 @@ static int ttm_mock_manager_alloc(struct ttm_resource_manager *man, + return 0; + + error_free_blocks: +- drm_buddy_free_list(mm, &mock_res->blocks, 0); ++ gpu_buddy_free_list(mm, &mock_res->blocks, 0); + ttm_resource_fini(man, &mock_res->base); + mutex_unlock(&manager->lock); + +@@ -78,10 +78,10 @@ static void ttm_mock_manager_free(struct ttm_resource_manager *man, + { + struct ttm_mock_manager *manager = to_mock_mgr(man); + struct ttm_mock_resource *mock_res = to_mock_mgr_resource(res); +- struct drm_buddy *mm = &manager->mm; ++ struct gpu_buddy *mm = &manager->mm; + + mutex_lock(&manager->lock); +- drm_buddy_free_list(mm, &mock_res->blocks, 0); ++ gpu_buddy_free_list(mm, &mock_res->blocks, 0); + mutex_unlock(&manager->lock); + + ttm_resource_fini(man, res); +@@ -105,7 +105,7 @@ int ttm_mock_manager_init(struct ttm_device *bdev, u32 mem_type, u32 size) + + mutex_init(&manager->lock); + +- err = drm_buddy_init(&manager->mm, size, PAGE_SIZE); ++ err = gpu_buddy_init(&manager->mm, size, PAGE_SIZE); + + if (err) { + kfree(manager); +@@ -141,7 +141,7 @@ void ttm_mock_manager_fini(struct ttm_device *bdev, u32 mem_type) + ttm_resource_manager_set_used(man, false); + + mutex_lock(&mock_man->lock); +- drm_buddy_fini(&mock_man->mm); ++ gpu_buddy_fini(&mock_man->mm); + mutex_unlock(&mock_man->lock); + + ttm_set_driver_manager(bdev, mem_type, NULL); +diff --git a/drivers/gpu/drm/ttm/tests/ttm_mock_manager.h b/drivers/gpu/drm/ttm/tests/ttm_mock_manager.h +index e4c95f86a4670a..08710756fd8e0f 100644 +--- a/drivers/gpu/drm/ttm/tests/ttm_mock_manager.h ++++ b/drivers/gpu/drm/ttm/tests/ttm_mock_manager.h +@@ -5,11 +5,11 @@ + #ifndef TTM_MOCK_MANAGER_H + #define TTM_MOCK_MANAGER_H + +-#include <drm/drm_buddy.h> ++#include <linux/gpu_buddy.h> + + struct ttm_mock_manager { + struct ttm_resource_manager man; +- struct drm_buddy mm; ++ struct gpu_buddy mm; + u64 default_page_size; + /* protects allocations of mock buffer objects */ + struct mutex lock; +diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c +index baf27c70a4193a..01083720e4e7f5 100644 +--- a/drivers/gpu/drm/ttm/ttm_pool.c ++++ b/drivers/gpu/drm/ttm/ttm_pool.c +@@ -981,9 +981,31 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt, + return -EBUSY; + + #ifdef CONFIG_X86 +- /* Anything returned to the system needs to be cached. */ +- if (tt->caching != ttm_cached) +- set_pages_array_wb(tt->pages, tt->num_pages); ++ /* Anything returned to the system needs to be cached. Walk allocations ++ * skipping NULL pages and issue set_pages_array_wb() per contiguous run. ++ */ ++ if (tt->caching != ttm_cached) { ++ pgoff_t run_start = 0, run_count = 0; ++ ++ for (i = 0; i < tt->num_pages; i += num_pages) { ++ page = tt->pages[i]; ++ if (unlikely(!page || ttm_backup_page_ptr_is_handle(page))) { ++ if (run_count) { ++ set_pages_array_wb(&tt->pages[run_start], ++ run_count); ++ run_count = 0; ++ } ++ num_pages = 1; ++ continue; ++ } ++ num_pages = 1UL << ttm_pool_page_order(pool, page); ++ if (!run_count) ++ run_start = i; ++ run_count += num_pages; ++ } ++ if (run_count) ++ set_pages_array_wb(&tt->pages[run_start], run_count); ++ } + #endif + + if (tt->dma_address || flags->purge) { +@@ -991,7 +1013,7 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt, + unsigned int order; + + page = tt->pages[i]; +- if (unlikely(!page)) { ++ if (unlikely(!page || ttm_backup_page_ptr_is_handle(page))) { + num_pages = 1; + continue; + } +@@ -1034,6 +1056,10 @@ long ttm_pool_backup(struct ttm_pool *pool, struct ttm_tt *tt, + if (unlikely(!page)) + continue; + ++ /* Already-handled entry from a previous attempt. */ ++ if (unlikely(ttm_backup_page_ptr_is_handle(page))) ++ continue; ++ + ttm_pool_split_for_swap(pool, page); + + shandle = ttm_backup_backup_page(backup, page, flags->writeback, i, +diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c +index ab29dde223618c..b499f6635cd24f 100644 +--- a/drivers/gpu/drm/v3d/v3d_gem.c ++++ b/drivers/gpu/drm/v3d/v3d_gem.c +@@ -45,6 +45,18 @@ v3d_init_hw_state(struct v3d_dev *v3d) + static void + v3d_idle_axi(struct v3d_dev *v3d, int core) + { ++ if (v3d->ver >= V3D_GEN_71) { ++ V3D_WRITE(V3D_GMP_CFG(v3d->ver), V3D_GMP_CFG_STOP_REQ); ++ ++ if (wait_for((V3D_READ(V3D_GMP_STATUS(v3d->ver)) & ++ (V3D_GMP_STATUS_RD_COUNT_MASK | ++ V3D_GMP_STATUS_WR_COUNT_MASK | ++ V3D_GMP_STATUS_CFG_BUSY)) == 0, 100)) { ++ drm_err(&v3d->drm, "Failed to wait for safe GMP shutdown\n"); ++ } ++ return; ++ } ++ + V3D_CORE_WRITE(core, V3D_GMP_CFG(v3d->ver), V3D_GMP_CFG_STOP_REQ); + + if (wait_for((V3D_CORE_READ(core, V3D_GMP_STATUS(v3d->ver)) & +diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c +index a1efda9c39f925..cd7996592db374 100644 +--- a/drivers/gpu/drm/vc4/vc4_bo.c ++++ b/drivers/gpu/drm/vc4/vc4_bo.c +@@ -733,9 +733,13 @@ static int vc4_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct + { + struct vc4_bo *bo = to_vc4_bo(obj); + +- if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) { +- DRM_DEBUG("mmapping of shader BOs for writing not allowed.\n"); +- return -EINVAL; ++ if (bo->validated_shader) { ++ if (vma->vm_flags & VM_WRITE) { ++ DRM_DEBUG("mmapping of shader BOs for writing not allowed.\n"); ++ return -EINVAL; ++ } ++ ++ vm_flags_clear(vma, VM_MAYWRITE); + } + + mutex_lock(&bo->madv_lock); +@@ -1046,7 +1050,7 @@ static void vc4_bo_cache_destroy(struct drm_device *dev, void *unused) + struct vc4_dev *vc4 = to_vc4_dev(dev); + int i; + +- timer_delete(&vc4->bo_cache.time_timer); ++ timer_shutdown_sync(&vc4->bo_cache.time_timer); + cancel_work_sync(&vc4->bo_cache.time_work); + + vc4_bo_cache_purge(dev); +diff --git a/drivers/gpu/drm/virtio/virtgpu_gem.c b/drivers/gpu/drm/virtio/virtgpu_gem.c +index 015b5debd7451b..7174086119c514 100644 +--- a/drivers/gpu/drm/virtio/virtgpu_gem.c ++++ b/drivers/gpu/drm/virtio/virtgpu_gem.c +@@ -139,13 +139,15 @@ void virtio_gpu_gem_object_close(struct drm_gem_object *obj, + if (!vgdev->has_virgl_3d) + return; + +- objs = virtio_gpu_array_alloc(1); +- if (!objs) +- return; +- virtio_gpu_array_add_obj(objs, obj); ++ if (vfpriv->context_created) { ++ objs = virtio_gpu_array_alloc(1); ++ if (!objs) ++ return; ++ virtio_gpu_array_add_obj(objs, obj); + +- virtio_gpu_cmd_context_detach_resource(vgdev, vfpriv->ctx_id, +- objs); ++ virtio_gpu_cmd_context_detach_resource(vgdev, vfpriv->ctx_id, ++ objs); ++ } + virtio_gpu_notify(vgdev); + } + +diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c +index 1c15cbf326b78c..4a25347734fda4 100644 +--- a/drivers/gpu/drm/virtio/virtgpu_kms.c ++++ b/drivers/gpu/drm/virtio/virtgpu_kms.c +@@ -48,7 +48,10 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work) + virtio_gpu_cmd_get_edids(vgdev); + virtio_gpu_cmd_get_display_info(vgdev); + virtio_gpu_notify(vgdev); +- drm_helper_hpd_irq_event(vgdev->ddev); ++ wait_event_timeout(vgdev->resp_wq, ++ !vgdev->display_info_pending, ++ 5 * HZ); ++ drm_kms_helper_hotplug_event(vgdev->ddev); + } + events_clear |= VIRTIO_GPU_EVENT_DISPLAY; + } +diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c +index 8181b22b9b46a1..83d46a8edf79fe 100644 +--- a/drivers/gpu/drm/virtio/virtgpu_vq.c ++++ b/drivers/gpu/drm/virtio/virtgpu_vq.c +@@ -839,9 +839,6 @@ static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev, + vgdev->display_info_pending = false; + spin_unlock(&vgdev->display_info_lock); + wake_up(&vgdev->resp_wq); +- +- if (!drm_helper_hpd_irq_event(vgdev->ddev)) +- drm_kms_helper_hotplug_event(vgdev->ddev); + } + + static void virtio_gpu_cmd_get_capset_info_cb(struct virtio_gpu_device *vgdev, +@@ -896,7 +893,8 @@ static int virtio_get_edid_block(void *data, u8 *buf, + struct virtio_gpu_resp_edid *resp = data; + size_t start = block * EDID_LENGTH; + +- if (start + len > le32_to_cpu(resp->size)) ++ if (start + len > le32_to_cpu(resp->size) || ++ start + len > sizeof(resp->edid)) + return -EINVAL; + memcpy(buf, resp->edid + start, len); + return 0; +diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +index 7e281c3c6bc58d..8e01e13eebf4d5 100644 +--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c ++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +@@ -77,7 +77,7 @@ static int vmw_gb_surface_unbind(struct vmw_resource *res, + static int vmw_gb_surface_destroy(struct vmw_resource *res); + static int + vmw_gb_surface_define_internal(struct drm_device *dev, +- struct drm_vmw_gb_surface_create_ext_req *req, ++ const struct drm_vmw_gb_surface_create_ext_req *req, + struct drm_vmw_gb_surface_create_rep *rep, + struct drm_file *file_priv); + static int +@@ -1503,7 +1503,7 @@ int vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev, void *data, + */ + static int + vmw_gb_surface_define_internal(struct drm_device *dev, +- struct drm_vmw_gb_surface_create_ext_req *req, ++ const struct drm_vmw_gb_surface_create_ext_req *req, + struct drm_vmw_gb_surface_create_rep *rep, + struct drm_file *file_priv) + { +@@ -1521,9 +1521,21 @@ vmw_gb_surface_define_internal(struct drm_device *dev, + req->base.svga3d_flags); + + /* array_size must be null for non-GL3 host. */ +- if (req->base.array_size > 0 && !has_sm4_context(dev_priv)) { +- VMW_DEBUG_USER("SM4 surface not supported.\n"); +- return -EINVAL; ++ if (req->base.array_size > 0) { ++ if (has_sm5_context(dev_priv)) { ++ if (req->base.array_size > SVGA3D_SM5_MAX_SURFACE_ARRAYSIZE) { ++ VMW_DEBUG_USER("Invalid Surface Array Size.\n"); ++ return -EINVAL; ++ } ++ } else if (has_sm4_context(dev_priv)) { ++ if (req->base.array_size > SVGA3D_SM4_MAX_SURFACE_ARRAYSIZE) { ++ VMW_DEBUG_USER("Invalid Surface Array Size.\n"); ++ return -EINVAL; ++ } ++ } else { ++ VMW_DEBUG_USER("SM4+ surface not supported.\n"); ++ return -EINVAL; ++ } + } + + if (!has_sm4_1_context(dev_priv)) { +diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c +index 0dabe85351392e..5c531b8d921110 100644 +--- a/drivers/gpu/drm/xe/xe_bo.c ++++ b/drivers/gpu/drm/xe/xe_bo.c +@@ -930,6 +930,21 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict, + xe_pm_runtime_get_noresume(xe); + } + ++ /* ++ * Attach CCS BBs before submitting the copy job below so a VF ++ * migration racing the copy sees valid, up to date attach state. ++ */ ++ if (IS_VF_CCS_READY(xe) && ++ ((move_lacks_source && new_mem->mem_type == XE_PL_TT) || ++ (old_mem_type == XE_PL_SYSTEM && new_mem->mem_type == XE_PL_TT)) && ++ handle_system_ccs) { ++ ret = xe_sriov_vf_ccs_attach_bo(bo, new_mem); ++ if (ret) { ++ xe_pm_runtime_put(xe); ++ goto out; ++ } ++ } ++ + if (move_lacks_source) { + u32 flags = 0; + +@@ -967,22 +982,19 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict, + ttm_bo_move_null(ttm_bo, new_mem); + } + +- dma_fence_put(fence); +- xe_pm_runtime_put(xe); +- + /* +- * CCS meta data is migrated from TT -> SMEM. So, let us detach the +- * BBs from BO as it is no longer needed. ++ * Detach must wait for the copy above to complete: a VF migration ++ * racing an in-flight copy must still see valid CCS BBs, so don't ++ * tear them down until the copy fence has signaled. + */ + if (IS_VF_CCS_READY(xe) && old_mem_type == XE_PL_TT && +- new_mem->mem_type == XE_PL_SYSTEM) ++ new_mem->mem_type == XE_PL_SYSTEM) { ++ dma_fence_wait(fence, false); + xe_sriov_vf_ccs_detach_bo(bo); ++ } + +- if (IS_VF_CCS_READY(xe) && +- ((move_lacks_source && new_mem->mem_type == XE_PL_TT) || +- (old_mem_type == XE_PL_SYSTEM && new_mem->mem_type == XE_PL_TT)) && +- handle_system_ccs) +- ret = xe_sriov_vf_ccs_attach_bo(bo); ++ dma_fence_put(fence); ++ xe_pm_runtime_put(xe); + + out: + if ((!ttm_bo->resource || ttm_bo->resource->mem_type == XE_PL_SYSTEM) && +@@ -1174,7 +1186,7 @@ int xe_bo_notifier_prepare_pinned(struct xe_bo *bo) + backup = xe_bo_init_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL, xe_bo_size(bo), + DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel, + XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS | +- XE_BO_FLAG_PINNED, &exec); ++ XE_BO_FLAG_PINNED, NULL, &exec); + if (IS_ERR(backup)) { + drm_exec_retry_on_contention(&exec); + ret = PTR_ERR(backup); +@@ -1315,7 +1327,7 @@ int xe_bo_evict_pinned(struct xe_bo *bo) + xe_bo_size(bo), + DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel, + XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS | +- XE_BO_FLAG_PINNED, &exec); ++ XE_BO_FLAG_PINNED, NULL, &exec); + if (IS_ERR(backup)) { + drm_exec_retry_on_contention(&exec); + ret = PTR_ERR(backup); +@@ -1663,6 +1675,8 @@ static void xe_ttm_bo_destroy(struct ttm_buffer_object *ttm_bo) + + if (bo->ttm.base.import_attach) + drm_prime_gem_destroy(&bo->ttm.base, NULL); ++ if (bo->dma_buf) ++ dma_buf_put(bo->dma_buf); + drm_gem_object_release(&bo->ttm.base); + + xe_assert(xe, list_empty(&ttm_bo->base.gpuva.list)); +@@ -2080,6 +2094,8 @@ void xe_bo_free(struct xe_bo *bo) + * @cpu_caching: The cpu caching used for system memory backing store. + * @type: The TTM buffer object type. + * @flags: XE_BO_FLAG_ flags. ++ * @dma_buf: The dma-buf to reference for the BO lifetime (imported BOs), ++ * or NULL. + * @exec: The drm_exec transaction to use for exhaustive eviction. + * + * Initialize or create an xe buffer object. On failure, any allocated buffer +@@ -2091,7 +2107,8 @@ struct xe_bo *xe_bo_init_locked(struct xe_device *xe, struct xe_bo *bo, + struct xe_tile *tile, struct dma_resv *resv, + struct ttm_lru_bulk_move *bulk, size_t size, + u16 cpu_caching, enum ttm_bo_type type, +- u32 flags, struct drm_exec *exec) ++ u32 flags, struct dma_buf *dma_buf, ++ struct drm_exec *exec) + { + struct ttm_operation_ctx ctx = { + .interruptible = true, +@@ -2177,6 +2194,17 @@ struct xe_bo *xe_bo_init_locked(struct xe_device *xe, struct xe_bo *bo, + placement = (type == ttm_bo_type_sg || + bo->flags & XE_BO_FLAG_DEFER_BACKING) ? &sys_placement : + &bo->placement; ++ ++ /* ++ * For imported BOs, keep the exporter dma-buf alive for the BO ++ * lifetime. Taken before ttm_bo_init_reserved() to also cover a ++ * creation failure there. Released in xe_ttm_bo_destroy(). ++ */ ++ if (dma_buf) { ++ get_dma_buf(dma_buf); ++ bo->dma_buf = dma_buf; ++ } ++ + err = ttm_bo_init_reserved(&xe->ttm, &bo->ttm, type, + placement, alignment, + &ctx, NULL, resv, xe_ttm_bo_destroy); +@@ -2291,7 +2319,7 @@ __xe_bo_create_locked(struct xe_device *xe, + vm && !xe_vm_in_fault_mode(vm) && + flags & XE_BO_FLAG_USER ? + &vm->lru_bulk_move : NULL, size, +- cpu_caching, type, flags, exec); ++ cpu_caching, type, flags, NULL, exec); + if (IS_ERR(bo)) + return bo; + +diff --git a/drivers/gpu/drm/xe/xe_bo.h b/drivers/gpu/drm/xe/xe_bo.h +index a77af42b5f9ea1..9c1ba37983d9d6 100644 +--- a/drivers/gpu/drm/xe/xe_bo.h ++++ b/drivers/gpu/drm/xe/xe_bo.h +@@ -93,7 +93,8 @@ struct xe_bo *xe_bo_init_locked(struct xe_device *xe, struct xe_bo *bo, + struct xe_tile *tile, struct dma_resv *resv, + struct ttm_lru_bulk_move *bulk, size_t size, + u16 cpu_caching, enum ttm_bo_type type, +- u32 flags, struct drm_exec *exec); ++ u32 flags, struct dma_buf *dma_buf, ++ struct drm_exec *exec); + struct xe_bo *xe_bo_create_locked(struct xe_device *xe, struct xe_tile *tile, + struct xe_vm *vm, size_t size, + enum ttm_bo_type type, u32 flags, +diff --git a/drivers/gpu/drm/xe/xe_bo_types.h b/drivers/gpu/drm/xe/xe_bo_types.h +index d4fe3c8dca5be2..88e3d8b33c532b 100644 +--- a/drivers/gpu/drm/xe/xe_bo_types.h ++++ b/drivers/gpu/drm/xe/xe_bo_types.h +@@ -35,6 +35,8 @@ struct xe_bo { + struct xe_bo *backup_obj; + /** @parent_obj: Ref to parent bo if this a backup_obj */ + struct xe_bo *parent_obj; ++ /** @dma_buf: Imported dma-buf ref to keep its resv alive. */ ++ struct dma_buf *dma_buf; + /** @flags: flags for this buffer object */ + u32 flags; + /** @vm: VM this BO is attached to, for extobj this will be NULL */ +diff --git a/drivers/gpu/drm/xe/xe_dma_buf.c b/drivers/gpu/drm/xe/xe_dma_buf.c +index eeea2a6e15b5c8..07010f097e5848 100644 +--- a/drivers/gpu/drm/xe/xe_dma_buf.c ++++ b/drivers/gpu/drm/xe/xe_dma_buf.c +@@ -251,7 +251,7 @@ xe_dma_buf_create_obj(struct drm_device *dev, struct dma_buf *dma_buf) + + bo = xe_bo_init_locked(xe, NULL, NULL, resv, NULL, dma_buf->size, + 0, /* Will require 1way or 2way for vm_bind */ +- ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, &exec); ++ ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, dma_buf, &exec); + drm_exec_retry_on_contention(&exec); + if (IS_ERR(bo)) { + ret = PTR_ERR(bo); +diff --git a/drivers/gpu/drm/xe/xe_guc_buf.c b/drivers/gpu/drm/xe/xe_guc_buf.c +index 502ca3a4ee6064..3de6377ae2d521 100644 +--- a/drivers/gpu/drm/xe/xe_guc_buf.c ++++ b/drivers/gpu/drm/xe/xe_guc_buf.c +@@ -13,6 +13,8 @@ + #include "xe_guc_buf.h" + #include "xe_sa.h" + ++#define XE_GUC_BUF_CACHE_DEFAULT_SIZE SZ_8K ++ + static struct xe_guc *cache_to_guc(struct xe_guc_buf_cache *cache) + { + return container_of(cache, struct xe_guc, buf); +@@ -23,21 +25,12 @@ static struct xe_gt *cache_to_gt(struct xe_guc_buf_cache *cache) + return guc_to_gt(cache_to_guc(cache)); + } + +-/** +- * xe_guc_buf_cache_init() - Initialize the GuC Buffer Cache. +- * @cache: the &xe_guc_buf_cache to initialize +- * +- * The Buffer Cache allows to obtain a reusable buffer that can be used to pass +- * indirect H2G data to GuC without a need to create a ad-hoc allocation. +- * +- * Return: 0 on success or a negative error code on failure. +- */ +-int xe_guc_buf_cache_init(struct xe_guc_buf_cache *cache) ++static int guc_buf_cache_init(struct xe_guc_buf_cache *cache, u32 size) + { + struct xe_gt *gt = cache_to_gt(cache); + struct xe_sa_manager *sam; + +- sam = __xe_sa_bo_manager_init(gt_to_tile(gt), SZ_8K, 0, sizeof(u32)); ++ sam = __xe_sa_bo_manager_init(gt_to_tile(gt), size, 0, sizeof(u32), 0); + if (IS_ERR(sam)) + return PTR_ERR(sam); + cache->sam = sam; +@@ -48,6 +41,35 @@ int xe_guc_buf_cache_init(struct xe_guc_buf_cache *cache) + return 0; + } + ++/** ++ * xe_guc_buf_cache_init() - Initialize the GuC Buffer Cache. ++ * @cache: the &xe_guc_buf_cache to initialize ++ * ++ * The Buffer Cache allows to obtain a reusable buffer that can be used to pass ++ * data to GuC or read data from GuC without a need to create a ad-hoc allocation. ++ * ++ * Return: 0 on success or a negative error code on failure. ++ */ ++int xe_guc_buf_cache_init(struct xe_guc_buf_cache *cache) ++{ ++ return guc_buf_cache_init(cache, XE_GUC_BUF_CACHE_DEFAULT_SIZE); ++} ++ ++/** ++ * xe_guc_buf_cache_init_with_size() - Initialize the GuC Buffer Cache. ++ * @cache: the &xe_guc_buf_cache to initialize ++ * @size: size in bytes ++ * ++ * Like xe_guc_buf_cache_init(), except it allows the caller to make the cache ++ * buffer larger, allowing to accommodate larger objects. ++ * ++ * Return: 0 on success or a negative error code on failure. ++ */ ++int xe_guc_buf_cache_init_with_size(struct xe_guc_buf_cache *cache, u32 size) ++{ ++ return guc_buf_cache_init(cache, max(XE_GUC_BUF_CACHE_DEFAULT_SIZE, size)); ++} ++ + /** + * xe_guc_buf_cache_dwords() - Number of dwords the GuC Buffer Cache supports. + * @cache: the &xe_guc_buf_cache to query +diff --git a/drivers/gpu/drm/xe/xe_guc_buf.h b/drivers/gpu/drm/xe/xe_guc_buf.h +index 0d67604d96bdd7..8204e589625013 100644 +--- a/drivers/gpu/drm/xe/xe_guc_buf.h ++++ b/drivers/gpu/drm/xe/xe_guc_buf.h +@@ -12,6 +12,7 @@ + #include "xe_guc_buf_types.h" + + int xe_guc_buf_cache_init(struct xe_guc_buf_cache *cache); ++int xe_guc_buf_cache_init_with_size(struct xe_guc_buf_cache *cache, u32 size); + u32 xe_guc_buf_cache_dwords(struct xe_guc_buf_cache *cache); + struct xe_guc_buf xe_guc_buf_reserve(struct xe_guc_buf_cache *cache, u32 dwords); + struct xe_guc_buf xe_guc_buf_from_data(struct xe_guc_buf_cache *cache, +diff --git a/drivers/gpu/drm/xe/xe_i2c.c b/drivers/gpu/drm/xe/xe_i2c.c +index 48dfcb41fa08c1..2788dc6510d6ac 100644 +--- a/drivers/gpu/drm/xe/xe_i2c.c ++++ b/drivers/gpu/drm/xe/xe_i2c.c +@@ -94,18 +94,21 @@ static int xe_i2c_register_adapter(struct xe_i2c *i2c) + struct platform_device *pdev; + struct fwnode_handle *fwnode; + int ret; ++ u32 id; + + fwnode = fwnode_create_software_node(xe_i2c_adapter_properties, NULL); + if (IS_ERR(fwnode)) + return PTR_ERR(fwnode); + ++ id = (pci_domain_nr(pci->bus) << 16) | pci_dev_id(pci); ++ + /* + * Not using platform_device_register_full() here because we don't have + * a handle to the platform_device before it returns. xe_i2c_notifier() + * uses that handle, but it may be called before + * platform_device_register_full() is done. + */ +- pdev = platform_device_alloc(adapter_name, pci_dev_id(pci)); ++ pdev = platform_device_alloc(adapter_name, id); + if (!pdev) { + ret = -ENOMEM; + goto err_fwnode_remove; +diff --git a/drivers/gpu/drm/xe/xe_migrate.c b/drivers/gpu/drm/xe/xe_migrate.c +index b6905f35d6c81f..e0a14360d312e0 100644 +--- a/drivers/gpu/drm/xe/xe_migrate.c ++++ b/drivers/gpu/drm/xe/xe_migrate.c +@@ -33,6 +33,7 @@ + #include "xe_res_cursor.h" + #include "xe_sa.h" + #include "xe_sched_job.h" ++#include "xe_sriov_vf_ccs.h" + #include "xe_sync.h" + #include "xe_trace_bo.h" + #include "xe_validation.h" +@@ -1000,6 +1001,8 @@ static int emit_flush_invalidate(struct xe_exec_queue *q, u32 *dw, int i, + * @tile: Tile whose migration context to be used. + * @q : Execution to be used along with migration context. + * @src_bo: The buffer object @src is currently bound to. ++ * @new_mem: The (not yet committed) destination resource @src_bo is being ++ * moved into; src_bo->ttm.resource is still the old resource. + * @read_write : Creates BB commands for CCS read/write. + * + * Creates batch buffer instructions to copy CCS metadata from CCS pool to +@@ -1011,23 +1014,28 @@ static int emit_flush_invalidate(struct xe_exec_queue *q, u32 *dw, int i, + */ + int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q, + struct xe_bo *src_bo, ++ struct ttm_resource *new_mem, + enum xe_sriov_vf_ccs_rw_ctxs read_write) + + { + bool src_is_pltt = read_write == XE_SRIOV_VF_CCS_READ_CTX; + bool dst_is_pltt = read_write == XE_SRIOV_VF_CCS_WRITE_CTX; +- struct ttm_resource *src = src_bo->ttm.resource; ++ struct ttm_resource *src = new_mem; + struct xe_migrate *m = tile->migrate; + struct xe_gt *gt = tile->primary_gt; + u32 batch_size, batch_size_allocated; + struct xe_device *xe = gt_to_xe(gt); + struct xe_res_cursor src_it, ccs_it; ++ struct xe_sriov_vf_ccs_ctx *ctx; ++ struct xe_sa_manager *bb_pool; + u64 size = xe_bo_size(src_bo); + struct xe_bb *bb = NULL; + u64 src_L0, src_L0_ofs; + u32 src_L0_pt; + int err; + ++ ctx = &xe->sriov.vf.ccs.contexts[read_write]; ++ + xe_res_first_sg(xe_bo_sg(src_bo), 0, size, &src_it); + + xe_res_first_sg(xe_bo_sg(src_bo), xe_bo_ccs_pages_start(src_bo), +@@ -1060,11 +1068,15 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q, + size -= src_L0; + } + ++ bb_pool = ctx->mem.ccs_bb_pool; ++ guard(mutex) (xe_sa_bo_swap_guard(bb_pool)); ++ xe_sa_bo_swap_shadow(bb_pool); ++ + bb = xe_bb_ccs_new(gt, batch_size, read_write); + if (IS_ERR(bb)) { + drm_err(&xe->drm, "BB allocation failed.\n"); + err = PTR_ERR(bb); +- goto err_ret; ++ return err; + } + + batch_size_allocated = batch_size; +@@ -1113,10 +1125,52 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q, + xe_assert(xe, (batch_size_allocated == bb->len)); + src_bo->bb_ccs[read_write] = bb; + ++ xe_sriov_vf_ccs_rw_update_bb_addr(ctx); ++ xe_sa_bo_sync_shadow(bb->bo); + return 0; ++} + +-err_ret: +- return err; ++/** ++ * xe_migrate_ccs_rw_copy_clear() - Clear the CCS read/write batch buffer ++ * content. ++ * @src_bo: The buffer object @src is currently bound to. ++ * @read_write : Creates BB commands for CCS read/write. ++ * ++ * Directly clearing the BB lacks atomicity and can lead to undefined ++ * behavior if the vCPU is halted mid-operation during the clearing ++ * process. To avoid this issue, we use a shadow buffer object approach. ++ * ++ * First swap the SA BO address with the shadow BO, perform the clearing ++ * operation on the BB, update the shadow BO in the ring buffer, then ++ * sync the shadow and the actual buffer to maintain consistency. ++ * ++ * Returns: None. ++ */ ++void xe_migrate_ccs_rw_copy_clear(struct xe_bo *src_bo, ++ enum xe_sriov_vf_ccs_rw_ctxs read_write) ++{ ++ struct xe_bb *bb = src_bo->bb_ccs[read_write]; ++ struct xe_device *xe = xe_bo_device(src_bo); ++ struct xe_sriov_vf_ccs_ctx *ctx; ++ struct xe_sa_manager *bb_pool; ++ u32 *cs; ++ ++ xe_assert(xe, IS_SRIOV_VF(xe)); ++ ++ ctx = &xe->sriov.vf.ccs.contexts[read_write]; ++ bb_pool = ctx->mem.ccs_bb_pool; ++ ++ guard(mutex) (xe_sa_bo_swap_guard(bb_pool)); ++ xe_sa_bo_swap_shadow(bb_pool); ++ ++ cs = xe_sa_bo_cpu_addr(bb->bo); ++ memset(cs, MI_NOOP, bb->len * sizeof(u32)); ++ xe_sriov_vf_ccs_rw_update_bb_addr(ctx); ++ ++ xe_sa_bo_sync_shadow(bb->bo); ++ ++ xe_bb_free(bb, NULL); ++ src_bo->bb_ccs[read_write] = NULL; + } + + /** +diff --git a/drivers/gpu/drm/xe/xe_migrate.h b/drivers/gpu/drm/xe/xe_migrate.h +index bc55f650204b83..8bac669685ee92 100644 +--- a/drivers/gpu/drm/xe/xe_migrate.h ++++ b/drivers/gpu/drm/xe/xe_migrate.h +@@ -129,8 +129,12 @@ struct dma_fence *xe_migrate_copy(struct xe_migrate *m, + + int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q, + struct xe_bo *src_bo, ++ struct ttm_resource *new_mem, + enum xe_sriov_vf_ccs_rw_ctxs read_write); + ++void xe_migrate_ccs_rw_copy_clear(struct xe_bo *src_bo, ++ enum xe_sriov_vf_ccs_rw_ctxs read_write); ++ + struct xe_lrc *xe_migrate_lrc(struct xe_migrate *migrate); + struct xe_exec_queue *xe_migrate_exec_queue(struct xe_migrate *migrate); + int xe_migrate_access_memory(struct xe_migrate *m, struct xe_bo *bo, +diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c +index 1f0262adc3ae38..de0d104fc8b667 100644 +--- a/drivers/gpu/drm/xe/xe_pt.c ++++ b/drivers/gpu/drm/xe/xe_pt.c +@@ -999,12 +999,22 @@ xe_vm_populate_pgtable(struct xe_migrate_pt_update *pt_update, struct xe_tile *t + u64 *ptr = data; + u32 i; + ++ /* ++ * @qword_ofs is the absolute entry offset within the page table, while ++ * @ptes is indexed relative to @update->ofs (its first entry). The GPU ++ * path (write_pgtable) splits a single update into MAX_PTE_PER_SDI-sized ++ * chunks, calling this with an advancing @qword_ofs but a fresh @data ++ * pointer per chunk, so translate back into a @ptes index rather than ++ * assuming the chunk starts at ptes[0]. ++ */ + for (i = 0; i < num_qwords; i++) { ++ u32 idx = qword_ofs - update->ofs + i; ++ + if (map) + xe_map_wr(tile_to_xe(tile), map, (qword_ofs + i) * +- sizeof(u64), u64, ptes[i].pte); ++ sizeof(u64), u64, ptes[idx].pte); + else +- ptr[i] = ptes[i].pte; ++ ptr[i] = ptes[idx].pte; + } + } + +diff --git a/drivers/gpu/drm/xe/xe_res_cursor.h b/drivers/gpu/drm/xe/xe_res_cursor.h +index 4e00008b708176..5f4ab08c068694 100644 +--- a/drivers/gpu/drm/xe/xe_res_cursor.h ++++ b/drivers/gpu/drm/xe/xe_res_cursor.h +@@ -58,7 +58,7 @@ struct xe_res_cursor { + /** @dma_addr: Current element in a struct drm_pagemap_addr array */ + const struct drm_pagemap_addr *dma_addr; + /** @mm: Buddy allocator for VRAM cursor */ +- struct drm_buddy *mm; ++ struct gpu_buddy *mm; + /** + * @dma_start: DMA start address for the current segment. + * This may be different to @dma_addr.addr since elements in +@@ -69,7 +69,7 @@ struct xe_res_cursor { + u64 dma_seg_size; + }; + +-static struct drm_buddy *xe_res_get_buddy(struct ttm_resource *res) ++static struct gpu_buddy *xe_res_get_buddy(struct ttm_resource *res) + { + struct ttm_resource_manager *mgr; + +@@ -104,30 +104,30 @@ static inline void xe_res_first(struct ttm_resource *res, + case XE_PL_STOLEN: + case XE_PL_VRAM0: + case XE_PL_VRAM1: { +- struct drm_buddy_block *block; ++ struct gpu_buddy_block *block; + struct list_head *head, *next; +- struct drm_buddy *mm = xe_res_get_buddy(res); ++ struct gpu_buddy *mm = xe_res_get_buddy(res); + + head = &to_xe_ttm_vram_mgr_resource(res)->blocks; + + block = list_first_entry_or_null(head, +- struct drm_buddy_block, ++ struct gpu_buddy_block, + link); + if (!block) + goto fallback; + +- while (start >= drm_buddy_block_size(mm, block)) { +- start -= drm_buddy_block_size(mm, block); ++ while (start >= gpu_buddy_block_size(mm, block)) { ++ start -= gpu_buddy_block_size(mm, block); + + next = block->link.next; + if (next != head) +- block = list_entry(next, struct drm_buddy_block, ++ block = list_entry(next, struct gpu_buddy_block, + link); + } + + cur->mm = mm; +- cur->start = drm_buddy_block_offset(block) + start; +- cur->size = min(drm_buddy_block_size(mm, block) - start, ++ cur->start = gpu_buddy_block_offset(block) + start; ++ cur->size = min(gpu_buddy_block_size(mm, block) - start, + size); + cur->remaining = size; + cur->node = block; +@@ -259,7 +259,7 @@ static inline void xe_res_first_dma(const struct drm_pagemap_addr *dma_addr, + */ + static inline void xe_res_next(struct xe_res_cursor *cur, u64 size) + { +- struct drm_buddy_block *block; ++ struct gpu_buddy_block *block; + struct list_head *next; + u64 start; + +@@ -295,18 +295,18 @@ static inline void xe_res_next(struct xe_res_cursor *cur, u64 size) + block = cur->node; + + next = block->link.next; +- block = list_entry(next, struct drm_buddy_block, link); ++ block = list_entry(next, struct gpu_buddy_block, link); + + +- while (start >= drm_buddy_block_size(cur->mm, block)) { +- start -= drm_buddy_block_size(cur->mm, block); ++ while (start >= gpu_buddy_block_size(cur->mm, block)) { ++ start -= gpu_buddy_block_size(cur->mm, block); + + next = block->link.next; +- block = list_entry(next, struct drm_buddy_block, link); ++ block = list_entry(next, struct gpu_buddy_block, link); + } + +- cur->start = drm_buddy_block_offset(block) + start; +- cur->size = min(drm_buddy_block_size(cur->mm, block) - start, ++ cur->start = gpu_buddy_block_offset(block) + start; ++ cur->size = min(gpu_buddy_block_size(cur->mm, block) - start, + cur->remaining); + cur->node = block; + break; +diff --git a/drivers/gpu/drm/xe/xe_sa.c b/drivers/gpu/drm/xe/xe_sa.c +index fedd017d6dd36a..d9e0d30f8135e9 100644 +--- a/drivers/gpu/drm/xe/xe_sa.c ++++ b/drivers/gpu/drm/xe/xe_sa.c +@@ -29,6 +29,7 @@ static void xe_sa_bo_manager_fini(struct drm_device *drm, void *arg) + kvfree(sa_manager->cpu_ptr); + + sa_manager->bo = NULL; ++ sa_manager->shadow = NULL; + } + + /** +@@ -37,12 +38,14 @@ static void xe_sa_bo_manager_fini(struct drm_device *drm, void *arg) + * @size: number of bytes to allocate + * @guard: number of bytes to exclude from suballocations + * @align: alignment for each suballocated chunk ++ * @flags: flags for suballocator + * + * Prepares the suballocation manager for suballocations. + * + * Return: a pointer to the &xe_sa_manager or an ERR_PTR on failure. + */ +-struct xe_sa_manager *__xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 guard, u32 align) ++struct xe_sa_manager *__xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, ++ u32 guard, u32 align, u32 flags) + { + struct xe_device *xe = tile_to_xe(tile); + struct xe_sa_manager *sa_manager; +@@ -79,6 +82,26 @@ struct xe_sa_manager *__xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u3 + memset(sa_manager->cpu_ptr, 0, bo->ttm.base.size); + } + ++ if (flags & XE_SA_BO_MANAGER_FLAG_SHADOW) { ++ struct xe_bo *shadow; ++ ++ ret = drmm_mutex_init(&xe->drm, &sa_manager->swap_guard); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ shadow = xe_managed_bo_create_pin_map(xe, tile, size, ++ XE_BO_FLAG_VRAM_IF_DGFX(tile) | ++ XE_BO_FLAG_GGTT | ++ XE_BO_FLAG_GGTT_INVALIDATE | ++ XE_BO_FLAG_PINNED_NORESTORE); ++ if (IS_ERR(shadow)) { ++ drm_err(&xe->drm, "Failed to prepare %uKiB BO for SA manager (%pe)\n", ++ size / SZ_1K, shadow); ++ return ERR_CAST(shadow); ++ } ++ sa_manager->shadow = shadow; ++ } ++ + drm_suballoc_manager_init(&sa_manager->base, managed_size, align); + ret = drmm_add_action_or_reset(&xe->drm, xe_sa_bo_manager_fini, + sa_manager); +@@ -88,6 +111,48 @@ struct xe_sa_manager *__xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u3 + return sa_manager; + } + ++/** ++ * xe_sa_bo_swap_shadow() - Swap the SA BO with shadow BO. ++ * @sa_manager: the XE sub allocator manager ++ * ++ * Swaps the sub-allocator primary buffer object with shadow buffer object. ++ * ++ * Return: None. ++ */ ++void xe_sa_bo_swap_shadow(struct xe_sa_manager *sa_manager) ++{ ++ struct xe_device *xe = tile_to_xe(sa_manager->bo->tile); ++ ++ xe_assert(xe, sa_manager->shadow); ++ lockdep_assert_held(&sa_manager->swap_guard); ++ ++ swap(sa_manager->bo, sa_manager->shadow); ++ if (!sa_manager->bo->vmap.is_iomem) ++ sa_manager->cpu_ptr = sa_manager->bo->vmap.vaddr; ++} ++ ++/** ++ * xe_sa_bo_sync_shadow() - Sync the SA Shadow BO with primary BO. ++ * @sa_bo: the sub-allocator buffer object. ++ * ++ * Synchronize sub-allocator shadow buffer object with primary buffer object. ++ * ++ * Return: None. ++ */ ++void xe_sa_bo_sync_shadow(struct drm_suballoc *sa_bo) ++{ ++ struct xe_sa_manager *sa_manager = to_xe_sa_manager(sa_bo->manager); ++ struct xe_device *xe = tile_to_xe(sa_manager->bo->tile); ++ ++ xe_assert(xe, sa_manager->shadow); ++ lockdep_assert_held(&sa_manager->swap_guard); ++ ++ xe_map_memcpy_to(xe, &sa_manager->shadow->vmap, ++ drm_suballoc_soffset(sa_bo), ++ xe_sa_bo_cpu_addr(sa_bo), ++ drm_suballoc_size(sa_bo)); ++} ++ + /** + * __xe_sa_bo_new() - Make a suballocation but use custom gfp flags. + * @sa_manager: the &xe_sa_manager +diff --git a/drivers/gpu/drm/xe/xe_sa.h b/drivers/gpu/drm/xe/xe_sa.h +index 99dbf0eea54025..90ffa93a000ce4 100644 +--- a/drivers/gpu/drm/xe/xe_sa.h ++++ b/drivers/gpu/drm/xe/xe_sa.h +@@ -14,12 +14,14 @@ + struct dma_fence; + struct xe_tile; + +-struct xe_sa_manager *__xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 guard, u32 align); ++#define XE_SA_BO_MANAGER_FLAG_SHADOW BIT(0) ++struct xe_sa_manager *__xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, ++ u32 guard, u32 align, u32 flags); + struct drm_suballoc *__xe_sa_bo_new(struct xe_sa_manager *sa_manager, u32 size, gfp_t gfp); + + static inline struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 align) + { +- return __xe_sa_bo_manager_init(tile, size, SZ_4K, align); ++ return __xe_sa_bo_manager_init(tile, size, SZ_4K, align, 0); + } + + /** +@@ -68,4 +70,18 @@ static inline void *xe_sa_bo_cpu_addr(struct drm_suballoc *sa) + drm_suballoc_soffset(sa); + } + ++void xe_sa_bo_swap_shadow(struct xe_sa_manager *sa_manager); ++void xe_sa_bo_sync_shadow(struct drm_suballoc *sa_bo); ++ ++/** ++ * xe_sa_bo_swap_guard() - Retrieve the SA BO swap guard within sub-allocator. ++ * @sa_manager: the &xe_sa_manager ++ * ++ * Return: Sub alloctor swap guard mutex. ++ */ ++static inline struct mutex *xe_sa_bo_swap_guard(struct xe_sa_manager *sa_manager) ++{ ++ return &sa_manager->swap_guard; ++} ++ + #endif +diff --git a/drivers/gpu/drm/xe/xe_sa_types.h b/drivers/gpu/drm/xe/xe_sa_types.h +index cb7238799dcb20..1085c9c37d6b61 100644 +--- a/drivers/gpu/drm/xe/xe_sa_types.h ++++ b/drivers/gpu/drm/xe/xe_sa_types.h +@@ -12,6 +12,9 @@ struct xe_bo; + struct xe_sa_manager { + struct drm_suballoc_manager base; + struct xe_bo *bo; ++ struct xe_bo *shadow; ++ /** @swap_guard: Timeline guard updating @bo and @shadow */ ++ struct mutex swap_guard; + void *cpu_ptr; + bool is_iomem; + }; +diff --git a/drivers/gpu/drm/xe/xe_sriov_vf_ccs.c b/drivers/gpu/drm/xe/xe_sriov_vf_ccs.c +index 739a3eb180b53c..e03714ef7ae996 100644 +--- a/drivers/gpu/drm/xe/xe_sriov_vf_ccs.c ++++ b/drivers/gpu/drm/xe/xe_sriov_vf_ccs.c +@@ -148,7 +148,8 @@ static int alloc_bb_pool(struct xe_tile *tile, struct xe_sriov_vf_ccs_ctx *ctx) + xe_sriov_info(xe, "Allocating %s CCS BB pool size = %lldMB\n", + ctx->ctx_id ? "Restore" : "Save", bb_pool_size / SZ_1M); + +- sa_manager = xe_sa_bo_manager_init(tile, bb_pool_size, SZ_16); ++ sa_manager = __xe_sa_bo_manager_init(tile, bb_pool_size, SZ_4K, SZ_16, ++ XE_SA_BO_MANAGER_FLAG_SHADOW); + + if (IS_ERR(sa_manager)) { + xe_sriov_err(xe, "Suballocator init failed with error: %pe\n", +@@ -160,9 +161,12 @@ static int alloc_bb_pool(struct xe_tile *tile, struct xe_sriov_vf_ccs_ctx *ctx) + offset = 0; + xe_map_memset(xe, &sa_manager->bo->vmap, offset, MI_NOOP, + bb_pool_size); ++ xe_map_memset(xe, &sa_manager->shadow->vmap, offset, MI_NOOP, ++ bb_pool_size); + + offset = bb_pool_size - sizeof(u32); + xe_map_wr(xe, &sa_manager->bo->vmap, offset, u32, MI_BATCH_BUFFER_END); ++ xe_map_wr(xe, &sa_manager->shadow->vmap, offset, u32, MI_BATCH_BUFFER_END); + + ctx->mem.ccs_bb_pool = sa_manager; + +@@ -311,9 +315,23 @@ err_ret: + return err; + } + ++#define XE_SRIOV_VF_CCS_RW_BB_ADDR_OFFSET (2 * sizeof(u32)) ++void xe_sriov_vf_ccs_rw_update_bb_addr(struct xe_sriov_vf_ccs_ctx *ctx) ++{ ++ u64 addr = xe_sa_manager_gpu_addr(ctx->mem.ccs_bb_pool); ++ struct xe_lrc *lrc = xe_exec_queue_lrc(ctx->mig_q); ++ struct xe_device *xe = gt_to_xe(ctx->mig_q->gt); ++ ++ xe_device_wmb(xe); ++ xe_map_wr(xe, &lrc->bo->vmap, XE_SRIOV_VF_CCS_RW_BB_ADDR_OFFSET, u32, addr); ++ xe_device_wmb(xe); ++} ++ + /** + * xe_sriov_vf_ccs_attach_bo - Insert CCS read write commands in the BO. + * @bo: the &buffer object to which batch buffer commands will be added. ++ * @new_mem: the (not yet committed) destination resource @bo is being moved ++ * into; bo->ttm.resource is still the old resource at this point. + * + * This function shall be called only by VF. It inserts the PTEs and copy + * command instructions in the BO by calling xe_migrate_ccs_rw_copy() +@@ -321,7 +339,7 @@ err_ret: + * + * Returns: 0 if successful, negative error code on failure. + */ +-int xe_sriov_vf_ccs_attach_bo(struct xe_bo *bo) ++int xe_sriov_vf_ccs_attach_bo(struct xe_bo *bo, struct ttm_resource *new_mem) + { + struct xe_device *xe = xe_bo_device(bo); + enum xe_sriov_vf_ccs_rw_ctxs ctx_id; +@@ -340,7 +358,21 @@ int xe_sriov_vf_ccs_attach_bo(struct xe_bo *bo) + xe_assert(xe, !bb); + + ctx = &xe->sriov.vf.ccs.contexts[ctx_id]; +- err = xe_migrate_ccs_rw_copy(tile, ctx->mig_q, bo, ctx_id); ++ err = xe_migrate_ccs_rw_copy(tile, ctx->mig_q, bo, new_mem, ctx_id); ++ if (err) ++ goto err_unwind; ++ } ++ return 0; ++ ++err_unwind: ++ /* ++ * Clean up any contexts already attached. Can't reuse ++ * xe_sriov_vf_ccs_detach_bo() here as it requires both contexts ++ * attached before cleaning up either one. ++ */ ++ for_each_ccs_rw_ctx(ctx_id) { ++ if (bo->bb_ccs[ctx_id]) ++ xe_migrate_ccs_rw_copy_clear(bo, ctx_id); + } + return err; + } +@@ -371,9 +403,7 @@ int xe_sriov_vf_ccs_detach_bo(struct xe_bo *bo) + if (!bb) + continue; + +- memset(bb->cs, MI_NOOP, bb->len * sizeof(u32)); +- xe_bb_free(bb, NULL); +- bo->bb_ccs[ctx_id] = NULL; ++ xe_migrate_ccs_rw_copy_clear(bo, ctx_id); + } + return 0; + } +diff --git a/drivers/gpu/drm/xe/xe_sriov_vf_ccs.h b/drivers/gpu/drm/xe/xe_sriov_vf_ccs.h +index 0745c0ff022828..00d2c9dbe00d9a 100644 +--- a/drivers/gpu/drm/xe/xe_sriov_vf_ccs.h ++++ b/drivers/gpu/drm/xe/xe_sriov_vf_ccs.h +@@ -11,14 +11,16 @@ + #include "xe_sriov_vf_ccs_types.h" + + struct drm_printer; ++struct ttm_resource; + struct xe_device; + struct xe_bo; + + int xe_sriov_vf_ccs_init(struct xe_device *xe); +-int xe_sriov_vf_ccs_attach_bo(struct xe_bo *bo); ++int xe_sriov_vf_ccs_attach_bo(struct xe_bo *bo, struct ttm_resource *new_mem); + int xe_sriov_vf_ccs_detach_bo(struct xe_bo *bo); + int xe_sriov_vf_ccs_register_context(struct xe_device *xe); + void xe_sriov_vf_ccs_print(struct xe_device *xe, struct drm_printer *p); ++void xe_sriov_vf_ccs_rw_update_bb_addr(struct xe_sriov_vf_ccs_ctx *ctx); + + static inline bool xe_sriov_vf_ccs_ready(struct xe_device *xe) + { +diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c +index 65452c20609ed8..e1b8030b6bcf5e 100644 +--- a/drivers/gpu/drm/xe/xe_svm.c ++++ b/drivers/gpu/drm/xe/xe_svm.c +@@ -689,7 +689,7 @@ static u64 block_offset_to_pfn(struct xe_vram_region *vr, u64 offset) + return PHYS_PFN(offset + vr->hpa_base); + } + +-static struct drm_buddy *vram_to_buddy(struct xe_vram_region *vram) ++static struct gpu_buddy *vram_to_buddy(struct xe_vram_region *vram) + { + return &vram->ttm.mm; + } +@@ -700,16 +700,16 @@ static int xe_svm_populate_devmem_pfn(struct drm_pagemap_devmem *devmem_allocati + struct xe_bo *bo = to_xe_bo(devmem_allocation); + struct ttm_resource *res = bo->ttm.resource; + struct list_head *blocks = &to_xe_ttm_vram_mgr_resource(res)->blocks; +- struct drm_buddy_block *block; ++ struct gpu_buddy_block *block; + int j = 0; + + list_for_each_entry(block, blocks, link) { + struct xe_vram_region *vr = block->private; +- struct drm_buddy *buddy = vram_to_buddy(vr); +- u64 block_pfn = block_offset_to_pfn(vr, drm_buddy_block_offset(block)); ++ struct gpu_buddy *buddy = vram_to_buddy(vr); ++ u64 block_pfn = block_offset_to_pfn(vr, gpu_buddy_block_offset(block)); + int i; + +- for (i = 0; i < drm_buddy_block_size(buddy, block) >> PAGE_SHIFT; ++i) ++ for (i = 0; i < gpu_buddy_block_size(buddy, block) >> PAGE_SHIFT; ++i) + pfn[j++] = block_pfn + i; + } + +@@ -877,7 +877,7 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap, + struct dma_fence *pre_migrate_fence = NULL; + struct xe_device *xe = vr->xe; + struct device *dev = xe->drm.dev; +- struct drm_buddy_block *block; ++ struct gpu_buddy_block *block; + struct xe_validation_ctx vctx; + struct list_head *blocks; + struct drm_exec exec; +@@ -1074,10 +1074,8 @@ retry: + + xe_svm_range_fault_count_stats_incr(gt, range); + +- if (ctx.devmem_only && !range->base.pages.flags.migrate_devmem) { +- err = -EACCES; +- goto out; +- } ++ if (ctx.devmem_only && !range->base.pages.flags.migrate_devmem) ++ return -EACCES; + + if (xe_svm_range_is_valid(range, tile, ctx.devmem_only)) { + xe_svm_range_valid_fault_count_stats_incr(gt, range); +diff --git a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c +index 9175b4a2214b8c..f3d72773835ccf 100644 +--- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c ++++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c +@@ -6,6 +6,7 @@ + + #include <drm/drm_managed.h> + #include <drm/drm_drv.h> ++#include <drm/drm_buddy.h> + + #include <drm/ttm/ttm_placement.h> + #include <drm/ttm/ttm_range_manager.h> +@@ -17,16 +18,16 @@ + #include "xe_ttm_vram_mgr.h" + #include "xe_vram_types.h" + +-static inline struct drm_buddy_block * ++static inline struct gpu_buddy_block * + xe_ttm_vram_mgr_first_block(struct list_head *list) + { +- return list_first_entry_or_null(list, struct drm_buddy_block, link); ++ return list_first_entry_or_null(list, struct gpu_buddy_block, link); + } + +-static inline bool xe_is_vram_mgr_blocks_contiguous(struct drm_buddy *mm, ++static inline bool xe_is_vram_mgr_blocks_contiguous(struct gpu_buddy *mm, + struct list_head *head) + { +- struct drm_buddy_block *block; ++ struct gpu_buddy_block *block; + u64 start, size; + + block = xe_ttm_vram_mgr_first_block(head); +@@ -34,12 +35,12 @@ static inline bool xe_is_vram_mgr_blocks_contiguous(struct drm_buddy *mm, + return false; + + while (head != block->link.next) { +- start = drm_buddy_block_offset(block); +- size = drm_buddy_block_size(mm, block); ++ start = gpu_buddy_block_offset(block); ++ size = gpu_buddy_block_size(mm, block); + +- block = list_entry(block->link.next, struct drm_buddy_block, ++ block = list_entry(block->link.next, struct gpu_buddy_block, + link); +- if (start + size != drm_buddy_block_offset(block)) ++ if (start + size != gpu_buddy_block_offset(block)) + return false; + } + +@@ -53,7 +54,7 @@ static int xe_ttm_vram_mgr_new(struct ttm_resource_manager *man, + { + struct xe_ttm_vram_mgr *mgr = to_xe_ttm_vram_mgr(man); + struct xe_ttm_vram_mgr_resource *vres; +- struct drm_buddy *mm = &mgr->mm; ++ struct gpu_buddy *mm = &mgr->mm; + u64 size, min_page_size; + unsigned long lpfn; + int err; +@@ -80,10 +81,10 @@ static int xe_ttm_vram_mgr_new(struct ttm_resource_manager *man, + INIT_LIST_HEAD(&vres->blocks); + + if (place->flags & TTM_PL_FLAG_TOPDOWN) +- vres->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION; ++ vres->flags |= GPU_BUDDY_TOPDOWN_ALLOCATION; + + if (place->fpfn || lpfn != man->size >> PAGE_SHIFT) +- vres->flags |= DRM_BUDDY_RANGE_ALLOCATION; ++ vres->flags |= GPU_BUDDY_RANGE_ALLOCATION; + + if (WARN_ON(!vres->base.size)) { + err = -EINVAL; +@@ -119,27 +120,27 @@ static int xe_ttm_vram_mgr_new(struct ttm_resource_manager *man, + lpfn = max_t(unsigned long, place->fpfn + (size >> PAGE_SHIFT), lpfn); + } + +- err = drm_buddy_alloc_blocks(mm, (u64)place->fpfn << PAGE_SHIFT, ++ err = gpu_buddy_alloc_blocks(mm, (u64)place->fpfn << PAGE_SHIFT, + (u64)lpfn << PAGE_SHIFT, size, + min_page_size, &vres->blocks, vres->flags); + if (err) + goto error_unlock; + + if (place->flags & TTM_PL_FLAG_CONTIGUOUS) { +- if (!drm_buddy_block_trim(mm, NULL, vres->base.size, &vres->blocks)) ++ if (!gpu_buddy_block_trim(mm, NULL, vres->base.size, &vres->blocks)) + size = vres->base.size; + } + + if (lpfn <= mgr->visible_size >> PAGE_SHIFT) { + vres->used_visible_size = size; + } else { +- struct drm_buddy_block *block; ++ struct gpu_buddy_block *block; + + list_for_each_entry(block, &vres->blocks, link) { +- u64 start = drm_buddy_block_offset(block); ++ u64 start = gpu_buddy_block_offset(block); + + if (start < mgr->visible_size) { +- u64 end = start + drm_buddy_block_size(mm, block); ++ u64 end = start + gpu_buddy_block_size(mm, block); + + vres->used_visible_size += + min(end, mgr->visible_size) - start; +@@ -159,11 +160,11 @@ static int xe_ttm_vram_mgr_new(struct ttm_resource_manager *man, + * the object. + */ + if (vres->base.placement & TTM_PL_FLAG_CONTIGUOUS) { +- struct drm_buddy_block *block = list_first_entry(&vres->blocks, ++ struct gpu_buddy_block *block = list_first_entry(&vres->blocks, + typeof(*block), + link); + +- vres->base.start = drm_buddy_block_offset(block) >> PAGE_SHIFT; ++ vres->base.start = gpu_buddy_block_offset(block) >> PAGE_SHIFT; + } else { + vres->base.start = XE_BO_INVALID_OFFSET; + } +@@ -185,10 +186,10 @@ static void xe_ttm_vram_mgr_del(struct ttm_resource_manager *man, + struct xe_ttm_vram_mgr_resource *vres = + to_xe_ttm_vram_mgr_resource(res); + struct xe_ttm_vram_mgr *mgr = to_xe_ttm_vram_mgr(man); +- struct drm_buddy *mm = &mgr->mm; ++ struct gpu_buddy *mm = &mgr->mm; + + mutex_lock(&mgr->lock); +- drm_buddy_free_list(mm, &vres->blocks, 0); ++ gpu_buddy_free_list(mm, &vres->blocks, 0); + mgr->visible_avail += vres->used_visible_size; + mutex_unlock(&mgr->lock); + +@@ -201,7 +202,7 @@ static void xe_ttm_vram_mgr_debug(struct ttm_resource_manager *man, + struct drm_printer *printer) + { + struct xe_ttm_vram_mgr *mgr = to_xe_ttm_vram_mgr(man); +- struct drm_buddy *mm = &mgr->mm; ++ struct gpu_buddy *mm = &mgr->mm; + + mutex_lock(&mgr->lock); + drm_printf(printer, "default_page_size: %lluKiB\n", +@@ -224,8 +225,8 @@ static bool xe_ttm_vram_mgr_intersects(struct ttm_resource_manager *man, + struct xe_ttm_vram_mgr *mgr = to_xe_ttm_vram_mgr(man); + struct xe_ttm_vram_mgr_resource *vres = + to_xe_ttm_vram_mgr_resource(res); +- struct drm_buddy *mm = &mgr->mm; +- struct drm_buddy_block *block; ++ struct gpu_buddy *mm = &mgr->mm; ++ struct gpu_buddy_block *block; + + if (!place->fpfn && !place->lpfn) + return true; +@@ -235,9 +236,9 @@ static bool xe_ttm_vram_mgr_intersects(struct ttm_resource_manager *man, + + list_for_each_entry(block, &vres->blocks, link) { + unsigned long fpfn = +- drm_buddy_block_offset(block) >> PAGE_SHIFT; ++ gpu_buddy_block_offset(block) >> PAGE_SHIFT; + unsigned long lpfn = fpfn + +- (drm_buddy_block_size(mm, block) >> PAGE_SHIFT); ++ (gpu_buddy_block_size(mm, block) >> PAGE_SHIFT); + + if (place->fpfn < lpfn && place->lpfn > fpfn) + return true; +@@ -254,8 +255,8 @@ static bool xe_ttm_vram_mgr_compatible(struct ttm_resource_manager *man, + struct xe_ttm_vram_mgr *mgr = to_xe_ttm_vram_mgr(man); + struct xe_ttm_vram_mgr_resource *vres = + to_xe_ttm_vram_mgr_resource(res); +- struct drm_buddy *mm = &mgr->mm; +- struct drm_buddy_block *block; ++ struct gpu_buddy *mm = &mgr->mm; ++ struct gpu_buddy_block *block; + + if (!place->fpfn && !place->lpfn) + return true; +@@ -265,9 +266,9 @@ static bool xe_ttm_vram_mgr_compatible(struct ttm_resource_manager *man, + + list_for_each_entry(block, &vres->blocks, link) { + unsigned long fpfn = +- drm_buddy_block_offset(block) >> PAGE_SHIFT; ++ gpu_buddy_block_offset(block) >> PAGE_SHIFT; + unsigned long lpfn = fpfn + +- (drm_buddy_block_size(mm, block) >> PAGE_SHIFT); ++ (gpu_buddy_block_size(mm, block) >> PAGE_SHIFT); + + if (fpfn < place->fpfn || lpfn > place->lpfn) + return false; +@@ -297,7 +298,7 @@ static void ttm_vram_mgr_fini(struct drm_device *dev, void *arg) + + WARN_ON_ONCE(mgr->visible_avail != mgr->visible_size); + +- drm_buddy_fini(&mgr->mm); ++ gpu_buddy_fini(&mgr->mm); + + ttm_resource_manager_cleanup(&mgr->manager); + +@@ -328,7 +329,7 @@ int __xe_ttm_vram_mgr_init(struct xe_device *xe, struct xe_ttm_vram_mgr *mgr, + mgr->visible_avail = io_size; + + ttm_resource_manager_init(man, &xe->ttm, size); +- err = drm_buddy_init(&mgr->mm, man->size, default_page_size); ++ err = gpu_buddy_init(&mgr->mm, man->size, default_page_size); + if (err) + return err; + +@@ -376,7 +377,7 @@ int xe_ttm_vram_mgr_alloc_sgt(struct xe_device *xe, + if (!*sgt) + return -ENOMEM; + +- /* Determine the number of DRM_BUDDY blocks to export */ ++ /* Determine the number of GPU_BUDDY blocks to export */ + xe_res_first(res, offset, length, &cursor); + while (cursor.remaining) { + num_entries++; +@@ -393,10 +394,10 @@ int xe_ttm_vram_mgr_alloc_sgt(struct xe_device *xe, + 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 GPU_BUDDY blocks to populate scatterlist nodes ++ * @note: Use iterator api to get first the GPU_BUDDY block + * and the number of bytes from it. Access the following +- * DRM_BUDDY block(s) if more buffer needs to exported ++ * GPU_BUDDY block(s) if more buffer needs to exported + */ + xe_res_first(res, offset, length, &cursor); + for_each_sgtable_sg((*sgt), sg, i) { +diff --git a/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h b/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h +index 1144f9232ebbba..674a846f99862e 100644 +--- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h ++++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h +@@ -6,7 +6,7 @@ + #ifndef _XE_TTM_VRAM_MGR_TYPES_H_ + #define _XE_TTM_VRAM_MGR_TYPES_H_ + +-#include <drm/drm_buddy.h> ++#include <linux/gpu_buddy.h> + #include <drm/ttm/ttm_device.h> + + /** +@@ -18,7 +18,7 @@ struct xe_ttm_vram_mgr { + /** @manager: Base TTM resource manager */ + struct ttm_resource_manager manager; + /** @mm: DRM buddy allocator which manages the VRAM */ +- struct drm_buddy mm; ++ struct gpu_buddy mm; + /** @visible_size: Proped size of the CPU visible portion */ + u64 visible_size; + /** @visible_avail: CPU visible portion still unallocated */ +diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c +index 8f7b8f2da06bac..ed0c8acd0fe27c 100644 +--- a/drivers/gpu/drm/xe/xe_vm.c ++++ b/drivers/gpu/drm/xe/xe_vm.c +@@ -1626,10 +1626,10 @@ err_close: + return ERR_PTR(err); + + err_svm_fini: +- if (flags & XE_VM_FLAG_FAULT_MODE) { +- vm->size = 0; /* close the vm */ +- xe_svm_fini(vm); +- } ++ vm->size = 0; /* close the vm */ ++ if (flags & XE_VM_FLAG_FAULT_MODE) ++ xe_svm_close(vm); ++ xe_svm_fini(vm); + err_no_resv: + mutex_destroy(&vm->snap_mutex); + for_each_tile(tile, xe, id) +@@ -3393,6 +3393,8 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe, struct xe_vm *vm, + op == DRM_XE_VM_BIND_OP_MAP_USERPTR) || + XE_IOCTL_DBG(xe, coh_mode == XE_COH_NONE && + op == DRM_XE_VM_BIND_OP_MAP_USERPTR) || ++ XE_IOCTL_DBG(xe, !IS_DGFX(xe) && coh_mode == XE_COH_NONE && ++ is_cpu_addr_mirror) || + XE_IOCTL_DBG(xe, op == DRM_XE_VM_BIND_OP_MAP_USERPTR && + !IS_ENABLED(CONFIG_DRM_GPUSVM)) || + XE_IOCTL_DBG(xe, obj && +diff --git a/drivers/gpu/drm/xe/xe_wopcm.c b/drivers/gpu/drm/xe/xe_wopcm.c +index ada0d0aa6b7494..2fd2a82be89f87 100644 +--- a/drivers/gpu/drm/xe/xe_wopcm.c ++++ b/drivers/gpu/drm/xe/xe_wopcm.c +@@ -49,9 +49,9 @@ + */ + + /* Default WOPCM size is 2MB from Gen11, 1MB on previous platforms */ +-/* FIXME: Larger size require for 2 tile PVC, do a proper probe sooner or later */ ++/* FIXME: Larger size require for some platforms, do a proper probe sooner or later */ + #define DGFX_WOPCM_SIZE SZ_4M +-/* FIXME: Larger size require for MTL, do a proper probe sooner or later */ ++#define LNL_WOPCM_SIZE SZ_8M + #define MTL_WOPCM_SIZE SZ_4M + #define WOPCM_SIZE SZ_2M + +@@ -181,9 +181,14 @@ err_out: + + u32 xe_wopcm_size(struct xe_device *xe) + { +- return IS_DGFX(xe) ? DGFX_WOPCM_SIZE : +- xe->info.platform == XE_METEORLAKE ? MTL_WOPCM_SIZE : +- WOPCM_SIZE; ++ if (xe->info.platform >= XE_LUNARLAKE) ++ return LNL_WOPCM_SIZE; ++ else if (IS_DGFX(xe)) ++ return DGFX_WOPCM_SIZE; ++ else if (xe->info.platform == XE_METEORLAKE) ++ return MTL_WOPCM_SIZE; ++ else ++ return WOPCM_SIZE; + } + + /** +diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c +index 3801eab63282ff..3313ead8bfcc24 100644 +--- a/drivers/gpu/host1x/bus.c ++++ b/drivers/gpu/host1x/bus.c +@@ -1001,10 +1001,10 @@ void host1x_bo_clear_cached_mappings(struct host1x_bo *bo) + if (WARN_ON(!cache)) + continue; + +- mutex_lock(&mapping->cache->lock); ++ mutex_lock(&cache->lock); + WARN_ON(kref_read(&mapping->ref) != 1); + __host1x_bo_unpin(&mapping->ref); +- mutex_unlock(&mapping->cache->lock); ++ mutex_unlock(&cache->lock); + } + } + EXPORT_SYMBOL(host1x_bo_clear_cached_mappings); +diff --git a/drivers/gpu/tests/Makefile b/drivers/gpu/tests/Makefile +new file mode 100644 +index 00000000000000..4183e6e2de4511 +--- /dev/null ++++ b/drivers/gpu/tests/Makefile +@@ -0,0 +1,4 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++gpu_buddy_tests-y = gpu_buddy_test.o gpu_random.o ++obj-$(CONFIG_GPU_BUDDY_KUNIT_TEST) += gpu_buddy_tests.o +diff --git a/drivers/gpu/tests/gpu_buddy_test.c b/drivers/gpu/tests/gpu_buddy_test.c +new file mode 100644 +index 00000000000000..3f689e1f3581aa +--- /dev/null ++++ b/drivers/gpu/tests/gpu_buddy_test.c +@@ -0,0 +1,788 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * Copyright © 2019 Intel Corporation ++ * Copyright © 2022 Maíra Canal <[email protected]> ++ */ ++ ++#include <kunit/test.h> ++ ++#include <linux/prime_numbers.h> ++#include <linux/sched/signal.h> ++#include <linux/sizes.h> ++ ++#include <linux/gpu_buddy.h> ++ ++#include "gpu_random.h" ++ ++static unsigned int random_seed; ++ ++static inline u64 get_size(int order, u64 chunk_size) ++{ ++ return (1 << order) * chunk_size; ++} ++ ++static void gpu_test_buddy_alloc_range_bias(struct kunit *test) ++{ ++ u32 mm_size, size, ps, bias_size, bias_start, bias_end, bias_rem; ++ GPU_RND_STATE(prng, random_seed); ++ unsigned int i, count, *order; ++ struct gpu_buddy_block *block; ++ unsigned long flags; ++ struct gpu_buddy mm; ++ LIST_HEAD(allocated); ++ ++ bias_size = SZ_1M; ++ ps = roundup_pow_of_two(prandom_u32_state(&prng) % bias_size); ++ ps = max(SZ_4K, ps); ++ mm_size = (SZ_8M-1) & ~(ps-1); /* Multiple roots */ ++ ++ kunit_info(test, "mm_size=%u, ps=%u\n", mm_size, ps); ++ ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, ps), ++ "buddy_init failed\n"); ++ ++ count = mm_size / bias_size; ++ order = gpu_random_order(count, &prng); ++ KUNIT_EXPECT_TRUE(test, order); ++ ++ /* ++ * Idea is to split the address space into uniform bias ranges, and then ++ * in some random order allocate within each bias, using various ++ * patterns within. This should detect if allocations leak out from a ++ * given bias, for example. ++ */ ++ ++ for (i = 0; i < count; i++) { ++ LIST_HEAD(tmp); ++ u32 size; ++ ++ bias_start = order[i] * bias_size; ++ bias_end = bias_start + bias_size; ++ bias_rem = bias_size; ++ ++ /* internal round_up too big */ ++ KUNIT_ASSERT_TRUE_MSG(test, ++ gpu_buddy_alloc_blocks(&mm, bias_start, ++ bias_end, bias_size + ps, bias_size, ++ &allocated, ++ GPU_BUDDY_RANGE_ALLOCATION), ++ "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", ++ bias_start, bias_end, bias_size, bias_size); ++ ++ /* size too big */ ++ KUNIT_ASSERT_TRUE_MSG(test, ++ gpu_buddy_alloc_blocks(&mm, bias_start, ++ bias_end, bias_size + ps, ps, ++ &allocated, ++ GPU_BUDDY_RANGE_ALLOCATION), ++ "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n", ++ bias_start, bias_end, bias_size + ps, ps); ++ ++ /* bias range too small for size */ ++ KUNIT_ASSERT_TRUE_MSG(test, ++ gpu_buddy_alloc_blocks(&mm, bias_start + ps, ++ bias_end, bias_size, ps, ++ &allocated, ++ GPU_BUDDY_RANGE_ALLOCATION), ++ "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n", ++ bias_start + ps, bias_end, bias_size, ps); ++ ++ /* bias misaligned */ ++ KUNIT_ASSERT_TRUE_MSG(test, ++ gpu_buddy_alloc_blocks(&mm, bias_start + ps, ++ bias_end - ps, ++ bias_size >> 1, bias_size >> 1, ++ &allocated, ++ GPU_BUDDY_RANGE_ALLOCATION), ++ "buddy_alloc h didn't fail with bias(%x-%x), size=%u, ps=%u\n", ++ bias_start + ps, bias_end - ps, bias_size >> 1, bias_size >> 1); ++ ++ /* single big page */ ++ KUNIT_ASSERT_FALSE_MSG(test, ++ gpu_buddy_alloc_blocks(&mm, bias_start, ++ bias_end, bias_size, bias_size, ++ &tmp, ++ GPU_BUDDY_RANGE_ALLOCATION), ++ "buddy_alloc i failed with bias(%x-%x), size=%u, ps=%u\n", ++ bias_start, bias_end, bias_size, bias_size); ++ gpu_buddy_free_list(&mm, &tmp, 0); ++ ++ /* single page with internal round_up */ ++ KUNIT_ASSERT_FALSE_MSG(test, ++ gpu_buddy_alloc_blocks(&mm, bias_start, ++ bias_end, ps, bias_size, ++ &tmp, ++ GPU_BUDDY_RANGE_ALLOCATION), ++ "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", ++ bias_start, bias_end, ps, bias_size); ++ gpu_buddy_free_list(&mm, &tmp, 0); ++ ++ /* random size within */ ++ size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps); ++ if (size) ++ KUNIT_ASSERT_FALSE_MSG(test, ++ gpu_buddy_alloc_blocks(&mm, bias_start, ++ bias_end, size, ps, ++ &tmp, ++ GPU_BUDDY_RANGE_ALLOCATION), ++ "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", ++ bias_start, bias_end, size, ps); ++ ++ bias_rem -= size; ++ /* too big for current avail */ ++ KUNIT_ASSERT_TRUE_MSG(test, ++ gpu_buddy_alloc_blocks(&mm, bias_start, ++ bias_end, bias_rem + ps, ps, ++ &allocated, ++ GPU_BUDDY_RANGE_ALLOCATION), ++ "buddy_alloc didn't fail with bias(%x-%x), size=%u, ps=%u\n", ++ bias_start, bias_end, bias_rem + ps, ps); ++ ++ if (bias_rem) { ++ /* random fill of the remainder */ ++ size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps); ++ size = max(size, ps); ++ ++ KUNIT_ASSERT_FALSE_MSG(test, ++ gpu_buddy_alloc_blocks(&mm, bias_start, ++ bias_end, size, ps, ++ &allocated, ++ GPU_BUDDY_RANGE_ALLOCATION), ++ "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", ++ bias_start, bias_end, size, ps); ++ /* ++ * Intentionally allow some space to be left ++ * unallocated, and ideally not always on the bias ++ * boundaries. ++ */ ++ gpu_buddy_free_list(&mm, &tmp, 0); ++ } else { ++ list_splice_tail(&tmp, &allocated); ++ } ++ } ++ ++ kfree(order); ++ gpu_buddy_free_list(&mm, &allocated, 0); ++ gpu_buddy_fini(&mm); ++ ++ /* ++ * Something more free-form. Idea is to pick a random starting bias ++ * range within the address space and then start filling it up. Also ++ * randomly grow the bias range in both directions as we go along. This ++ * should give us bias start/end which is not always uniform like above, ++ * and in some cases will require the allocator to jump over already ++ * allocated nodes in the middle of the address space. ++ */ ++ ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, ps), ++ "buddy_init failed\n"); ++ ++ bias_start = round_up(prandom_u32_state(&prng) % (mm_size - ps), ps); ++ bias_end = round_up(bias_start + prandom_u32_state(&prng) % (mm_size - bias_start), ps); ++ bias_end = max(bias_end, bias_start + ps); ++ bias_rem = bias_end - bias_start; ++ ++ do { ++ u32 size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps); ++ ++ KUNIT_ASSERT_FALSE_MSG(test, ++ gpu_buddy_alloc_blocks(&mm, bias_start, ++ bias_end, size, ps, ++ &allocated, ++ GPU_BUDDY_RANGE_ALLOCATION), ++ "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", ++ bias_start, bias_end, size, ps); ++ bias_rem -= size; ++ ++ /* ++ * Try to randomly grow the bias range in both directions, or ++ * only one, or perhaps don't grow at all. ++ */ ++ do { ++ u32 old_bias_start = bias_start; ++ u32 old_bias_end = bias_end; ++ ++ if (bias_start) ++ bias_start -= round_up(prandom_u32_state(&prng) % bias_start, ps); ++ if (bias_end != mm_size) ++ bias_end += round_up(prandom_u32_state(&prng) % (mm_size - bias_end), ps); ++ ++ bias_rem += old_bias_start - bias_start; ++ bias_rem += bias_end - old_bias_end; ++ } while (!bias_rem && (bias_start || bias_end != mm_size)); ++ } while (bias_rem); ++ ++ KUNIT_ASSERT_EQ(test, bias_start, 0); ++ KUNIT_ASSERT_EQ(test, bias_end, mm_size); ++ KUNIT_ASSERT_TRUE_MSG(test, ++ gpu_buddy_alloc_blocks(&mm, bias_start, bias_end, ++ ps, ps, ++ &allocated, ++ GPU_BUDDY_RANGE_ALLOCATION), ++ "buddy_alloc passed with bias(%x-%x), size=%u\n", ++ bias_start, bias_end, ps); ++ ++ gpu_buddy_free_list(&mm, &allocated, 0); ++ gpu_buddy_fini(&mm); ++ ++ /* ++ * Allocate cleared blocks in the bias range when the GPU buddy's clear avail is ++ * zero. This will validate the bias range allocation in scenarios like system boot ++ * when no cleared blocks are available and exercise the fallback path too. The resulting ++ * blocks should always be dirty. ++ */ ++ ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, ps), ++ "buddy_init failed\n"); ++ ++ bias_start = round_up(prandom_u32_state(&prng) % (mm_size - ps), ps); ++ bias_end = round_up(bias_start + prandom_u32_state(&prng) % (mm_size - bias_start), ps); ++ bias_end = max(bias_end, bias_start + ps); ++ bias_rem = bias_end - bias_start; ++ ++ flags = GPU_BUDDY_CLEAR_ALLOCATION | GPU_BUDDY_RANGE_ALLOCATION; ++ size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps); ++ ++ KUNIT_ASSERT_FALSE_MSG(test, ++ gpu_buddy_alloc_blocks(&mm, bias_start, ++ bias_end, size, ps, ++ &allocated, ++ flags), ++ "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", ++ bias_start, bias_end, size, ps); ++ ++ list_for_each_entry(block, &allocated, link) ++ KUNIT_EXPECT_EQ(test, gpu_buddy_block_is_clear(block), false); ++ ++ gpu_buddy_free_list(&mm, &allocated, 0); ++ gpu_buddy_fini(&mm); ++} ++ ++static void gpu_test_buddy_alloc_clear(struct kunit *test) ++{ ++ unsigned long n_pages, total, i = 0; ++ const unsigned long ps = SZ_4K; ++ struct gpu_buddy_block *block; ++ const int max_order = 12; ++ LIST_HEAD(allocated); ++ struct gpu_buddy mm; ++ unsigned int order; ++ u32 mm_size, size; ++ LIST_HEAD(dirty); ++ LIST_HEAD(clean); ++ ++ mm_size = SZ_4K << max_order; ++ KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); ++ ++ KUNIT_EXPECT_EQ(test, mm.max_order, max_order); ++ ++ /* ++ * Idea is to allocate and free some random portion of the address space, ++ * returning those pages as non-dirty and randomly alternate between ++ * requesting dirty and non-dirty pages (not going over the limit ++ * we freed as non-dirty), putting that into two separate lists. ++ * Loop over both lists at the end checking that the dirty list ++ * is indeed all dirty pages and vice versa. Free it all again, ++ * keeping the dirty/clear status. ++ */ ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, ++ 5 * ps, ps, &allocated, ++ GPU_BUDDY_TOPDOWN_ALLOCATION), ++ "buddy_alloc hit an error size=%lu\n", 5 * ps); ++ gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED); ++ ++ n_pages = 10; ++ do { ++ unsigned long flags; ++ struct list_head *list; ++ int slot = i % 2; ++ ++ if (slot == 0) { ++ list = &dirty; ++ flags = 0; ++ } else { ++ list = &clean; ++ flags = GPU_BUDDY_CLEAR_ALLOCATION; ++ } ++ ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, ++ ps, ps, list, ++ flags), ++ "buddy_alloc hit an error size=%lu\n", ps); ++ } while (++i < n_pages); ++ ++ list_for_each_entry(block, &clean, link) ++ KUNIT_EXPECT_EQ(test, gpu_buddy_block_is_clear(block), true); ++ ++ list_for_each_entry(block, &dirty, link) ++ KUNIT_EXPECT_EQ(test, gpu_buddy_block_is_clear(block), false); ++ ++ gpu_buddy_free_list(&mm, &clean, GPU_BUDDY_CLEARED); ++ ++ /* ++ * Trying to go over the clear limit for some allocation. ++ * The allocation should never fail with reasonable page-size. ++ */ ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, ++ 10 * ps, ps, &clean, ++ GPU_BUDDY_CLEAR_ALLOCATION), ++ "buddy_alloc hit an error size=%lu\n", 10 * ps); ++ ++ gpu_buddy_free_list(&mm, &clean, GPU_BUDDY_CLEARED); ++ gpu_buddy_free_list(&mm, &dirty, 0); ++ gpu_buddy_fini(&mm); ++ ++ KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); ++ ++ /* ++ * Create a new mm. Intentionally fragment the address space by creating ++ * two alternating lists. Free both lists, one as dirty the other as clean. ++ * Try to allocate double the previous size with matching min_page_size. The ++ * allocation should never fail as it calls the force_merge. Also check that ++ * the page is always dirty after force_merge. Free the page as dirty, then ++ * repeat the whole thing, increment the order until we hit the max_order. ++ */ ++ ++ i = 0; ++ n_pages = mm_size / ps; ++ do { ++ struct list_head *list; ++ int slot = i % 2; ++ ++ if (slot == 0) ++ list = &dirty; ++ else ++ list = &clean; ++ ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, ++ ps, ps, list, 0), ++ "buddy_alloc hit an error size=%lu\n", ps); ++ } while (++i < n_pages); ++ ++ gpu_buddy_free_list(&mm, &clean, GPU_BUDDY_CLEARED); ++ gpu_buddy_free_list(&mm, &dirty, 0); ++ ++ order = 1; ++ do { ++ size = SZ_4K << order; ++ ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, ++ size, size, &allocated, ++ GPU_BUDDY_CLEAR_ALLOCATION), ++ "buddy_alloc hit an error size=%u\n", size); ++ total = 0; ++ list_for_each_entry(block, &allocated, link) { ++ if (size != mm_size) ++ KUNIT_EXPECT_EQ(test, gpu_buddy_block_is_clear(block), false); ++ total += gpu_buddy_block_size(&mm, block); ++ } ++ KUNIT_EXPECT_EQ(test, total, size); ++ ++ gpu_buddy_free_list(&mm, &allocated, 0); ++ } while (++order <= max_order); ++ ++ gpu_buddy_fini(&mm); ++ ++ /* ++ * Create a new mm with a non power-of-two size. Allocate a random size from each ++ * root, free as cleared and then call fini. This will ensure the multi-root ++ * force merge during fini. ++ */ ++ mm_size = (SZ_4K << max_order) + (SZ_4K << (max_order - 2)); ++ ++ KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); ++ KUNIT_EXPECT_EQ(test, mm.max_order, max_order); ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, SZ_4K << max_order, ++ 4 * ps, ps, &allocated, ++ GPU_BUDDY_RANGE_ALLOCATION), ++ "buddy_alloc hit an error size=%lu\n", 4 * ps); ++ gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED); ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, SZ_4K << max_order, ++ 2 * ps, ps, &allocated, ++ GPU_BUDDY_CLEAR_ALLOCATION), ++ "buddy_alloc hit an error size=%lu\n", 2 * ps); ++ gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED); ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, SZ_4K << max_order, mm_size, ++ ps, ps, &allocated, ++ GPU_BUDDY_RANGE_ALLOCATION), ++ "buddy_alloc hit an error size=%lu\n", ps); ++ gpu_buddy_free_list(&mm, &allocated, GPU_BUDDY_CLEARED); ++ gpu_buddy_fini(&mm); ++} ++ ++static void gpu_test_buddy_alloc_contiguous(struct kunit *test) ++{ ++ const unsigned long ps = SZ_4K, mm_size = 16 * 3 * SZ_4K; ++ unsigned long i, n_pages, total; ++ struct gpu_buddy_block *block; ++ struct gpu_buddy mm; ++ LIST_HEAD(left); ++ LIST_HEAD(middle); ++ LIST_HEAD(right); ++ LIST_HEAD(allocated); ++ ++ KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, mm_size, ps)); ++ ++ /* ++ * Idea is to fragment the address space by alternating block ++ * allocations between three different lists; one for left, middle and ++ * right. We can then free a list to simulate fragmentation. In ++ * particular we want to exercise the GPU_BUDDY_CONTIGUOUS_ALLOCATION, ++ * including the try_harder path. ++ */ ++ ++ i = 0; ++ n_pages = mm_size / ps; ++ do { ++ struct list_head *list; ++ int slot = i % 3; ++ ++ if (slot == 0) ++ list = &left; ++ else if (slot == 1) ++ list = &middle; ++ else ++ list = &right; ++ KUNIT_ASSERT_FALSE_MSG(test, ++ gpu_buddy_alloc_blocks(&mm, 0, mm_size, ++ ps, ps, list, 0), ++ "buddy_alloc hit an error size=%lu\n", ++ ps); ++ } while (++i < n_pages); ++ ++ KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, ++ 3 * ps, ps, &allocated, ++ GPU_BUDDY_CONTIGUOUS_ALLOCATION), ++ "buddy_alloc didn't error size=%lu\n", 3 * ps); ++ ++ gpu_buddy_free_list(&mm, &middle, 0); ++ KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, ++ 3 * ps, ps, &allocated, ++ GPU_BUDDY_CONTIGUOUS_ALLOCATION), ++ "buddy_alloc didn't error size=%lu\n", 3 * ps); ++ KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, ++ 2 * ps, ps, &allocated, ++ GPU_BUDDY_CONTIGUOUS_ALLOCATION), ++ "buddy_alloc didn't error size=%lu\n", 2 * ps); ++ ++ gpu_buddy_free_list(&mm, &right, 0); ++ KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, ++ 3 * ps, ps, &allocated, ++ GPU_BUDDY_CONTIGUOUS_ALLOCATION), ++ "buddy_alloc didn't error size=%lu\n", 3 * ps); ++ /* ++ * At this point we should have enough contiguous space for 2 blocks, ++ * however they are never buddies (since we freed middle and right) so ++ * will require the try_harder logic to find them. ++ */ ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, ++ 2 * ps, ps, &allocated, ++ GPU_BUDDY_CONTIGUOUS_ALLOCATION), ++ "buddy_alloc hit an error size=%lu\n", 2 * ps); ++ ++ gpu_buddy_free_list(&mm, &left, 0); ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, 0, mm_size, ++ 3 * ps, ps, &allocated, ++ GPU_BUDDY_CONTIGUOUS_ALLOCATION), ++ "buddy_alloc hit an error size=%lu\n", 3 * ps); ++ ++ total = 0; ++ list_for_each_entry(block, &allocated, link) ++ total += gpu_buddy_block_size(&mm, block); ++ ++ KUNIT_ASSERT_EQ(test, total, ps * 2 + ps * 3); ++ ++ gpu_buddy_free_list(&mm, &allocated, 0); ++ gpu_buddy_fini(&mm); ++} ++ ++static void gpu_test_buddy_alloc_pathological(struct kunit *test) ++{ ++ u64 mm_size, size, start = 0; ++ struct gpu_buddy_block *block; ++ const int max_order = 3; ++ unsigned long flags = 0; ++ int order, top; ++ struct gpu_buddy mm; ++ LIST_HEAD(blocks); ++ LIST_HEAD(holes); ++ LIST_HEAD(tmp); ++ ++ /* ++ * Create a pot-sized mm, then allocate one of each possible ++ * order within. This should leave the mm with exactly one ++ * page left. Free the largest block, then whittle down again. ++ * Eventually we will have a fully 50% fragmented mm. ++ */ ++ ++ mm_size = SZ_4K << max_order; ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K), ++ "buddy_init failed\n"); ++ ++ KUNIT_EXPECT_EQ(test, mm.max_order, max_order); ++ ++ for (top = max_order; top; top--) { ++ /* Make room by freeing the largest allocated block */ ++ block = list_first_entry_or_null(&blocks, typeof(*block), link); ++ if (block) { ++ list_del(&block->link); ++ gpu_buddy_free_block(&mm, block); ++ } ++ ++ for (order = top; order--;) { ++ size = get_size(order, mm.chunk_size); ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, ++ mm_size, size, size, ++ &tmp, flags), ++ "buddy_alloc hit -ENOMEM with order=%d, top=%d\n", ++ order, top); ++ ++ block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link); ++ KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); ++ ++ list_move_tail(&block->link, &blocks); ++ } ++ ++ /* There should be one final page for this sub-allocation */ ++ size = get_size(0, mm.chunk_size); ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, ++ size, size, &tmp, flags), ++ "buddy_alloc hit -ENOMEM for hole\n"); ++ ++ block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link); ++ KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); ++ ++ list_move_tail(&block->link, &holes); ++ ++ size = get_size(top, mm.chunk_size); ++ KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, ++ size, size, &tmp, flags), ++ "buddy_alloc unexpectedly succeeded at top-order %d/%d, it should be full!", ++ top, max_order); ++ } ++ ++ gpu_buddy_free_list(&mm, &holes, 0); ++ ++ /* Nothing larger than blocks of chunk_size now available */ ++ for (order = 1; order <= max_order; order++) { ++ size = get_size(order, mm.chunk_size); ++ KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, ++ size, size, &tmp, flags), ++ "buddy_alloc unexpectedly succeeded at order %d, it should be full!", ++ order); ++ } ++ ++ list_splice_tail(&holes, &blocks); ++ gpu_buddy_free_list(&mm, &blocks, 0); ++ gpu_buddy_fini(&mm); ++} ++ ++static void gpu_test_buddy_alloc_pessimistic(struct kunit *test) ++{ ++ u64 mm_size, size, start = 0; ++ struct gpu_buddy_block *block, *bn; ++ const unsigned int max_order = 16; ++ unsigned long flags = 0; ++ struct gpu_buddy mm; ++ unsigned int order; ++ LIST_HEAD(blocks); ++ LIST_HEAD(tmp); ++ ++ /* ++ * Create a pot-sized mm, then allocate one of each possible ++ * order within. This should leave the mm with exactly one ++ * page left. ++ */ ++ ++ mm_size = SZ_4K << max_order; ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K), ++ "buddy_init failed\n"); ++ ++ KUNIT_EXPECT_EQ(test, mm.max_order, max_order); ++ ++ for (order = 0; order < max_order; order++) { ++ size = get_size(order, mm.chunk_size); ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, ++ size, size, &tmp, flags), ++ "buddy_alloc hit -ENOMEM with order=%d\n", ++ order); ++ ++ block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link); ++ KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); ++ ++ list_move_tail(&block->link, &blocks); ++ } ++ ++ /* And now the last remaining block available */ ++ size = get_size(0, mm.chunk_size); ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, ++ size, size, &tmp, flags), ++ "buddy_alloc hit -ENOMEM on final alloc\n"); ++ ++ block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link); ++ KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); ++ ++ list_move_tail(&block->link, &blocks); ++ ++ /* Should be completely full! */ ++ for (order = max_order; order--;) { ++ size = get_size(order, mm.chunk_size); ++ KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, ++ size, size, &tmp, flags), ++ "buddy_alloc unexpectedly succeeded, it should be full!"); ++ } ++ ++ block = list_last_entry(&blocks, typeof(*block), link); ++ list_del(&block->link); ++ gpu_buddy_free_block(&mm, block); ++ ++ /* As we free in increasing size, we make available larger blocks */ ++ order = 1; ++ list_for_each_entry_safe(block, bn, &blocks, link) { ++ list_del(&block->link); ++ gpu_buddy_free_block(&mm, block); ++ ++ size = get_size(order, mm.chunk_size); ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, ++ size, size, &tmp, flags), ++ "buddy_alloc hit -ENOMEM with order=%d\n", ++ order); ++ ++ block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link); ++ KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); ++ ++ list_del(&block->link); ++ gpu_buddy_free_block(&mm, block); ++ order++; ++ } ++ ++ /* To confirm, now the whole mm should be available */ ++ size = get_size(max_order, mm.chunk_size); ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, ++ size, size, &tmp, flags), ++ "buddy_alloc (realloc) hit -ENOMEM with order=%d\n", ++ max_order); ++ ++ block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link); ++ KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); ++ ++ list_del(&block->link); ++ gpu_buddy_free_block(&mm, block); ++ gpu_buddy_free_list(&mm, &blocks, 0); ++ gpu_buddy_fini(&mm); ++} ++ ++static void gpu_test_buddy_alloc_optimistic(struct kunit *test) ++{ ++ u64 mm_size, size, start = 0; ++ struct gpu_buddy_block *block; ++ unsigned long flags = 0; ++ const int max_order = 16; ++ struct gpu_buddy mm; ++ LIST_HEAD(blocks); ++ LIST_HEAD(tmp); ++ int order; ++ ++ /* ++ * Create a mm with one block of each order available, and ++ * try to allocate them all. ++ */ ++ ++ mm_size = SZ_4K * ((1 << (max_order + 1)) - 1); ++ ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_init(&mm, mm_size, SZ_4K), ++ "buddy_init failed\n"); ++ ++ KUNIT_EXPECT_EQ(test, mm.max_order, max_order); ++ ++ for (order = 0; order <= max_order; order++) { ++ size = get_size(order, mm.chunk_size); ++ KUNIT_ASSERT_FALSE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, ++ size, size, &tmp, flags), ++ "buddy_alloc hit -ENOMEM with order=%d\n", ++ order); ++ ++ block = list_first_entry_or_null(&tmp, struct gpu_buddy_block, link); ++ KUNIT_ASSERT_TRUE_MSG(test, block, "alloc_blocks has no blocks\n"); ++ ++ list_move_tail(&block->link, &blocks); ++ } ++ ++ /* Should be completely full! */ ++ size = get_size(0, mm.chunk_size); ++ KUNIT_ASSERT_TRUE_MSG(test, gpu_buddy_alloc_blocks(&mm, start, mm_size, ++ size, size, &tmp, flags), ++ "buddy_alloc unexpectedly succeeded, it should be full!"); ++ ++ gpu_buddy_free_list(&mm, &blocks, 0); ++ gpu_buddy_fini(&mm); ++} ++ ++static void gpu_test_buddy_alloc_limit(struct kunit *test) ++{ ++ u64 size = U64_MAX, start = 0; ++ struct gpu_buddy_block *block; ++ unsigned long flags = 0; ++ LIST_HEAD(allocated); ++ struct gpu_buddy mm; ++ ++ KUNIT_EXPECT_FALSE(test, gpu_buddy_init(&mm, size, SZ_4K)); ++ ++ KUNIT_EXPECT_EQ_MSG(test, mm.max_order, GPU_BUDDY_MAX_ORDER, ++ "mm.max_order(%d) != %d\n", mm.max_order, ++ GPU_BUDDY_MAX_ORDER); ++ ++ size = mm.chunk_size << mm.max_order; ++ KUNIT_EXPECT_FALSE(test, gpu_buddy_alloc_blocks(&mm, start, size, size, ++ mm.chunk_size, &allocated, flags)); ++ ++ block = list_first_entry_or_null(&allocated, struct gpu_buddy_block, link); ++ KUNIT_EXPECT_TRUE(test, block); ++ ++ KUNIT_EXPECT_EQ_MSG(test, gpu_buddy_block_order(block), mm.max_order, ++ "block order(%d) != %d\n", ++ gpu_buddy_block_order(block), mm.max_order); ++ ++ KUNIT_EXPECT_EQ_MSG(test, gpu_buddy_block_size(&mm, block), ++ BIT_ULL(mm.max_order) * mm.chunk_size, ++ "block size(%llu) != %llu\n", ++ gpu_buddy_block_size(&mm, block), ++ BIT_ULL(mm.max_order) * mm.chunk_size); ++ ++ gpu_buddy_free_list(&mm, &allocated, 0); ++ gpu_buddy_fini(&mm); ++} ++ ++static int gpu_buddy_suite_init(struct kunit_suite *suite) ++{ ++ while (!random_seed) ++ random_seed = get_random_u32(); ++ ++ kunit_info(suite, "Testing GPU buddy manager, with random_seed=0x%x\n", ++ random_seed); ++ ++ return 0; ++} ++ ++static struct kunit_case gpu_buddy_tests[] = { ++ KUNIT_CASE(gpu_test_buddy_alloc_limit), ++ KUNIT_CASE(gpu_test_buddy_alloc_optimistic), ++ KUNIT_CASE(gpu_test_buddy_alloc_pessimistic), ++ KUNIT_CASE(gpu_test_buddy_alloc_pathological), ++ KUNIT_CASE(gpu_test_buddy_alloc_contiguous), ++ KUNIT_CASE(gpu_test_buddy_alloc_clear), ++ KUNIT_CASE(gpu_test_buddy_alloc_range_bias), ++ {} ++}; ++ ++static struct kunit_suite gpu_buddy_test_suite = { ++ .name = "gpu_buddy", ++ .suite_init = gpu_buddy_suite_init, ++ .test_cases = gpu_buddy_tests, ++}; ++ ++kunit_test_suite(gpu_buddy_test_suite); ++ ++MODULE_AUTHOR("Intel Corporation"); ++MODULE_DESCRIPTION("Kunit test for gpu_buddy functions"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/gpu/tests/gpu_random.c b/drivers/gpu/tests/gpu_random.c +new file mode 100644 +index 00000000000000..6356372f7e52ed +--- /dev/null ++++ b/drivers/gpu/tests/gpu_random.c +@@ -0,0 +1,44 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include <linux/bitops.h> ++#include <linux/export.h> ++#include <linux/kernel.h> ++#include <linux/random.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++ ++#include "gpu_random.h" ++ ++u32 gpu_prandom_u32_max_state(u32 ep_ro, struct rnd_state *state) ++{ ++ return upper_32_bits((u64)prandom_u32_state(state) * ep_ro); ++} ++EXPORT_SYMBOL(gpu_prandom_u32_max_state); ++ ++void gpu_random_reorder(unsigned int *order, unsigned int count, ++ struct rnd_state *state) ++{ ++ unsigned int i, j; ++ ++ for (i = 0; i < count; ++i) { ++ BUILD_BUG_ON(sizeof(unsigned int) > sizeof(u32)); ++ j = gpu_prandom_u32_max_state(count, state); ++ swap(order[i], order[j]); ++ } ++} ++EXPORT_SYMBOL(gpu_random_reorder); ++ ++unsigned int *gpu_random_order(unsigned int count, struct rnd_state *state) ++{ ++ unsigned int *order, i; ++ ++ order = kmalloc_array(count, sizeof(*order), GFP_KERNEL); ++ if (!order) ++ return order; ++ ++ for (i = 0; i < count; i++) ++ order[i] = i; ++ ++ gpu_random_reorder(order, count, state); ++ return order; ++} ++EXPORT_SYMBOL(gpu_random_order); +diff --git a/drivers/gpu/tests/gpu_random.h b/drivers/gpu/tests/gpu_random.h +new file mode 100644 +index 00000000000000..b68cf344826445 +--- /dev/null ++++ b/drivers/gpu/tests/gpu_random.h +@@ -0,0 +1,28 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __GPU_RANDOM_H__ ++#define __GPU_RANDOM_H__ ++ ++/* This is a temporary home for a couple of utility functions that should ++ * be transposed to lib/ at the earliest convenience. ++ */ ++ ++#include <linux/prandom.h> ++ ++#define GPU_RND_STATE_INITIALIZER(seed__) ({ \ ++ struct rnd_state state__; \ ++ prandom_seed_state(&state__, (seed__)); \ ++ state__; \ ++}) ++ ++#define GPU_RND_STATE(name__, seed__) \ ++ struct rnd_state name__ = GPU_RND_STATE_INITIALIZER(seed__) ++ ++unsigned int *gpu_random_order(unsigned int count, ++ struct rnd_state *state); ++void gpu_random_reorder(unsigned int *order, ++ unsigned int count, ++ struct rnd_state *state); ++u32 gpu_prandom_u32_max_state(u32 ep_ro, ++ struct rnd_state *state); ++ ++#endif /* !__GPU_RANDOM_H__ */ +diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c +index 95c50d3a788ce7..13fd212ad40407 100644 +--- a/drivers/hwmon/asus-ec-sensors.c ++++ b/drivers/hwmon/asus-ec-sensors.c +@@ -870,7 +870,7 @@ struct ec_sensors_data { + /* sorted list of unique register banks */ + u8 banks[ASUS_EC_MAX_BANK + 1]; + /* in jiffies */ +- unsigned long last_updated; ++ u64 next_update; + struct lock_data lock_data; + /* number of board EC sensors */ + u8 nr_sensors; +@@ -1050,7 +1050,7 @@ static int asus_ec_block_read(const struct device *dev, + } + for (ireg = 0; ireg < ec->nr_registers; ireg++) { + reg_bank = register_bank(ec->registers[ireg]); +- if (reg_bank < bank) { ++ if (reg_bank != bank) { + continue; + } + ec_read(register_index(ec->registers[ireg]), +@@ -1139,13 +1139,12 @@ static int get_cached_value_or_update(const struct device *dev, + int sensor_index, + struct ec_sensors_data *state, s32 *value) + { +- if (time_after(jiffies, state->last_updated + HZ)) { ++ if (time_after64(get_jiffies_64(), state->next_update)) { + if (update_ec_sensors(dev, state)) { + dev_err(dev, "update_ec_sensors() failure\n"); + return -EIO; + } +- +- state->last_updated = jiffies; ++ state->next_update = get_jiffies_64() + HZ; + } + + *value = state->sensors[sensor_index].cached_value; +@@ -1263,6 +1262,7 @@ static int asus_ec_probe(struct platform_device *pdev) + if (!ec_data) + return -ENOMEM; + ++ ec_data->next_update = INITIAL_JIFFIES; + dev_set_drvdata(dev, ec_data); + ec_data->board_info = pboard_info; + +@@ -1353,9 +1353,11 @@ static int asus_ec_probe(struct platform_device *pdev) + if (!nr_count[type]) + continue; + +- asus_ec_hwmon_add_chan_info(asus_ec_hwmon_chan, dev, +- nr_count[type], type, +- hwmon_attributes[type]); ++ status = asus_ec_hwmon_add_chan_info(asus_ec_hwmon_chan, dev, ++ nr_count[type], type, ++ hwmon_attributes[type]); ++ if (status) ++ return status; + *ptr_asus_ec_ci++ = asus_ec_hwmon_chan++; + } + +diff --git a/drivers/hwmon/corsair-cpro.c b/drivers/hwmon/corsair-cpro.c +index b7b911f8359c7f..71e48b3bba60f0 100644 +--- a/drivers/hwmon/corsair-cpro.c ++++ b/drivers/hwmon/corsair-cpro.c +@@ -645,6 +645,7 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id) + + out_hw_close: + hid_hw_close(hdev); ++ hid_device_io_stop(hdev); + out_hw_stop: + hid_hw_stop(hdev); + return ret; +diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c +index ea28c9219507ad..4681af6843596b 100644 +--- a/drivers/hwmon/corsair-psu.c ++++ b/drivers/hwmon/corsair-psu.c +@@ -831,6 +831,7 @@ static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id + + fail_and_close: + hid_hw_close(hdev); ++ hid_device_io_stop(hdev); + fail_and_stop: + hid_hw_stop(hdev); + return ret; +diff --git a/drivers/hwmon/gigabyte_waterforce.c b/drivers/hwmon/gigabyte_waterforce.c +index 27487e215bddff..4eea05f8b569c2 100644 +--- a/drivers/hwmon/gigabyte_waterforce.c ++++ b/drivers/hwmon/gigabyte_waterforce.c +@@ -371,13 +371,15 @@ static int waterforce_probe(struct hid_device *hdev, const struct hid_device_id + if (IS_ERR(priv->hwmon_dev)) { + ret = PTR_ERR(priv->hwmon_dev); + hid_err(hdev, "hwmon registration failed with %d\n", ret); +- goto fail_and_close; ++ goto fail_and_io_stop; + } + + waterforce_debugfs_init(priv); + + return 0; + ++fail_and_io_stop: ++ hid_device_io_stop(hdev); + fail_and_close: + hid_hw_close(hdev); + fail_and_stop: +diff --git a/drivers/hwmon/nzxt-kraken3.c b/drivers/hwmon/nzxt-kraken3.c +index d00409bcab93ad..05525406c5fbb5 100644 +--- a/drivers/hwmon/nzxt-kraken3.c ++++ b/drivers/hwmon/nzxt-kraken3.c +@@ -948,7 +948,7 @@ static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *id + ret = kraken3_init_device(hdev); + if (ret < 0) { + hid_err(hdev, "device init failed with %d\n", ret); +- goto fail_and_close; ++ goto fail_and_stop_io; + } + + ret = kraken3_get_fw_ver(hdev); +@@ -960,13 +960,15 @@ static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *id + if (IS_ERR(priv->hwmon_dev)) { + ret = PTR_ERR(priv->hwmon_dev); + hid_err(hdev, "hwmon registration failed with %d\n", ret); +- goto fail_and_close; ++ goto fail_and_stop_io; + } + + kraken3_debugfs_init(priv, device_name); + + return 0; + ++fail_and_stop_io: ++ hid_device_io_stop(hdev); + fail_and_close: + hid_hw_close(hdev); + fail_and_stop: +diff --git a/drivers/hwmon/nzxt-smart2.c b/drivers/hwmon/nzxt-smart2.c +index 58ef9fa0184be4..e2316c46629d61 100644 +--- a/drivers/hwmon/nzxt-smart2.c ++++ b/drivers/hwmon/nzxt-smart2.c +@@ -768,7 +768,7 @@ static int nzxt_smart2_hid_probe(struct hid_device *hdev, + + out_hw_close: + hid_hw_close(hdev); +- ++ hid_device_io_stop(hdev); + out_hw_stop: + hid_hw_stop(hdev); + return ret; +diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c +index e18e80e832fd3f..175208d712b06e 100644 +--- a/drivers/hwmon/occ/common.c ++++ b/drivers/hwmon/occ/common.c +@@ -1052,32 +1052,49 @@ static int occ_setup_sensor_attrs(struct occ *occ) + } + + /* only need to do this once at startup, as OCC won't change sensors on us */ +-static void occ_parse_poll_response(struct occ *occ) ++static int occ_parse_poll_response(struct occ *occ) + { + unsigned int i, old_offset, offset = 0, size = 0; ++ u16 data_length; + struct occ_sensor *sensor; +- struct occ_sensors *sensors = &occ->sensors; ++ struct occ_sensors parsed = {}; ++ struct occ_sensors *sensors = &parsed; + struct occ_response *resp = &occ->resp; + struct occ_poll_response *poll = + (struct occ_poll_response *)&resp->data[0]; + struct occ_poll_response_header *header = &poll->header; + struct occ_sensor_data_block *block = &poll->block; + ++ data_length = get_unaligned_be16(&resp->data_length); ++ if (data_length < sizeof(*header) || data_length > OCC_RESP_DATA_BYTES) { ++ dev_err(occ->bus_dev, "invalid OCC poll response length %u\n", ++ data_length); ++ return -EMSGSIZE; ++ } ++ + dev_info(occ->bus_dev, "OCC found, code level: %.16s\n", + header->occ_code_level); + + for (i = 0; i < header->num_sensor_data_blocks; ++i) { + block = (struct occ_sensor_data_block *)((u8 *)block + offset); ++ if (size + sizeof(*header) + sizeof(block->header) > ++ data_length) { ++ dev_err(occ->bus_dev, ++ "truncated OCC sensor block header\n"); ++ return -EMSGSIZE; ++ } ++ + old_offset = offset; + offset = (block->header.num_sensors * + block->header.sensor_length) + sizeof(block->header); +- size += offset; + + /* validate all the length/size fields */ +- if ((size + sizeof(*header)) >= OCC_RESP_DATA_BYTES) { +- dev_warn(occ->bus_dev, "exceeded response buffer\n"); +- return; ++ if (size + sizeof(*header) + offset > data_length) { ++ dev_err(occ->bus_dev, ++ "exceeded OCC poll response length\n"); ++ return -EMSGSIZE; + } ++ size += offset; + + dev_dbg(occ->bus_dev, " %04x..%04x: %.4s (%d sensors)\n", + old_offset, offset - 1, block->header.eye_catcher, +@@ -1107,6 +1124,9 @@ static void occ_parse_poll_response(struct occ *occ) + + dev_dbg(occ->bus_dev, "Max resp size: %u+%zd=%zd\n", size, + sizeof(*header), size + sizeof(*header)); ++ occ->sensors = parsed; ++ ++ return 0; + } + + int occ_active(struct occ *occ, bool active) +@@ -1138,10 +1158,12 @@ int occ_active(struct occ *occ, bool active) + goto unlock; + } + +- occ->active = true; + occ->next_update = jiffies + OCC_UPDATE_FREQUENCY; +- occ_parse_poll_response(occ); ++ rc = occ_parse_poll_response(occ); ++ if (rc) ++ goto unlock; + ++ occ->active = true; + rc = occ_setup_sensor_attrs(occ); + if (rc) { + dev_err(occ->bus_dev, +diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c +index e3a7ab112ea955..dc888a11c7a09d 100644 +--- a/drivers/hwtracing/intel_th/core.c ++++ b/drivers/hwtracing/intel_th/core.c +@@ -843,18 +843,8 @@ out_put_device: + return err; + } + +-static int intel_th_output_release(struct inode *inode, struct file *file) +-{ +- struct intel_th_device *thdev = file->private_data; +- +- put_device(&thdev->dev); +- +- return 0; +-} +- + static const struct file_operations intel_th_output_fops = { + .open = intel_th_output_open, +- .release = intel_th_output_release, + .llseek = noop_llseek, + }; + +diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c +index f3a13b300835d5..d3170b1476de2a 100644 +--- a/drivers/hwtracing/intel_th/msu.c ++++ b/drivers/hwtracing/intel_th/msu.c +@@ -1490,8 +1490,10 @@ static int intel_th_msc_release(struct inode *inode, struct file *file) + { + struct msc_iter *iter = file->private_data; + struct msc *msc = iter->msc; ++ struct intel_th_device *thdev = msc->thdev; + + msc_iter_remove(iter, msc); ++ put_device(&thdev->dev); + + return 0; + } +diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c +index 75e6610cfd8129..1eeab337e5e533 100644 +--- a/drivers/i3c/master/mipi-i3c-hci/core.c ++++ b/drivers/i3c/master/mipi-i3c-hci/core.c +@@ -147,7 +147,10 @@ static int i3c_hci_bus_init(struct i3c_master_controller *m) + if (hci->quirks & HCI_QUIRK_RESP_BUF_THLD) + amd_set_resp_buf_thld(hci); + +- reg_set(HC_CONTROL, HC_CONTROL_BUS_ENABLE); ++ WRITE_ONCE(hci->irq_inactive, false); ++ ++ /* Enable bus with Hot-Join disabled */ ++ reg_set(HC_CONTROL, HC_CONTROL_BUS_ENABLE | HC_CONTROL_HOT_JOIN_CTRL); + dev_dbg(&hci->master.dev, "HC_CONTROL = %#x", reg_read(HC_CONTROL)); + + return 0; +@@ -536,6 +539,15 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id) + irqreturn_t result = IRQ_NONE; + u32 val; + ++ /* ++ * The IRQ can be shared, so the handler may be called when the IRQ is ++ * due to a different device. That could happen before the controller ++ * has been initialized, so exit immediately if IRQs are not expected ++ * for this device. ++ */ ++ if (READ_ONCE(hci->irq_inactive)) ++ return IRQ_NONE; ++ + val = reg_read(INTR_STATUS); + reg_write(INTR_STATUS, val); + dev_dbg(&hci->master.dev, "INTR_STATUS %#x", val); +@@ -775,6 +787,8 @@ static int i3c_hci_probe(struct platform_device *pdev) + if (ret) + return ret; + ++ WRITE_ONCE(hci->irq_inactive, true); ++ + irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(&pdev->dev, irq, i3c_hci_irq_handler, + IRQF_SHARED, NULL, hci); +diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h +index 32c8aecde9f76f..5502ab0a3535df 100644 +--- a/drivers/i3c/master/mipi-i3c-hci/hci.h ++++ b/drivers/i3c/master/mipi-i3c-hci/hci.h +@@ -46,6 +46,7 @@ struct i3c_hci { + void *io_data; + const struct hci_cmd_ops *cmd; + spinlock_t lock; ++ bool irq_inactive; + struct mutex control_mutex; + atomic_t next_cmd_tid; + u32 caps; +diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c +index ce511800b056cf..648acc2222cf54 100644 +--- a/drivers/infiniband/core/cma.c ++++ b/drivers/infiniband/core/cma.c +@@ -5237,7 +5237,7 @@ static int cma_netevent_callback(struct notifier_block *self, + + list_for_each_entry(current_id, &ips_node->id_list, id_list_entry) { + if (!memcmp(current_id->id.route.addr.dev_addr.dst_dev_addr, +- neigh->ha, ETH_ALEN)) ++ neigh->ha, neigh->dev->addr_len)) + continue; + cma_id_get(current_id); + if (!queue_work(cma_wq, ¤t_id->id.net_work)) +diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c +index 8f26bfb695861f..5150cd53d4435a 100644 +--- a/drivers/infiniband/core/mad.c ++++ b/drivers/infiniband/core/mad.c +@@ -2031,6 +2031,24 @@ void ib_mark_mad_done(struct ib_mad_send_wr_private *mad_send_wr) + change_mad_state(mad_send_wr, IB_MAD_STATE_EARLY_RESP); + } + ++static bool is_kernel_rmpp_data_response(struct ib_mad_agent_private *agent, ++ struct ib_mad_recv_wc *mad_recv_wc) ++{ ++ const struct ib_mad_hdr *mad_hdr = &mad_recv_wc->recv_buf.mad->mad_hdr; ++ struct ib_rmpp_mad *rmpp_mad; ++ ++ if (!ib_mad_kernel_rmpp_agent(&agent->agent) || ++ !ib_response_mad(mad_hdr) || ++ !ib_is_mad_class_rmpp(mad_hdr->mgmt_class)) ++ return false; ++ ++ rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad; ++ ++ return (ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & ++ IB_MGMT_RMPP_FLAG_ACTIVE) && ++ rmpp_mad->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_DATA; ++} ++ + static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, + struct ib_mad_recv_wc *mad_recv_wc) + { +@@ -2050,6 +2068,18 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, + } + + list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list); ++ if (is_kernel_rmpp_data_response(mad_agent_priv, mad_recv_wc)) { ++ spin_lock_irqsave(&mad_agent_priv->lock, flags); ++ mad_send_wr = ib_find_send_mad(mad_agent_priv, mad_recv_wc); ++ spin_unlock_irqrestore(&mad_agent_priv->lock, flags); ++ ++ if (!mad_send_wr) { ++ ib_free_recv_mad(mad_recv_wc); ++ deref_mad_agent(mad_agent_priv); ++ return; ++ } ++ } ++ + if (ib_mad_kernel_rmpp_agent(&mad_agent_priv->agent)) { + mad_recv_wc = ib_process_rmpp_recv_wc(mad_agent_priv, + mad_recv_wc); +diff --git a/drivers/infiniband/core/umem_dmabuf.c b/drivers/infiniband/core/umem_dmabuf.c +index b239ac09ec2921..4fc73f53342b7e 100644 +--- a/drivers/infiniband/core/umem_dmabuf.c ++++ b/drivers/infiniband/core/umem_dmabuf.c +@@ -206,6 +206,10 @@ static void ib_umem_dmabuf_revoke_locked(struct dma_buf_attachment *attach) + + if (umem_dmabuf->revoked) + return; ++ ++ if (umem_dmabuf->pinned_revoke) ++ umem_dmabuf->pinned_revoke(umem_dmabuf->private); ++ + ib_umem_dmabuf_unmap_pages(umem_dmabuf); + if (umem_dmabuf->pinned) { + dma_buf_unpin(umem_dmabuf->attach); +@@ -214,6 +218,11 @@ static void ib_umem_dmabuf_revoke_locked(struct dma_buf_attachment *attach) + umem_dmabuf->revoked = 1; + } + ++static struct dma_buf_attach_ops ib_umem_dmabuf_attach_pinned_revocable_ops = { ++ .allow_peer2peer = true, ++ .move_notify = ib_umem_dmabuf_revoke_locked, ++}; ++ + static struct ib_umem_dmabuf * + ib_umem_dmabuf_get_pinned_and_lock(struct ib_device *device, + struct device *dma_device, +@@ -266,6 +275,58 @@ ib_umem_dmabuf_get_pinned_with_dma_device(struct ib_device *device, + } + EXPORT_SYMBOL(ib_umem_dmabuf_get_pinned_with_dma_device); + ++/** ++ * ib_umem_dmabuf_get_pinned_revocable_and_lock - Map & pin a revocable dmabuf ++ * @device: IB device. ++ * @offset: Start offset. ++ * @size: Length. ++ * @fd: dmabuf fd. ++ * @access: Access flags. ++ * ++ * Obtains a umem from a dmabuf for drivers/devices that can support revocation. ++ * ++ * Returns with dma_resv_lock held upon success. The driver must set the revoke ++ * callback prior to unlock by calling ib_umem_dmabuf_set_revoke_locked(). ++ * ++ * When a revocation occurs, the revoke callback will be called. The driver must ++ * ensure that the region is no longer accessed when the callback returns. Any ++ * subsequent access attempts should also probably cause an AE for MRs. ++ * ++ * If the umem is used for an MR, the driver must ensure that the key remains in ++ * use such that it cannot be obtained by a new region until this region is ++ * fully deregistered (i.e., ibv_dereg_mr). If a driver needs to serialize with ++ * revoke calls, it can use dma_resv_lock. ++ * ++ * If successful, then the revoke callback may be called at any time and will ++ * also be called automatically upon ib_umem_release (serialized). The revoke ++ * callback will be called one time at most. ++ * ++ * Return: A pointer to ib_umem_dmabuf on success, or an ERR_PTR on failure. ++ */ ++struct ib_umem_dmabuf * ++ib_umem_dmabuf_get_pinned_revocable_and_lock(struct ib_device *device, ++ unsigned long offset, size_t size, ++ int fd, int access) ++{ ++ const struct dma_buf_attach_ops *ops = ++ &ib_umem_dmabuf_attach_pinned_revocable_ops; ++ ++ return ib_umem_dmabuf_get_pinned_and_lock(device, device->dma_device, ++ offset, size, fd, access, ++ ops); ++} ++EXPORT_SYMBOL(ib_umem_dmabuf_get_pinned_revocable_and_lock); ++ ++void ib_umem_dmabuf_set_revoke_locked(struct ib_umem_dmabuf *umem_dmabuf, ++ void (*revoke)(void *priv), void *priv) ++{ ++ dma_resv_assert_held(umem_dmabuf->attach->dmabuf->resv); ++ ++ umem_dmabuf->pinned_revoke = revoke; ++ umem_dmabuf->private = priv; ++} ++EXPORT_SYMBOL(ib_umem_dmabuf_set_revoke_locked); ++ + struct ib_umem_dmabuf *ib_umem_dmabuf_get_pinned(struct ib_device *device, + unsigned long offset, + size_t size, int fd, +diff --git a/drivers/infiniband/hw/erdma/erdma_qp.c b/drivers/infiniband/hw/erdma/erdma_qp.c +index 25f6c49aec7798..e002343832f74d 100644 +--- a/drivers/infiniband/hw/erdma/erdma_qp.c ++++ b/drivers/infiniband/hw/erdma/erdma_qp.c +@@ -734,7 +734,7 @@ int erdma_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *recv_wr, + const struct ib_recv_wr *wr = recv_wr; + struct erdma_qp *qp = to_eqp(ibqp); + unsigned long flags; +- int ret; ++ int ret = 0; + + spin_lock_irqsave(&qp->lock, flags); + +diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.c b/drivers/infiniband/hw/hns/hns_roce_hem.c +index 1680d0ac071ed1..ae7a3939124f23 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hem.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hem.c +@@ -842,7 +842,7 @@ static void hns_roce_cleanup_mhop_hem_table(struct hns_roce_dev *hr_dev, + mhop.bt_chunk_size; + + for (i = 0; i < table->num_hem; ++i) { +- obj = i * buf_chunk_size / table->obj_size; ++ obj = (u64)i * buf_chunk_size / table->obj_size; + if (table->hem[i]) + hns_roce_table_mhop_put(hr_dev, table, obj, 0); + } +diff --git a/drivers/infiniband/hw/irdma/uk.c b/drivers/infiniband/hw/irdma/uk.c +index 4cc81d61be7fad..7aab0076196677 100644 +--- a/drivers/infiniband/hw/irdma/uk.c ++++ b/drivers/infiniband/hw/irdma/uk.c +@@ -1540,15 +1540,12 @@ static const struct irdma_wqe_uk_ops iw_wqe_uk_ops_gen_1 = { + * irdma_setup_connection_wqes - setup WQEs necessary to complete + * connection. + * @qp: hw qp (user and kernel) +- * @info: qp initialization info + */ +-static void irdma_setup_connection_wqes(struct irdma_qp_uk *qp, +- struct irdma_qp_uk_init_info *info) ++static void irdma_setup_connection_wqes(struct irdma_qp_uk *qp) + { + u16 move_cnt = 1; + +- if (!info->legacy_mode && +- (qp->uk_attrs->feature_flags & IRDMA_FEATURE_RTS_AE)) ++ if (qp->uk_attrs->feature_flags & IRDMA_FEATURE_RTS_AE) + move_cnt = 3; + + qp->conn_wqes = move_cnt; +@@ -1699,7 +1696,7 @@ int irdma_uk_qp_init(struct irdma_qp_uk *qp, struct irdma_qp_uk_init_info *info) + sq_ring_size = qp->sq_size << info->sq_shift; + IRDMA_RING_INIT(qp->sq_ring, sq_ring_size); + if (info->first_sq_wq) { +- irdma_setup_connection_wqes(qp, info); ++ irdma_setup_connection_wqes(qp); + qp->swqe_polarity = 1; + qp->first_sq_wq = true; + } else { +diff --git a/drivers/infiniband/hw/irdma/user.h b/drivers/infiniband/hw/irdma/user.h +index aeebf768174abd..a0b409a895f0eb 100644 +--- a/drivers/infiniband/hw/irdma/user.h ++++ b/drivers/infiniband/hw/irdma/user.h +@@ -560,7 +560,6 @@ struct irdma_qp_uk_init_info { + u8 sq_shift; + u8 rq_shift; + int abi_ver; +- bool legacy_mode; + struct irdma_srq_uk *srq_uk; + }; + +diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c +index 2b85e32134a5b8..4084168d0194fb 100644 +--- a/drivers/infiniband/hw/irdma/verbs.c ++++ b/drivers/infiniband/hw/irdma/verbs.c +@@ -631,18 +631,16 @@ static int irdma_setup_umode_qp(struct ib_udata *udata, + + iwqp->ctx_info.qp_compl_ctx = req.user_compl_ctx; + iwqp->user_mode = 1; +- if (req.user_wqe_bufs) { +- info->qp_uk_init_info.legacy_mode = ucontext->legacy_mode; +- spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags); +- iwqp->iwpbl = irdma_get_pbl((unsigned long)req.user_wqe_bufs, +- &ucontext->qp_reg_mem_list); +- spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags); + +- if (!iwqp->iwpbl) { +- ret = -ENODATA; +- ibdev_dbg(&iwdev->ibdev, "VERBS: no pbl info\n"); +- return ret; +- } ++ spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags); ++ iwqp->iwpbl = irdma_get_pbl((unsigned long)req.user_wqe_bufs, ++ &ucontext->qp_reg_mem_list); ++ spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags); ++ ++ if (!iwqp->iwpbl) { ++ ret = -ENODATA; ++ ibdev_dbg(&iwdev->ibdev, "VERBS: no pbl info\n"); ++ return ret; + } + + if (!ucontext->use_raw_attrs) { +@@ -2068,10 +2066,6 @@ static int irdma_resize_cq(struct ib_cq *ibcq, int entries, + rdma_udata_to_drv_context(udata, struct irdma_ucontext, + ibucontext); + +- /* CQ resize not supported with legacy GEN_1 libi40iw */ +- if (ucontext->legacy_mode) +- return -EOPNOTSUPP; +- + if (ib_copy_from_udata(&req, udata, + min(sizeof(req), udata->inlen))) + return -EINVAL; +@@ -2550,7 +2544,7 @@ static int irdma_create_cq(struct ib_cq *ibcq, + cqmr = &iwpbl->cq_mr; + + if (rf->sc_dev.hw_attrs.uk_attrs.feature_flags & +- IRDMA_FEATURE_CQ_RESIZE && !ucontext->legacy_mode) { ++ IRDMA_FEATURE_CQ_RESIZE) { + spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags); + iwpbl_shadow = irdma_get_pbl( + (unsigned long)req.user_shadow_area, +@@ -2806,7 +2800,7 @@ static bool irdma_check_mem_contiguous(u64 *arr, u32 npages, u32 pg_size) + u32 pg_idx; + + for (pg_idx = 0; pg_idx < npages; pg_idx++) { +- if ((*arr + (pg_size * pg_idx)) != arr[pg_idx]) ++ if ((*arr + ((u64)pg_size * pg_idx)) != arr[pg_idx]) + return false; + } + +@@ -2839,7 +2833,7 @@ static bool irdma_check_mr_contiguous(struct irdma_pble_alloc *palloc, + + for (i = 0; i < lvl2->leaf_cnt; i++, leaf++) { + arr = leaf->addr; +- if ((*start_addr + (i * pg_size * PBLE_PER_PAGE)) != *arr) ++ if ((*start_addr + ((u64)i * pg_size * PBLE_PER_PAGE)) != *arr) + return false; + ret = irdma_check_mem_contiguous(arr, leaf->cnt, pg_size); + if (!ret) +@@ -3756,6 +3750,9 @@ static struct ib_mr *irdma_rereg_user_mr(struct ib_mr *ib_mr, int flags, + if (flags & ~(IB_MR_REREG_TRANS | IB_MR_REREG_PD | IB_MR_REREG_ACCESS)) + return ERR_PTR(-EOPNOTSUPP); + ++ if (iwmr->type != IRDMA_MEMREG_TYPE_MEM) ++ return ERR_PTR(-EINVAL); ++ + ret = ib_umem_check_rereg(iwmr->region, flags, new_access); + if (ret) + return ERR_PTR(ret); +diff --git a/drivers/infiniband/hw/mana/wr.c b/drivers/infiniband/hw/mana/wr.c +index 1813567d3b16c9..36a1d506f08f65 100644 +--- a/drivers/infiniband/hw/mana/wr.c ++++ b/drivers/infiniband/hw/mana/wr.c +@@ -144,7 +144,7 @@ static int mana_ib_post_send_ud(struct mana_ib_qp *qp, const struct ib_ud_wr *wr + int mana_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, + const struct ib_send_wr **bad_wr) + { +- int err; ++ int err = 0; + struct mana_ib_qp *qp = container_of(ibqp, struct mana_ib_qp, ibqp); + + for (; wr; wr = wr->next) { +diff --git a/drivers/infiniband/sw/siw/siw_verbs.c b/drivers/infiniband/sw/siw/siw_verbs.c +index efa2f097b58289..9fbade0b85715a 100644 +--- a/drivers/infiniband/sw/siw/siw_verbs.c ++++ b/drivers/infiniband/sw/siw/siw_verbs.c +@@ -316,6 +316,7 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs, + struct siw_ucontext *uctx = + rdma_udata_to_drv_context(udata, struct siw_ucontext, + base_ucontext); ++ struct siw_uresp_create_qp uresp = {}; + unsigned long flags; + int num_sqe, num_rqe, rv = 0; + size_t length; +@@ -369,11 +370,6 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs, + spin_lock_init(&qp->rq_lock); + spin_lock_init(&qp->orq_lock); + +- rv = siw_qp_add(sdev, qp); +- if (rv) +- goto err_atomic; +- +- + /* All queue indices are derived from modulo operations + * on a free running 'get' (consumer) and 'put' (producer) + * unsigned counter. Having queue sizes at power of two +@@ -391,14 +387,14 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs, + + if (qp->sendq == NULL) { + rv = -ENOMEM; +- goto err_out_xa; ++ goto err_out; + } + if (attrs->sq_sig_type != IB_SIGNAL_REQ_WR) { + if (attrs->sq_sig_type == IB_SIGNAL_ALL_WR) + qp->attrs.flags |= SIW_SIGNAL_ALL_WR; + else { + rv = -EINVAL; +- goto err_out_xa; ++ goto err_out; + } + } + qp->pd = pd; +@@ -424,7 +420,7 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs, + + if (qp->recvq == NULL) { + rv = -ENOMEM; +- goto err_out_xa; ++ goto err_out; + } + qp->attrs.rq_size = num_rqe; + } +@@ -439,11 +435,8 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs, + qp->attrs.state = SIW_QP_STATE_IDLE; + + if (udata) { +- struct siw_uresp_create_qp uresp = {}; +- + uresp.num_sqe = num_sqe; + uresp.num_rqe = num_rqe; +- uresp.qp_id = qp_id(qp); + + if (qp->sendq) { + length = num_sqe * sizeof(struct siw_sqe); +@@ -452,7 +445,7 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs, + length, &uresp.sq_key); + if (!qp->sq_entry) { + rv = -ENOMEM; +- goto err_out_xa; ++ goto err_out; + } + } + +@@ -464,9 +457,23 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs, + if (!qp->rq_entry) { + uresp.sq_key = SIW_INVAL_UOBJ_KEY; + rv = -ENOMEM; +- goto err_out_xa; ++ goto err_out; + } + } ++ } ++ qp->tx_cpu = siw_get_tx_cpu(sdev); ++ if (qp->tx_cpu < 0) { ++ rv = -EINVAL; ++ goto err_out; ++ } ++ init_completion(&qp->qp_free); ++ ++ rv = siw_qp_add(sdev, qp); ++ if (rv) ++ goto err_out_tx; ++ ++ if (udata) { ++ uresp.qp_id = qp_id(qp); + + if (udata->outlen < sizeof(uresp)) { + rv = -EINVAL; +@@ -476,22 +483,19 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs, + if (rv) + goto err_out_xa; + } +- qp->tx_cpu = siw_get_tx_cpu(sdev); +- if (qp->tx_cpu < 0) { +- rv = -EINVAL; +- goto err_out_xa; +- } ++ + INIT_LIST_HEAD(&qp->devq); + spin_lock_irqsave(&sdev->lock, flags); + list_add_tail(&qp->devq, &sdev->qp_list); + spin_unlock_irqrestore(&sdev->lock, flags); + +- init_completion(&qp->qp_free); +- + return 0; + + err_out_xa: + xa_erase(&sdev->qp_xa, qp_id(qp)); ++err_out_tx: ++ siw_put_tx_cpu(qp->tx_cpu); ++err_out: + if (uctx) { + rdma_user_mmap_entry_remove(qp->sq_entry); + rdma_user_mmap_entry_remove(qp->rq_entry); +diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c +index 94113e14bf5995..168662a2cc890c 100644 +--- a/drivers/input/misc/ims-pcu.c ++++ b/drivers/input/misc/ims-pcu.c +@@ -448,6 +448,14 @@ static void ims_pcu_handle_response(struct ims_pcu *pcu) + } + } + ++static void ims_pcu_reset_packet(struct ims_pcu *pcu) ++{ ++ pcu->have_stx = false; ++ pcu->have_dle = false; ++ pcu->read_pos = 0; ++ pcu->check_sum = 0; ++} ++ + static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb) + { + int i; +@@ -460,6 +468,14 @@ static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb) + continue; + + if (pcu->have_dle) { ++ if (pcu->read_pos >= IMS_PCU_BUF_SIZE) { ++ dev_warn(pcu->dev, ++ "Packet too long (%d bytes), discarding\n", ++ pcu->read_pos); ++ ims_pcu_reset_packet(pcu); ++ continue; ++ } ++ + pcu->have_dle = false; + pcu->read_buf[pcu->read_pos++] = data; + pcu->check_sum += data; +@@ -472,10 +488,8 @@ static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb) + dev_warn(pcu->dev, + "Unexpected STX at byte %d, discarding old data\n", + pcu->read_pos); ++ ims_pcu_reset_packet(pcu); + pcu->have_stx = true; +- pcu->have_dle = false; +- pcu->read_pos = 0; +- pcu->check_sum = 0; + break; + + case IMS_PCU_PROTOCOL_DLE: +@@ -495,12 +509,18 @@ static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb) + ims_pcu_handle_response(pcu); + } + +- pcu->have_stx = false; +- pcu->have_dle = false; +- pcu->read_pos = 0; ++ ims_pcu_reset_packet(pcu); + break; + + default: ++ if (pcu->read_pos >= IMS_PCU_BUF_SIZE) { ++ dev_warn(pcu->dev, ++ "Packet too long (%d bytes), discarding\n", ++ pcu->read_pos); ++ ims_pcu_reset_packet(pcu); ++ continue; ++ } ++ + pcu->read_buf[pcu->read_pos++] = data; + pcu->check_sum += data; + break; +diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c +index 32175daa3dd8a1..69170146d44217 100644 +--- a/drivers/iommu/amd/init.c ++++ b/drivers/iommu/amd/init.c +@@ -3860,6 +3860,12 @@ not_found: + return 1; + + found: ++ if (early_acpihid_map_size == EARLY_MAP_SIZE) { ++ pr_err("Early ACPI HID map overflow - ignoring ivrs_acpihid%s\n", ++ str); ++ return 1; ++ } ++ + p = acpiid; + hid = strsep(&p, ":"); + uid = p; +diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c +index c458eec8a5bba8..12302647e26759 100644 +--- a/drivers/iommu/amd/iommu.c ++++ b/drivers/iommu/amd/iommu.c +@@ -1408,11 +1408,23 @@ static int iommu_completion_wait(struct amd_iommu *iommu) + int ret; + u64 data; + +- if (!iommu->need_sync) +- return 0; +- + raw_spin_lock_irqsave(&iommu->lock, flags); + ++ if (!iommu->need_sync) { ++ /* ++ * No command has been queued since the last completion-wait. ++ * A concurrent CPU may have already queued that CWAIT and ++ * cleared need_sync; need_sync == false only means a covering ++ * CWAIT is queued, not that all prior commands have completed. ++ * Wait for the last allocated sequence number so that any ++ * command queued before this call (possibly on another CPU) ++ * is guaranteed to have completed before returning. ++ */ ++ data = iommu->cmd_sem_val; ++ raw_spin_unlock_irqrestore(&iommu->lock, flags); ++ return wait_on_sem(iommu, data); ++ } ++ + data = get_cmdsem_val(iommu); + build_completion_wait(&cmd, iommu, data); + +@@ -1422,9 +1434,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu) + if (ret) + return ret; + +- ret = wait_on_sem(iommu, data); +- +- return ret; ++ return wait_on_sem(iommu, data); + } + + static void domain_flush_complete(struct protection_domain *domain) +diff --git a/drivers/iommu/intel/perf.c b/drivers/iommu/intel/perf.c +index dceeadc3ee7cdd..6afb55073e9f10 100644 +--- a/drivers/iommu/intel/perf.c ++++ b/drivers/iommu/intel/perf.c +@@ -63,7 +63,7 @@ void dmar_latency_disable(struct intel_iommu *iommu, enum latency_type type) + return; + + spin_lock_irqsave(&latency_lock, flags); +- memset(&lstat[type], 0, sizeof(*lstat) * DMAR_LATENCY_NUM); ++ memset(&lstat[type], 0, sizeof(*lstat)); + spin_unlock_irqrestore(&latency_lock, flags); + } + +diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c +index e147f71f91b722..6c275c7679459e 100644 +--- a/drivers/iommu/intel/svm.c ++++ b/drivers/iommu/intel/svm.c +@@ -27,7 +27,7 @@ + + void intel_svm_check(struct intel_iommu *iommu) + { +- if (!pasid_supported(iommu)) ++ if (!pasid_supported(iommu) || !ecap_smpwc(iommu->ecap)) + return; + + if (cpu_feature_enabled(X86_FEATURE_GBPAGES) && +diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c +index 03e59b85132aa7..d1e4fbc5a21d9b 100644 +--- a/drivers/md/dm-verity-fec.c ++++ b/drivers/md/dm-verity-fec.c +@@ -39,36 +39,6 @@ static inline u64 fec_interleave(struct dm_verity *v, u64 offset) + return offset + mod * (v->fec->rounds << v->data_dev_block_bits); + } + +-/* +- * Read error-correcting codes for the requested RS block. Returns a pointer +- * to the data block. Caller is responsible for releasing buf. +- */ +-static u8 *fec_read_parity(struct dm_verity *v, u64 rsb, int index, +- unsigned int *offset, unsigned int par_buf_offset, +- struct dm_buffer **buf, unsigned short ioprio) +-{ +- u64 position, block, rem; +- u8 *res; +- +- /* We have already part of parity bytes read, skip to the next block */ +- if (par_buf_offset) +- index++; +- +- position = (index + rsb) * v->fec->roots; +- block = div64_u64_rem(position, v->fec->io_size, &rem); +- *offset = par_buf_offset ? 0 : (unsigned int)rem; +- +- res = dm_bufio_read_with_ioprio(v->fec->bufio, block, buf, ioprio); +- if (IS_ERR(res)) { +- DMERR("%s: FEC %llu: parity read failed (block %llu): %ld", +- v->data_dev->name, (unsigned long long)rsb, +- (unsigned long long)block, PTR_ERR(res)); +- *buf = NULL; +- } +- +- return res; +-} +- + /* Loop over each preallocated buffer slot. */ + #define fec_for_each_prealloc_buffer(__i) \ + for (__i = 0; __i < DM_VERITY_FEC_BUF_PREALLOC; __i++) +@@ -116,15 +86,29 @@ static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_io *io, + { + int r, corrected = 0, res; + struct dm_buffer *buf; +- unsigned int n, i, j, offset, par_buf_offset = 0; +- uint16_t par_buf[DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN]; ++ unsigned int n, i, j, parity_pos, to_copy; ++ uint16_t par_buf[DM_VERITY_FEC_MAX_ROOTS]; + u8 *par, *block; ++ u64 parity_block; + struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size); + +- par = fec_read_parity(v, rsb, block_offset, &offset, +- par_buf_offset, &buf, bio->bi_ioprio); +- if (IS_ERR(par)) ++ /* ++ * Compute the index of the first parity block that will be needed and ++ * the starting position in that block. Then read that block. ++ * ++ * io_size is always a power of 2, but roots might not be. Note that ++ * when it's not, a codeword's parity bytes can span a block boundary. ++ */ ++ parity_block = (rsb + block_offset) * v->fec->roots; ++ parity_pos = parity_block & (v->fec->io_size - 1); ++ parity_block >>= v->data_dev_block_bits; ++ par = dm_bufio_read_with_ioprio(v->fec->bufio, parity_block, &buf, ++ bio->bi_ioprio); ++ if (IS_ERR(par)) { ++ DMERR("%s: FEC %llu: parity read failed (block %llu): %ld", ++ v->data_dev->name, rsb, parity_block, PTR_ERR(par)); + return PTR_ERR(par); ++ } + + /* + * Decode the RS blocks we have in bufs. Each RS block results in +@@ -132,8 +116,32 @@ static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_io *io, + */ + fec_for_each_buffer_rs_block(fio, n, i) { + block = fec_buffer_rs_block(v, fio, n, i); +- for (j = 0; j < v->fec->roots - par_buf_offset; j++) +- par_buf[par_buf_offset + j] = par[offset + j]; ++ ++ /* ++ * Copy the next 'roots' parity bytes to 'par_buf', reading ++ * another parity block if needed. ++ */ ++ to_copy = min(v->fec->io_size - parity_pos, v->fec->roots); ++ for (j = 0; j < to_copy; j++) ++ par_buf[j] = par[parity_pos++]; ++ if (to_copy < v->fec->roots) { ++ parity_block++; ++ parity_pos = 0; ++ ++ dm_bufio_release(buf); ++ par = dm_bufio_read_with_ioprio(v->fec->bufio, ++ parity_block, &buf, ++ bio->bi_ioprio); ++ if (IS_ERR(par)) { ++ DMERR("%s: FEC %llu: parity read failed (block %llu): %ld", ++ v->data_dev->name, rsb, parity_block, ++ PTR_ERR(par)); ++ return PTR_ERR(par); ++ } ++ for (; j < v->fec->roots; j++) ++ par_buf[j] = par[parity_pos++]; ++ } ++ + /* Decode an RS block using Reed-Solomon */ + res = decode_rs8(fio->rs, block, par_buf, v->fec->rsn, + NULL, neras, fio->erasures, 0, NULL); +@@ -148,26 +156,6 @@ static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_io *io, + block_offset++; + if (block_offset >= 1 << v->data_dev_block_bits) + goto done; +- +- /* Read the next block when we run out of parity bytes */ +- offset += (v->fec->roots - par_buf_offset); +- /* Check if parity bytes are split between blocks */ +- if (offset < v->fec->io_size && (offset + v->fec->roots) > v->fec->io_size) { +- par_buf_offset = v->fec->io_size - offset; +- for (j = 0; j < par_buf_offset; j++) +- par_buf[j] = par[offset + j]; +- offset += par_buf_offset; +- } else +- par_buf_offset = 0; +- +- if (offset >= v->fec->io_size) { +- dm_bufio_release(buf); +- +- par = fec_read_parity(v, rsb, block_offset, &offset, +- par_buf_offset, &buf, bio->bi_ioprio); +- if (IS_ERR(par)) +- return PTR_ERR(par); +- } + } + done: + r = corrected; +@@ -262,7 +250,7 @@ static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io, + (unsigned long long)block, PTR_ERR(bbuf)); + + /* assume the block is corrupted */ +- if (neras && *neras <= v->fec->roots) ++ if (neras && *neras < v->fec->roots) + fio->erasures[(*neras)++] = i; + + continue; +@@ -280,7 +268,7 @@ static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io, + * skip if we have already found the theoretical + * maximum number (i.e. fec->roots) of erasures + */ +- if (neras && *neras <= v->fec->roots && ++ if (neras && *neras < v->fec->roots && + fec_is_erasure(v, io, want_digest, bbuf)) + fio->erasures[(*neras)++] = i; + } +@@ -617,8 +605,8 @@ int verity_fec_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v, + + } else if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_ROOTS)) { + if (sscanf(arg_value, "%hhu%c", &num_c, &dummy) != 1 || !num_c || +- num_c < (DM_VERITY_FEC_RSM - DM_VERITY_FEC_MAX_RSN) || +- num_c > (DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN)) { ++ num_c < DM_VERITY_FEC_MIN_ROOTS || ++ num_c > DM_VERITY_FEC_MAX_ROOTS) { + ti->error = "Invalid " DM_VERITY_OPT_FEC_ROOTS; + return -EINVAL; + } +diff --git a/drivers/md/dm-verity-fec.h b/drivers/md/dm-verity-fec.h +index ec37e607cb3f09..8552b5d3c91527 100644 +--- a/drivers/md/dm-verity-fec.h ++++ b/drivers/md/dm-verity-fec.h +@@ -13,8 +13,8 @@ + + /* Reed-Solomon(M, N) parameters */ + #define DM_VERITY_FEC_RSM 255 +-#define DM_VERITY_FEC_MAX_RSN 253 +-#define DM_VERITY_FEC_MIN_RSN 231 /* ~10% space overhead */ ++#define DM_VERITY_FEC_MIN_ROOTS 2 /* RS(255, 253): ~0.8% space overhead */ ++#define DM_VERITY_FEC_MAX_ROOTS 24 /* RS(255, 231): ~10% space overhead */ + + /* buffers for deinterleaving and decoding */ + #define DM_VERITY_FEC_BUF_PREALLOC 1 /* buffers to preallocate */ +@@ -50,7 +50,7 @@ struct dm_verity_fec { + /* per-bio data */ + struct dm_verity_fec_io { + struct rs_control *rs; /* Reed-Solomon state */ +- int erasures[DM_VERITY_FEC_MAX_RSN]; /* erasures for decode_rs8 */ ++ int erasures[DM_VERITY_FEC_MAX_ROOTS]; /* erasures for decode_rs8 */ + u8 *bufs[DM_VERITY_FEC_BUF_MAX]; /* bufs for deinterleaving */ + unsigned int nbufs; /* number of buffers allocated */ + u8 *output; /* buffer for corrected output */ +diff --git a/drivers/md/dm.c b/drivers/md/dm.c +index fb6bcd598c5b85..28d825cc69c537 100644 +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -735,7 +735,16 @@ static struct table_device *open_table_device(struct mapped_device *md, + return ERR_PTR(-ENOMEM); + refcount_set(&td->count, 1); + +- bdev_file = bdev_file_open_by_dev(dev, mode, _dm_claim_ptr, NULL); ++ /* ++ * Open the backing device with kernel rather than caller ++ * credentials. Otherwise the caller's credentials would be ++ * pinned in bdev_file->f_cred until the table device is closed. ++ * That would keep the caller's thread keyring alive long beyond the ++ * lifetime of the caller, breaking userspace expectation (e.g. ++ * cryptsetup(8) leaking the LUKS volume key). ++ */ ++ scoped_with_kernel_creds() ++ bdev_file = bdev_file_open_by_dev(dev, mode, _dm_claim_ptr, NULL); + if (IS_ERR(bdev_file)) { + r = PTR_ERR(bdev_file); + goto out_free_td; +diff --git a/drivers/media/cec/platform/seco/seco-cec.c b/drivers/media/cec/platform/seco/seco-cec.c +index b7bb49f0239577..97ed9654c78a10 100644 +--- a/drivers/media/cec/platform/seco/seco-cec.c ++++ b/drivers/media/cec/platform/seco/seco-cec.c +@@ -649,7 +649,7 @@ static int secocec_probe(struct platform_device *pdev) + + ret = secocec_ir_probe(secocec); + if (ret) +- goto err_notifier; ++ goto err_unregister_adapter; + + platform_set_drvdata(pdev, secocec); + +@@ -657,6 +657,10 @@ static int secocec_probe(struct platform_device *pdev) + + return ret; + ++err_unregister_adapter: ++ cec_notifier_cec_adap_unregister(secocec->notifier, secocec->cec_adap); ++ cec_unregister_adapter(secocec->cec_adap); ++ goto err; + err_notifier: + cec_notifier_cec_adap_unregister(secocec->notifier, secocec->cec_adap); + err_delete_adapter: +diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c +index 2df566f409b65e..28313e284bb7d9 100644 +--- a/drivers/media/common/videobuf2/videobuf2-core.c ++++ b/drivers/media/common/videobuf2/videobuf2-core.c +@@ -3006,8 +3006,8 @@ static int __vb2_cleanup_fileio(struct vb2_queue *q) + * @nonblock: mode selector (1 means blocking calls, 0 means nonblocking) + * @read: access mode selector (1 means read, 0 means write) + */ +-static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count, +- loff_t *ppos, int nonblock, int read) ++static ssize_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count, ++ loff_t *ppos, int nonblock, int read) + { + struct vb2_fileio_data *fileio; + struct vb2_fileio_buf *buf; +@@ -3170,15 +3170,15 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ + return ret; + } + +-size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, +- loff_t *ppos, int nonblocking) ++ssize_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, ++ loff_t *ppos, int nonblocking) + { + return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1); + } + EXPORT_SYMBOL_GPL(vb2_read); + +-size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count, +- loff_t *ppos, int nonblocking) ++ssize_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count, ++ loff_t *ppos, int nonblocking) + { + return __vb2_perform_fileio(q, (char __user *) data, count, + ppos, nonblocking, 0); +diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c +index 3b4e46dac1bf11..16f5f7e430922d 100644 +--- a/drivers/media/dvb-frontends/rtl2832.c ++++ b/drivers/media/dvb-frontends/rtl2832.c +@@ -1115,10 +1115,10 @@ static void rtl2832_remove(struct i2c_client *client) + + dev_dbg(&client->dev, "\n"); + +- cancel_delayed_work_sync(&dev->i2c_gate_work); +- + i2c_mux_del_adapters(dev->muxc); + ++ cancel_delayed_work_sync(&dev->i2c_gate_work); ++ + regmap_exit(dev->regmap); + + kfree(dev); +diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c +index 0357624968f1b5..787e2ef202a59c 100644 +--- a/drivers/media/dvb-frontends/rtl2832_sdr.c ++++ b/drivers/media/dvb-frontends/rtl2832_sdr.c +@@ -399,7 +399,8 @@ static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_dev *dev) + } + + /* Must be called with vb_queue_lock hold */ +-static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_dev *dev) ++static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_dev *dev, ++ enum vb2_buffer_state state) + { + struct platform_device *pdev = dev->pdev; + unsigned long flags; +@@ -413,7 +414,7 @@ static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_dev *dev) + buf = list_entry(dev->queued_bufs.next, + struct rtl2832_sdr_frame_buf, list); + list_del(&buf->list); +- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); ++ vb2_buffer_done(&buf->vb.vb2_buf, state); + } + spin_unlock_irqrestore(&dev->queued_bufs_lock, flags); + } +@@ -855,11 +856,15 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count) + + dev_dbg(&pdev->dev, "\n"); + +- if (!dev->udev) ++ if (!dev->udev) { ++ rtl2832_sdr_cleanup_queued_bufs(dev, VB2_BUF_STATE_QUEUED); + return -ENODEV; ++ } + +- if (mutex_lock_interruptible(&dev->v4l2_lock)) ++ if (mutex_lock_interruptible(&dev->v4l2_lock)) { ++ rtl2832_sdr_cleanup_queued_bufs(dev, VB2_BUF_STATE_QUEUED); + return -ERESTARTSYS; ++ } + + if (d->props->power_ctrl) + d->props->power_ctrl(d, 1); +@@ -900,7 +905,11 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count) + if (ret) + goto err; + ++ mutex_unlock(&dev->v4l2_lock); ++ return 0; ++ + err: ++ rtl2832_sdr_cleanup_queued_bufs(dev, VB2_BUF_STATE_QUEUED); + mutex_unlock(&dev->v4l2_lock); + + return ret; +@@ -920,7 +929,7 @@ static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq) + rtl2832_sdr_kill_urbs(dev); + rtl2832_sdr_free_urbs(dev); + rtl2832_sdr_free_stream_bufs(dev); +- rtl2832_sdr_cleanup_queued_bufs(dev); ++ rtl2832_sdr_cleanup_queued_bufs(dev, VB2_BUF_STATE_ERROR); + rtl2832_sdr_unset_adc(dev); + + /* sleep tuner */ +diff --git a/drivers/media/i2c/alvium-csi2.c b/drivers/media/i2c/alvium-csi2.c +index 1f088acecf367b..8ea5e9951de042 100644 +--- a/drivers/media/i2c/alvium-csi2.c ++++ b/drivers/media/i2c/alvium-csi2.c +@@ -2100,20 +2100,21 @@ static int alvium_ctrl_init(struct alvium_dev *alvium) + V4L2_CID_PIXEL_RATE, 0, + ALVIUM_DEFAULT_PIXEL_RATE_MHZ, 1, + ALVIUM_DEFAULT_PIXEL_RATE_MHZ); +- ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + /* Link freq is fixed */ + ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, + V4L2_CID_LINK_FREQ, + 0, 0, &alvium->link_freq); +- ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; ++ if (ctrls->link_freq) ++ ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + /* Auto/manual white balance */ + if (alvium->avail_ft.auto_whiteb) { + ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops, + V4L2_CID_AUTO_WHITE_BALANCE, + 0, 1, 1, 1); +- v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false); ++ if (ctrls->auto_wb) ++ v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false); + } + + ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, +@@ -2122,6 +2123,7 @@ static int alvium_ctrl_init(struct alvium_dev *alvium) + alvium->max_bbalance, + alvium->inc_bbalance, + alvium->dft_bbalance); ++ + ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, + V4L2_CID_RED_BALANCE, + alvium->min_rbalance, +@@ -2136,7 +2138,9 @@ static int alvium_ctrl_init(struct alvium_dev *alvium) + V4L2_CID_EXPOSURE_AUTO, + V4L2_EXPOSURE_MANUAL, 0, + V4L2_EXPOSURE_AUTO); +- v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true); ++ if (ctrls->auto_exp) ++ v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, ++ V4L2_EXPOSURE_MANUAL, true); + } + + ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, +@@ -2145,14 +2149,16 @@ static int alvium_ctrl_init(struct alvium_dev *alvium) + alvium->max_exp, + alvium->inc_exp, + alvium->dft_exp); +- ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; ++ if (ctrls->exposure) ++ ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; + + /* Auto/manual gain */ + if (alvium->avail_ft.auto_gain) { + ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, + V4L2_CID_AUTOGAIN, + 0, 1, 1, 1); +- v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true); ++ if (ctrls->auto_gain) ++ v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true); + } + + if (alvium->avail_ft.gain) { +@@ -2162,7 +2168,8 @@ static int alvium_ctrl_init(struct alvium_dev *alvium) + alvium->max_gain, + alvium->inc_gain, + alvium->dft_gain); +- ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; ++ if (ctrls->gain) ++ ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; + } + + if (alvium->avail_ft.sat) +diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c +index 4734c7b4d37b95..00aec91e3d4994 100644 +--- a/drivers/media/i2c/imx219.c ++++ b/drivers/media/i2c/imx219.c +@@ -71,7 +71,7 @@ + + /* V_TIMING internal */ + #define IMX219_REG_FRM_LENGTH_A CCI_REG16(0x0160) +-#define IMX219_FLL_MAX 0xffff ++#define IMX219_FLL_MAX 0xfffe + #define IMX219_VBLANK_MIN 32 + #define IMX219_REG_LINE_LENGTH_A CCI_REG16(0x0162) + #define IMX219_LLP_MIN 0x0d78 +diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c +index a39f445ce22a0d..43d658a90f08e6 100644 +--- a/drivers/media/pci/cx23885/cx23885-core.c ++++ b/drivers/media/pci/cx23885/cx23885-core.c +@@ -990,8 +990,12 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) + } + + /* PCIe stuff */ +- dev->lmmio = ioremap(pci_resource_start(dev->pci, 0), +- pci_resource_len(dev->pci, 0)); ++ dev->lmmio = pci_ioremap_bar(dev->pci, 0); ++ if (!dev->lmmio) { ++ dev_err(&dev->pci->dev, "CORE %s: can't ioremap MMIO memory\n", ++ dev->name); ++ goto err_release_region; ++ } + + dev->bmmio = (u8 __iomem *)dev->lmmio; + +@@ -1096,6 +1100,12 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) + } + + return 0; ++ ++err_release_region: ++ release_mem_region(pci_resource_start(dev->pci, 0), ++ pci_resource_len(dev->pci, 0)); ++ cx23885_devcount--; ++ return -ENODEV; + } + + static void cx23885_dev_unregister(struct cx23885_dev *dev) +diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c +index e1185aa669f480..c1d55b98367447 100644 +--- a/drivers/media/pci/dm1105/dm1105.c ++++ b/drivers/media/pci/dm1105/dm1105.c +@@ -1194,6 +1194,7 @@ static void dm1105_remove(struct pci_dev *pdev) + + dm1105_hw_exit(dev); + free_irq(pdev->irq, dev); ++ destroy_workqueue(dev->wq); + pci_iounmap(pdev, dev->io_mem); + pci_release_regions(pdev); + pci_disable_device(pdev); +diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c b/drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c +index db28748434530f..237906cb131ac7 100644 +--- a/drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c ++++ b/drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c +@@ -288,15 +288,27 @@ static const struct dwc_dphy_freq_range freqranges[DPHY_FREQ_RANGE_NUM] = { + + static u16 get_hsfreq_by_mbps(u32 mbps) + { +- unsigned int i = DPHY_FREQ_RANGE_NUM; +- +- while (i--) { +- if (freqranges[i].default_mbps == mbps || +- (mbps >= freqranges[i].min && mbps <= freqranges[i].max)) +- return i; ++ u16 best = DPHY_FREQ_RANGE_INVALID_INDEX; ++ unsigned int i; ++ ++ for (i = 0; i < DPHY_FREQ_RANGE_NUM; i++) { ++ if (mbps > freqranges[i].max) ++ continue; ++ ++ if (mbps < freqranges[i].min) ++ break; ++ ++ if (best == DPHY_FREQ_RANGE_INVALID_INDEX || ++ freqranges[i].osc_freq_target > ++ freqranges[best].osc_freq_target || ++ (freqranges[i].osc_freq_target == ++ freqranges[best].osc_freq_target && ++ abs((int)mbps - (int)freqranges[i].default_mbps) < ++ abs((int)mbps - (int)freqranges[best].default_mbps))) ++ best = i; + } + +- return DPHY_FREQ_RANGE_INVALID_INDEX; ++ return best; + } + + static int ipu6_isys_dwc_phy_config(struct ipu6_isys *isys, +diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c +index 4a51b873e47ad6..2b1672737d8419 100644 +--- a/drivers/media/pci/saa7134/saa7134-video.c ++++ b/drivers/media/pci/saa7134/saa7134-video.c +@@ -1714,8 +1714,10 @@ int saa7134_video_init1(struct saa7134_dev *dev) + q->dev = &dev->pci->dev; + ret = vb2_queue_init(q); + if (ret) +- return ret; +- saa7134_pgtable_alloc(dev->pci, &dev->video_q.pt); ++ goto err_free_ctrl; ++ ret = saa7134_pgtable_alloc(dev->pci, &dev->video_q.pt); ++ if (ret) ++ goto err_free_ctrl; + + q = &dev->vbi_vbq; + q->type = V4L2_BUF_TYPE_VBI_CAPTURE; +@@ -1732,11 +1734,24 @@ int saa7134_video_init1(struct saa7134_dev *dev) + q->lock = &dev->lock; + q->dev = &dev->pci->dev; + ret = vb2_queue_init(q); +- if (ret) +- return ret; +- saa7134_pgtable_alloc(dev->pci, &dev->vbi_q.pt); ++ if (ret) { ++ saa7134_pgtable_free(dev->pci, &dev->video_q.pt); ++ goto err_free_ctrl; ++ } ++ ++ ret = saa7134_pgtable_alloc(dev->pci, &dev->vbi_q.pt); ++ if (ret) { ++ saa7134_pgtable_free(dev->pci, &dev->video_q.pt); ++ goto err_free_ctrl; ++ } + + return 0; ++ ++err_free_ctrl: ++ v4l2_ctrl_handler_free(&dev->ctrl_handler); ++ if (card_has_radio(dev)) ++ v4l2_ctrl_handler_free(&dev->radio_ctrl_handler); ++ return ret; + } + + void saa7134_video_fini(struct saa7134_dev *dev) +diff --git a/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c b/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c +index c80667dd766210..ec25299e52abca 100644 +--- a/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c ++++ b/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c +@@ -107,6 +107,8 @@ static void c3_isp_params_awb_wt(struct c3_isp_device *isp, + c3_isp_write(isp, ISP_AWB_BLK_WT_ADDR, 0); + + zones_num = cfg->horiz_zones_num * cfg->vert_zones_num; ++ if (zones_num > C3_ISP_AWB_MAX_ZONES) ++ zones_num = C3_ISP_AWB_MAX_ZONES; + + /* Need to write 8 weights at once */ + for (i = 0; i < zones_num / 8; i++) { +@@ -223,6 +225,8 @@ static void c3_isp_params_ae_wt(struct c3_isp_device *isp, + c3_isp_write(isp, ISP_AE_BLK_WT_ADDR, 0); + + zones_num = cfg->horiz_zones_num * cfg->vert_zones_num; ++ if (zones_num > C3_ISP_AE_MAX_ZONES) ++ zones_num = C3_ISP_AE_MAX_ZONES; + + /* Need to write 8 weights at once */ + for (i = 0; i < zones_num / 8; i++) { +diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c +index b83e43245277b4..88ccd2f3746985 100644 +--- a/drivers/media/platform/aspeed/aspeed-video.c ++++ b/drivers/media/platform/aspeed/aspeed-video.c +@@ -2327,6 +2327,7 @@ static int aspeed_video_probe(struct platform_device *pdev) + rc = aspeed_video_setup_video(video); + if (rc) { + aspeed_video_free_buf(video, &video->jpeg); ++ of_reserved_mem_device_release(&pdev->dev); + clk_unprepare(video->vclk); + clk_unprepare(video->eclk); + return rc; +diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +index 24fc0d0d3f4aa7..50cba21fdcdcef 100644 +--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c ++++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +@@ -226,13 +226,6 @@ static int start_encode(struct vpu_instance *inst, u32 *fail_res) + } else { + dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_start_one_frame success\n", + __func__); +- /* +- * Remove the source buffer from the ready-queue now and finish +- * it in the videobuf2 framework once the index is returned by the +- * firmware in finish_encode +- */ +- if (src_buf) +- v4l2_m2m_src_buf_remove_by_idx(m2m_ctx, src_buf->vb2_buf.index); + } + + return 0; +@@ -259,27 +252,13 @@ static void wave5_vpu_enc_finish_encode(struct vpu_instance *inst) + __func__, enc_output_info.pic_type, enc_output_info.recon_frame_index, + enc_output_info.enc_src_idx, enc_output_info.enc_pic_byte, enc_output_info.pts); + +- /* +- * The source buffer will not be found in the ready-queue as it has been +- * dropped after sending of the encode firmware command, locate it in +- * the videobuf2 queue directly +- */ + if (enc_output_info.enc_src_idx >= 0) { +- struct vb2_buffer *vb = vb2_get_buffer(v4l2_m2m_get_src_vq(m2m_ctx), +- enc_output_info.enc_src_idx); +- if (vb->state != VB2_BUF_STATE_ACTIVE) +- dev_warn(inst->dev->dev, +- "%s: encoded buffer (%d) was not in ready queue %i.", +- __func__, enc_output_info.enc_src_idx, vb->state); +- else +- src_buf = to_vb2_v4l2_buffer(vb); +- +- if (src_buf) { ++ src_buf = v4l2_m2m_src_buf_remove_by_idx(m2m_ctx, enc_output_info.enc_src_idx); ++ if (!src_buf) { ++ dev_warn(inst->dev->dev, "%s: no source buffer found\n", __func__); ++ } else { + inst->timestamp = src_buf->vb2_buf.timestamp; + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); +- } else { +- dev_warn(inst->dev->dev, "%s: no source buffer with index: %d found\n", +- __func__, enc_output_info.enc_src_idx); + } + } + +diff --git a/drivers/media/platform/marvell/cafe-driver.c b/drivers/media/platform/marvell/cafe-driver.c +index f9796de92aa77d..39967ec5e7ee35 100644 +--- a/drivers/media/platform/marvell/cafe-driver.c ++++ b/drivers/media/platform/marvell/cafe-driver.c +@@ -609,6 +609,7 @@ static void cafe_pci_remove(struct pci_dev *pdev) + return; + } + cafe_shutdown(cam); ++ pci_disable_device(pdev); + kfree(cam); + } + +diff --git a/drivers/media/platform/nuvoton/npcm-video.c b/drivers/media/platform/nuvoton/npcm-video.c +index 44e904e61801e8..c4c5c318f7865a 100644 +--- a/drivers/media/platform/nuvoton/npcm-video.c ++++ b/drivers/media/platform/nuvoton/npcm-video.c +@@ -1720,10 +1720,12 @@ static int npcm_video_init(struct npcm_video *video) + if (rc) { + dev_err(dev, "Failed to set DMA mask\n"); + of_reserved_mem_device_release(dev); ++ return rc; + } + + rc = npcm_video_ece_init(video); + if (rc) { ++ of_reserved_mem_device_release(dev); + dev_err(dev, "Failed to initialize ECE\n"); + return rc; + } +@@ -1748,42 +1750,55 @@ static int npcm_video_probe(struct platform_device *pdev) + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) { + dev_err(&pdev->dev, "Failed to parse VCD reg in DTS\n"); +- return PTR_ERR(regs); ++ rc = PTR_ERR(regs); ++ goto err_free; + } + + video->vcd_regmap = devm_regmap_init_mmio(&pdev->dev, regs, + &npcm_video_regmap_cfg); + if (IS_ERR(video->vcd_regmap)) { + dev_err(&pdev->dev, "Failed to initialize VCD regmap\n"); +- return PTR_ERR(video->vcd_regmap); ++ rc = PTR_ERR(video->vcd_regmap); ++ goto err_free; + } + + video->reset = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(video->reset)) { + dev_err(&pdev->dev, "Failed to get VCD reset control in DTS\n"); +- return PTR_ERR(video->reset); ++ rc = PTR_ERR(video->reset); ++ goto err_free; + } + + video->gcr_regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "nuvoton,sysgcr"); +- if (IS_ERR(video->gcr_regmap)) +- return PTR_ERR(video->gcr_regmap); ++ if (IS_ERR(video->gcr_regmap)) { ++ rc = PTR_ERR(video->gcr_regmap); ++ goto err_free; ++ } + + video->gfx_regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "nuvoton,sysgfxi"); +- if (IS_ERR(video->gfx_regmap)) +- return PTR_ERR(video->gfx_regmap); ++ if (IS_ERR(video->gfx_regmap)) { ++ rc = PTR_ERR(video->gfx_regmap); ++ goto err_free; ++ } + + rc = npcm_video_init(video); + if (rc) +- return rc; ++ goto err_free; + + rc = npcm_video_setup_video(video); + if (rc) +- return rc; ++ goto err_release_mem; + + dev_info(video->dev, "NPCM video driver probed\n"); + return 0; ++ ++err_release_mem: ++ of_reserved_mem_device_release(&pdev->dev); ++err_free: ++ kfree(video); ++ return rc; + } + + static void npcm_video_remove(struct platform_device *pdev) +@@ -1798,6 +1813,7 @@ static void npcm_video_remove(struct platform_device *pdev) + v4l2_device_unregister(v4l2_dev); + if (video->ece.enable) + npcm_video_ece_stop(video); ++ kfree(video); + of_reserved_mem_device_release(dev); + } + +diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c +index 60fed2fe200dca..a6ed1d124472a6 100644 +--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c ++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c +@@ -517,6 +517,8 @@ static int mxc_isi_probe(struct platform_device *pdev) + return 0; + + err_xbar: ++ while (i--) ++ mxc_isi_pipe_cleanup(&isi->pipes[i]); + mxc_isi_crossbar_cleanup(&isi->crossbar); + + return ret; +diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h +index e84af5127e4e79..681a05045cd28a 100644 +--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h ++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h +@@ -11,6 +11,7 @@ + #define __MXC_ISI_CORE_H__ + + #include <linux/list.h> ++#include <linux/math.h> + #include <linux/mutex.h> + #include <linux/spinlock.h> + #include <linux/types.h> +@@ -412,4 +413,19 @@ static inline void mxc_isi_debug_cleanup(struct mxc_isi_dev *isi) + } + #endif + ++/* ++ * ISI scaling engine works in two parts: it performs pre-decimation of ++ * the image followed by bilinear filtering to achieve the desired ++ * downscaling factor. ++ * ++ * The decimation filter provides a maximum downscaling factor of 8, and ++ * the subsequent bilinear filter provides a maximum downscaling factor ++ * of 2. Combined, the maximum scaling factor can be up to 16. ++ */ ++static inline unsigned int ++mxc_isi_clamp_downscale_16(unsigned int val, unsigned int max_val) ++{ ++ return clamp(val, max(1U, DIV_ROUND_UP(max_val, 16)), max_val); ++} ++ + #endif /* __MXC_ISI_CORE_H__ */ +diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c +index ede6cc74c02340..3562c9f5ae2ef4 100644 +--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c ++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c +@@ -492,6 +492,7 @@ err_free: + + void mxc_isi_crossbar_cleanup(struct mxc_isi_crossbar *xbar) + { ++ v4l2_subdev_cleanup(&xbar->sd); + media_entity_cleanup(&xbar->sd.entity); + kfree(xbar->pads); + kfree(xbar->inputs); +diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c +index 9225a7ac1c3ee7..0bfd9b8f5f1088 100644 +--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c ++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c +@@ -112,7 +112,14 @@ static u32 mxc_isi_channel_scaling_ratio(unsigned int from, unsigned int to, + else + *dec = 8; + +- return min_t(u32, from * 0x1000 / (to * *dec), ISI_DOWNSCALE_THRESHOLD); ++ /* ++ * The ISI rounds output dimensions up to the next integer (i.MX93 RM ++ * section 57.7.8). Calculate the scale factor such that the theoretical ++ * output (input / scale_factor) rounds up to exactly the desired ++ * output. ++ */ ++ return min_t(u32, DIV_ROUND_UP(from * 0x1000, to * *dec), ++ ISI_DOWNSCALE_THRESHOLD); + } + + static void mxc_isi_channel_set_scaling(struct mxc_isi_pipe *pipe, +diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c +index 00afcbfbdde484..f2a73f0f1ac774 100644 +--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c ++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c +@@ -509,9 +509,14 @@ __mxc_isi_m2m_try_fmt_vid(struct mxc_isi_m2m_ctx *ctx, + const enum mxc_isi_video_type type) + { + if (type == MXC_ISI_VIDEO_M2M_CAP) { +- /* Downscaling only */ +- pix->width = min(pix->width, ctx->queues.out.format.width); +- pix->height = min(pix->height, ctx->queues.out.format.height); ++ const struct v4l2_pix_format_mplane *format = ++ &ctx->queues.out.format; ++ ++ /* Downscaling only, by up to 16. */ ++ pix->width = mxc_isi_clamp_downscale_16(pix->width, ++ format->width); ++ pix->height = mxc_isi_clamp_downscale_16(pix->height, ++ format->height); + } + + return mxc_isi_format_try(ctx->m2m->pipe, pix, type); +diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c +index a41c51dd9ce0f2..2d0843c86534cc 100644 +--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c ++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c +@@ -641,16 +641,19 @@ static int mxc_isi_pipe_set_selection(struct v4l2_subdev *sd, + /* Composing is supported on the sink only. */ + return -EINVAL; + +- /* The sink crop is bound by the sink format downscaling only). */ ++ /* ++ * The ISI supports downscaling only, with a factor up to 16. ++ * Clamp the compose rectangle size accordingly. ++ */ + format = mxc_isi_pipe_get_pad_format(pipe, state, + MXC_ISI_PIPE_PAD_SINK); + + sel->r.left = 0; + sel->r.top = 0; +- sel->r.width = clamp(sel->r.width, MXC_ISI_MIN_WIDTH, +- format->width); +- sel->r.height = clamp(sel->r.height, MXC_ISI_MIN_HEIGHT, +- format->height); ++ sel->r.width = mxc_isi_clamp_downscale_16(sel->r.width, ++ format->width); ++ sel->r.height = mxc_isi_clamp_downscale_16(sel->r.height, ++ format->height); + + rect = mxc_isi_pipe_get_pad_compose(pipe, state, + MXC_ISI_PIPE_PAD_SINK); +@@ -796,18 +799,20 @@ int mxc_isi_pipe_init(struct mxc_isi_dev *isi, unsigned int id) + irq = platform_get_irq(to_platform_device(isi->dev), id); + if (irq < 0) { + ret = irq; +- goto error; ++ goto error_subdev; + } + + ret = devm_request_irq(isi->dev, irq, mxc_isi_pipe_irq_handler, + 0, dev_name(isi->dev), pipe); + if (ret < 0) { + dev_err(isi->dev, "failed to request IRQ (%d)\n", ret); +- goto error; ++ goto error_subdev; + } + + return 0; + ++error_subdev: ++ v4l2_subdev_cleanup(sd); + error: + media_entity_cleanup(&sd->entity); + mutex_destroy(&pipe->lock); +@@ -819,6 +824,7 @@ void mxc_isi_pipe_cleanup(struct mxc_isi_pipe *pipe) + { + struct v4l2_subdev *sd = &pipe->sd; + ++ v4l2_subdev_cleanup(sd); + media_entity_cleanup(&sd->entity); + mutex_destroy(&pipe->lock); + } +diff --git a/drivers/media/platform/qcom/camss/camss-csid-680.c b/drivers/media/platform/qcom/camss/camss-csid-680.c +index 3ad3a174bcfb8c..edf01ba79907d6 100644 +--- a/drivers/media/platform/qcom/camss/camss-csid-680.c ++++ b/drivers/media/platform/qcom/camss/camss-csid-680.c +@@ -219,9 +219,9 @@ static void __csid_configure_top(struct csid_device *csid) + CSID_TOP_IO_PATH_CFG0(csid->id)); + } + +-static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc) ++static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 port, u8 vc) + { +- struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; ++ struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + port]; + const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats, + csid->res->formats->nformats, + input_format->code); +@@ -233,28 +233,28 @@ static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 + lane_cnt = 4; + + val = 0; +- writel(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(vc)); ++ writel(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(port)); + + /* + * DT_ID is a two bit bitfield that is concatenated with + * the four least significant bits of the five bit VC + * bitfield to generate an internal CID value. + * +- * CSID_RDI_CFG0(vc) ++ * CSID_RDI_CFG0(port) + * DT_ID : 28:27 + * VC : 26:22 + * DT : 21:16 + * + * CID : VC 3:0 << 2 | DT_ID 1:0 + */ +- dt_id = vc & 0x03; ++ dt_id = port & 0x03; + + /* note: for non-RDI path, this should be format->decode_format */ + val |= DECODE_FORMAT_PAYLOAD_ONLY << RDI_CFG0_DECODE_FORMAT; + val |= format->data_type << RDI_CFG0_DATA_TYPE; + val |= vc << RDI_CFG0_VIRTUAL_CHANNEL; + val |= dt_id << RDI_CFG0_DT_ID; +- writel(val, csid->base + CSID_RDI_CFG0(vc)); ++ writel(val, csid->base + CSID_RDI_CFG0(port)); + + val = RDI_CFG1_TIMESTAMP_STB_FRAME; + val |= RDI_CFG1_BYTE_CNTR_EN; +@@ -265,23 +265,23 @@ static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 + val |= RDI_CFG1_CROP_V_EN; + val |= RDI_CFG1_PACKING_MIPI; + +- writel(val, csid->base + CSID_RDI_CFG1(vc)); ++ writel(val, csid->base + CSID_RDI_CFG1(port)); + + val = 0; +- writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(vc)); ++ writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(port)); + + val = 1; +- writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(vc)); ++ writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(port)); + + val = 0; +- writel(val, csid->base + CSID_RDI_CTRL(vc)); ++ writel(val, csid->base + CSID_RDI_CTRL(port)); + +- val = readl(csid->base + CSID_RDI_CFG0(vc)); ++ val = readl(csid->base + CSID_RDI_CFG0(port)); + if (enable) + val |= RDI_CFG0_ENABLE; + else + val &= ~RDI_CFG0_ENABLE; +- writel(val, csid->base + CSID_RDI_CFG0(vc)); ++ writel(val, csid->base + CSID_RDI_CFG0(port)); + } + + static void csid_configure_stream(struct csid_device *csid, u8 enable) +@@ -290,11 +290,11 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable) + + __csid_configure_top(csid); + +- /* Loop through all enabled VCs and configure stream for each */ ++ /* Loop through all enabled ports and configure a stream for each */ + for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) { + if (csid->phy.en_vc & BIT(i)) { +- __csid_configure_rdi_stream(csid, enable, i); +- __csid_configure_rx(csid, &csid->phy, i); ++ __csid_configure_rdi_stream(csid, enable, i, 0); ++ __csid_configure_rx(csid, &csid->phy, 0); + __csid_ctrl_rdi(csid, enable, i); + } + } +diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen2.c b/drivers/media/platform/qcom/camss/camss-csid-gen2.c +index 2a1746dcc1c5b8..eadcb2f7e3aaa1 100644 +--- a/drivers/media/platform/qcom/camss/camss-csid-gen2.c ++++ b/drivers/media/platform/qcom/camss/camss-csid-gen2.c +@@ -203,10 +203,10 @@ static void __csid_ctrl_rdi(struct csid_device *csid, int enable, u8 rdi) + writel_relaxed(val, csid->base + CSID_RDI_CTRL(rdi)); + } + +-static void __csid_configure_testgen(struct csid_device *csid, u8 enable, u8 vc) ++static void __csid_configure_testgen(struct csid_device *csid, u8 enable, u8 port, u8 vc) + { + struct csid_testgen_config *tg = &csid->testgen; +- struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; ++ struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + port]; + const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats, + csid->res->formats->nformats, + input_format->code); +@@ -253,10 +253,10 @@ static void __csid_configure_testgen(struct csid_device *csid, u8 enable, u8 vc) + writel_relaxed(val, csid->base + CSID_TPG_CTRL); + } + +-static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc) ++static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 port, u8 vc) + { + /* Source pads matching RDI channels on hardware. Pad 1 -> RDI0, Pad 2 -> RDI1, etc. */ +- struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; ++ struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + port]; + const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats, + csid->res->formats->nformats, + input_format->code); +@@ -267,14 +267,14 @@ static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 + * the four least significant bits of the five bit VC + * bitfield to generate an internal CID value. + * +- * CSID_RDI_CFG0(vc) ++ * CSID_RDI_CFG0(port) + * DT_ID : 28:27 + * VC : 26:22 + * DT : 21:16 + * + * CID : VC 3:0 << 2 | DT_ID 1:0 + */ +- u8 dt_id = vc & 0x03; ++ u8 dt_id = port & 0x03; + + val = 1 << RDI_CFG0_BYTE_CNTR_EN; + val |= 1 << RDI_CFG0_FORMAT_MEASURE_EN; +@@ -284,56 +284,57 @@ static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 + val |= format->data_type << RDI_CFG0_DATA_TYPE; + val |= vc << RDI_CFG0_VIRTUAL_CHANNEL; + val |= dt_id << RDI_CFG0_DT_ID; +- writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_CFG0(port)); + + /* CSID_TIMESTAMP_STB_POST_IRQ */ + val = 2 << RDI_CFG1_TIMESTAMP_STB_SEL; +- writel_relaxed(val, csid->base + CSID_RDI_CFG1(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_CFG1(port)); + + val = 1; +- writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(port)); + + val = 0; +- writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PATTERN(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PATTERN(port)); + + val = 1; +- writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(port)); + + val = 0; +- writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(port)); + + val = 1; +- writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PERIOD(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PERIOD(port)); + + val = 0; +- writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PATTERN(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PATTERN(port)); + + val = 1; +- writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PERIOD(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PERIOD(port)); + + val = 0; +- writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PATTERN(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PATTERN(port)); + + val = 0; +- writel_relaxed(val, csid->base + CSID_RDI_CTRL(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_CTRL(port)); + +- val = readl_relaxed(csid->base + CSID_RDI_CFG0(vc)); ++ val = readl_relaxed(csid->base + CSID_RDI_CFG0(port)); + val |= enable << RDI_CFG0_ENABLE; +- writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc)); ++ writel_relaxed(val, csid->base + CSID_RDI_CFG0(port)); + } + + static void csid_configure_stream(struct csid_device *csid, u8 enable) + { + struct csid_testgen_config *tg = &csid->testgen; + u8 i; +- /* Loop through all enabled VCs and configure stream for each */ ++ ++ /* Loop through all enabled ports and configure a stream for each */ + for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) + if (csid->phy.en_vc & BIT(i)) { + if (tg->enabled) +- __csid_configure_testgen(csid, enable, i); ++ __csid_configure_testgen(csid, enable, i, 0); + +- __csid_configure_rdi_stream(csid, enable, i); +- __csid_configure_rx(csid, &csid->phy, i); ++ __csid_configure_rdi_stream(csid, enable, i, 0); ++ __csid_configure_rx(csid, &csid->phy, 0); + __csid_ctrl_rdi(csid, enable, i); + } + } +diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen3.c b/drivers/media/platform/qcom/camss/camss-csid-gen3.c +index bd059243790ede..ed5c5766efd36f 100644 +--- a/drivers/media/platform/qcom/camss/camss-csid-gen3.c ++++ b/drivers/media/platform/qcom/camss/camss-csid-gen3.c +@@ -145,12 +145,12 @@ static void __csid_configure_wrapper(struct csid_device *csid) + writel(val, csid->camss->csid_wrapper_base + CSID_IO_PATH_CFG0(csid->id)); + } + +-static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc) ++static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 port, u8 vc) + { + u32 val; + u8 lane_cnt = csid->phy.lane_cnt; + /* Source pads matching RDI channels on hardware. Pad 1 -> RDI0, Pad 2 -> RDI1, etc. */ +- struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; ++ struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + port]; + const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats, + csid->res->formats->nformats, + input_format->code); +@@ -163,14 +163,14 @@ static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 + * the four least significant bits of the five bit VC + * bitfield to generate an internal CID value. + * +- * CSID_RDI_CFG0(vc) ++ * CSID_RDI_CFG0(port) + * DT_ID : 28:27 + * VC : 26:22 + * DT : 21:16 + * + * CID : VC 3:0 << 2 | DT_ID 1:0 + */ +- u8 dt_id = vc & 0x03; ++ u8 dt_id = port & 0x03; + + val = RDI_CFG0_TIMESTAMP_EN; + val |= RDI_CFG0_TIMESTAMP_STB_SEL; +@@ -180,7 +180,7 @@ static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 + val |= format->data_type << RDI_CFG0_DT; + val |= dt_id << RDI_CFG0_DT_ID; + +- writel(val, csid->base + CSID_RDI_CFG0(vc)); ++ writel(val, csid->base + CSID_RDI_CFG0(port)); + + val = RDI_CFG1_PACKING_FORMAT_MIPI; + val |= RDI_CFG1_PIX_STORE; +@@ -189,22 +189,22 @@ static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 + val |= RDI_CFG1_CROP_H_EN; + val |= RDI_CFG1_CROP_V_EN; + +- writel(val, csid->base + CSID_RDI_CFG1(vc)); ++ writel(val, csid->base + CSID_RDI_CFG1(port)); + + val = 0; +- writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(vc)); ++ writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(port)); + + val = 1; +- writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(vc)); ++ writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(port)); + + val = 0; +- writel(val, csid->base + CSID_RDI_CTRL(vc)); ++ writel(val, csid->base + CSID_RDI_CTRL(port)); + +- val = readl(csid->base + CSID_RDI_CFG0(vc)); ++ val = readl(csid->base + CSID_RDI_CFG0(port)); + + if (enable) + val |= RDI_CFG0_EN; +- writel(val, csid->base + CSID_RDI_CFG0(vc)); ++ writel(val, csid->base + CSID_RDI_CFG0(port)); + } + + static void csid_configure_stream(struct csid_device *csid, u8 enable) +@@ -213,11 +213,11 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable) + + __csid_configure_wrapper(csid); + +- /* Loop through all enabled VCs and configure stream for each */ ++ /* Loop through all enabled ports and configure a stream for each */ + for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) + if (csid->phy.en_vc & BIT(i)) { +- __csid_configure_rdi_stream(csid, enable, i); +- __csid_configure_rx(csid, &csid->phy, i); ++ __csid_configure_rdi_stream(csid, enable, i, 0); ++ __csid_configure_rx(csid, &csid->phy, 0); + __csid_ctrl_rdi(csid, enable, i); + } + } +diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c +index a197833bac6183..cdeb78ba605aeb 100644 +--- a/drivers/media/platform/qcom/iris/iris_probe.c ++++ b/drivers/media/platform/qcom/iris/iris_probe.c +@@ -256,12 +256,12 @@ static int iris_probe(struct platform_device *pdev) + core->iris_platform_data = of_device_get_match_data(core->dev); + + ret = devm_request_threaded_irq(core->dev, core->irq, iris_hfi_isr, +- iris_hfi_isr_handler, IRQF_TRIGGER_HIGH, "iris", core); ++ iris_hfi_isr_handler, ++ IRQF_TRIGGER_HIGH | IRQF_NO_AUTOEN, ++ "iris", core); + if (ret) + return ret; + +- disable_irq_nosync(core->irq); +- + iris_init_ops(core); + core->iris_platform_data->init_hfi_command_ops(core); + core->iris_platform_data->init_hfi_response_ops(core); +diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h +index a5a57369ef0eb0..10e62f2646d089 100644 +--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h ++++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h +@@ -60,6 +60,7 @@ + #define ICnMC_CSCTHR BIT(5) + #define ICnMC_INF(x) ((x) << 16) + #define ICnMC_VCSEL(x) ((x) << 22) ++#define ICnMC_VCSEL_MASK GENMASK(23, 22) + #define ICnMC_INF_MASK GENMASK(21, 16) + + #define ICnMS_IA BIT(2) +diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c +index 162e2ace693184..6aea7c244df1b5 100644 +--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c ++++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c +@@ -262,19 +262,24 @@ static void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru, + u8 csi_vc) + { + const struct rzg2l_cru_info *info = cru->info; +- u32 icnmc = ICnMC_INF(ip_fmt->datatype); ++ u32 icnmc = rzg2l_cru_read(cru, info->image_conv) & ~(ICnMC_INF_MASK | ++ ICnMC_VCSEL_MASK); ++ icnmc |= ICnMC_INF(ip_fmt->datatype); + ++ /* ++ * VC filtering goes through SVC register on G3E/V2H. ++ * ++ * FIXME: virtual channel filtering is likely broken and only VC=0 ++ * works. ++ */ + if (cru->info->regs[ICnSVC]) { + rzg2l_cru_write(cru, ICnSVCNUM, csi_vc); + rzg2l_cru_write(cru, ICnSVC, ICnSVC_SVC0(0) | ICnSVC_SVC1(1) | + ICnSVC_SVC2(2) | ICnSVC_SVC3(3)); ++ } else { ++ icnmc |= ICnMC_VCSEL(csi_vc); + } + +- icnmc |= rzg2l_cru_read(cru, info->image_conv) & ~ICnMC_INF_MASK; +- +- /* Set virtual channel CSI2 */ +- icnmc |= ICnMC_VCSEL(csi_vc); +- + rzg2l_cru_write(cru, info->image_conv, icnmc); + } + +diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c +index 13762861b76942..200b498127919e 100644 +--- a/drivers/media/platform/st/stm32/stm32-dcmi.c ++++ b/drivers/media/platform/st/stm32/stm32-dcmi.c +@@ -2063,6 +2063,7 @@ static int dcmi_probe(struct platform_device *pdev) + return 0; + + err_cleanup: ++ v4l2_async_nf_unregister(&dcmi->notifier); + v4l2_async_nf_cleanup(&dcmi->notifier); + err_media_entity_cleanup: + media_entity_cleanup(&dcmi->vdev->entity); +diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c +index b18e273ef4a3e6..e9cab99775bc9a 100644 +--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c ++++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c +@@ -398,8 +398,10 @@ static int dcmipp_bytecap_start_streaming(struct vb2_queue *vq, + */ + if (!vcap->s_subdev) { + pad = media_pad_remote_pad_first(&vcap->vdev.entity.pads[0]); +- if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) +- return -EINVAL; ++ if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) { ++ ret = -EINVAL; ++ goto err_buffer_done; ++ } + vcap->s_subdev = media_entity_to_v4l2_subdev(pad->entity); + vcap->s_subdev_pad_nb = pad->index; + } +diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c +index e911c7f7acc524..4781db21c20552 100644 +--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c ++++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c +@@ -234,8 +234,10 @@ static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count) + int ret; + + csi_fmt = sun4i_csi_find_format(&csi->fmt.pixelformat, NULL); +- if (!csi_fmt) +- return -EINVAL; ++ if (!csi_fmt) { ++ ret = -EINVAL; ++ goto err_clear_dma_queue; ++ } + + dev_dbg(csi->dev, "Starting capture\n"); + +diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c +index b7d278b3889f28..8e6f452f76c73c 100644 +--- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c ++++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c +@@ -504,9 +504,9 @@ static void hdmirx_hpd_ctrl(struct snps_hdmirx_dev *hdmirx_dev, bool en) + hdmirx_writel(hdmirx_dev, CORE_CONFIG, + hdmirx_dev->hpd_trigger_level_high ? en : !en); + +- /* 100ms delay as per HDMI spec */ ++ /* 100ms delay as per HDMI spec + extra 50ms to cover internal delay */ + if (!en) +- msleep(100); ++ msleep(100 + 50); + } + + static void hdmirx_write_edid_data(struct snps_hdmirx_dev *hdmirx_dev, +diff --git a/drivers/media/platform/ti/davinci/vpif_capture.c b/drivers/media/platform/ti/davinci/vpif_capture.c +index 243c6196b0247c..9fbef24025744e 100644 +--- a/drivers/media/platform/ti/davinci/vpif_capture.c ++++ b/drivers/media/platform/ti/davinci/vpif_capture.c +@@ -1499,7 +1499,7 @@ vpif_capture_get_pdata(struct platform_device *pdev, + * video ports & endpoints data. + */ + if (pdev->dev.parent && pdev->dev.parent->of_node) +- pdev->dev.of_node = pdev->dev.parent->of_node; ++ device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent); + if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node) + return pdev->dev.platform_data; + +diff --git a/drivers/media/platform/ti/vpe/vpe.c b/drivers/media/platform/ti/vpe/vpe.c +index 6029d4e8e0bd34..e6c3aee946c162 100644 +--- a/drivers/media/platform/ti/vpe/vpe.c ++++ b/drivers/media/platform/ti/vpe/vpe.c +@@ -2546,7 +2546,8 @@ static int vpe_probe(struct platform_device *pdev) + "vpe_top"); + if (!dev->res) { + dev_err(&pdev->dev, "missing 'vpe_top' resources data\n"); +- return -ENODEV; ++ ret = -ENODEV; ++ goto v4l2_dev_unreg; + } + + /* +diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c +index fcf3bd9bcda2d0..83af9fa1ce9494 100644 +--- a/drivers/media/platform/verisilicon/hantro_v4l2.c ++++ b/drivers/media/platform/verisilicon/hantro_v4l2.c +@@ -222,6 +222,7 @@ static int vidioc_enum_fmt(struct file *file, void *priv, + unsigned int num_fmts, i, j = 0; + bool skip_mode_none, enum_all_formats; + u32 index = f->index & ~V4L2_FMTDESC_FLAG_ENUM_ALL; ++ bool need_postproc = ctx->need_postproc; + + /* + * If the V4L2_FMTDESC_FLAG_ENUM_ALL flag is set, we want to enumerate all +@@ -230,6 +231,9 @@ static int vidioc_enum_fmt(struct file *file, void *priv, + enum_all_formats = !!(f->index & V4L2_FMTDESC_FLAG_ENUM_ALL); + f->index = index; + ++ if (enum_all_formats) ++ need_postproc = HANTRO_AUTO_POSTPROC; ++ + /* + * When dealing with an encoder: + * - on the capture side we want to filter out all MODE_NONE formats. +@@ -242,7 +246,7 @@ static int vidioc_enum_fmt(struct file *file, void *priv, + */ + skip_mode_none = capture == ctx->is_encoder; + +- formats = hantro_get_formats(ctx, &num_fmts, HANTRO_AUTO_POSTPROC); ++ formats = hantro_get_formats(ctx, &num_fmts, need_postproc); + for (i = 0; i < num_fmts; i++) { + bool mode_none = formats[i].codec_mode == HANTRO_MODE_NONE; + fmt = &formats[i]; +diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c +index 9980346cb5ea38..bfe89782dce438 100644 +--- a/drivers/media/radio/radio-si476x.c ++++ b/drivers/media/radio/radio-si476x.c +@@ -1493,6 +1493,7 @@ static int si476x_radio_probe(struct platform_device *pdev) + return 0; + exit: + v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); ++ v4l2_device_unregister(&radio->v4l2dev); + return rval; + } + +diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.c b/drivers/media/test-drivers/vidtv/vidtv_bridge.c +index 52b2abe16dcf56..8a8e097d2ac965 100644 +--- a/drivers/media/test-drivers/vidtv/vidtv_bridge.c ++++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.c +@@ -594,8 +594,10 @@ static int __init vidtv_bridge_init(void) + int ret; + + ret = platform_device_register(&vidtv_bridge_dev); +- if (ret) ++ if (ret) { ++ platform_device_put(&vidtv_bridge_dev); + return ret; ++ } + + ret = platform_driver_register(&vidtv_bridge_driver); + if (ret) +diff --git a/drivers/media/test-drivers/vimc/vimc-core.c b/drivers/media/test-drivers/vimc/vimc-core.c +index f632c77e52f5d8..bc0474d8059aea 100644 +--- a/drivers/media/test-drivers/vimc/vimc-core.c ++++ b/drivers/media/test-drivers/vimc/vimc-core.c +@@ -422,6 +422,7 @@ static int __init vimc_init(void) + if (ret) { + dev_err(&vimc_pdev.dev, + "platform device registration failed (err=%d)\n", ret); ++ platform_device_put(&vimc_pdev); + return ret; + } + +diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c +index 86506be36acb0c..f44930502bdaf1 100644 +--- a/drivers/media/test-drivers/vivid/vivid-core.c ++++ b/drivers/media/test-drivers/vivid/vivid-core.c +@@ -2289,8 +2289,10 @@ static int __init vivid_init(void) + } + } + ret = platform_device_register(&vivid_pdev); +- if (ret) ++ if (ret) { ++ platform_device_put(&vivid_pdev); + goto free_output_strings; ++ } + ret = platform_driver_register(&vivid_pdrv); + if (ret) + goto unreg_device; +@@ -2311,7 +2313,7 @@ static int __init vivid_init(void) + destroy_hdmi_wq: + destroy_workqueue(update_hdmi_ctrls_workqueue); + unreg_driver: +- platform_driver_register(&vivid_pdrv); ++ platform_driver_unregister(&vivid_pdrv); + unreg_device: + platform_device_unregister(&vivid_pdev); + free_output_strings: +diff --git a/drivers/media/test-drivers/vivid/vivid-ctrls.c b/drivers/media/test-drivers/vivid/vivid-ctrls.c +index f94c15ff84f78f..a8a134b36720eb 100644 +--- a/drivers/media/test-drivers/vivid/vivid-ctrls.c ++++ b/drivers/media/test-drivers/vivid/vivid-ctrls.c +@@ -609,17 +609,24 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl) + break; + case VIVID_CID_REDUCED_FPS: + dev->reduced_fps = ctrl->val; +- vivid_update_format_cap(dev, true); ++ if (dev->input_type[dev->input] == HDMI) ++ vivid_update_reduced_fps(dev); + break; + case VIVID_CID_HAS_CROP_CAP: ++ if (vb2_is_busy(&dev->vb_vid_cap_q)) ++ return -EBUSY; + dev->has_crop_cap = ctrl->val; + vivid_update_format_cap(dev, true); + break; + case VIVID_CID_HAS_COMPOSE_CAP: ++ if (vb2_is_busy(&dev->vb_vid_cap_q)) ++ return -EBUSY; + dev->has_compose_cap = ctrl->val; + vivid_update_format_cap(dev, true); + break; + case VIVID_CID_HAS_SCALER_CAP: ++ if (vb2_is_busy(&dev->vb_vid_cap_q)) ++ return -EBUSY; + dev->has_scaler_cap = ctrl->val; + vivid_update_format_cap(dev, true); + break; +@@ -1116,14 +1123,20 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl) + + switch (ctrl->id) { + case VIVID_CID_HAS_CROP_OUT: ++ if (vb2_is_busy(&dev->vb_vid_out_q)) ++ return -EBUSY; + dev->has_crop_out = ctrl->val; + vivid_update_format_out(dev); + break; + case VIVID_CID_HAS_COMPOSE_OUT: ++ if (vb2_is_busy(&dev->vb_vid_out_q)) ++ return -EBUSY; + dev->has_compose_out = ctrl->val; + vivid_update_format_out(dev); + break; + case VIVID_CID_HAS_SCALER_OUT: ++ if (vb2_is_busy(&dev->vb_vid_out_q)) ++ return -EBUSY; + dev->has_scaler_out = ctrl->val; + vivid_update_format_out(dev); + break; +diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c +index 8b3162e8203271..d1c09bdb2f3b0b 100644 +--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c ++++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c +@@ -362,6 +362,24 @@ static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev) + return TPG_PIXEL_ASPECT_SQUARE; + } + ++void vivid_update_reduced_fps(struct vivid_dev *dev) ++{ ++ struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt; ++ unsigned int size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt); ++ u64 pixelclock; ++ ++ if (dev->reduced_fps && can_reduce_fps(bt)) { ++ pixelclock = div_u64(bt->pixelclock * 1000, 1001); ++ bt->flags |= V4L2_DV_FL_REDUCED_FPS; ++ } else { ++ pixelclock = bt->pixelclock; ++ bt->flags &= ~V4L2_DV_FL_REDUCED_FPS; ++ } ++ dev->timeperframe_vid_cap = (struct v4l2_fract) { ++ size / 100, (u32)pixelclock / 100 ++ }; ++} ++ + /* + * Called whenever the format has to be reset which can occur when + * changing inputs, standard, timings, etc. +@@ -370,8 +388,12 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) + { + struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt; + u32 dims[V4L2_CTRL_MAX_DIMS] = {}; +- unsigned size; +- u64 pixelclock; ++ ++ /* ++ * This resets the format, so must never be called while vb2_is_busy(). ++ */ ++ if (WARN_ON(vb2_is_busy(&dev->vb_vid_cap_q))) ++ return; + + switch (dev->input_type[dev->input]) { + case WEBCAM: +@@ -400,17 +422,7 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) + case HDMI: + dev->src_rect.width = bt->width; + dev->src_rect.height = bt->height; +- size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt); +- if (dev->reduced_fps && can_reduce_fps(bt)) { +- pixelclock = div_u64(bt->pixelclock * 1000, 1001); +- bt->flags |= V4L2_DV_FL_REDUCED_FPS; +- } else { +- pixelclock = bt->pixelclock; +- bt->flags &= ~V4L2_DV_FL_REDUCED_FPS; +- } +- dev->timeperframe_vid_cap = (struct v4l2_fract) { +- size / 100, (u32)pixelclock / 100 +- }; ++ vivid_update_reduced_fps(dev); + if (bt->interlaced) + dev->field_cap = V4L2_FIELD_ALTERNATE; + else +diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.h b/drivers/media/test-drivers/vivid/vivid-vid-cap.h +index 38a99f7e038eaa..d08a85927510f1 100644 +--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.h ++++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.h +@@ -9,6 +9,7 @@ + #define _VIVID_VID_CAP_H_ + + void vivid_update_quality(struct vivid_dev *dev); ++void vivid_update_reduced_fps(struct vivid_dev *dev); + void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls); + void vivid_update_outputs(struct vivid_dev *dev); + void vivid_update_connected_outputs(struct vivid_dev *dev); +diff --git a/drivers/media/test-drivers/vivid/vivid-vid-out.c b/drivers/media/test-drivers/vivid/vivid-vid-out.c +index 8c037b90833e74..23e1d5a189eed1 100644 +--- a/drivers/media/test-drivers/vivid/vivid-vid-out.c ++++ b/drivers/media/test-drivers/vivid/vivid-vid-out.c +@@ -214,6 +214,12 @@ void vivid_update_format_out(struct vivid_dev *dev) + unsigned size, p; + u64 pixelclock; + ++ /* ++ * This resets the format, so must never be called while vb2_is_busy(). ++ */ ++ if (WARN_ON(vb2_is_busy(&dev->vb_vid_out_q))) ++ return; ++ + switch (dev->output_type[dev->output]) { + case SVID: + default: +diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c +index 08f0920cf6ca2f..7bad5d8ea186a1 100644 +--- a/drivers/media/usb/airspy/airspy.c ++++ b/drivers/media/usb/airspy/airspy.c +@@ -522,11 +522,13 @@ static int airspy_start_streaming(struct vb2_queue *vq, unsigned int count) + + dev_dbg(s->dev, "\n"); + +- if (!s->udev) +- return -ENODEV; +- + mutex_lock(&s->v4l2_lock); + ++ if (!s->udev) { ++ ret = -ENODEV; ++ goto err_clear_bit; ++ } ++ + s->sequence = 0; + + set_bit(POWER_ON, &s->flags); +diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c +index 691f073892b36c..d96b9ab276b766 100644 +--- a/drivers/media/usb/cx231xx/cx231xx-cards.c ++++ b/drivers/media/usb/cx231xx/cx231xx-cards.c +@@ -1575,7 +1575,8 @@ static int cx231xx_init_v4l2(struct cx231xx *dev, + dev->video_mode.end_point_addr, + dev->video_mode.num_alt); + +- dev->video_mode.alt_max_pkt_size = devm_kmalloc_array(&udev->dev, 32, dev->video_mode.num_alt, GFP_KERNEL); ++ dev->video_mode.alt_max_pkt_size = devm_kmalloc_array(&interface->dev, 32, ++ dev->video_mode.num_alt, GFP_KERNEL); + if (dev->video_mode.alt_max_pkt_size == NULL) + return -ENOMEM; + +@@ -1616,7 +1617,8 @@ static int cx231xx_init_v4l2(struct cx231xx *dev, + dev->vbi_mode.num_alt); + + /* compute alternate max packet sizes for vbi */ +- dev->vbi_mode.alt_max_pkt_size = devm_kmalloc_array(&udev->dev, 32, dev->vbi_mode.num_alt, GFP_KERNEL); ++ dev->vbi_mode.alt_max_pkt_size = devm_kmalloc_array(&interface->dev, 32, ++ dev->vbi_mode.num_alt, GFP_KERNEL); + if (dev->vbi_mode.alt_max_pkt_size == NULL) + return -ENOMEM; + +@@ -1658,7 +1660,9 @@ static int cx231xx_init_v4l2(struct cx231xx *dev, + "sliced CC EndPoint Addr 0x%x, Alternate settings: %i\n", + dev->sliced_cc_mode.end_point_addr, + dev->sliced_cc_mode.num_alt); +- dev->sliced_cc_mode.alt_max_pkt_size = devm_kmalloc_array(&udev->dev, 32, dev->sliced_cc_mode.num_alt, GFP_KERNEL); ++ dev->sliced_cc_mode.alt_max_pkt_size = devm_kmalloc_array(&interface->dev, 32, ++ dev->sliced_cc_mode.num_alt, ++ GFP_KERNEL); + if (dev->sliced_cc_mode.alt_max_pkt_size == NULL) + return -ENOMEM; + +@@ -1722,7 +1726,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, + udev = usb_get_dev(interface_to_usbdev(interface)); + + /* allocate memory for our device state and initialize it */ +- dev = devm_kzalloc(&udev->dev, sizeof(*dev), GFP_KERNEL); ++ dev = devm_kzalloc(&interface->dev, sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + retval = -ENOMEM; + goto err_if; +@@ -1852,7 +1856,9 @@ static int cx231xx_usb_probe(struct usb_interface *interface, + dev->ts1_mode.end_point_addr, + dev->ts1_mode.num_alt); + +- dev->ts1_mode.alt_max_pkt_size = devm_kmalloc_array(&udev->dev, 32, dev->ts1_mode.num_alt, GFP_KERNEL); ++ dev->ts1_mode.alt_max_pkt_size = devm_kmalloc_array(&interface->dev, 32, ++ dev->ts1_mode.num_alt, ++ GFP_KERNEL); + if (dev->ts1_mode.alt_max_pkt_size == NULL) { + retval = -ENOMEM; + goto err_video_alt; +diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c +index 33099f39146afd..235b685f853646 100644 +--- a/drivers/media/usb/msi2500/msi2500.c ++++ b/drivers/media/usb/msi2500/msi2500.c +@@ -541,7 +541,8 @@ static int msi2500_isoc_init(struct msi2500_dev *dev) + } + + /* Must be called with vb_queue_lock hold */ +-static void msi2500_cleanup_queued_bufs(struct msi2500_dev *dev) ++static void msi2500_cleanup_queued_bufs(struct msi2500_dev *dev, ++ enum vb2_buffer_state state) + { + unsigned long flags; + +@@ -554,7 +555,7 @@ static void msi2500_cleanup_queued_bufs(struct msi2500_dev *dev) + buf = list_entry(dev->queued_bufs.next, + struct msi2500_frame_buf, list); + list_del(&buf->list); +- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); ++ vb2_buffer_done(&buf->vb.vb2_buf, state); + } + spin_unlock_irqrestore(&dev->queued_bufs_lock, flags); + } +@@ -830,25 +831,40 @@ static int msi2500_start_streaming(struct vb2_queue *vq, unsigned int count) + + dev_dbg(dev->dev, "\n"); + +- if (!dev->udev) +- return -ENODEV; ++ if (!dev->udev) { ++ ret = -ENODEV; ++ goto err_cleanup; ++ } + +- if (mutex_lock_interruptible(&dev->v4l2_lock)) +- return -ERESTARTSYS; ++ if (mutex_lock_interruptible(&dev->v4l2_lock)) { ++ ret = -ERESTARTSYS; ++ goto err_cleanup; ++ } + + /* wake-up tuner */ + v4l2_subdev_call(dev->v4l2_subdev, core, s_power, 1); + + ret = msi2500_set_usb_adc(dev); ++ if (ret) ++ goto err_unlock_cleanup; + + ret = msi2500_isoc_init(dev); + if (ret) +- msi2500_cleanup_queued_bufs(dev); ++ goto err_unlock_cleanup; + + ret = msi2500_ctrl_msg(dev, CMD_START_STREAMING, 0); ++ if (ret) ++ goto err_isoc_cleanup; + + mutex_unlock(&dev->v4l2_lock); ++ return 0; + ++err_isoc_cleanup: ++ msi2500_isoc_cleanup(dev); ++err_unlock_cleanup: ++ mutex_unlock(&dev->v4l2_lock); ++err_cleanup: ++ msi2500_cleanup_queued_bufs(dev, VB2_BUF_STATE_QUEUED); + return ret; + } + +@@ -863,7 +879,7 @@ static void msi2500_stop_streaming(struct vb2_queue *vq) + if (dev->udev) + msi2500_isoc_cleanup(dev); + +- msi2500_cleanup_queued_bufs(dev); ++ msi2500_cleanup_queued_bufs(dev, VB2_BUF_STATE_ERROR); + + /* according to tests, at least 700us delay is required */ + msleep(20); +diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c +index c6e5d031f068b2..4cc278d711aee0 100644 +--- a/drivers/media/usb/pwc/pwc-if.c ++++ b/drivers/media/usb/pwc/pwc-if.c +@@ -710,11 +710,15 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) + struct pwc_device *pdev = vb2_get_drv_priv(vq); + int r; + +- if (!pdev->udev) ++ if (!pdev->udev) { ++ pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_QUEUED); + return -ENODEV; ++ } + +- if (mutex_lock_interruptible(&pdev->v4l2_lock)) ++ if (mutex_lock_interruptible(&pdev->v4l2_lock)) { ++ pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_QUEUED); + return -ERESTARTSYS; ++ } + /* Turn on camera and set LEDS on */ + pwc_camera_power(pdev, 1); + pwc_set_leds(pdev, leds[0], leds[1]); +@@ -726,6 +730,11 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) + pwc_camera_power(pdev, 0); + /* And cleanup any queued bufs!! */ + pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_QUEUED); ++ if (pdev->fill_buf) { ++ vb2_buffer_done(&pdev->fill_buf->vb.vb2_buf, ++ VB2_BUF_STATE_QUEUED); ++ pdev->fill_buf = NULL; ++ } + } + mutex_unlock(&pdev->v4l2_lock); + +diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c +index 85d07ef44f626b..838e9aef703c84 100644 +--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c ++++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c +@@ -882,6 +882,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + struct v4l2_ctrl_h264_decode_params *p_h264_dec_params; + struct v4l2_ctrl_hevc_sps *p_hevc_sps; + struct v4l2_ctrl_hevc_pps *p_hevc_pps; ++ struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params; + struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering; + struct v4l2_ctrl_hevc_decode_params *p_hevc_decode_params; + struct v4l2_area *area; +@@ -1171,6 +1172,18 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, + break; + + case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: ++ p_hevc_slice_params = p; ++ ++ if (p_hevc_slice_params->num_ref_idx_l0_active_minus1 >= ++ V4L2_HEVC_DPB_ENTRIES_NUM_MAX) ++ return -EINVAL; ++ ++ if (p_hevc_slice_params->slice_type != V4L2_HEVC_SLICE_TYPE_B) ++ break; ++ ++ if (p_hevc_slice_params->num_ref_idx_l1_active_minus1 >= ++ V4L2_HEVC_DPB_ENTRIES_NUM_MAX) ++ return -EINVAL; + break; + + case V4L2_CTRL_TYPE_HDR10_CLL_INFO: +diff --git a/drivers/media/v4l2-core/v4l2-ctrls-request.c b/drivers/media/v4l2-core/v4l2-ctrls-request.c +index e77f722b36a48e..aa5566a8fb7d31 100644 +--- a/drivers/media/v4l2-core/v4l2-ctrls-request.c ++++ b/drivers/media/v4l2-core/v4l2-ctrls-request.c +@@ -348,13 +348,12 @@ void v4l2_ctrl_request_complete(struct media_request *req, + ret = v4l2_ctrl_handler_init(hdl, (main_hdl->nr_of_buckets - 1) * 8); + if (!ret) + ret = v4l2_ctrl_request_bind(req, hdl, main_hdl); +- if (ret) { +- v4l2_ctrl_handler_free(hdl); +- kfree(hdl); +- return; +- } ++ if (ret) ++ goto error; + hdl->request_is_queued = true; + obj = media_request_object_find(req, &req_ops, main_hdl); ++ if (!obj) ++ goto error; + } + hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj); + +@@ -389,6 +388,11 @@ void v4l2_ctrl_request_complete(struct media_request *req, + mutex_unlock(main_hdl->lock); + media_request_object_complete(obj); + media_request_object_put(obj); ++ return; ++ ++error: ++ v4l2_ctrl_handler_free(hdl); ++ kfree(hdl); + } + EXPORT_SYMBOL(v4l2_ctrl_request_complete); + +diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c +index cb153ce42c45d6..a8becf88b75369 100644 +--- a/drivers/media/v4l2-core/v4l2-fwnode.c ++++ b/drivers/media/v4l2-core/v4l2-fwnode.c +@@ -1246,7 +1246,7 @@ v4l2_async_nf_parse_fwnode_sensor(struct device *dev, + return 0; + } + +-int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) ++int __v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd, struct module *module) + { + struct v4l2_async_notifier *notifier; + int ret; +@@ -1272,7 +1272,7 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) + if (ret < 0) + goto out_cleanup; + +- ret = v4l2_async_register_subdev(sd); ++ ret = __v4l2_async_register_subdev(sd, module); + if (ret < 0) + goto out_unregister; + +@@ -1290,7 +1290,7 @@ out_cleanup: + + return ret; + } +-EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor); ++EXPORT_SYMBOL_GPL(__v4l2_async_register_subdev_sensor); + + MODULE_DESCRIPTION("V4L2 fwnode binding parsing library"); + MODULE_LICENSE("GPL"); +diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c +index 25e66bf18f5fc9..349022153b18ed 100644 +--- a/drivers/media/v4l2-core/v4l2-subdev.c ++++ b/drivers/media/v4l2-core/v4l2-subdev.c +@@ -2506,6 +2506,10 @@ int v4l2_subdev_s_stream_helper(struct v4l2_subdev *sd, int enable) + u64 source_mask = 0; + int pad_index = -1; + ++ if (WARN_ON(!v4l2_subdev_has_op(sd, pad, enable_streams) || ++ !v4l2_subdev_has_op(sd, pad, disable_streams))) ++ return -ENOIOCTLCMD; ++ + /* + * Find the source pad. This helper is meant for subdevs that have a + * single source pad, so failures shouldn't happen, but catch them +diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c +index 2c810ab12e6202..a6f0bc150d7701 100644 +--- a/drivers/misc/mei/bus.c ++++ b/drivers/misc/mei/bus.c +@@ -4,6 +4,7 @@ + * Intel Management Engine Interface (Intel MEI) Linux driver + */ + ++#include <linux/cleanup.h> + #include <linux/module.h> + #include <linux/device.h> + #include <linux/kernel.h> +@@ -1317,15 +1318,16 @@ static void mei_dev_bus_put(struct mei_device *bus) + static void mei_cl_bus_dev_release(struct device *dev) + { + struct mei_cl_device *cldev = to_mei_cl_device(dev); +- struct mei_device *mdev = cldev->cl->dev; ++ struct mei_device *bus = cldev->bus; + struct mei_cl *cl; + +- mei_cl_flush_queues(cldev->cl, NULL); +- mei_me_cl_put(cldev->me_cl); +- mei_dev_bus_put(cldev->bus); +- +- list_for_each_entry(cl, &mdev->file_list, link) +- WARN_ON(cl == cldev->cl); ++ scoped_guard(mutex, &bus->device_lock) { ++ mei_cl_flush_queues(cldev->cl, NULL); ++ mei_me_cl_put(cldev->me_cl); ++ list_for_each_entry(cl, &bus->file_list, link) ++ WARN_ON(cl == cldev->cl); ++ } ++ mei_dev_bus_put(bus); + + kfree(cldev->cl); + kfree(cldev); +diff --git a/drivers/misc/nsm.c b/drivers/misc/nsm.c +index ef7b3274234099..3960506eb7ab3d 100644 +--- a/drivers/misc/nsm.c ++++ b/drivers/misc/nsm.c +@@ -367,7 +367,7 @@ static long nsm_dev_ioctl(struct file *file, unsigned int cmd, + /* Copy user argument struct to kernel argument struct */ + r = -EFAULT; + if (copy_from_user(&raw, argp, _IOC_SIZE(cmd))) +- goto out; ++ return r; + + mutex_lock(&nsm->lock); + +@@ -413,6 +413,7 @@ static int nsm_device_init_vq(struct virtio_device *vdev) + } + + static const struct file_operations nsm_dev_fops = { ++ .owner = THIS_MODULE, + .unlocked_ioctl = nsm_dev_ioctl, + .compat_ioctl = compat_ptr_ioctl, + }; +diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c +index 93c4e145009e00..1614e9995ee68c 100644 +--- a/drivers/mmc/host/vub300.c ++++ b/drivers/mmc/host/vub300.c +@@ -2115,19 +2115,19 @@ static int vub300_probe(struct usb_interface *interface, + command_out_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!command_out_urb) { + retval = -ENOMEM; +- goto error0; ++ goto err_put_udev; + } + command_res_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!command_res_urb) { + retval = -ENOMEM; +- goto error1; ++ goto err_free_out_urb; + } + /* this also allocates memory for our VUB300 mmc host device */ + mmc = mmc_alloc_host(sizeof(*vub300), &udev->dev); + if (!mmc) { + retval = -ENOMEM; + dev_err(&udev->dev, "not enough memory for the mmc_host\n"); +- goto error4; ++ goto err_free_res_urb; + } + /* MMC core transfer sizes tunable parameters */ + mmc->caps = 0; +@@ -2344,23 +2344,29 @@ static int vub300_probe(struct usb_interface *interface, + interface_to_InterfaceNumber(interface)); + retval = mmc_add_host(mmc); + if (retval) +- goto error6; ++ goto err_stop_io; + + return 0; +-error6: +- timer_delete_sync(&vub300->inactivity_timer); ++ ++err_stop_io: ++ vub300->interface = NULL; ++ kref_put(&vub300->kref, vub300_delete); ++ ++ return retval; ++ + err_free_host: + mmc_free_host(mmc); + /* + * and hence also frees vub300 + * which is contained at the end of struct mmc + */ +-error4: ++err_free_res_urb: + usb_free_urb(command_res_urb); +-error1: ++err_free_out_urb: + usb_free_urb(command_out_urb); +-error0: ++err_put_udev: + usb_put_dev(udev); ++ + return retval; + } + +diff --git a/drivers/mtd/maps/vmu-flash.c b/drivers/mtd/maps/vmu-flash.c +index 3667faefe6c58f..e992f4d1417e6f 100644 +--- a/drivers/mtd/maps/vmu-flash.c ++++ b/drivers/mtd/maps/vmu-flash.c +@@ -610,7 +610,7 @@ static int vmu_connect(struct maple_device *mdev) + + basic_flash_data = be32_to_cpu(mdev->devinfo.function_data[c - 1]); + +- card = kmalloc(sizeof(struct memcard), GFP_KERNEL); ++ card = kzalloc_obj(struct memcard); + if (!card) { + error = -ENOMEM; + goto fail_nomem; +@@ -628,15 +628,13 @@ static int vmu_connect(struct maple_device *mdev) + * Not sure there are actually any multi-partition devices in the + * real world, but the hardware supports them, so, so will we + */ +- card->parts = kmalloc_array(card->partitions, sizeof(struct vmupart), +- GFP_KERNEL); ++ card->parts = kzalloc_objs(struct vmupart, card->partitions); + if (!card->parts) { + error = -ENOMEM; + goto fail_partitions; + } + +- card->mtd = kmalloc_array(card->partitions, sizeof(struct mtd_info), +- GFP_KERNEL); ++ card->mtd = kzalloc_objs(struct mtd_info, card->partitions); + if (!card->mtd) { + error = -ENOMEM; + goto fail_mtd_info; +diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c +index 64808493b4f5ea..42cabd3c1efad1 100644 +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -104,6 +104,15 @@ static void mtd_release(struct device *dev) + device_destroy(&mtd_class, index + 1); + } + ++/* ++ * No-op device release used in add_mtd_device() error paths. ++ * Prevents mtd_release() from being called via device_release(), ++ * which would free the mtd_info that the caller still manages. ++ */ ++static void mtd_dev_release_nop(struct device *dev) ++{ ++} ++ + static void mtd_device_release(struct kref *kref) + { + struct mtd_info *mtd = container_of(kref, struct mtd_info, refcnt); +@@ -798,10 +807,8 @@ int add_mtd_device(struct mtd_info *mtd) + mtd_check_of_node(mtd); + of_node_get(mtd_get_of_node(mtd)); + error = device_register(&mtd->dev); +- if (error) { +- put_device(&mtd->dev); ++ if (error) + goto fail_added; +- } + + /* Add the nvmem provider */ + error = mtd_nvmem_add(mtd); +@@ -839,8 +846,16 @@ int add_mtd_device(struct mtd_info *mtd) + return 0; + + fail_nvmem_add: +- device_unregister(&mtd->dev); ++ device_del(&mtd->dev); + fail_added: ++ /* ++ * Clear type and set nop release to prevent mtd_release() -> ++ * release_mtd_partition() -> free_partition() from freeing mtd. ++ * The caller handles cleanup on failure. ++ */ ++ mtd->dev.type = NULL; ++ mtd->dev.release = mtd_dev_release_nop; ++ put_device(&mtd->dev); + of_node_put(mtd_get_of_node(mtd)); + fail_devname: + idr_remove(&mtd_idr, i); +diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c +index d8f2e5be2d315e..42ff7deace80c5 100644 +--- a/drivers/mtd/mtdswap.c ++++ b/drivers/mtd/mtdswap.c +@@ -125,6 +125,7 @@ struct mtdswap_dev { + + char *page_buf; + char *oob_buf; ++ struct dentry *debugfs_stats; + }; + + struct mtdswap_oobdata { +@@ -1262,7 +1263,8 @@ static int mtdswap_add_debugfs(struct mtdswap_dev *d) + if (IS_ERR_OR_NULL(root)) + return -1; + +- debugfs_create_file("mtdswap_stats", S_IRUSR, root, d, &mtdswap_fops); ++ d->debugfs_stats = debugfs_create_file("mtdswap_stats", 0400, root, ++ d, &mtdswap_fops); + + return 0; + } +@@ -1463,6 +1465,7 @@ static void mtdswap_remove_dev(struct mtd_blktrans_dev *dev) + { + struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev); + ++ debugfs_remove(d->debugfs_stats); + del_mtd_blktrans_dev(dev); + mtdswap_cleanup(d); + kfree(d); +diff --git a/drivers/mtd/nand/ecc-mtk.c b/drivers/mtd/nand/ecc-mtk.c +index c75bb8b80cc1e1..96703f0a418ea2 100644 +--- a/drivers/mtd/nand/ecc-mtk.c ++++ b/drivers/mtd/nand/ecc-mtk.c +@@ -123,8 +123,8 @@ static int mt7622_ecc_regs[] = { + [ECC_DECIRQ_STA] = 0x144, + }; + +-static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc, +- enum mtk_ecc_operation op) ++static inline int mtk_ecc_wait_idle(struct mtk_ecc *ecc, ++ enum mtk_ecc_operation op) + { + struct device *dev = ecc->dev; + u32 val; +@@ -136,6 +136,8 @@ static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc, + if (ret) + dev_warn(dev, "%s NOT idle\n", + op == ECC_ENCODE ? "encoder" : "decoder"); ++ ++ return ret; + } + + static irqreturn_t mtk_ecc_irq(int irq, void *id) +@@ -312,7 +314,11 @@ int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config) + return ret; + } + +- mtk_ecc_wait_idle(ecc, op); ++ ret = mtk_ecc_wait_idle(ecc, op); ++ if (ret) { ++ mutex_unlock(&ecc->lock); ++ return ret; ++ } + + ret = mtk_ecc_config(ecc, config); + if (ret) { +@@ -412,7 +418,9 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config, + if (ret) + goto timeout; + +- mtk_ecc_wait_idle(ecc, ECC_ENCODE); ++ ret = mtk_ecc_wait_idle(ecc, ECC_ENCODE); ++ if (ret) ++ goto timeout; + + /* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */ + len = (config->strength * ecc->caps->parity_bits + 7) >> 3; +diff --git a/drivers/net/amt.c b/drivers/net/amt.c +index e4d1aa26d7bbd7..2bc8781f07c2d0 100644 +--- a/drivers/net/amt.c ++++ b/drivers/net/amt.c +@@ -1211,7 +1211,7 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev) + data = true; + } + v6 = false; +- group.ip4 = iph->daddr; ++ group.ip4 = ip_hdr(skb)->daddr; + #if IS_ENABLED(CONFIG_IPV6) + } else if (iph->version == 6) { + ip6h = ipv6_hdr(skb); +@@ -1235,7 +1235,7 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev) + data = true; + } + v6 = true; +- group.ip6 = ip6h->daddr; ++ group.ip6 = ipv6_hdr(skb)->daddr; + #endif + } else { + dev->stats.tx_errors++; +@@ -1278,12 +1278,12 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev) + hlist_for_each_entry_rcu(gnode, &tunnel->groups[hash], + node) { + if (!v6) { +- if (gnode->group_addr.ip4 == iph->daddr) ++ if (gnode->group_addr.ip4 == group.ip4) + goto found; + #if IS_ENABLED(CONFIG_IPV6) + } else { + if (ipv6_addr_equal(&gnode->group_addr.ip6, +- &ip6h->daddr)) ++ &group.ip6)) + goto found; + #endif + } +@@ -2000,14 +2000,18 @@ static void amt_igmpv3_report_handler(struct amt_dev *amt, struct sk_buff *skb, + struct igmpv3_report *ihrv3 = igmpv3_report_hdr(skb); + int len = skb_transport_offset(skb) + sizeof(*ihrv3); + void *zero_grec = (void *)&igmpv3_zero_grec; +- struct iphdr *iph = ip_hdr(skb); + struct amt_group_node *gnode; + union amt_addr group, host; + struct igmpv3_grec *grec; ++ __be32 saddr; + u16 nsrcs; ++ u16 ngrec; + int i; + +- for (i = 0; i < ntohs(ihrv3->ngrec); i++) { ++ saddr = ip_hdr(skb)->saddr; ++ ngrec = ntohs(ihrv3->ngrec); ++ ++ for (i = 0; i < ngrec; i++) { + len += sizeof(*grec); + if (!ip_mc_may_pull(skb, len)) + break; +@@ -2019,10 +2023,13 @@ static void amt_igmpv3_report_handler(struct amt_dev *amt, struct sk_buff *skb, + if (!ip_mc_may_pull(skb, len)) + break; + ++ grec = (void *)(skb->data + len - sizeof(*grec) - ++ nsrcs * sizeof(__be32)); ++ + memset(&group, 0, sizeof(union amt_addr)); + group.ip4 = grec->grec_mca; + memset(&host, 0, sizeof(union amt_addr)); +- host.ip4 = iph->saddr; ++ host.ip4 = saddr; + gnode = amt_lookup_group(tunnel, &group, &host, false); + if (!gnode) { + gnode = amt_add_group(amt, tunnel, &group, &host, +@@ -2162,14 +2169,18 @@ static void amt_mldv2_report_handler(struct amt_dev *amt, struct sk_buff *skb, + struct mld2_report *mld2r = (struct mld2_report *)icmp6_hdr(skb); + int len = skb_transport_offset(skb) + sizeof(*mld2r); + void *zero_grec = (void *)&mldv2_zero_grec; +- struct ipv6hdr *ip6h = ipv6_hdr(skb); + struct amt_group_node *gnode; + union amt_addr group, host; + struct mld2_grec *grec; ++ struct in6_addr saddr; + u16 nsrcs; ++ u16 ngrec; + int i; + +- for (i = 0; i < ntohs(mld2r->mld2r_ngrec); i++) { ++ saddr = ipv6_hdr(skb)->saddr; ++ ngrec = ntohs(mld2r->mld2r_ngrec); ++ ++ for (i = 0; i < ngrec; i++) { + len += sizeof(*grec); + if (!ipv6_mc_may_pull(skb, len)) + break; +@@ -2181,10 +2192,13 @@ static void amt_mldv2_report_handler(struct amt_dev *amt, struct sk_buff *skb, + if (!ipv6_mc_may_pull(skb, len)) + break; + ++ grec = (void *)(skb->data + len - sizeof(*grec) - ++ nsrcs * sizeof(struct in6_addr)); ++ + memset(&group, 0, sizeof(union amt_addr)); + group.ip6 = grec->grec_mca; + memset(&host, 0, sizeof(union amt_addr)); +- host.ip6 = ip6h->saddr; ++ host.ip6 = saddr; + gnode = amt_lookup_group(tunnel, &group, &host, true); + if (!gnode) { + gnode = amt_add_group(amt, tunnel, &group, &host, +@@ -2305,7 +2319,9 @@ static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb) + skb_push(skb, sizeof(*eth)); + skb_reset_mac_header(skb); + skb_pull(skb, sizeof(*eth)); +- eth = eth_hdr(skb); ++ ++ if (skb_cow_head(skb, 0)) ++ return true; + + if (!pskb_may_pull(skb, sizeof(*iph))) + return true; +@@ -2315,6 +2331,7 @@ static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb) + if (!ipv4_is_multicast(iph->daddr)) + return true; + skb->protocol = htons(ETH_P_IP); ++ eth = eth_hdr(skb); + eth->h_proto = htons(ETH_P_IP); + ip_eth_mc_map(iph->daddr, eth->h_dest); + #if IS_ENABLED(CONFIG_IPV6) +@@ -2328,6 +2345,7 @@ static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb) + if (!ipv6_addr_is_multicast(&ip6h->daddr)) + return true; + skb->protocol = htons(ETH_P_IPV6); ++ eth = eth_hdr(skb); + eth->h_proto = htons(ETH_P_IPV6); + ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest); + #endif +@@ -2351,10 +2369,12 @@ static bool amt_membership_query_handler(struct amt_dev *amt, + struct sk_buff *skb) + { + struct amt_header_membership_query *amtmq; +- struct igmpv3_query *ihv3; + struct ethhdr *eth, *oeth; ++ struct igmpv3_query *ihv3; ++ u8 h_source[ETH_ALEN]; + struct iphdr *iph; + int hdr_size, len; ++ u64 response_mac; + + hdr_size = sizeof(*amtmq) + sizeof(struct udphdr); + if (!pskb_may_pull(skb, hdr_size)) +@@ -2367,6 +2387,8 @@ static bool amt_membership_query_handler(struct amt_dev *amt, + if (amtmq->nonce != amt->nonce) + return true; + ++ response_mac = amtmq->response_mac; ++ + hdr_size -= sizeof(*eth); + if (iptunnel_pull_header(skb, hdr_size, htons(ETH_P_TEB), false)) + return true; +@@ -2376,6 +2398,9 @@ static bool amt_membership_query_handler(struct amt_dev *amt, + skb_pull(skb, sizeof(*eth)); + skb_reset_network_header(skb); + eth = eth_hdr(skb); ++ ether_addr_copy(h_source, oeth->h_source); ++ if (skb_cow_head(skb, 0)) ++ return true; + if (!pskb_may_pull(skb, sizeof(*iph))) + return true; + +@@ -2388,6 +2413,7 @@ static bool amt_membership_query_handler(struct amt_dev *amt, + sizeof(*ihv3))) + return true; + ++ iph = ip_hdr(skb); + if (!ipv4_is_multicast(iph->daddr)) + return true; + +@@ -2395,10 +2421,11 @@ static bool amt_membership_query_handler(struct amt_dev *amt, + skb_reset_transport_header(skb); + skb_push(skb, sizeof(*iph) + AMT_IPHDR_OPTS); + WRITE_ONCE(amt->ready4, true); +- amt->mac = amtmq->response_mac; ++ amt->mac = response_mac; + amt->req_cnt = 0; + amt->qi = ihv3->qqic; + skb->protocol = htons(ETH_P_IP); ++ eth = eth_hdr(skb); + eth->h_proto = htons(ETH_P_IP); + ip_eth_mc_map(iph->daddr, eth->h_dest); + #if IS_ENABLED(CONFIG_IPV6) +@@ -2421,10 +2448,11 @@ static bool amt_membership_query_handler(struct amt_dev *amt, + skb_reset_transport_header(skb); + skb_push(skb, sizeof(*ip6h) + AMT_IP6HDR_OPTS); + WRITE_ONCE(amt->ready6, true); +- amt->mac = amtmq->response_mac; ++ amt->mac = response_mac; + amt->req_cnt = 0; + amt->qi = mld2q->mld2q_qqic; + skb->protocol = htons(ETH_P_IPV6); ++ eth = eth_hdr(skb); + eth->h_proto = htons(ETH_P_IPV6); + ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest); + #endif +@@ -2432,7 +2460,7 @@ static bool amt_membership_query_handler(struct amt_dev *amt, + return true; + } + +- ether_addr_copy(eth->h_source, oeth->h_source); ++ ether_addr_copy(eth->h_source, h_source); + skb->pkt_type = PACKET_MULTICAST; + skb->ip_summed = CHECKSUM_NONE; + len = skb->len; +@@ -2455,8 +2483,11 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb) + struct ethhdr *eth; + struct iphdr *iph; + int len, hdr_size; ++ u64 response_mac; ++ __be32 saddr; ++ __be32 nonce; + +- iph = ip_hdr(skb); ++ saddr = ip_hdr(skb)->saddr; + + hdr_size = sizeof(*amtmu) + sizeof(struct udphdr); + if (!pskb_may_pull(skb, hdr_size)) +@@ -2466,15 +2497,18 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb) + if (amtmu->reserved || amtmu->version) + return true; + ++ nonce = amtmu->nonce; ++ response_mac = amtmu->response_mac; ++ + if (iptunnel_pull_header(skb, hdr_size, skb->protocol, false)) + return true; + + skb_reset_network_header(skb); + + list_for_each_entry_rcu(tunnel, &amt->tunnel_list, list) { +- if (tunnel->ip4 == iph->saddr) { +- if ((amtmu->nonce == tunnel->nonce && +- amtmu->response_mac == tunnel->mac)) { ++ if (tunnel->ip4 == saddr) { ++ if ((nonce == tunnel->nonce && ++ response_mac == tunnel->mac)) { + mod_delayed_work(amt_wq, &tunnel->gc_wq, + msecs_to_jiffies(amt_gmi(amt)) + * 3); +@@ -2492,6 +2526,9 @@ report: + if (!pskb_may_pull(skb, sizeof(*iph))) + return true; + ++ if (skb_cow_head(skb, 0)) ++ return true; ++ + iph = ip_hdr(skb); + if (iph->version == 4) { + if (ip_mc_check_igmp(skb)) { +@@ -2508,6 +2545,7 @@ report: + eth = eth_hdr(skb); + skb->protocol = htons(ETH_P_IP); + eth->h_proto = htons(ETH_P_IP); ++ iph = ip_hdr(skb); + ip_eth_mc_map(iph->daddr, eth->h_dest); + #if IS_ENABLED(CONFIG_IPV6) + } else if (iph->version == 6) { +@@ -2527,6 +2565,7 @@ report: + eth = eth_hdr(skb); + skb->protocol = htons(ETH_P_IPV6); + eth->h_proto = htons(ETH_P_IPV6); ++ ip6h = ipv6_hdr(skb); + ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest); + #endif + } else { +@@ -2772,7 +2811,7 @@ drop: + static int amt_rcv(struct sock *sk, struct sk_buff *skb) + { + struct amt_dev *amt; +- struct iphdr *iph; ++ __be32 saddr; + int type; + bool err; + +@@ -2785,7 +2824,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb) + } + + skb->dev = amt->dev; +- iph = ip_hdr(skb); ++ saddr = ip_hdr(skb)->saddr; + type = amt_parse_type(skb); + if (type == -1) { + err = true; +@@ -2795,7 +2834,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb) + if (amt->mode == AMT_MODE_GATEWAY) { + switch (type) { + case AMT_MSG_ADVERTISEMENT: +- if (iph->saddr != amt->discovery_ip) { ++ if (saddr != amt->discovery_ip) { + netdev_dbg(amt->dev, "Invalid Relay IP\n"); + err = true; + goto drop; +@@ -2807,7 +2846,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb) + } + goto out; + case AMT_MSG_MULTICAST_DATA: +- if (iph->saddr != amt->remote_ip) { ++ if (saddr != amt->remote_ip) { + netdev_dbg(amt->dev, "Invalid Relay IP\n"); + err = true; + goto drop; +@@ -2818,7 +2857,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb) + else + goto out; + case AMT_MSG_MEMBERSHIP_QUERY: +- if (iph->saddr != amt->remote_ip) { ++ if (saddr != amt->remote_ip) { + netdev_dbg(amt->dev, "Invalid Relay IP\n"); + err = true; + goto drop; +@@ -2995,9 +3034,15 @@ static int amt_dev_open(struct net_device *dev) + amt->event_idx = 0; + amt->nr_events = 0; + ++ enable_delayed_work(&amt->discovery_wq); ++ enable_delayed_work(&amt->req_wq); ++ + err = amt_socket_create(amt); +- if (err) ++ if (err) { ++ disable_delayed_work(&amt->req_wq); ++ disable_delayed_work(&amt->discovery_wq); + return err; ++ } + + amt->req_cnt = 0; + amt->remote_ip = 0; +@@ -3023,8 +3068,8 @@ static int amt_dev_stop(struct net_device *dev) + struct sk_buff *skb; + int i; + +- cancel_delayed_work_sync(&amt->req_wq); +- cancel_delayed_work_sync(&amt->discovery_wq); ++ disable_delayed_work_sync(&amt->req_wq); ++ disable_delayed_work_sync(&amt->discovery_wq); + cancel_delayed_work_sync(&amt->secret_wq); + + /* shutdown */ +@@ -3278,6 +3323,8 @@ static int amt_newlink(struct net_device *dev, + 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); ++ disable_delayed_work(&amt->req_wq); ++ disable_delayed_work(&amt->discovery_wq); + INIT_LIST_HEAD(&amt->tunnel_list); + return 0; + err: +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index e38cae22fe025e..52af663e12e0c1 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -3422,7 +3422,8 @@ static void bond_send_validate(struct bonding *bond, struct slave *slave) + { + bond_arp_send_all(bond, slave); + #if IS_ENABLED(CONFIG_IPV6) +- bond_ns_send_all(bond, slave); ++ if (likely(ipv6_mod_enabled())) ++ bond_ns_send_all(bond, slave); + #endif + } + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 5efd03c2deea77..64ab34e37c36f9 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -2326,8 +2326,7 @@ static int airoha_tc_setup_qdisc_ets(struct airoha_gdm_port *port, + if (opt->parent == TC_H_ROOT) + return -EINVAL; + +- channel = TC_H_MAJ(opt->handle) >> 16; +- channel = channel % AIROHA_NUM_QOS_CHANNELS; ++ channel = TC_H_MIN(opt->parent) % AIROHA_NUM_QOS_CHANNELS; + + switch (opt->command) { + case TC_ETS_REPLACE: +diff --git a/drivers/net/ethernet/airoha/airoha_npu.c b/drivers/net/ethernet/airoha/airoha_npu.c +index 8c883f2b2d36b7..d6547834d3c783 100644 +--- a/drivers/net/ethernet/airoha/airoha_npu.c ++++ b/drivers/net/ethernet/airoha/airoha_npu.c +@@ -154,7 +154,7 @@ static int airoha_npu_send_msg(struct airoha_npu *npu, int func_id, + dma_addr_t dma_addr; + int ret; + +- dma_addr = dma_map_single(npu->dev, p, size, DMA_TO_DEVICE); ++ dma_addr = dma_map_single(npu->dev, p, size, DMA_BIDIRECTIONAL); + ret = dma_mapping_error(npu->dev, dma_addr); + if (ret) + return ret; +@@ -177,7 +177,7 @@ static int airoha_npu_send_msg(struct airoha_npu *npu, int func_id, + + spin_unlock_bh(&npu->cores[core].lock); + +- dma_unmap_single(npu->dev, dma_addr, size, DMA_TO_DEVICE); ++ dma_unmap_single(npu->dev, dma_addr, size, DMA_BIDIRECTIONAL); + + return ret; + } +diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c +index 798839aa1010b8..8defd194568f25 100644 +--- a/drivers/net/ethernet/airoha/airoha_ppe.c ++++ b/drivers/net/ethernet/airoha/airoha_ppe.c +@@ -1575,6 +1575,7 @@ void airoha_ppe_deinit(struct airoha_eth *eth) + npu = rcu_replace_pointer(eth->npu, NULL, + lockdep_is_held(&flow_offload_mutex)); + if (npu) { ++ synchronize_rcu(); + npu->ops.ppe_deinit(npu); + airoha_npu_put(npu); + } +diff --git a/drivers/net/ethernet/amd/pds_core/adminq.c b/drivers/net/ethernet/amd/pds_core/adminq.c +index 097bb092bdb8cd..eadb4b604fbe3c 100644 +--- a/drivers/net/ethernet/amd/pds_core/adminq.c ++++ b/drivers/net/ethernet/amd/pds_core/adminq.c +@@ -18,7 +18,13 @@ static int pdsc_process_notifyq(struct pdsc_qcq *qcq) + comp = cq_info->comp; + eid = le64_to_cpu(comp->event.eid); + while (eid > pdsc->last_eid) { +- u16 ecode = le16_to_cpu(comp->event.ecode); ++ u16 ecode; ++ ++ /* Order the payload read after the event id, the field the ++ * driver uses to detect a new completion. ++ */ ++ dma_rmb(); ++ ecode = le16_to_cpu(comp->event.ecode); + + switch (ecode) { + case PDS_EVENT_LINK_CHANGE: +@@ -101,6 +107,10 @@ void pdsc_process_adminq(struct pdsc_qcq *qcq) + spin_lock_irqsave(&pdsc->adminq_lock, irqflags); + comp = cq->info[cq->tail_idx].comp; + while (pdsc_color_match(comp->color, cq->done_color)) { ++ /* Order the payload reads after the color bit, the field the ++ * driver uses to detect a new completion. ++ */ ++ dma_rmb(); + q_info = &q->info[q->tail_idx]; + q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1); + +diff --git a/drivers/net/ethernet/amd/pds_core/auxbus.c b/drivers/net/ethernet/amd/pds_core/auxbus.c +index 92f359f2b44920..874812bafc1d39 100644 +--- a/drivers/net/ethernet/amd/pds_core/auxbus.c ++++ b/drivers/net/ethernet/amd/pds_core/auxbus.c +@@ -177,17 +177,21 @@ void pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf, + { + struct pds_auxiliary_dev *padev; + +- if (!*pd_ptr) +- return; +- + mutex_lock(&pf->config_lock); + ++ /* A concurrent del may have already torn this device down and ++ * cleared it. ++ */ + padev = *pd_ptr; ++ if (!padev) ++ goto out_unlock; ++ + pds_client_unregister(pf, padev->client_id); + auxiliary_device_delete(&padev->aux_dev); + auxiliary_device_uninit(&padev->aux_dev); + *pd_ptr = NULL; + ++out_unlock: + mutex_unlock(&pf->config_lock); + } + +@@ -210,6 +214,13 @@ int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf, + + mutex_lock(&pf->config_lock); + ++ /* Nothing to do if the aux device is already present. This also ++ * guards against a second add overwriting *pd_ptr and leaking the ++ * first, symmetric with the check in pdsc_auxbus_dev_del(). ++ */ ++ if (*pd_ptr) ++ goto out_unlock; ++ + mask = BIT_ULL(PDSC_S_FW_DEAD) | + BIT_ULL(PDSC_S_STOPPING_DRIVER); + if (cf->state & mask) { +diff --git a/drivers/net/ethernet/amd/pds_core/core.c b/drivers/net/ethernet/amd/pds_core/core.c +index 076dfe2910c770..d02e096a2c5fb3 100644 +--- a/drivers/net/ethernet/amd/pds_core/core.c ++++ b/drivers/net/ethernet/amd/pds_core/core.c +@@ -110,7 +110,6 @@ static void pdsc_qcq_intr_free(struct pdsc *pdsc, struct pdsc_qcq *qcq) + return; + + pdsc_intr_free(pdsc, qcq->intx); +- qcq->intx = PDS_CORE_INTR_INDEX_NOT_ASSIGNED; + } + + static int pdsc_qcq_intr_alloc(struct pdsc *pdsc, struct pdsc_qcq *qcq) +@@ -145,6 +144,12 @@ void pdsc_qcq_free(struct pdsc *pdsc, struct pdsc_qcq *qcq) + + pdsc_qcq_intr_free(pdsc, qcq); + ++ /* Drain any work queued by ISR before it was freed above */ ++ if (qcq->work.func) ++ cancel_work_sync(&qcq->work); ++ ++ qcq->intx = PDS_CORE_INTR_INDEX_NOT_ASSIGNED; ++ + if (qcq->q_base) + dma_free_coherent(dev, qcq->q_size, + qcq->q_base, qcq->q_base_pa); +@@ -304,8 +309,11 @@ err_out: + + static void pdsc_core_uninit(struct pdsc *pdsc) + { +- pdsc_qcq_free(pdsc, &pdsc->notifyqcq); ++ /* Free adminqcq first: its work accesses notifyqcq, so we must ++ * disable its IRQ and drain its work before freeing notifyqcq. ++ */ + pdsc_qcq_free(pdsc, &pdsc->adminqcq); ++ pdsc_qcq_free(pdsc, &pdsc->notifyqcq); + + if (pdsc->kern_dbpage) { + iounmap(pdsc->kern_dbpage); +@@ -478,8 +486,6 @@ void pdsc_teardown(struct pdsc *pdsc, bool removing) + { + if (!pdsc->pdev->is_virtfn) + pdsc_devcmd_reset(pdsc); +- if (pdsc->adminqcq.work.func) +- cancel_work_sync(&pdsc->adminqcq.work); + + pdsc_core_uninit(pdsc); + +@@ -530,6 +536,7 @@ static void pdsc_adminq_wait_and_dec_once_unused(struct pdsc *pdsc) + dev_dbg_ratelimited(pdsc->dev, "%s: adminq in use\n", + __func__); + cpu_relax(); ++ cond_resched(); + } + } + +@@ -603,9 +610,10 @@ void pdsc_pci_reset_thread(struct work_struct *work) + struct pdsc *pdsc = container_of(work, struct pdsc, pci_reset_work); + struct pci_dev *pdev = pdsc->pdev; + +- pci_dev_get(pdev); +- pci_reset_function(pdev); +- pci_dev_put(pdev); ++ /* Use try variant to avoid deadlock with pdsc_remove(). ++ * If lock is contended, the watchdog timer will retry. ++ */ ++ pci_try_reset_function(pdev); + } + + static void pdsc_check_pci_health(struct pdsc *pdsc) +diff --git a/drivers/net/ethernet/amd/pds_core/devlink.c b/drivers/net/ethernet/amd/pds_core/devlink.c +index 621791a3c543be..e35572f099c884 100644 +--- a/drivers/net/ethernet/amd/pds_core/devlink.c ++++ b/drivers/net/ethernet/amd/pds_core/devlink.c +@@ -89,6 +89,12 @@ int pdsc_dl_flash_update(struct devlink *dl, + { + struct pdsc *pdsc = devlink_priv(dl); + ++ if (params->component) { ++ NL_SET_ERR_MSG_MOD(extack, ++ "Component update not supported by this device"); ++ return -EOPNOTSUPP; ++ } ++ + return pdsc_firmware_update(pdsc, params->fw, extack); + } + +diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c +index c7a2eff576325f..a4962dba3140b8 100644 +--- a/drivers/net/ethernet/amd/pds_core/main.c ++++ b/drivers/net/ethernet/amd/pds_core/main.c +@@ -239,6 +239,10 @@ static int pdsc_init_pf(struct pdsc *pdsc) + /* General workqueue and timer, but don't start timer yet */ + snprintf(wq_name, sizeof(wq_name), "%s.%d", PDS_CORE_DRV_NAME, pdsc->uid); + pdsc->wq = create_singlethread_workqueue(wq_name); ++ if (!pdsc->wq) { ++ err = -ENOMEM; ++ goto err_out_unmap_bars; ++ } + INIT_WORK(&pdsc->health_work, pdsc_health_thread); + INIT_WORK(&pdsc->pci_reset_work, pdsc_pci_reset_thread); + timer_setup(&pdsc->wdtimer, pdsc_wdtimer_cb, 0); +@@ -254,7 +258,7 @@ static int pdsc_init_pf(struct pdsc *pdsc) + err = pdsc_setup(pdsc, PDSC_SETUP_INIT); + if (err) { + mutex_unlock(&pdsc->config_lock); +- goto err_out_unmap_bars; ++ goto err_out_shutdown_timer; + } + + err = pdsc_start(pdsc); +@@ -306,13 +310,14 @@ err_out_stop: + pdsc_stop(pdsc); + err_out_teardown: + pdsc_teardown(pdsc, PDSC_TEARDOWN_REMOVING); +-err_out_unmap_bars: ++err_out_shutdown_timer: + timer_shutdown_sync(&pdsc->wdtimer); + if (pdsc->wq) + destroy_workqueue(pdsc->wq); + mutex_destroy(&pdsc->config_lock); + mutex_destroy(&pdsc->devcmd_lock); + pci_free_irq_vectors(pdsc->pdev); ++err_out_unmap_bars: + pdsc_unmap_bars(pdsc); + err_out_release_regions: + pci_release_regions(pdsc->pdev); +@@ -436,8 +441,6 @@ static void pdsc_remove(struct pci_dev *pdev) + pdsc_auxbus_dev_del(pdsc, pdsc, &pdsc->padev); + + timer_shutdown_sync(&pdsc->wdtimer); +- if (pdsc->wq) +- destroy_workqueue(pdsc->wq); + + mutex_lock(&pdsc->config_lock); + set_bit(PDSC_S_STOPPING_DRIVER, &pdsc->state); +@@ -445,6 +448,9 @@ static void pdsc_remove(struct pci_dev *pdev) + pdsc_stop(pdsc); + pdsc_teardown(pdsc, PDSC_TEARDOWN_REMOVING); + mutex_unlock(&pdsc->config_lock); ++ ++ if (pdsc->wq) ++ destroy_workqueue(pdsc->wq); + mutex_destroy(&pdsc->config_lock); + mutex_destroy(&pdsc->devcmd_lock); + +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +index 7675bb98f02956..c2d22fdb6c1829 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +@@ -267,9 +267,14 @@ static void xgbe_an37_set(struct xgbe_prv_data *pdata, bool enable, + + XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_CTRL1, reg); + +- reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_PCS_DIG_CTRL); +- reg |= XGBE_VEND2_MAC_AUTO_SW; +- XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_PCS_DIG_CTRL, reg); ++ if (pdata->an_mode == XGBE_AN_MODE_CL37_SGMII) { ++ reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_PCS_DIG_CTRL); ++ if (enable) ++ reg |= XGBE_VEND2_MAC_AUTO_SW; ++ else ++ reg &= ~XGBE_VEND2_MAC_AUTO_SW; ++ XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_PCS_DIG_CTRL, reg); ++ } + } + + static void xgbe_an37_restart(struct xgbe_prv_data *pdata) +diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +index 18d86badd6ea73..6fd478572ef8ff 100644 +--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c ++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +@@ -4732,6 +4732,7 @@ static void dpaa2_eth_disconnect_mac(struct dpaa2_eth_priv *priv) + dpaa2_mac_disconnect(mac); + + dpaa2_mac_close(mac); ++ put_device(&mac->mc_dev->dev); + kfree(mac); + } + +diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c +index 789a46f6938eea..846300b77e8acc 100644 +--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c ++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c +@@ -1511,6 +1511,7 @@ static void dpaa2_switch_port_disconnect_mac(struct ethsw_port_priv *port_priv) + dpaa2_mac_disconnect(mac); + + dpaa2_mac_close(mac); ++ put_device(&mac->mc_dev->dev); + kfree(mac); + } + +diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.c b/drivers/net/ethernet/freescale/fman/fman_dtsec.c +index 51402dff72c5ff..52f13b61bc6993 100644 +--- a/drivers/net/ethernet/freescale/fman/fman_dtsec.c ++++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.c +@@ -900,22 +900,28 @@ static void dtsec_mac_config(struct phylink_config *config, unsigned int mode, + { + struct mac_device *mac_dev = fman_config_to_mac(config); + struct dtsec_regs __iomem *regs = mac_dev->fman_mac->regs; +- u32 tmp; ++ u32 ecntrl, maccfg2; ++ ++ maccfg2 = ioread32be(®s->maccfg2); ++ maccfg2 &= ~(MACCFG2_NIBBLE_MODE | MACCFG2_BYTE_MODE); + + switch (state->interface) { + case PHY_INTERFACE_MODE_RMII: +- tmp = DTSEC_ECNTRL_RMM; ++ ecntrl = DTSEC_ECNTRL_RMM; ++ maccfg2 |= MACCFG2_NIBBLE_MODE; + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: +- tmp = DTSEC_ECNTRL_GMIIM | DTSEC_ECNTRL_RPM; ++ ecntrl = DTSEC_ECNTRL_GMIIM | DTSEC_ECNTRL_RPM; ++ maccfg2 |= MACCFG2_BYTE_MODE; + break; + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: +- tmp = DTSEC_ECNTRL_TBIM | DTSEC_ECNTRL_SGMIIM; ++ ecntrl = DTSEC_ECNTRL_TBIM | DTSEC_ECNTRL_SGMIIM; ++ maccfg2 |= MACCFG2_BYTE_MODE; + break; + default: + dev_warn(mac_dev->dev, "cannot configure dTSEC for %s\n", +@@ -923,7 +929,8 @@ static void dtsec_mac_config(struct phylink_config *config, unsigned int mode, + return; + } + +- iowrite32be(tmp, ®s->ecntrl); ++ iowrite32be(ecntrl, ®s->ecntrl); ++ iowrite32be(maccfg2, ®s->maccfg2); + } + + static void dtsec_link_up(struct phylink_config *config, struct phy_device *phy, +diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h +index 4cc6dcbfd367b8..9e7d6860b83fa1 100644 +--- a/drivers/net/ethernet/google/gve/gve.h ++++ b/drivers/net/ethernet/google/gve/gve.h +@@ -13,6 +13,7 @@ + #include <linux/netdevice.h> + #include <linux/net_tstamp.h> + #include <linux/pci.h> ++#include <linux/timer.h> + #include <linux/ptp_clock_kernel.h> + #include <linux/u64_stats_sync.h> + #include <net/page_pool/helpers.h> +@@ -41,6 +42,7 @@ + + /* Interval to schedule a stats report update, 20000ms. */ + #define GVE_STATS_REPORT_TIMER_PERIOD 20000 ++#define GVE_RX_NAPI_RESCHED_MS 20 /* msecs */ + + /* Numbers of NIC tx/rx stats in stats report. */ + #define NIC_TX_STATS_REPORT_NUM 0 +@@ -338,6 +340,7 @@ struct gve_rx_ring { + struct xdp_rxq_info xdp_rxq; + struct xsk_buff_pool *xsk_pool; + struct page_frag_cache page_cache; /* Page cache to allocate XDP frames */ ++ struct timer_list starvation_timer; /* for queue starvation recovery */ + }; + + /* A TX desc ring entry */ +diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c +index 6a0430a93ed752..fc0c7991c3a252 100644 +--- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c ++++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c +@@ -18,6 +18,16 @@ + #include <net/tcp.h> + #include <net/xdp_sock_drv.h> + ++static void gve_rx_starvation_timer(struct timer_list *t) ++{ ++ struct gve_rx_ring *rx = timer_container_of(rx, t, starvation_timer); ++ struct gve_priv *priv = rx->gve; ++ struct gve_notify_block *block; ++ ++ block = &priv->ntfy_blocks[rx->ntfy_id]; ++ napi_schedule(&block->napi); ++} ++ + static void gve_rx_free_hdr_bufs(struct gve_priv *priv, struct gve_rx_ring *rx) + { + struct device *hdev = &priv->pdev->dev; +@@ -120,6 +130,7 @@ void gve_rx_stop_ring_dqo(struct gve_priv *priv, int idx) + + if (rx->dqo.page_pool) + page_pool_disable_direct_recycling(rx->dqo.page_pool); ++ timer_shutdown_sync(&rx->starvation_timer); + gve_remove_napi(priv, ntfy_idx); + gve_rx_remove_from_block(priv, idx); + gve_rx_reset_ring_dqo(priv, idx); +@@ -208,8 +219,10 @@ static int gve_rx_alloc_hdr_bufs(struct gve_priv *priv, struct gve_rx_ring *rx, + void gve_rx_start_ring_dqo(struct gve_priv *priv, int idx) + { + int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx); ++ struct gve_rx_ring *rx = &priv->rx[idx]; + + gve_rx_add_to_block(priv, idx); ++ timer_setup(&rx->starvation_timer, gve_rx_starvation_timer, 0); + gve_add_napi(priv, ntfy_idx, gve_napi_poll_dqo); + } + +@@ -363,6 +376,7 @@ void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx) + struct gve_rx_compl_queue_dqo *complq = &rx->dqo.complq; + struct gve_rx_buf_queue_dqo *bufq = &rx->dqo.bufq; + struct gve_priv *priv = rx->gve; ++ u32 num_bufs_avail_to_hw; + u32 num_avail_slots; + u32 num_full_slots; + u32 num_posted = 0; +@@ -398,6 +412,26 @@ void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx) + } + + rx->fill_cnt += num_posted; ++ ++ /* If the queue has fewer than GVE_RX_BUF_THRESH_DQO descriptors ++ * visible to the hardware, the hardware is in danger of starving ++ * and cannot trigger interrupts. ++ * ++ * We use a threshold of 32 because a single maximum-sized RSC ++ * packet can consume up to 19 descriptors in the Rx path. Lower ++ * thresholds (e.g., 8 or 16) would be unsafe as they could cause ++ * the device to drop/stall on a maximum-sized RSC packet. ++ * ++ * Start the timer to periodically reschedule NAPI and recover. ++ */ ++ num_bufs_avail_to_hw = ++ ((bufq->tail & ~(GVE_RX_BUF_THRESH_DQO - 1)) - ++ bufq->head) & bufq->mask; ++ ++ if (num_bufs_avail_to_hw < GVE_RX_BUF_THRESH_DQO) { ++ mod_timer(&rx->starvation_timer, ++ jiffies + msecs_to_jiffies(GVE_RX_NAPI_RESCHED_MS)); ++ } + } + + static void gve_rx_skb_csum(struct sk_buff *skb, +diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c +index 18376bcc718a20..fc2c47dcfaabea 100644 +--- a/drivers/net/ethernet/hisilicon/hip04_eth.c ++++ b/drivers/net/ethernet/hisilicon/hip04_eth.c +@@ -594,7 +594,11 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget) + skb = build_skb(buf, priv->rx_buf_size); + if (unlikely(!skb)) { + net_dbg_ratelimited("build_skb failed\n"); +- goto refill; ++ /* Retain the slot; return budget so NAPI retries this ++ * buffer. Refill would overwrite rx_buf[]/rx_phys[] ++ * and leak them. ++ */ ++ return budget; + } + + dma_unmap_single(priv->dev, priv->rx_phys[priv->rx_head], +@@ -622,14 +626,15 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget) + rx++; + } + +-refill: + buf = netdev_alloc_frag(priv->rx_buf_size); + if (!buf) + goto done; + phys = dma_map_single(priv->dev, buf, + RX_BUF_SIZE, DMA_FROM_DEVICE); +- if (dma_mapping_error(priv->dev, phys)) ++ if (dma_mapping_error(priv->dev, phys)) { ++ skb_free_frag(buf); + goto done; ++ } + priv->rx_buf[priv->rx_head] = buf; + priv->rx_phys[priv->rx_head] = phys; + hip04_set_recv_desc(priv, phys); +diff --git a/drivers/net/ethernet/huawei/hinic/hinic_dev.h b/drivers/net/ethernet/huawei/hinic/hinic_dev.h +index 52ea97c818b8ec..d9ab94910a2a79 100644 +--- a/drivers/net/ethernet/huawei/hinic/hinic_dev.h ++++ b/drivers/net/ethernet/huawei/hinic/hinic_dev.h +@@ -104,8 +104,6 @@ struct hinic_dev { + u16 num_rss; + u16 rss_limit; + struct hinic_rss_type rss_type; +- u8 *rss_hkey_user; +- s32 *rss_indir_user; + struct hinic_intr_coal_info *rx_intr_coalesce; + struct hinic_intr_coal_info *tx_intr_coalesce; + struct hinic_sriov_info sriov_info; +diff --git a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c +index e9f338e9dbe7ae..cd4c295ec7aeb3 100644 +--- a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c ++++ b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c +@@ -1064,17 +1064,6 @@ static int __set_rss_rxfh(struct net_device *netdev, + int err; + + if (indir) { +- if (!nic_dev->rss_indir_user) { +- nic_dev->rss_indir_user = +- kzalloc(sizeof(u32) * HINIC_RSS_INDIR_SIZE, +- GFP_KERNEL); +- if (!nic_dev->rss_indir_user) +- return -ENOMEM; +- } +- +- memcpy(nic_dev->rss_indir_user, indir, +- sizeof(u32) * HINIC_RSS_INDIR_SIZE); +- + err = hinic_rss_set_indir_tbl(nic_dev, + nic_dev->rss_tmpl_idx, indir); + if (err) +@@ -1082,16 +1071,6 @@ static int __set_rss_rxfh(struct net_device *netdev, + } + + if (key) { +- if (!nic_dev->rss_hkey_user) { +- nic_dev->rss_hkey_user = +- kzalloc(HINIC_RSS_KEY_SIZE * 2, GFP_KERNEL); +- +- if (!nic_dev->rss_hkey_user) +- return -ENOMEM; +- } +- +- memcpy(nic_dev->rss_hkey_user, key, HINIC_RSS_KEY_SIZE); +- + err = hinic_rss_set_template_tbl(nic_dev, + nic_dev->rss_tmpl_idx, key); + if (err) +diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h +index 6886188043764c..fc4eae0a00cd3b 100644 +--- a/drivers/net/ethernet/intel/ice/ice.h ++++ b/drivers/net/ethernet/intel/ice/ice.h +@@ -765,6 +765,9 @@ static inline bool ice_is_txtime_ena(const struct ice_tx_ring *ring) + struct ice_vsi *vsi = ring->vsi; + struct ice_pf *pf = vsi->back; + ++ if (vsi->type != ICE_VSI_PF) ++ return false; ++ + return test_bit(ring->q_index, pf->txtime_txqs); + } + +diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c +index c30e27bbfe6e25..b069e6c514fb12 100644 +--- a/drivers/net/ethernet/intel/ice/ice_eswitch.c ++++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c +@@ -512,9 +512,6 @@ int ice_eswitch_attach_vf(struct ice_pf *pf, struct ice_vf *vf) + struct ice_repr *repr; + int err; + +- if (!ice_is_eswitch_mode_switchdev(pf)) +- return 0; +- + repr = ice_repr_create_vf(vf); + if (IS_ERR(repr)) + return PTR_ERR(repr); +diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c +index aebf8e08a297be..e8ab36d0f11d82 100644 +--- a/drivers/net/ethernet/intel/ice/ice_lag.c ++++ b/drivers/net/ethernet/intel/ice/ice_lag.c +@@ -2624,7 +2624,7 @@ int ice_init_lag(struct ice_pf *pf) + goto free_lport_res; + + /* associate recipes to profiles */ +- for (n = 0; n < ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER; n++) { ++ for (n = 0; n < ICE_MAX_NUM_PROFILES; n++) { + err = ice_aq_get_recipe_to_profile(&pf->hw, n, + &recipe_bits, NULL); + if (err) +diff --git a/drivers/net/ethernet/intel/ice/ice_parser.c b/drivers/net/ethernet/intel/ice/ice_parser.c +index 664beb64f5570d..0c240e90a54e1a 100644 +--- a/drivers/net/ethernet/intel/ice/ice_parser.c ++++ b/drivers/net/ethernet/intel/ice/ice_parser.c +@@ -2368,6 +2368,9 @@ int ice_parser_profile_init(struct ice_parser_result *rslt, + u16 proto_off = 0; + u16 off; + ++ if (rslt->ptype >= ICE_FLOW_PTYPE_MAX) ++ return -EINVAL; ++ + memset(prof, 0, sizeof(*prof)); + set_bit(rslt->ptype, prof->ptypes); + if (blk == ICE_BLK_SW) { +diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c +index 86eb3d0315a279..30a34ed2ae60a8 100644 +--- a/drivers/net/ethernet/intel/ice/ice_ptp.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp.c +@@ -350,7 +350,7 @@ static u64 ice_ptp_extend_40b_ts(struct ice_pf *pf, u64 in_tstamp) + return 0; + } + +- return ice_ptp_extend_32b_ts(pf->ptp.cached_phc_time, ++ return ice_ptp_extend_32b_ts(READ_ONCE(pf->ptp.cached_phc_time), + (in_tstamp >> 8) & mask); + } + +@@ -2994,6 +2994,11 @@ void ice_ptp_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type) + struct ice_ptp *ptp = &pf->ptp; + int err; + ++ if (ptp->state == ICE_PTP_UNINIT) { ++ dev_dbg(ice_pf_to_dev(pf), "PTP was not initialized, skipping rebuild\n"); ++ return; ++ } ++ + if (ptp->state == ICE_PTP_READY) { + ice_ptp_prepare_for_reset(pf, reset_type); + } else if (ptp->state != ICE_PTP_RESETTING) { +diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c +index 843e82fd3bf936..6a0b724e46f9ac 100644 +--- a/drivers/net/ethernet/intel/ice/ice_sriov.c ++++ b/drivers/net/ethernet/intel/ice/ice_sriov.c +@@ -484,12 +484,14 @@ static int ice_start_vfs(struct ice_pf *pf) + goto teardown; + } + +- retval = ice_eswitch_attach_vf(pf, vf); +- if (retval) { +- dev_err(ice_pf_to_dev(pf), "Failed to attach VF %d to eswitch, error %d", +- vf->vf_id, retval); +- ice_vf_vsi_release(vf); +- goto teardown; ++ if (ice_is_eswitch_mode_switchdev(pf)) { ++ retval = ice_eswitch_attach_vf(pf, vf); ++ if (retval) { ++ dev_err(ice_pf_to_dev(pf), "Failed to attach VF %d to eswitch, error %d", ++ vf->vf_id, retval); ++ ice_vf_vsi_release(vf); ++ goto teardown; ++ } + } + + set_bit(ICE_VF_STATE_INIT, vf->vf_states); +diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c +index 4f86412a9c0c3a..bab968b05540b1 100644 +--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c ++++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c +@@ -812,7 +812,8 @@ void ice_reset_all_vfs(struct ice_pf *pf) + } + ice_vf_post_vsi_rebuild(vf); + +- ice_eswitch_attach_vf(pf, vf); ++ if (ice_is_eswitch_mode_switchdev(pf)) ++ ice_eswitch_attach_vf(pf, vf); + + mutex_unlock(&vf->cfg_lock); + } +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +index ad733f4da3c185..019bd49015c603 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +@@ -435,7 +435,7 @@ struct rvu_pfvf *rvu_get_pfvf(struct rvu *rvu, int pcifunc) + return &rvu->pf[rvu_get_pf(rvu->pdev, pcifunc)]; + } + +-static bool is_pf_func_valid(struct rvu *rvu, u16 pcifunc) ++bool is_pf_func_valid(struct rvu *rvu, u16 pcifunc) + { + int pf, vf, nvfs; + u64 cfg; +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +index 914ba2b691ec80..c9ed5276690d36 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +@@ -900,6 +900,7 @@ u16 rvu_get_rsrc_mapcount(struct rvu_pfvf *pfvf, int blkaddr); + struct rvu_pfvf *rvu_get_pfvf(struct rvu *rvu, int pcifunc); + void rvu_get_pf_numvfs(struct rvu *rvu, int pf, int *numvfs, int *hwvf); + bool is_block_implemented(struct rvu_hwinfo *hw, int blkaddr); ++bool is_pf_func_valid(struct rvu *rvu, u16 pcifunc); + bool is_pffunc_map_valid(struct rvu *rvu, u16 pcifunc, int blktype); + int rvu_get_lf(struct rvu *rvu, struct rvu_block *block, u16 pcifunc, u16 slot); + int rvu_lf_reset(struct rvu *rvu, struct rvu_block *block, int lf); +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c +index d2163da28d18f0..fa4ea1258d29d5 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c +@@ -178,6 +178,15 @@ int rvu_mbox_handler_lmtst_tbl_setup(struct rvu *rvu, + * pcifunc (will be the one who is calling this mailbox). + */ + if (req->base_pcifunc) { ++ /* A VF is untrusted and must not redirect its LMTLINE to ++ * another PF's region, so confine VF callers to their own PF. ++ */ ++ if (is_vf(req->hdr.pcifunc) && ++ (!is_pf_func_valid(rvu, req->base_pcifunc) || ++ rvu_get_pf(rvu->pdev, req->hdr.pcifunc) != ++ rvu_get_pf(rvu->pdev, req->base_pcifunc))) ++ return -EPERM; ++ + /* Calculating the LMT table index equivalent to primary + * pcifunc. + */ +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c +index 4415d0ce9aef4e..d43c034b0264a6 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c +@@ -97,6 +97,14 @@ int rvu_mbox_handler_rep_event_notify(struct rvu *rvu, struct rep_event *req, + { + struct rep_evtq_ent *qentry; + ++ /* The mailbox dispatcher normalises only the header pcifunc; the ++ * nested struct rep_event::pcifunc body field is sender-controlled ++ * and is later used by rvu_rep_up_notify() to index rvu->pf[] / ++ * rvu->hwvf[]. Reject out-of-range body selectors before queueing. ++ */ ++ if (!is_pf_func_valid(rvu, req->pcifunc)) ++ return -EINVAL; ++ + qentry = kmalloc(sizeof(*qentry), GFP_ATOMIC); + if (!qentry) + return -ENOMEM; +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c +index 64c6d9162ef644..17e8f6e51808b5 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c +@@ -146,6 +146,7 @@ exit: + if (allocated) { + pfvf->flags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC; + pfvf->flags |= OTX2_FLAG_NTUPLE_SUPPORT; ++ pfvf->flags |= OTX2_FLAG_TC_FLOWER_SUPPORT; + } + + if (allocated != count) +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c +index 26a08d2cfbb1b6..f4906c67d5eee4 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c +@@ -30,6 +30,7 @@ + #define OTX2_UNSUPP_LSE_DEPTH GENMASK(6, 4) + + #define MCAST_INVALID_GRP (-1U) ++#define RATE_MANTISSA_BITS 8 + + struct otx2_tc_flow_stats { + u64 bytes; +@@ -90,28 +91,30 @@ static void otx2_get_egress_burst_cfg(struct otx2_nic *nic, u32 burst, + static void otx2_get_egress_rate_cfg(u64 maxrate, u32 *exp, + u32 *mantissa, u32 *div_exp) + { +- u64 tmp; +- + /* Rate calculation by hardware + * + * PIR_ADD = ((256 + mantissa) << exp) / 256 + * rate = (2 * PIR_ADD) / ( 1 << div_exp) + * The resultant rate is in Mbps. ++ * ++ * Use div_exp = 0 and compute exp/mantissa for maxrate / 2; the ++ * leading factor of two yields the full rate. Rates below 2 Mbps ++ * are floored to the smallest step (exp = 0, mantissa = 0). + */ + +- /* 2Mbps to 100Gbps can be expressed with div_exp = 0. +- * Setting this to '0' will ease the calculation of +- * exponent and mantissa. +- */ + *div_exp = 0; +- + if (maxrate) { +- *exp = ilog2(maxrate) ? ilog2(maxrate) - 1 : 0; +- tmp = maxrate - rounddown_pow_of_two(maxrate); +- if (maxrate < MAX_RATE_MANTISSA) +- *mantissa = tmp * 2; +- else +- *mantissa = tmp / (1ULL << (*exp - 7)); ++ maxrate = maxrate / 2; ++ if (!maxrate) { ++ /* Rates below 2 Mbps map to the smallest step */ ++ *exp = 0; ++ *mantissa = 0; ++ } else { ++ *exp = ilog2(maxrate); ++ /* Clear MSB and derive fractional bits */ ++ maxrate &= ~BIT(*exp); ++ *mantissa = (maxrate << RATE_MANTISSA_BITS) >> *exp; ++ } + } else { + /* Instead of disabling rate limiting, set all values to max */ + *exp = MAX_RATE_EXPONENT; +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c +index cf8f14ce4cd50d..20db77552545e8 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c +@@ -158,6 +158,13 @@ static int mlx5e_dcbnl_ieee_getets(struct net_device *netdev, + } + memcpy(ets->tc_tsa, priv->dcbx.tc_tsa, sizeof(ets->tc_tsa)); + ++ /* Report 0 for non ETS TSA */ ++ for (i = 0; i < ets->ets_cap; i++) { ++ if (ets->tc_tx_bw[i] == MLX5E_MAX_BW_ALLOC && ++ priv->dcbx.tc_tsa[i] != IEEE_8021QAZ_TSA_ETS) ++ ets->tc_tx_bw[i] = 0; ++ } ++ + return err; + } + +@@ -302,6 +309,14 @@ static int mlx5e_dbcnl_validate_ets(struct net_device *netdev, + } + } + ++ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { ++ if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_CB_SHAPER) { ++ netdev_err(netdev, ++ "Failed to validate ETS: CB Shaper is not supported\n"); ++ return -EOPNOTSUPP; ++ } ++ } ++ + /* Validate Bandwidth Sum */ + for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { + if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) { +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +index 893e1380a7c973..8a07b9e8dc3861 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +@@ -2027,7 +2027,7 @@ static int mlx5e_get_module_info(struct net_device *netdev, + int size_read = 0; + u8 data[4] = {0}; + +- size_read = mlx5_query_module_eeprom(dev, 0, 2, data); ++ size_read = mlx5_query_module_eeprom(dev, 0, 2, data, NULL); + if (size_read < 2) + return -EIO; + +@@ -2069,6 +2069,7 @@ static int mlx5e_get_module_eeprom(struct net_device *netdev, + struct mlx5_core_dev *mdev = priv->mdev; + int offset = ee->offset; + int size_read; ++ u8 status = 0; + int i = 0; + + if (!ee->len) +@@ -2078,15 +2079,15 @@ static int mlx5e_get_module_eeprom(struct net_device *netdev, + + while (i < ee->len) { + size_read = mlx5_query_module_eeprom(mdev, offset, ee->len - i, +- data + i); +- ++ data + i, &status); + if (!size_read) + /* Done reading */ + return 0; + + if (size_read < 0) { +- netdev_err(priv->netdev, "%s: mlx5_query_eeprom failed:0x%x\n", +- __func__, size_read); ++ netdev_err(netdev, ++ "%s: mlx5_query_eeprom failed:0x%x, status %u\n", ++ __func__, size_read, status); + return size_read; + } + +@@ -2106,6 +2107,7 @@ static int mlx5e_get_module_eeprom_by_page(struct net_device *netdev, + struct mlx5_core_dev *mdev = priv->mdev; + u8 *data = page_data->data; + int size_read; ++ u8 status = 0; + int i = 0; + + if (!page_data->length) +@@ -2119,7 +2121,8 @@ static int mlx5e_get_module_eeprom_by_page(struct net_device *netdev, + query.page = page_data->page; + while (i < page_data->length) { + query.size = page_data->length - i; +- size_read = mlx5_query_module_eeprom_by_page(mdev, &query, data + i); ++ size_read = mlx5_query_module_eeprom_by_page(mdev, &query, ++ data + i, &status); + + /* Done reading, return how many bytes was read */ + if (!size_read) +@@ -2128,8 +2131,8 @@ static int mlx5e_get_module_eeprom_by_page(struct net_device *netdev, + if (size_read < 0) { + NL_SET_ERR_MSG_FMT_MOD( + extack, +- "Query module eeprom by page failed, read %u bytes, err %d", +- i, size_read); ++ "Query module eeprom by page failed, read %u bytes, err %d, status %u", ++ i, size_read, status); + return size_read; + } + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +index f660ef37b0a631..7e754b72f889fa 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +@@ -211,11 +211,11 @@ static void mlx5e_disable_async_events(struct mlx5e_priv *priv) + + static int mlx5e_devcom_event_mpv(int event, void *my_data, void *event_data) + { +- struct mlx5e_priv *slave_priv = my_data; ++ struct mlx5e_priv *master_priv = event_data; + + switch (event) { + case MPV_DEVCOM_MASTER_UP: +- mlx5_devcom_comp_set_ready(slave_priv->devcom, true); ++ mlx5_devcom_comp_set_ready(master_priv->devcom, true); + break; + case MPV_DEVCOM_MASTER_DOWN: + /* no need for comp set ready false since we unregister after +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/helper.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/helper.c +index 3ce455c2535c40..53f064ebd1c181 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/helper.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/helper.c +@@ -71,7 +71,7 @@ int esw_egress_acl_vlan_create(struct mlx5_eswitch *esw, + flow_act.action = flow_action; + vport->egress.allowed_vlan = + mlx5_add_flow_rules(vport->egress.acl, spec, +- &flow_act, fwd_dest, 0); ++ &flow_act, fwd_dest, fwd_dest ? 1 : 0); + if (IS_ERR(vport->egress.allowed_vlan)) { + err = PTR_ERR(vport->egress.allowed_vlan); + esw_warn(esw->dev, +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +index 09c544bdf70da9..e08903d002a10b 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +@@ -358,11 +358,11 @@ int mlx5_set_port_fcs(struct mlx5_core_dev *mdev, u8 enable); + void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported, + bool *enabled); + int mlx5_query_module_eeprom(struct mlx5_core_dev *dev, +- u16 offset, u16 size, u8 *data); ++ u16 offset, u16 size, u8 *data, u8 *status); + int + mlx5_query_module_eeprom_by_page(struct mlx5_core_dev *dev, + struct mlx5_module_eeprom_query_params *params, +- u8 *data); ++ u8 *data, u8 *status); + + int mlx5_query_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *out); + int mlx5_set_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *in); +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c +index 876e648c91ba8b..23796fb353e4df 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/port.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c +@@ -289,11 +289,11 @@ int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num) + } + + static int mlx5_query_module_id(struct mlx5_core_dev *dev, int module_num, +- u8 *module_id) ++ u8 *module_id, u8 *status) + { + u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {}; + u32 out[MLX5_ST_SZ_DW(mcia_reg)]; +- int err, status; ++ int err; + u8 *ptr; + + MLX5_SET(mcia_reg, in, i2c_device_address, MLX5_I2C_ADDR_LOW); +@@ -308,13 +308,13 @@ static int mlx5_query_module_id(struct mlx5_core_dev *dev, int module_num, + if (err) + return err; + +- status = MLX5_GET(mcia_reg, out, status); +- if (status) { +- mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n", +- status); ++ if (MLX5_GET(mcia_reg, out, status)) { ++ if (status) ++ *status = MLX5_GET(mcia_reg, out, status); + return -EIO; + } +- ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0); ++ ++ ptr = MLX5_ADDR_OF(mcia_reg, out, dwords); + + *module_id = ptr[0]; + +@@ -370,13 +370,14 @@ static int mlx5_mcia_max_bytes(struct mlx5_core_dev *dev) + } + + static int mlx5_query_mcia(struct mlx5_core_dev *dev, +- struct mlx5_module_eeprom_query_params *params, u8 *data) ++ struct mlx5_module_eeprom_query_params *params, ++ u8 *data, u8 *status) + { + u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {}; + u32 out[MLX5_ST_SZ_DW(mcia_reg)]; +- int status, err; + void *ptr; + u16 size; ++ int err; + + size = min_t(int, params->size, mlx5_mcia_max_bytes(dev)); + +@@ -392,21 +393,20 @@ static int mlx5_query_mcia(struct mlx5_core_dev *dev, + if (err) + return err; + +- status = MLX5_GET(mcia_reg, out, status); +- if (status) { +- mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n", +- status); ++ if (MLX5_GET(mcia_reg, out, status)) { ++ if (status) ++ *status = MLX5_GET(mcia_reg, out, status); + return -EIO; + } + +- ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0); ++ ptr = MLX5_ADDR_OF(mcia_reg, out, dwords); + memcpy(data, ptr, size); + + return size; + } + + int mlx5_query_module_eeprom(struct mlx5_core_dev *dev, +- u16 offset, u16 size, u8 *data) ++ u16 offset, u16 size, u8 *data, u8 *status) + { + struct mlx5_module_eeprom_query_params query = {0}; + u8 module_id; +@@ -416,7 +416,8 @@ int mlx5_query_module_eeprom(struct mlx5_core_dev *dev, + if (err) + return err; + +- err = mlx5_query_module_id(dev, query.module_number, &module_id); ++ err = mlx5_query_module_id(dev, query.module_number, &module_id, ++ status); + if (err) + return err; + +@@ -442,12 +443,12 @@ int mlx5_query_module_eeprom(struct mlx5_core_dev *dev, + query.size = size; + query.offset = offset; + +- return mlx5_query_mcia(dev, &query, data); ++ return mlx5_query_mcia(dev, &query, data, status); + } + + int mlx5_query_module_eeprom_by_page(struct mlx5_core_dev *dev, + struct mlx5_module_eeprom_query_params *params, +- u8 *data) ++ u8 *data, u8 *status) + { + int err; + +@@ -461,7 +462,7 @@ int mlx5_query_module_eeprom_by_page(struct mlx5_core_dev *dev, + return -EINVAL; + } + +- return mlx5_query_mcia(dev, params, data); ++ return mlx5_query_mcia(dev, params, data, status); + } + + static int mlx5_query_port_pvlc(struct mlx5_core_dev *dev, u32 *pvlc, +diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c +index 243f8d11be6848..81cbc47de0c62d 100644 +--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c ++++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c +@@ -125,6 +125,8 @@ static int mana_gd_query_max_resources(struct pci_dev *pdev) + } else { + /* If dynamic allocation is enabled we have already allocated + * hwc msi ++ * Also, we make sure in this case the following is always true ++ * (num_msix_usable - 1 HWC) <= num_online_cpus() + */ + gc->num_msix_usable = min(resp.max_msix, num_online_cpus() + 1); + } +@@ -1587,8 +1589,8 @@ void mana_gd_free_res_map(struct gdma_resource *r) + * do the same thing. + */ + +-static int irq_setup(unsigned int *irqs, unsigned int len, int node, +- bool skip_first_cpu) ++static int mana_irq_setup_numa_aware(unsigned int *irqs, unsigned int len, ++ int node, bool skip_first_cpu) + { + const struct cpumask *next, *prev = cpu_none_mask; + cpumask_var_t cpus __free(free_cpumask_var); +@@ -1624,11 +1626,24 @@ done: + return 0; + } + ++/* must be called with cpus_read_lock() held */ ++static void mana_irq_setup_linear(unsigned int *irqs, unsigned int len) ++{ ++ int cpu; ++ ++ for_each_online_cpu(cpu) { ++ if (len == 0) ++ break; ++ ++ irq_set_affinity_and_hint(*irqs++, cpumask_of(cpu)); ++ len--; ++ } ++} ++ + static int mana_gd_setup_dyn_irqs(struct pci_dev *pdev, int nvec) + { + struct gdma_context *gc = pci_get_drvdata(pdev); + struct gdma_irq_context *gic; +- bool skip_first_cpu = false; + int *irqs, irq, err, i; + + irqs = kmalloc_array(nvec, sizeof(int), GFP_KERNEL); +@@ -1636,10 +1651,12 @@ static int mana_gd_setup_dyn_irqs(struct pci_dev *pdev, int nvec) + return -ENOMEM; + + /* ++ * In this function, num_msix_usable = HWC IRQ + Queue IRQ. ++ * nvec is only Queue IRQ (HWC already setup). + * While processing the next pci irq vector, we start with index 1, + * as IRQ vector at index 0 is already processed for HWC. + * However, the population of irqs array starts with index 0, to be +- * further used in irq_setup() ++ * further used in mana_irq_setup_numa_aware() + */ + for (i = 1; i <= nvec; i++) { + gic = kzalloc(sizeof(*gic), GFP_KERNEL); +@@ -1669,18 +1686,51 @@ static int mana_gd_setup_dyn_irqs(struct pci_dev *pdev, int nvec) + } + + /* +- * When calling irq_setup() for dynamically added IRQs, if number of +- * CPUs is more than or equal to allocated MSI-X, we need to skip the +- * first CPU sibling group since they are already affinitized to HWC IRQ ++ * When calling mana_irq_setup_numa_aware() for dynamically added IRQs, ++ * if number of CPUs is more than or equal to allocated MSI-X, we need to ++ * skip the first CPU sibling group since they are already affinitized to ++ * HWC IRQ + */ + cpus_read_lock(); +- if (gc->num_msix_usable <= num_online_cpus()) +- skip_first_cpu = true; ++ if (gc->num_msix_usable <= num_online_cpus()) { ++ err = mana_irq_setup_numa_aware(irqs, nvec, gc->numa_node, ++ true); ++ if (err) { ++ cpus_read_unlock(); ++ goto free_irq; ++ } ++ } else { ++ /* ++ * When num_msix_usable are more than num_online_cpus, our ++ * queue IRQs should be equal to num of online vCPUs. ++ * We try to make sure queue IRQs spread across all vCPUs. ++ * In such a case NUMA or CPU core affinity does not matter. ++ * Note: in this case the total mana IRQ should always be ++ * num_online_cpus + 1. The first HWC IRQ is already handled ++ * in HWC setup calls ++ * However, if CPUs went offline since num_msix_usable was ++ * computed, queue IRQs will be more than num_online_cpus(). ++ * In such cases remaining extra IRQs will retain their default ++ * affinity. ++ */ ++ int first_unassigned = num_online_cpus(); + +- err = irq_setup(irqs, nvec, gc->numa_node, skip_first_cpu); +- if (err) { +- cpus_read_unlock(); +- goto free_irq; ++ if (nvec > first_unassigned) { ++ char buf[32]; ++ ++ if (first_unassigned == nvec - 1) ++ snprintf(buf, sizeof(buf), "%d", ++ first_unassigned); ++ else ++ snprintf(buf, sizeof(buf), "%d-%d", ++ first_unassigned, nvec - 1); ++ ++ dev_dbg(&pdev->dev, ++ "MANA IRQ indices #%s will retain the default CPU affinity\n", ++ buf); ++ } ++ ++ mana_irq_setup_linear(irqs, nvec); + } + + cpus_read_unlock(); +@@ -1766,7 +1816,7 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev, int nvec) + nvec -= 1; + } + +- err = irq_setup(irqs, nvec, gc->numa_node, false); ++ err = mana_irq_setup_numa_aware(irqs, nvec, gc->numa_node, false); + if (err) { + cpus_read_unlock(); + goto free_irq; +diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c +index 62418f164dbac1..adf25acb0d46f1 100644 +--- a/drivers/net/ethernet/microsoft/mana/mana_en.c ++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c +@@ -2160,6 +2160,19 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq, + rxbuf_oob = &rxq->rx_oobs[curr]; + WARN_ON_ONCE(rxbuf_oob->wqe_inf.wqe_size_in_bu != 1); + ++ if (unlikely(pktlen > rxq->datasize)) { ++ /* Increase it even if mana_rx_skb() isn't called. */ ++ rxq->rx_cq.work_done++; ++ ++ ++ndev->stats.rx_dropped; ++ netdev_warn_once(ndev, ++ "Dropped oversized RX packet: len=%u, datasize=%u\n", ++ pktlen, rxq->datasize); ++ ++ /* Reuse the RX buffer since rxbuf_oob is unchanged. */ ++ goto drop; ++ } ++ + mana_refill_rx_oob(dev, rxq, rxbuf_oob, &old_buf, &old_fp); + + /* Unsuccessful refill will have old_buf == NULL. +diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c +index 279ea0b5695577..55525f45e447b7 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c ++++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c +@@ -96,6 +96,9 @@ static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res) + res->mutex = + nfp_cpp_mutex_alloc(cpp, + NFP_RESOURCE_TBL_TARGET, addr, key); ++ if (!res->mutex) ++ return -ENOMEM; ++ + res->cpp_id = NFP_CPP_ID(entry.region.cpp_target, + entry.region.cpp_action, + entry.region.cpp_token); +diff --git a/drivers/net/ethernet/realtek/rtase/rtase.h b/drivers/net/ethernet/realtek/rtase/rtase.h +index b9209eb6ea7350..43087b17a0ff27 100644 +--- a/drivers/net/ethernet/realtek/rtase/rtase.h ++++ b/drivers/net/ethernet/realtek/rtase/rtase.h +@@ -188,6 +188,12 @@ enum rtase_sw_flag_content { + RTASE_SWF_MSIX_ENABLED = BIT(2), + }; + ++enum rtase_parse_result { ++ RTASE_PARSE_OK, ++ RTASE_PARSE_SKIP, ++ RTASE_PARSE_DROP, ++}; ++ + #define RSVD_MASK 0x3FFFC000 + + struct rtase_tx_desc { +@@ -359,4 +365,6 @@ struct rtase_private { + + #define RTASE_MSS_MASK GENMASK(28, 18) + ++#define RTASE_MIN_PAD_LEN 47 ++ + #endif /* RTASE_H */ +diff --git a/drivers/net/ethernet/realtek/rtase/rtase_main.c b/drivers/net/ethernet/realtek/rtase/rtase_main.c +index 55105d34bc7977..a57a525327a3be 100644 +--- a/drivers/net/ethernet/realtek/rtase/rtase_main.c ++++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c +@@ -61,6 +61,7 @@ + #include <linux/pci.h> + #include <linux/pm_runtime.h> + #include <linux/prefetch.h> ++#include <linux/ptp_classify.h> + #include <linux/rtnetlink.h> + #include <linux/tcp.h> + #include <asm/irq.h> +@@ -1249,6 +1250,199 @@ static u32 rtase_tx_csum(struct sk_buff *skb, const struct net_device *dev) + return csum_cmd; + } + ++static enum rtase_parse_result rtase_get_l3_proto(struct sk_buff *skb, ++ __be16 *proto, ++ u32 *network_offset) ++{ ++ struct vlan_hdr *vh, _vh; ++ struct ethhdr *eh, _eh; ++ u32 offset = ETH_HLEN; ++ ++ eh = skb_header_pointer(skb, 0, sizeof(_eh), &_eh); ++ if (!eh) ++ return RTASE_PARSE_DROP; ++ ++ *proto = eh->h_proto; ++ ++ while (eth_type_vlan(*proto)) { ++ vh = skb_header_pointer(skb, offset, sizeof(_vh), &_vh); ++ if (!vh) ++ return RTASE_PARSE_DROP; ++ ++ *proto = vh->h_vlan_encapsulated_proto; ++ offset += VLAN_HLEN; ++ } ++ ++ *network_offset = offset; ++ ++ return RTASE_PARSE_OK; ++} ++ ++static bool rtase_pad_to_transport_len(struct sk_buff *skb, ++ u32 transport_offset, ++ u32 pad_to_len) ++{ ++ u32 trans_data_len; ++ u32 pad_len; ++ ++ trans_data_len = skb->len - transport_offset; ++ if (trans_data_len >= pad_to_len) ++ return true; ++ ++ if (skb_is_nonlinear(skb)) { ++ if (skb_linearize(skb)) ++ return false; ++ } ++ ++ pad_len = pad_to_len - trans_data_len; ++ if (__skb_put_padto(skb, skb->len + pad_len, false)) ++ return false; ++ ++ return true; ++} ++ ++static enum rtase_parse_result rtase_get_transport_offset(struct sk_buff *skb, ++ u32 *transport_offset, ++ u8 *transport_proto, ++ u32 *pad_to_len) ++{ ++ enum rtase_parse_result ret; ++ struct ipv6hdr *i6h, _i6h; ++ struct iphdr *ih, _ih; ++ bool non_first_frag; ++ __be16 proto; ++ u32 offset; ++ u32 no; ++ ++ ret = rtase_get_l3_proto(skb, &proto, &no); ++ if (ret != RTASE_PARSE_OK) ++ return ret; ++ ++ switch (proto) { ++ case htons(ETH_P_IP): ++ ih = skb_header_pointer(skb, no, sizeof(_ih), &_ih); ++ if (!ih) ++ return RTASE_PARSE_DROP; ++ ++ if (ih->ihl < 5) ++ return RTASE_PARSE_DROP; ++ ++ offset = no + ih->ihl * 4; ++ if (offset > skb->len) ++ return RTASE_PARSE_DROP; ++ ++ non_first_frag = ntohs(ih->frag_off) & IP_OFFSET; ++ ++ if (ih->protocol == IPPROTO_TCP) { ++ if (skb->len - offset < sizeof(struct tcphdr)) { ++ if (non_first_frag) { ++ *transport_offset = offset; ++ *transport_proto = IPPROTO_TCP; ++ *pad_to_len = sizeof(struct tcphdr); ++ ++ return RTASE_PARSE_OK; ++ } ++ ++ return RTASE_PARSE_DROP; ++ } ++ ++ return RTASE_PARSE_SKIP; ++ } ++ ++ if (ih->protocol != IPPROTO_UDP) ++ return RTASE_PARSE_SKIP; ++ ++ *transport_offset = offset; ++ *transport_proto = IPPROTO_UDP; ++ ++ if (skb->len - offset < sizeof(struct udphdr)) { ++ if (non_first_frag) { ++ *pad_to_len = sizeof(struct udphdr); ++ ++ return RTASE_PARSE_OK; ++ } ++ ++ return RTASE_PARSE_DROP; ++ } ++ ++ return RTASE_PARSE_OK; ++ ++ case htons(ETH_P_IPV6): ++ i6h = skb_header_pointer(skb, no, sizeof(_i6h), &_i6h); ++ if (!i6h) ++ return RTASE_PARSE_DROP; ++ ++ offset = no + sizeof(*i6h); ++ ++ if (i6h->nexthdr == IPPROTO_TCP) { ++ if (skb->len - offset < sizeof(struct tcphdr)) ++ return RTASE_PARSE_DROP; ++ ++ return RTASE_PARSE_SKIP; ++ } ++ ++ if (i6h->nexthdr != IPPROTO_UDP) ++ return RTASE_PARSE_SKIP; ++ ++ if (skb->len - offset < sizeof(struct udphdr)) ++ return RTASE_PARSE_DROP; ++ ++ *transport_offset = offset; ++ *transport_proto = IPPROTO_UDP; ++ ++ return RTASE_PARSE_OK; ++ ++ default: ++ return RTASE_PARSE_SKIP; ++ } ++} ++ ++static bool rtase_skb_pad(struct sk_buff *skb) ++{ ++ enum rtase_parse_result ret; ++ u32 transport_offset; ++ __be16 *dest, _dest; ++ u32 trans_data_len; ++ u32 pad_to_len = 0; ++ u8 transport_proto; ++ u16 dest_port; ++ ++ ret = rtase_get_transport_offset(skb, &transport_offset, ++ &transport_proto, &pad_to_len); ++ if (ret == RTASE_PARSE_SKIP) { ++ return true; ++ } else if (ret == RTASE_PARSE_DROP) { ++ netdev_dbg(skb->dev, "drop malformed packet\n"); ++ return false; ++ } ++ ++ if (pad_to_len && ++ !rtase_pad_to_transport_len(skb, transport_offset, pad_to_len)) ++ return false; ++ ++ if (transport_proto != IPPROTO_UDP) ++ return true; ++ ++ trans_data_len = skb->len - transport_offset; ++ if (trans_data_len < offsetof(struct udphdr, len) || ++ trans_data_len >= RTASE_MIN_PAD_LEN) ++ return true; ++ ++ dest = skb_header_pointer(skb, ++ transport_offset + ++ offsetof(struct udphdr, dest), ++ sizeof(_dest), &_dest); ++ if (!dest) ++ return true; ++ ++ dest_port = ntohs(*dest); ++ if (dest_port != PTP_EV_PORT && dest_port != PTP_GEN_PORT) ++ return true; ++ ++ return rtase_pad_to_transport_len(skb, transport_offset, ++ RTASE_MIN_PAD_LEN); ++} ++ + static int rtase_xmit_frags(struct rtase_ring *ring, struct sk_buff *skb, + u32 opts1, u32 opts2) + { +@@ -1362,6 +1556,9 @@ static netdev_tx_t rtase_start_xmit(struct sk_buff *skb, + opts2 |= rtase_tx_csum(skb, dev); + } + ++ if (!rtase_skb_pad(skb)) ++ goto err_dma_0; ++ + frags = rtase_xmit_frags(ring, skb, opts1, opts2); + if (unlikely(frags < 0)) + goto err_dma_0; +diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h +index acd7719506b612..83929477b058b6 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/common.h ++++ b/drivers/net/ethernet/stmicro/stmmac/common.h +@@ -197,9 +197,6 @@ struct stmmac_extra_stats { + unsigned long irq_pcs_ane_n; + unsigned long irq_pcs_link_n; + unsigned long irq_rgmii_n; +- unsigned long pcs_link; +- unsigned long pcs_duplex; +- unsigned long pcs_speed; + /* debug register */ + unsigned long mtl_tx_status_fifo_full; + unsigned long mtl_tx_fifo_not_empty; +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c +index 47fda982d6b151..a54bd924032c12 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c +@@ -524,6 +524,32 @@ static int intel_set_reg_access(const struct pmc_serdes_regs *regs, int max_regs + return ret; + } + ++/* ++ * Return true if the SerDes lane rate must change to serve @interface. ++ * If the current rate cannot be determined, reconfigure as before. ++ */ ++static bool intel_serdes_needs_reconfig(struct stmmac_priv *priv, ++ struct intel_priv_data *intel_priv, ++ phy_interface_t interface) ++{ ++ u32 cur_rate, want_rate; ++ int data; ++ ++ if (!intel_priv->mdio_adhoc_addr) ++ return true; ++ ++ data = mdiobus_read(priv->mii, intel_priv->mdio_adhoc_addr, ++ SERDES_GCR0); ++ if (data < 0) ++ return true; ++ ++ cur_rate = (data & SERDES_RATE_MASK) >> SERDES_RATE_PCIE_SHIFT; ++ want_rate = interface == PHY_INTERFACE_MODE_2500BASEX ? ++ SERDES_RATE_PCIE_GEN2 : SERDES_RATE_PCIE_GEN1; ++ ++ return cur_rate != want_rate; ++} ++ + static int intel_mac_finish(struct net_device *ndev, + void *intel_data, + unsigned int mode, +@@ -535,6 +561,11 @@ static int intel_mac_finish(struct net_device *ndev, + int max_regs = 0; + int ret = 0; + ++ if (!intel_serdes_needs_reconfig(priv, intel_priv, interface)) { ++ priv->plat->phy_interface = interface; ++ return 0; ++ } ++ + ret = intel_tsn_lane_is_available(ndev, intel_priv); + if (ret < 0) { + netdev_info(priv->dev, "No TSN lane available to set the registers.\n"); +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c +index ab431bf9b25f29..e6bce3a433a789 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c +@@ -209,9 +209,8 @@ static void loongson_dwmac_dma_init_channel(struct stmmac_priv *priv, + value |= DMA_BUS_MODE_MAXPBL; + + value |= DMA_BUS_MODE_USP; +- value &= ~(DMA_BUS_MODE_PBL_MASK | DMA_BUS_MODE_RPBL_MASK); +- value |= (txpbl << DMA_BUS_MODE_PBL_SHIFT); +- value |= (rxpbl << DMA_BUS_MODE_RPBL_SHIFT); ++ value = u32_replace_bits(value, txpbl, DMA_BUS_MODE_PBL_MASK); ++ value = u32_replace_bits(value, rxpbl, DMA_BUS_MODE_RPBL_MASK); + + /* Set the Fixed burst mode */ + if (dma_cfg->fixed_burst) +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +index 2ff5db6d41ca08..e40d0d69630375 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +@@ -5,6 +5,7 @@ + */ + + #include <linux/mfd/altera-sysmgr.h> ++#include <linux/clocksource_ids.h> + #include <linux/of.h> + #include <linux/of_address.h> + #include <linux/of_net.h> +@@ -15,8 +16,10 @@ + #include <linux/reset.h> + #include <linux/stmmac.h> + ++#include "dwxgmac2.h" + #include "stmmac.h" + #include "stmmac_platform.h" ++#include "stmmac_ptp.h" + + #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 + #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 +@@ -41,9 +44,17 @@ + #define SGMII_ADAPTER_ENABLE 0x0000 + #define SGMII_ADAPTER_DISABLE 0x0001 + ++#define SMTG_MDIO_ADDR 0x15 ++#define SMTG_TSC_WORD0 0xC ++#define SMTG_TSC_WORD1 0xD ++#define SMTG_TSC_WORD2 0xE ++#define SMTG_TSC_WORD3 0xF ++#define SMTG_TSC_SHIFT 16 ++ + struct socfpga_dwmac; + struct socfpga_dwmac_ops { + int (*set_phy_mode)(struct socfpga_dwmac *dwmac_priv); ++ void (*setup_plat_dat)(struct socfpga_dwmac *dwmac_priv); + }; + + struct socfpga_dwmac { +@@ -268,6 +279,111 @@ static int socfpga_set_phy_mode_common(int phymode, u32 *val) + return 0; + } + ++static void get_smtgtime(struct mii_bus *mii, int smtg_addr, u64 *smtg_time) ++{ ++ u64 ns; ++ ++ ns = mdiobus_read(mii, smtg_addr, SMTG_TSC_WORD3); ++ ns <<= SMTG_TSC_SHIFT; ++ ns |= mdiobus_read(mii, smtg_addr, SMTG_TSC_WORD2); ++ ns <<= SMTG_TSC_SHIFT; ++ ns |= mdiobus_read(mii, smtg_addr, SMTG_TSC_WORD1); ++ ns <<= SMTG_TSC_SHIFT; ++ ns |= mdiobus_read(mii, smtg_addr, SMTG_TSC_WORD0); ++ ++ *smtg_time = ns; ++} ++ ++static int smtg_crosststamp(ktime_t *device, struct system_counterval_t *system, ++ void *ctx) ++{ ++ struct stmmac_priv *priv = (struct stmmac_priv *)ctx; ++ u32 num_snapshot, gpio_value, acr_value; ++ void __iomem *ptpaddr = priv->ptpaddr; ++ void __iomem *ioaddr = priv->hw->pcsr; ++ unsigned long flags; ++ u64 smtg_time = 0; ++ u64 ptp_time = 0; ++ int i, ret; ++ u32 v; ++ ++ /* Both internal crosstimestamping and external triggered event ++ * timestamping cannot be run concurrently. ++ */ ++ if (priv->plat->flags & STMMAC_FLAG_EXT_SNAPSHOT_EN) ++ return -EBUSY; ++ ++ mutex_lock(&priv->aux_ts_lock); ++ /* Enable Internal snapshot trigger */ ++ acr_value = readl(ptpaddr + PTP_ACR); ++ acr_value &= ~PTP_ACR_MASK; ++ switch (priv->plat->int_snapshot_num) { ++ case AUX_SNAPSHOT0: ++ acr_value |= PTP_ACR_ATSEN0; ++ break; ++ case AUX_SNAPSHOT1: ++ acr_value |= PTP_ACR_ATSEN1; ++ break; ++ case AUX_SNAPSHOT2: ++ acr_value |= PTP_ACR_ATSEN2; ++ break; ++ case AUX_SNAPSHOT3: ++ acr_value |= PTP_ACR_ATSEN3; ++ break; ++ default: ++ mutex_unlock(&priv->aux_ts_lock); ++ return -EINVAL; ++ } ++ writel(acr_value, ptpaddr + PTP_ACR); ++ ++ /* Clear FIFO */ ++ acr_value = readl(ptpaddr + PTP_ACR); ++ acr_value |= PTP_ACR_ATSFC; ++ writel(acr_value, ptpaddr + PTP_ACR); ++ /* Release the mutex */ ++ mutex_unlock(&priv->aux_ts_lock); ++ ++ /* Trigger Internal snapshot signal. Create a rising edge by just toggle ++ * the GPO0 to low and back to high. ++ */ ++ gpio_value = readl(ioaddr + XGMAC_GPIO_STATUS); ++ gpio_value &= ~XGMAC_GPIO_GPO0; ++ writel(gpio_value, ioaddr + XGMAC_GPIO_STATUS); ++ gpio_value |= XGMAC_GPIO_GPO0; ++ writel(gpio_value, ioaddr + XGMAC_GPIO_STATUS); ++ ++ /* Poll for time sync operation done */ ++ ret = readl_poll_timeout(priv->ioaddr + XGMAC_INT_STATUS, v, ++ (v & XGMAC_INT_TSIS), 100, 10000); ++ if (ret) { ++ netdev_err(priv->dev, "%s: Wait for time sync operation timeout\n", ++ __func__); ++ return ret; ++ } ++ ++ *system = (struct system_counterval_t) { ++ .cycles = 0, ++ .cs_id = CSID_ARM_ARCH_COUNTER, ++ .use_nsecs = false, ++ }; ++ ++ num_snapshot = FIELD_GET(XGMAC_TIMESTAMP_ATSNS_MASK, ++ readl(ioaddr + XGMAC_TIMESTAMP_STATUS)); ++ ++ /* Repeat until the timestamps are from the FIFO last segment */ ++ for (i = 0; i < num_snapshot; i++) { ++ read_lock_irqsave(&priv->ptp_lock, flags); ++ stmmac_get_ptptime(priv, ptpaddr, &ptp_time); ++ *device = ns_to_ktime(ptp_time); ++ read_unlock_irqrestore(&priv->ptp_lock, flags); ++ } ++ ++ get_smtgtime(priv->mii, SMTG_MDIO_ADDR, &smtg_time); ++ system->cycles = smtg_time; ++ ++ return 0; ++} ++ + static int socfpga_gen5_set_phy_mode(struct socfpga_dwmac *dwmac) + { + struct regmap *sys_mgr_base_addr = dwmac->sys_mgr_base_addr; +@@ -441,6 +557,40 @@ static int socfpga_dwmac_init(struct platform_device *pdev, void *bsp_priv) + return dwmac->ops->set_phy_mode(dwmac); + } + ++static void socfpga_gen5_setup_plat_dat(struct socfpga_dwmac *dwmac) ++{ ++ struct plat_stmmacenet_data *plat_dat = dwmac->plat_dat; ++ ++ plat_dat->core_type = DWMAC_CORE_GMAC; ++ ++ /* Rx watchdog timer in dwmac is buggy in this hw */ ++ plat_dat->riwt_off = 1; ++} ++ ++static void socfpga_agilex5_setup_plat_dat(struct socfpga_dwmac *dwmac) ++{ ++ struct plat_stmmacenet_data *plat_dat = dwmac->plat_dat; ++ ++ plat_dat->core_type = DWMAC_CORE_XGMAC; ++ ++ /* Enable TBS */ ++ switch (plat_dat->tx_queues_to_use) { ++ case 8: ++ plat_dat->tx_queues_cfg[7].tbs_en = true; ++ fallthrough; ++ case 7: ++ plat_dat->tx_queues_cfg[6].tbs_en = true; ++ break; ++ default: ++ /* Tx Queues 0 - 5 doesn't support TBS on Agilex5 */ ++ break; ++ } ++ ++ /* Hw supported cross-timestamp */ ++ plat_dat->int_snapshot_num = AUX_SNAPSHOT0; ++ plat_dat->crosststamp = smtg_crosststamp; ++} ++ + static int socfpga_dwmac_probe(struct platform_device *pdev) + { + struct plat_stmmacenet_data *plat_dat; +@@ -497,25 +647,31 @@ static int socfpga_dwmac_probe(struct platform_device *pdev) + plat_dat->pcs_init = socfpga_dwmac_pcs_init; + plat_dat->pcs_exit = socfpga_dwmac_pcs_exit; + plat_dat->select_pcs = socfpga_dwmac_select_pcs; +- plat_dat->core_type = DWMAC_CORE_GMAC; + +- plat_dat->riwt_off = 1; ++ ops->setup_plat_dat(dwmac); + + return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); + } + + static const struct socfpga_dwmac_ops socfpga_gen5_ops = { + .set_phy_mode = socfpga_gen5_set_phy_mode, ++ .setup_plat_dat = socfpga_gen5_setup_plat_dat, + }; + + static const struct socfpga_dwmac_ops socfpga_gen10_ops = { + .set_phy_mode = socfpga_gen10_set_phy_mode, ++ .setup_plat_dat = socfpga_gen5_setup_plat_dat, ++}; ++ ++static const struct socfpga_dwmac_ops socfpga_agilex5_ops = { ++ .set_phy_mode = socfpga_gen10_set_phy_mode, ++ .setup_plat_dat = socfpga_agilex5_setup_plat_dat, + }; + + static const struct of_device_id socfpga_dwmac_match[] = { + { .compatible = "altr,socfpga-stmmac", .data = &socfpga_gen5_ops }, + { .compatible = "altr,socfpga-stmmac-a10-s10", .data = &socfpga_gen10_ops }, +- { .compatible = "altr,socfpga-stmmac-agilex5", .data = &socfpga_gen10_ops }, ++ { .compatible = "altr,socfpga-stmmac-agilex5", .data = &socfpga_agilex5_ops }, + { } + }; + MODULE_DEVICE_TABLE(of, socfpga_dwmac_match); +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100.h b/drivers/net/ethernet/stmicro/stmmac/dwmac100.h +index 7ab791c8d355fb..eae929955ad780 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100.h ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100.h +@@ -59,8 +59,7 @@ + #define MAC_CORE_INIT (MAC_CONTROL_HBD) + + /* MAC FLOW CTRL defines */ +-#define MAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */ +-#define MAC_FLOW_CTRL_PT_SHIFT 16 ++#define MAC_FLOW_CTRL_PT_MASK GENMASK(31, 16) /* Pause Time Mask */ + #define MAC_FLOW_CTRL_PASS 0x00000004 /* Pass Control Frames */ + #define MAC_FLOW_CTRL_ENABLE 0x00000002 /* Flow Control Enable */ + #define MAC_FLOW_CTRL_PAUSE 0x00000001 /* Flow Control Busy ... */ +@@ -76,10 +75,8 @@ + /* DMA Bus Mode register defines */ + #define DMA_BUS_MODE_DBO 0x00100000 /* Descriptor Byte Ordering */ + #define DMA_BUS_MODE_BLE 0x00000080 /* Big Endian/Little Endian */ +-#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */ +-#define DMA_BUS_MODE_PBL_SHIFT 8 +-#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */ +-#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */ ++#define DMA_BUS_MODE_PBL_MASK GENMASK(13, 8) /* Programmable Burst Len */ ++#define DMA_BUS_MODE_DSL_MASK GENMASK(6, 2) /* Descriptor Skip Length */ + #define DMA_BUS_MODE_BAR_BUS 0x00000002 /* Bar-Bus Arbitration */ + #define DMA_BUS_MODE_DEFAULT 0x00000000 + +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h +index 0c011a47d5a3e9..12c82235c1d7e8 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h +@@ -77,7 +77,6 @@ enum power_event { + /* SGMII/RGMII status register */ + #define GMAC_RGSMIIIS_LNKMODE BIT(0) + #define GMAC_RGSMIIIS_SPEED GENMASK(2, 1) +-#define GMAC_RGSMIIIS_SPEED_SHIFT 1 + #define GMAC_RGSMIIIS_LNKSTS BIT(3) + #define GMAC_RGSMIIIS_JABTO BIT(4) + #define GMAC_RGSMIIIS_FALSECARDET BIT(5) +@@ -134,8 +133,7 @@ enum inter_frame_gap { + #define GMAC_MII_ADDR_WRITE 0x00000002 /* MII Write */ + #define GMAC_MII_ADDR_BUSY 0x00000001 /* MII Busy */ + /* GMAC FLOW CTRL defines */ +-#define GMAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */ +-#define GMAC_FLOW_CTRL_PT_SHIFT 16 ++#define GMAC_FLOW_CTRL_PT_MASK GENMASK(31, 16) /* Pause Time Mask */ + #define GMAC_FLOW_CTRL_UP 0x00000008 /* Unicast pause frame enable */ + #define GMAC_FLOW_CTRL_RFE 0x00000004 /* Rx Flow Control Enable */ + #define GMAC_FLOW_CTRL_TFE 0x00000002 /* Tx Flow Control Enable */ +@@ -148,7 +146,6 @@ enum inter_frame_gap { + #define GMAC_DEBUG_TWCSTS BIT(22) /* MTL Tx FIFO Write Controller */ + /* MTL Tx FIFO Read Controller Status */ + #define GMAC_DEBUG_TRCSTS_MASK GENMASK(21, 20) +-#define GMAC_DEBUG_TRCSTS_SHIFT 20 + #define GMAC_DEBUG_TRCSTS_IDLE 0 + #define GMAC_DEBUG_TRCSTS_READ 1 + #define GMAC_DEBUG_TRCSTS_TXW 2 +@@ -156,7 +153,6 @@ enum inter_frame_gap { + #define GMAC_DEBUG_TXPAUSED BIT(19) /* MAC Transmitter in PAUSE */ + /* MAC Transmit Frame Controller Status */ + #define GMAC_DEBUG_TFCSTS_MASK GENMASK(18, 17) +-#define GMAC_DEBUG_TFCSTS_SHIFT 17 + #define GMAC_DEBUG_TFCSTS_IDLE 0 + #define GMAC_DEBUG_TFCSTS_WAIT 1 + #define GMAC_DEBUG_TFCSTS_GEN_PAUSE 2 +@@ -164,13 +160,11 @@ enum inter_frame_gap { + /* MAC GMII or MII Transmit Protocol Engine Status */ + #define GMAC_DEBUG_TPESTS BIT(16) + #define GMAC_DEBUG_RXFSTS_MASK GENMASK(9, 8) /* MTL Rx FIFO Fill-level */ +-#define GMAC_DEBUG_RXFSTS_SHIFT 8 + #define GMAC_DEBUG_RXFSTS_EMPTY 0 + #define GMAC_DEBUG_RXFSTS_BT 1 + #define GMAC_DEBUG_RXFSTS_AT 2 + #define GMAC_DEBUG_RXFSTS_FULL 3 + #define GMAC_DEBUG_RRCSTS_MASK GENMASK(6, 5) /* MTL Rx FIFO Read Controller */ +-#define GMAC_DEBUG_RRCSTS_SHIFT 5 + #define GMAC_DEBUG_RRCSTS_IDLE 0 + #define GMAC_DEBUG_RRCSTS_RDATA 1 + #define GMAC_DEBUG_RRCSTS_RSTAT 2 +@@ -178,7 +172,6 @@ enum inter_frame_gap { + #define GMAC_DEBUG_RWCSTS BIT(4) /* MTL Rx FIFO Write Controller Active */ + /* MAC Receive Frame Controller FIFO Status */ + #define GMAC_DEBUG_RFCFCSTS_MASK GENMASK(2, 1) +-#define GMAC_DEBUG_RFCFCSTS_SHIFT 1 + /* MAC GMII or MII Receive Protocol Engine Status */ + #define GMAC_DEBUG_RPESTS BIT(0) + +@@ -188,8 +181,7 @@ enum inter_frame_gap { + #define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */ + #define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */ + /* Programmable burst length (passed thorugh platform)*/ +-#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */ +-#define DMA_BUS_MODE_PBL_SHIFT 8 ++#define DMA_BUS_MODE_PBL_MASK GENMASK(13, 8) /* Programmable Burst Len */ + #define DMA_BUS_MODE_ATDS 0x00000080 /* Alternate Descriptor Size */ + + enum rx_tx_priority_ratio { +@@ -200,8 +192,7 @@ enum rx_tx_priority_ratio { + + #define DMA_BUS_MODE_FB 0x00010000 /* Fixed burst */ + #define DMA_BUS_MODE_MB 0x04000000 /* Mixed burst */ +-#define DMA_BUS_MODE_RPBL_MASK 0x007e0000 /* Rx-Programmable Burst Len */ +-#define DMA_BUS_MODE_RPBL_SHIFT 17 ++#define DMA_BUS_MODE_RPBL_MASK GENMASK(22, 17) /* Rx-Programmable Burst Len */ + #define DMA_BUS_MODE_USP 0x00800000 + #define DMA_BUS_MODE_MAXPBL 0x01000000 + #define DMA_BUS_MODE_AAL 0x02000000 +@@ -321,7 +312,6 @@ enum rtc_control { + /* PTP and timestamping registers */ + + #define GMAC3_X_ATSNS GENMASK(29, 25) +-#define GMAC3_X_ATSNS_SHIFT 25 + + #define GMAC_PTP_TCR_ATSFC BIT(24) + #define GMAC_PTP_TCR_ATSEN0 BIT(25) +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +index fe776ddf688952..5bf717188c92df 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +@@ -240,7 +240,7 @@ static void dwmac1000_flow_ctrl(struct mac_device_info *hw, unsigned int duplex, + + if (duplex) { + pr_debug("\tduplex mode: PAUSE %d\n", pause_time); +- flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT); ++ flow |= FIELD_PREP(GMAC_FLOW_CTRL_PT_MASK, pause_time); + } + + writel(flow, ioaddr + GMAC_FLOW_CTRL); +@@ -266,34 +266,8 @@ static void dwmac1000_pmt(struct mac_device_info *hw, unsigned long mode) + /* RGMII or SMII interface */ + static void dwmac1000_rgsmii(void __iomem *ioaddr, struct stmmac_extra_stats *x) + { +- u32 status; +- +- status = readl(ioaddr + GMAC_RGSMIIIS); ++ readl(ioaddr + GMAC_RGSMIIIS); + x->irq_rgmii_n++; +- +- /* Check the link status */ +- if (status & GMAC_RGSMIIIS_LNKSTS) { +- int speed_value; +- +- x->pcs_link = 1; +- +- speed_value = ((status & GMAC_RGSMIIIS_SPEED) >> +- GMAC_RGSMIIIS_SPEED_SHIFT); +- if (speed_value == GMAC_RGSMIIIS_SPEED_125) +- x->pcs_speed = SPEED_1000; +- else if (speed_value == GMAC_RGSMIIIS_SPEED_25) +- x->pcs_speed = SPEED_100; +- else +- x->pcs_speed = SPEED_10; +- +- x->pcs_duplex = (status & GMAC_RGSMIIIS_LNKMOD_MASK); +- +- pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed, +- x->pcs_duplex ? "Full" : "Half"); +- } else { +- x->pcs_link = 0; +- pr_info("Link is Down\n"); +- } + } + + static int dwmac1000_irq_status(struct mac_device_info *hw, +@@ -412,8 +386,8 @@ static void dwmac1000_debug(struct stmmac_priv *priv, void __iomem *ioaddr, + if (value & GMAC_DEBUG_TWCSTS) + x->mmtl_fifo_ctrl++; + if (value & GMAC_DEBUG_TRCSTS_MASK) { +- u32 trcsts = (value & GMAC_DEBUG_TRCSTS_MASK) +- >> GMAC_DEBUG_TRCSTS_SHIFT; ++ u32 trcsts = FIELD_GET(GMAC_DEBUG_TRCSTS_MASK, value); ++ + if (trcsts == GMAC_DEBUG_TRCSTS_WRITE) + x->mtl_tx_fifo_read_ctrl_write++; + else if (trcsts == GMAC_DEBUG_TRCSTS_TXW) +@@ -426,8 +400,7 @@ static void dwmac1000_debug(struct stmmac_priv *priv, void __iomem *ioaddr, + if (value & GMAC_DEBUG_TXPAUSED) + x->mac_tx_in_pause++; + if (value & GMAC_DEBUG_TFCSTS_MASK) { +- u32 tfcsts = (value & GMAC_DEBUG_TFCSTS_MASK) +- >> GMAC_DEBUG_TFCSTS_SHIFT; ++ u32 tfcsts = FIELD_GET(GMAC_DEBUG_TFCSTS_MASK, value); + + if (tfcsts == GMAC_DEBUG_TFCSTS_XFER) + x->mac_tx_frame_ctrl_xfer++; +@@ -441,8 +414,7 @@ static void dwmac1000_debug(struct stmmac_priv *priv, void __iomem *ioaddr, + if (value & GMAC_DEBUG_TPESTS) + x->mac_gmii_tx_proto_engine++; + if (value & GMAC_DEBUG_RXFSTS_MASK) { +- u32 rxfsts = (value & GMAC_DEBUG_RXFSTS_MASK) +- >> GMAC_DEBUG_RRCSTS_SHIFT; ++ u32 rxfsts = FIELD_GET(GMAC_DEBUG_RXFSTS_MASK, value); + + if (rxfsts == GMAC_DEBUG_RXFSTS_FULL) + x->mtl_rx_fifo_fill_level_full++; +@@ -454,8 +426,7 @@ static void dwmac1000_debug(struct stmmac_priv *priv, void __iomem *ioaddr, + x->mtl_rx_fifo_fill_level_empty++; + } + if (value & GMAC_DEBUG_RRCSTS_MASK) { +- u32 rrcsts = (value & GMAC_DEBUG_RRCSTS_MASK) >> +- GMAC_DEBUG_RRCSTS_SHIFT; ++ u32 rrcsts = FIELD_GET(GMAC_DEBUG_RRCSTS_MASK, value); + + if (rrcsts == GMAC_DEBUG_RRCSTS_FLUSH) + x->mtl_rx_fifo_read_ctrl_flush++; +@@ -469,8 +440,8 @@ static void dwmac1000_debug(struct stmmac_priv *priv, void __iomem *ioaddr, + if (value & GMAC_DEBUG_RWCSTS) + x->mtl_rx_fifo_ctrl_active++; + if (value & GMAC_DEBUG_RFCFCSTS_MASK) +- x->mac_rx_frame_ctrl_fifo = (value & GMAC_DEBUG_RFCFCSTS_MASK) +- >> GMAC_DEBUG_RFCFCSTS_SHIFT; ++ x->mac_rx_frame_ctrl_fifo = FIELD_GET(GMAC_DEBUG_RFCFCSTS_MASK, ++ value); + if (value & GMAC_DEBUG_RPESTS) + x->mac_gmii_rx_proto_engine++; + } +@@ -566,7 +537,7 @@ void dwmac1000_timestamp_interrupt(struct stmmac_priv *priv) + if (!(priv->plat->flags & STMMAC_FLAG_EXT_SNAPSHOT_EN)) + return; + +- num_snapshot = (ts_status & GMAC3_X_ATSNS) >> GMAC3_X_ATSNS_SHIFT; ++ num_snapshot = FIELD_GET(GMAC3_X_ATSNS, ts_status); + + for (i = 0; i < num_snapshot; i++) { + read_lock_irqsave(&priv->ptp_lock, flags); +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c +index 118a22406a2e93..cacbf6d4365c71 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c +@@ -29,13 +29,10 @@ static void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi) + if (axi->axi_xit_frm) + value |= DMA_AXI_LPI_XIT_FRM; + +- value &= ~DMA_AXI_WR_OSR_LMT; +- value |= (axi->axi_wr_osr_lmt & DMA_AXI_WR_OSR_LMT_MASK) << +- DMA_AXI_WR_OSR_LMT_SHIFT; +- +- value &= ~DMA_AXI_RD_OSR_LMT; +- value |= (axi->axi_rd_osr_lmt & DMA_AXI_RD_OSR_LMT_MASK) << +- DMA_AXI_RD_OSR_LMT_SHIFT; ++ value = u32_replace_bits(value, axi->axi_wr_osr_lmt, ++ DMA_AXI_WR_OSR_LMT); ++ value = u32_replace_bits(value, axi->axi_rd_osr_lmt, ++ DMA_AXI_RD_OSR_LMT); + + /* Depending on the UNDEF bit the Master AXI will perform any burst + * length according to the BLEN programmed (by default all BLEN are +@@ -88,9 +85,8 @@ static void dwmac1000_dma_init_channel(struct stmmac_priv *priv, + if (dma_cfg->pblx8) + value |= DMA_BUS_MODE_MAXPBL; + value |= DMA_BUS_MODE_USP; +- value &= ~(DMA_BUS_MODE_PBL_MASK | DMA_BUS_MODE_RPBL_MASK); +- value |= (txpbl << DMA_BUS_MODE_PBL_SHIFT); +- value |= (rxpbl << DMA_BUS_MODE_RPBL_SHIFT); ++ value = u32_replace_bits(value, txpbl, DMA_BUS_MODE_PBL_MASK); ++ value = u32_replace_bits(value, rxpbl, DMA_BUS_MODE_RPBL_MASK); + + /* Set the Fixed burst mode */ + if (dma_cfg->fixed_burst) +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c +index 14e847c0e1a91d..dbc0c1019ed5e8 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c +@@ -132,7 +132,7 @@ static void dwmac100_flow_ctrl(struct mac_device_info *hw, unsigned int duplex, + unsigned int flow = MAC_FLOW_CTRL_ENABLE; + + if (duplex) +- flow |= (pause_time << MAC_FLOW_CTRL_PT_SHIFT); ++ flow |= FIELD_PREP(MAC_FLOW_CTRL_PT_MASK, pause_time); + writel(flow, ioaddr + MAC_FLOW_CTRL); + } + +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c +index 82957db47c9911..12b2bf2d739ab9 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c +@@ -22,7 +22,8 @@ static void dwmac100_dma_init(void __iomem *ioaddr, + struct stmmac_dma_cfg *dma_cfg) + { + /* Enable Application Access by writing to DMA CSR0 */ +- writel(DMA_BUS_MODE_DEFAULT | (dma_cfg->pbl << DMA_BUS_MODE_PBL_SHIFT), ++ writel(DMA_BUS_MODE_DEFAULT | ++ FIELD_PREP(DMA_BUS_MODE_PBL_MASK, dma_cfg->pbl), + ioaddr + DMA_BUS_MODE); + + /* Mask interrupts by writing to CSR7 */ +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h +index 3dec1a264cf609..7a6609185fd0c9 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h +@@ -95,7 +95,7 @@ + + /* MAC Flow Control TX */ + #define GMAC_TX_FLOW_CTRL_TFE BIT(1) +-#define GMAC_TX_FLOW_CTRL_PT_SHIFT 16 ++#define GMAC_TX_FLOW_CTRL_PT_MASK GENMASK(31, 16) + + /* MAC Interrupt bitmap*/ + #define GMAC_INT_RGSMIIS BIT(0) +@@ -145,23 +145,19 @@ enum power_event { + + /* MAC Debug bitmap */ + #define GMAC_DEBUG_TFCSTS_MASK GENMASK(18, 17) +-#define GMAC_DEBUG_TFCSTS_SHIFT 17 + #define GMAC_DEBUG_TFCSTS_IDLE 0 + #define GMAC_DEBUG_TFCSTS_WAIT 1 + #define GMAC_DEBUG_TFCSTS_GEN_PAUSE 2 + #define GMAC_DEBUG_TFCSTS_XFER 3 + #define GMAC_DEBUG_TPESTS BIT(16) + #define GMAC_DEBUG_RFCFCSTS_MASK GENMASK(2, 1) +-#define GMAC_DEBUG_RFCFCSTS_SHIFT 1 + #define GMAC_DEBUG_RPESTS BIT(0) + + /* MAC config */ + #define GMAC_CONFIG_ARPEN BIT(31) + #define GMAC_CONFIG_SARC GENMASK(30, 28) +-#define GMAC_CONFIG_SARC_SHIFT 28 + #define GMAC_CONFIG_IPC BIT(27) + #define GMAC_CONFIG_IPG GENMASK(26, 24) +-#define GMAC_CONFIG_IPG_SHIFT 24 + #define GMAC_CONFIG_2K BIT(22) + #define GMAC_CONFIG_ACS BIT(20) + #define GMAC_CONFIG_BE BIT(18) +@@ -169,7 +165,6 @@ enum power_event { + #define GMAC_CONFIG_JE BIT(16) + #define GMAC_CONFIG_PS BIT(15) + #define GMAC_CONFIG_FES BIT(14) +-#define GMAC_CONFIG_FES_SHIFT 14 + #define GMAC_CONFIG_DM BIT(13) + #define GMAC_CONFIG_LM BIT(12) + #define GMAC_CONFIG_DCRS BIT(9) +@@ -178,11 +173,9 @@ enum power_event { + + /* MAC extended config */ + #define GMAC_CONFIG_EIPG GENMASK(29, 25) +-#define GMAC_CONFIG_EIPG_SHIFT 25 + #define GMAC_CONFIG_EIPG_EN BIT(24) + #define GMAC_CONFIG_HDSMS GENMASK(22, 20) +-#define GMAC_CONFIG_HDSMS_SHIFT 20 +-#define GMAC_CONFIG_HDSMS_256 (0x2 << GMAC_CONFIG_HDSMS_SHIFT) ++#define GMAC_CONFIG_HDSMS_256 FIELD_PREP_CONST(GMAC_CONFIG_HDSMS, 0x2) + + /* MAC HW features0 bitmap */ + #define GMAC_HW_FEAT_SAVLANINS BIT(27) +@@ -245,7 +238,6 @@ enum power_event { + + /* MAC HW ADDR regs */ + #define GMAC_HI_DCS GENMASK(18, 16) +-#define GMAC_HI_DCS_SHIFT 16 + #define GMAC_HI_REG_AE BIT(31) + + /* L3/L4 Filters regs */ +@@ -260,7 +252,6 @@ enum power_event { + #define GMAC_L3SAM0 BIT(2) + #define GMAC_L3PEN0 BIT(0) + #define GMAC_L4DP0 GENMASK(31, 16) +-#define GMAC_L4DP0_SHIFT 16 + #define GMAC_L4SP0 GENMASK(15, 0) + + /* MAC Timestamp Status */ +@@ -317,39 +308,32 @@ static inline u32 mtl_chanx_base_addr(const struct dwmac4_addrs *addrs, + #define MTL_OP_MODE_TSF BIT(1) + + #define MTL_OP_MODE_TQS_MASK GENMASK(24, 16) +-#define MTL_OP_MODE_TQS_SHIFT 16 + +-#define MTL_OP_MODE_TTC_MASK 0x70 +-#define MTL_OP_MODE_TTC_SHIFT 4 +- +-#define MTL_OP_MODE_TTC_32 0 +-#define MTL_OP_MODE_TTC_64 (1 << MTL_OP_MODE_TTC_SHIFT) +-#define MTL_OP_MODE_TTC_96 (2 << MTL_OP_MODE_TTC_SHIFT) +-#define MTL_OP_MODE_TTC_128 (3 << MTL_OP_MODE_TTC_SHIFT) +-#define MTL_OP_MODE_TTC_192 (4 << MTL_OP_MODE_TTC_SHIFT) +-#define MTL_OP_MODE_TTC_256 (5 << MTL_OP_MODE_TTC_SHIFT) +-#define MTL_OP_MODE_TTC_384 (6 << MTL_OP_MODE_TTC_SHIFT) +-#define MTL_OP_MODE_TTC_512 (7 << MTL_OP_MODE_TTC_SHIFT) ++#define MTL_OP_MODE_TTC_MASK GENMASK(6, 4) ++#define MTL_OP_MODE_TTC_32 FIELD_PREP(MTL_OP_MODE_TTC_MASK, 0) ++#define MTL_OP_MODE_TTC_64 FIELD_PREP(MTL_OP_MODE_TTC_MASK, 1) ++#define MTL_OP_MODE_TTC_96 FIELD_PREP(MTL_OP_MODE_TTC_MASK, 2) ++#define MTL_OP_MODE_TTC_128 FIELD_PREP(MTL_OP_MODE_TTC_MASK, 3) ++#define MTL_OP_MODE_TTC_192 FIELD_PREP(MTL_OP_MODE_TTC_MASK, 4) ++#define MTL_OP_MODE_TTC_256 FIELD_PREP(MTL_OP_MODE_TTC_MASK, 5) ++#define MTL_OP_MODE_TTC_384 FIELD_PREP(MTL_OP_MODE_TTC_MASK, 6) ++#define MTL_OP_MODE_TTC_512 FIELD_PREP(MTL_OP_MODE_TTC_MASK, 7) + + #define MTL_OP_MODE_RQS_MASK GENMASK(29, 20) +-#define MTL_OP_MODE_RQS_SHIFT 20 + + #define MTL_OP_MODE_RFD_MASK GENMASK(19, 14) +-#define MTL_OP_MODE_RFD_SHIFT 14 + + #define MTL_OP_MODE_RFA_MASK GENMASK(13, 8) +-#define MTL_OP_MODE_RFA_SHIFT 8 + + #define MTL_OP_MODE_EHFC BIT(7) + #define MTL_OP_MODE_DIS_TCP_EF BIT(6) + + #define MTL_OP_MODE_RTC_MASK GENMASK(1, 0) +-#define MTL_OP_MODE_RTC_SHIFT 0 + +-#define MTL_OP_MODE_RTC_32 (1 << MTL_OP_MODE_RTC_SHIFT) +-#define MTL_OP_MODE_RTC_64 0 +-#define MTL_OP_MODE_RTC_96 (2 << MTL_OP_MODE_RTC_SHIFT) +-#define MTL_OP_MODE_RTC_128 (3 << MTL_OP_MODE_RTC_SHIFT) ++#define MTL_OP_MODE_RTC_32 FIELD_PREP(MTL_OP_MODE_RTC_MASK, 1) ++#define MTL_OP_MODE_RTC_64 FIELD_PREP(MTL_OP_MODE_RTC_MASK, 0) ++#define MTL_OP_MODE_RTC_96 FIELD_PREP(MTL_OP_MODE_RTC_MASK, 2) ++#define MTL_OP_MODE_RTC_128 FIELD_PREP(MTL_OP_MODE_RTC_MASK, 3) + + /* MTL ETS Control register */ + #define MTL_ETS_CTRL_BASE_ADDR 0x00000d10 +@@ -454,7 +438,6 @@ static inline u32 mtl_low_credx_base_addr(const struct dwmac4_addrs *addrs, + + /* MTL debug: Tx FIFO Read Controller Status */ + #define MTL_DEBUG_TRCSTS_MASK GENMASK(2, 1) +-#define MTL_DEBUG_TRCSTS_SHIFT 1 + #define MTL_DEBUG_TRCSTS_IDLE 0 + #define MTL_DEBUG_TRCSTS_READ 1 + #define MTL_DEBUG_TRCSTS_TXW 2 +@@ -469,7 +452,6 @@ static inline u32 mtl_low_credx_base_addr(const struct dwmac4_addrs *addrs, + #define MTL_DEBUG_RXFSTS_AT 2 + #define MTL_DEBUG_RXFSTS_FULL 3 + #define MTL_DEBUG_RRCSTS_MASK GENMASK(2, 1) +-#define MTL_DEBUG_RRCSTS_SHIFT 1 + #define MTL_DEBUG_RRCSTS_IDLE 0 + #define MTL_DEBUG_RRCSTS_RDATA 1 + #define MTL_DEBUG_RRCSTS_RSTAT 2 +@@ -523,7 +505,6 @@ static inline u32 mtl_low_credx_base_addr(const struct dwmac4_addrs *addrs, + #define GMAC_PHYIF_CTRLSTATUS_SMIDRXS BIT(4) + #define GMAC_PHYIF_CTRLSTATUS_LNKMOD BIT(16) + #define GMAC_PHYIF_CTRLSTATUS_SPEED GENMASK(18, 17) +-#define GMAC_PHYIF_CTRLSTATUS_SPEED_SHIFT 17 + #define GMAC_PHYIF_CTRLSTATUS_LNKSTS BIT(19) + #define GMAC_PHYIF_CTRLSTATUS_JABTO BIT(20) + #define GMAC_PHYIF_CTRLSTATUS_FALSECARDET BIT(21) +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +index d85bc0bb5c3c05..1f61177ece453c 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +@@ -572,8 +572,8 @@ static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex, + flow = GMAC_TX_FLOW_CTRL_TFE; + + if (duplex) +- flow |= +- (pause_time << GMAC_TX_FLOW_CTRL_PT_SHIFT); ++ flow |= FIELD_PREP(GMAC_TX_FLOW_CTRL_PT_MASK, ++ pause_time); + + writel(flow, ioaddr + GMAC_QX_TX_FLOW_CTRL(queue)); + } +@@ -592,34 +592,8 @@ static void dwmac4_ctrl_ane(struct stmmac_priv *priv, bool ane, bool srgmi_ral, + /* RGMII or SMII interface */ + static void dwmac4_phystatus(void __iomem *ioaddr, struct stmmac_extra_stats *x) + { +- u32 status; +- +- status = readl(ioaddr + GMAC_PHYIF_CONTROL_STATUS); ++ readl(ioaddr + GMAC_PHYIF_CONTROL_STATUS); + x->irq_rgmii_n++; +- +- /* Check the link status */ +- if (status & GMAC_PHYIF_CTRLSTATUS_LNKSTS) { +- int speed_value; +- +- x->pcs_link = 1; +- +- speed_value = ((status & GMAC_PHYIF_CTRLSTATUS_SPEED) >> +- GMAC_PHYIF_CTRLSTATUS_SPEED_SHIFT); +- if (speed_value == GMAC_PHYIF_CTRLSTATUS_SPEED_125) +- x->pcs_speed = SPEED_1000; +- else if (speed_value == GMAC_PHYIF_CTRLSTATUS_SPEED_25) +- x->pcs_speed = SPEED_100; +- else +- x->pcs_speed = SPEED_10; +- +- x->pcs_duplex = (status & GMAC_PHYIF_CTRLSTATUS_LNKMOD); +- +- pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed, +- x->pcs_duplex ? "Full" : "Half"); +- } else { +- x->pcs_link = 0; +- pr_info("Link is Down\n"); +- } + } + + static int dwmac4_irq_mtl_status(struct stmmac_priv *priv, +@@ -717,8 +691,8 @@ static void dwmac4_debug(struct stmmac_priv *priv, void __iomem *ioaddr, + if (value & MTL_DEBUG_TWCSTS) + x->mmtl_fifo_ctrl++; + if (value & MTL_DEBUG_TRCSTS_MASK) { +- u32 trcsts = (value & MTL_DEBUG_TRCSTS_MASK) +- >> MTL_DEBUG_TRCSTS_SHIFT; ++ u32 trcsts = FIELD_GET(MTL_DEBUG_TRCSTS_MASK, value); ++ + if (trcsts == MTL_DEBUG_TRCSTS_WRITE) + x->mtl_tx_fifo_read_ctrl_write++; + else if (trcsts == MTL_DEBUG_TRCSTS_TXW) +@@ -749,8 +723,7 @@ static void dwmac4_debug(struct stmmac_priv *priv, void __iomem *ioaddr, + x->mtl_rx_fifo_fill_level_empty++; + } + if (value & MTL_DEBUG_RRCSTS_MASK) { +- u32 rrcsts = (value & MTL_DEBUG_RRCSTS_MASK) >> +- MTL_DEBUG_RRCSTS_SHIFT; ++ u32 rrcsts = FIELD_GET(MTL_DEBUG_RRCSTS_MASK, value); + + if (rrcsts == MTL_DEBUG_RRCSTS_FLUSH) + x->mtl_rx_fifo_read_ctrl_flush++; +@@ -769,8 +742,7 @@ static void dwmac4_debug(struct stmmac_priv *priv, void __iomem *ioaddr, + value = readl(ioaddr + GMAC_DEBUG); + + if (value & GMAC_DEBUG_TFCSTS_MASK) { +- u32 tfcsts = (value & GMAC_DEBUG_TFCSTS_MASK) +- >> GMAC_DEBUG_TFCSTS_SHIFT; ++ u32 tfcsts = FIELD_GET(GMAC_DEBUG_TFCSTS_MASK, value); + + if (tfcsts == GMAC_DEBUG_TFCSTS_XFER) + x->mac_tx_frame_ctrl_xfer++; +@@ -784,8 +756,8 @@ static void dwmac4_debug(struct stmmac_priv *priv, void __iomem *ioaddr, + if (value & GMAC_DEBUG_TPESTS) + x->mac_gmii_tx_proto_engine++; + if (value & GMAC_DEBUG_RFCFCSTS_MASK) +- x->mac_rx_frame_ctrl_fifo = (value & GMAC_DEBUG_RFCFCSTS_MASK) +- >> GMAC_DEBUG_RFCFCSTS_SHIFT; ++ x->mac_rx_frame_ctrl_fifo = FIELD_GET(GMAC_DEBUG_RFCFCSTS_MASK, ++ value); + if (value & GMAC_DEBUG_RPESTS) + x->mac_gmii_rx_proto_engine++; + } +@@ -806,8 +778,7 @@ static void dwmac4_sarc_configure(void __iomem *ioaddr, int val) + { + u32 value = readl(ioaddr + GMAC_CONFIG); + +- value &= ~GMAC_CONFIG_SARC; +- value |= val << GMAC_CONFIG_SARC_SHIFT; ++ value = u32_replace_bits(value, val, GMAC_CONFIG_SARC); + + writel(value, ioaddr + GMAC_CONFIG); + } +@@ -915,9 +886,9 @@ static int dwmac4_config_l4_filter(struct mac_device_info *hw, u32 filter_no, + writel(value, ioaddr + GMAC_L3L4_CTRL(filter_no)); + + if (sa) { +- value = match & GMAC_L4SP0; ++ value = FIELD_PREP(GMAC_L4SP0, match); + } else { +- value = (match << GMAC_L4DP0_SHIFT) & GMAC_L4DP0; ++ value = FIELD_PREP(GMAC_L4DP0, match); + } + + writel(value, ioaddr + GMAC_L4_ADDR(filter_no)); +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c +index d87a8b595e6a3b..617e55c3711ed2 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c +@@ -28,13 +28,10 @@ static void dwmac4_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi) + if (axi->axi_xit_frm) + value |= DMA_AXI_LPI_XIT_FRM; + +- value &= ~DMA_AXI_WR_OSR_LMT; +- value |= (axi->axi_wr_osr_lmt & DMA_AXI_OSR_MAX) << +- DMA_AXI_WR_OSR_LMT_SHIFT; +- +- value &= ~DMA_AXI_RD_OSR_LMT; +- value |= (axi->axi_rd_osr_lmt & DMA_AXI_OSR_MAX) << +- DMA_AXI_RD_OSR_LMT_SHIFT; ++ value = u32_replace_bits(value, axi->axi_wr_osr_lmt, ++ DMA_AXI_WR_OSR_LMT); ++ value = u32_replace_bits(value, axi->axi_rd_osr_lmt, ++ DMA_AXI_RD_OSR_LMT); + + /* Depending on the UNDEF bit the Master AXI will perform any burst + * length according to the BLEN programmed (by default all BLEN are +@@ -79,7 +76,7 @@ static void dwmac4_dma_init_rx_chan(struct stmmac_priv *priv, + u32 rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl; + + value = readl(ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan)); +- value = value | (rxpbl << DMA_BUS_MODE_RPBL_SHIFT); ++ value = value | FIELD_PREP(DMA_CHAN_RX_CTRL_RXPBL_MASK, rxpbl); + writel(value, ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan)); + + if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && likely(dma_cfg->eame)) +@@ -100,7 +97,7 @@ static void dwmac4_dma_init_tx_chan(struct stmmac_priv *priv, + u32 txpbl = dma_cfg->txpbl ?: dma_cfg->pbl; + + value = readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan)); +- value = value | (txpbl << DMA_BUS_MODE_PBL_SHIFT); ++ value = value | FIELD_PREP(DMA_CHAN_TX_CTRL_TXPBL_MASK, txpbl); + + /* Enable OSP to get best performance */ + value |= DMA_CONTROL_OSP; +@@ -125,7 +122,7 @@ static void dwmac4_dma_init_channel(struct stmmac_priv *priv, + /* common channel control register config */ + value = readl(ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, chan)); + if (dma_cfg->pblx8) +- value = value | DMA_BUS_MODE_PBL; ++ value = value | DMA_CHAN_CTRL_PBLX8; + writel(value, ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, chan)); + + /* Mask interrupts by writing to CSR7 */ +@@ -143,7 +140,7 @@ static void dwmac410_dma_init_channel(struct stmmac_priv *priv, + /* common channel control register config */ + value = readl(ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, chan)); + if (dma_cfg->pblx8) +- value = value | DMA_BUS_MODE_PBL; ++ value = value | DMA_CHAN_CTRL_PBLX8; + + writel(value, ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, chan)); + +@@ -175,10 +172,9 @@ static void dwmac4_dma_init(void __iomem *ioaddr, + + value = readl(ioaddr + DMA_BUS_MODE); + +- if (dma_cfg->multi_msi_en) { +- value &= ~DMA_BUS_MODE_INTM_MASK; +- value |= (DMA_BUS_MODE_INTM_MODE1 << DMA_BUS_MODE_INTM_SHIFT); +- } ++ if (dma_cfg->multi_msi_en) ++ value = u32_replace_bits(value, DMA_BUS_MODE_INTM_MODE1, ++ DMA_BUS_MODE_INTM_MASK); + + if (dma_cfg->dche) + value |= DMA_BUS_MODE_DCHE; +@@ -288,7 +284,7 @@ static void dwmac4_dma_rx_chan_op_mode(struct stmmac_priv *priv, + } + + mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK; +- mtl_rx_op |= rqs << MTL_OP_MODE_RQS_SHIFT; ++ mtl_rx_op |= FIELD_PREP(MTL_OP_MODE_RQS_MASK, rqs); + + /* Enable flow control only if each channel gets 4 KiB or more FIFO and + * only if channel is not an AVB channel. +@@ -319,11 +315,10 @@ static void dwmac4_dma_rx_chan_op_mode(struct stmmac_priv *priv, + break; + } + +- mtl_rx_op &= ~MTL_OP_MODE_RFD_MASK; +- mtl_rx_op |= rfd << MTL_OP_MODE_RFD_SHIFT; +- +- mtl_rx_op &= ~MTL_OP_MODE_RFA_MASK; +- mtl_rx_op |= rfa << MTL_OP_MODE_RFA_SHIFT; ++ mtl_rx_op = u32_replace_bits(mtl_rx_op, rfd, ++ MTL_OP_MODE_RFD_MASK); ++ mtl_rx_op = u32_replace_bits(mtl_rx_op, rfa, ++ MTL_OP_MODE_RFA_MASK); + } + + writel(mtl_rx_op, ioaddr + MTL_CHAN_RX_OP_MODE(dwmac4_addrs, channel)); +@@ -378,8 +373,8 @@ static void dwmac4_dma_tx_chan_op_mode(struct stmmac_priv *priv, + mtl_tx_op |= MTL_OP_MODE_TXQEN; + else + mtl_tx_op |= MTL_OP_MODE_TXQEN_AV; +- mtl_tx_op &= ~MTL_OP_MODE_TQS_MASK; +- mtl_tx_op |= tqs << MTL_OP_MODE_TQS_SHIFT; ++ ++ mtl_tx_op = u32_replace_bits(mtl_tx_op, tqs, MTL_OP_MODE_TQS_MASK); + + writel(mtl_tx_op, ioaddr + MTL_CHAN_TX_OP_MODE(dwmac4_addrs, channel)); + } +@@ -520,8 +515,7 @@ static void dwmac4_set_bfsize(struct stmmac_priv *priv, void __iomem *ioaddr, + const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; + u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan)); + +- value &= ~DMA_RBSZ_MASK; +- value |= (bfsize << DMA_RBSZ_SHIFT) & DMA_RBSZ_MASK; ++ value = u32_replace_bits(value, bfsize, DMA_RBSZ_MASK); + + writel(value, ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan)); + } +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h +index 4f980dcd395823..a019eb07afcf1c 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h +@@ -27,15 +27,11 @@ + /* DMA Bus Mode bitmap */ + #define DMA_BUS_MODE_DCHE BIT(19) + #define DMA_BUS_MODE_INTM_MASK GENMASK(17, 16) +-#define DMA_BUS_MODE_INTM_SHIFT 16 + #define DMA_BUS_MODE_INTM_MODE1 0x1 + #define DMA_BUS_MODE_SFT_RESET BIT(0) + + /* DMA SYS Bus Mode bitmap */ + #define DMA_BUS_MODE_SPH BIT(24) +-#define DMA_BUS_MODE_PBL BIT(16) +-#define DMA_BUS_MODE_PBL_SHIFT 16 +-#define DMA_BUS_MODE_RPBL_SHIFT 16 + #define DMA_BUS_MODE_MB BIT(14) + #define DMA_BUS_MODE_FB BIT(0) + +@@ -59,13 +55,7 @@ + #define DMA_AXI_EN_LPI BIT(31) + #define DMA_AXI_LPI_XIT_FRM BIT(30) + #define DMA_AXI_WR_OSR_LMT GENMASK(27, 24) +-#define DMA_AXI_WR_OSR_LMT_SHIFT 24 + #define DMA_AXI_RD_OSR_LMT GENMASK(19, 16) +-#define DMA_AXI_RD_OSR_LMT_SHIFT 16 +- +-#define DMA_AXI_OSR_MAX 0xf +-#define DMA_AXI_MAX_OSR_LIMIT ((DMA_AXI_OSR_MAX << DMA_AXI_WR_OSR_LMT_SHIFT) | \ +- (DMA_AXI_OSR_MAX << DMA_AXI_RD_OSR_LMT_SHIFT)) + + #define DMA_SYS_BUS_MB BIT(14) + #define DMA_AXI_1KBBE BIT(13) +@@ -134,19 +124,21 @@ static inline u32 dma_chanx_base_addr(const struct dwmac4_addrs *addrs, + #define DMA_CHAN_STATUS(addrs, x) (dma_chanx_base_addr(addrs, x) + 0x60) + + /* DMA Control X */ ++#define DMA_CHAN_CTRL_PBLX8 BIT(16) + #define DMA_CONTROL_SPH BIT(24) + #define DMA_CONTROL_MSS_MASK GENMASK(13, 0) + + /* DMA Tx Channel X Control register defines */ + #define DMA_CONTROL_EDSE BIT(28) ++#define DMA_CHAN_TX_CTRL_TXPBL_MASK GENMASK(21, 16) + #define DMA_CONTROL_TSE BIT(12) + #define DMA_CONTROL_OSP BIT(4) + #define DMA_CONTROL_ST BIT(0) + + /* DMA Rx Channel X Control register defines */ +-#define DMA_CONTROL_SR BIT(0) ++#define DMA_CHAN_RX_CTRL_RXPBL_MASK GENMASK(21, 16) + #define DMA_RBSZ_MASK GENMASK(14, 1) +-#define DMA_RBSZ_SHIFT 1 ++#define DMA_CONTROL_SR BIT(0) + + /* Interrupt status per channel */ + #define DMA_CHAN_STATUS_REB GENMASK(21, 19) +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c +index 57c03d49177447..c098047a3bff8a 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c +@@ -234,7 +234,7 @@ void stmmac_dwmac4_set_mac_addr(void __iomem *ioaddr, const u8 addr[6], + * bit that has no effect on the High Reg 0 where the bit 31 (MO) + * is RO. + */ +- data |= (STMMAC_CHAN0 << GMAC_HI_DCS_SHIFT); ++ data |= FIELD_PREP(GMAC_HI_DCS, STMMAC_CHAN0); + writel(data | GMAC_HI_REG_AE, ioaddr + high); + data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; + writel(data, ioaddr + low); +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h +index 5d9c18f5bbf587..14cfe0de3327ae 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h +@@ -59,11 +59,7 @@ static inline u32 dma_chan_base_addr(u32 base, u32 chan) + #define DMA_AXI_EN_LPI BIT(31) + #define DMA_AXI_LPI_XIT_FRM BIT(30) + #define DMA_AXI_WR_OSR_LMT GENMASK(23, 20) +-#define DMA_AXI_WR_OSR_LMT_SHIFT 20 +-#define DMA_AXI_WR_OSR_LMT_MASK 0xf + #define DMA_AXI_RD_OSR_LMT GENMASK(19, 16) +-#define DMA_AXI_RD_OSR_LMT_SHIFT 16 +-#define DMA_AXI_RD_OSR_LMT_MASK 0xf + + #define DMA_AXI_OSR_MAX 0xf + #define DMA_AXI_MAX_OSR_LIMIT ((DMA_AXI_OSR_MAX << DMA_AXI_WR_OSR_LMT_SHIFT) | \ +@@ -132,10 +128,8 @@ static inline u32 dma_chan_base_addr(u32 base, u32 chan) + #define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */ + #define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */ + #define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */ +-#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */ +-#define DMA_STATUS_TS_SHIFT 20 +-#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */ +-#define DMA_STATUS_RS_SHIFT 17 ++#define DMA_STATUS_TS_MASK GENMASK(22, 20) /* Transmit Process State */ ++#define DMA_STATUS_RS_MASK GENMASK(19, 17) /* Receive Process State */ + #define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */ + #define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */ + #define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */ +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c +index 467f1a05747ecf..2e979f07566500 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c +@@ -92,10 +92,7 @@ void dwmac_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan) + #ifdef DWMAC_DMA_DEBUG + static void show_tx_process_state(unsigned int status) + { +- unsigned int state; +- state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT; +- +- switch (state) { ++ switch (FIELD_GET(DMA_STATUS_TS_MASK, status)) { + case 0: + pr_debug("- TX (Stopped): Reset or Stop command\n"); + break; +@@ -123,10 +120,7 @@ static void show_tx_process_state(unsigned int status) + + static void show_rx_process_state(unsigned int status) + { +- unsigned int state; +- state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT; +- +- switch (state) { ++ switch (FIELD_GET(DMA_STATUS_RS_MASK, status)) { + case 0: + pr_debug("- RX (Stopped): Reset or Stop command\n"); + break; +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h +index 0d408ee17f3378..67e2d539c33853 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h ++++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h +@@ -24,17 +24,15 @@ + #define XGMAC_CONFIG_SS_2500 (0x6 << XGMAC_CONFIG_SS_OFF) + #define XGMAC_CONFIG_SS_10_MII (0x7 << XGMAC_CONFIG_SS_OFF) + #define XGMAC_CONFIG_SARC GENMASK(22, 20) +-#define XGMAC_CONFIG_SARC_SHIFT 20 + #define XGMAC_CONFIG_JD BIT(16) + #define XGMAC_CONFIG_TE BIT(0) + #define XGMAC_CORE_INIT_TX (XGMAC_CONFIG_JD) + #define XGMAC_RX_CONFIG 0x00000004 + #define XGMAC_CONFIG_ARPEN BIT(31) + #define XGMAC_CONFIG_GPSL GENMASK(29, 16) +-#define XGMAC_CONFIG_GPSL_SHIFT 16 + #define XGMAC_CONFIG_HDSMS GENMASK(14, 12) + #define XGMAC_CONFIG_HDSMS_SHIFT 12 +-#define XGMAC_CONFIG_HDSMS_256 (0x2 << XGMAC_CONFIG_HDSMS_SHIFT) ++#define XGMAC_CONFIG_HDSMS_256 FIELD_PREP(XGMAC_CONFIG_HDSMS, 0x2) + #define XGMAC_CONFIG_S2KP BIT(11) + #define XGMAC_CONFIG_LM BIT(10) + #define XGMAC_CONFIG_IPC BIT(9) +@@ -44,8 +42,10 @@ + #define XGMAC_CONFIG_CST BIT(2) + #define XGMAC_CONFIG_ACS BIT(1) + #define XGMAC_CONFIG_RE BIT(0) +-#define XGMAC_CORE_INIT_RX (XGMAC_CONFIG_GPSLCE | XGMAC_CONFIG_WD | \ +- (XGMAC_JUMBO_LEN << XGMAC_CONFIG_GPSL_SHIFT)) ++#define XGMAC_CORE_INIT_RX (XGMAC_CONFIG_GPSLCE | \ ++ XGMAC_CONFIG_WD | \ ++ FIELD_PREP(XGMAC_CONFIG_GPSL, \ ++ XGMAC_JUMBO_LEN)) + #define XGMAC_PACKET_FILTER 0x00000008 + #define XGMAC_FILTER_RA BIT(31) + #define XGMAC_FILTER_IPFE BIT(20) +@@ -79,6 +79,7 @@ + #define XGMAC_PSRQ(x) GENMASK((x) * 8 + 7, (x) * 8) + #define XGMAC_PSRQ_SHIFT(x) ((x) * 8) + #define XGMAC_INT_STATUS 0x000000b0 ++#define XGMAC_INT_TSIS BIT(12) + #define XGMAC_LPIIS BIT(5) + #define XGMAC_PMTIS BIT(4) + #define XGMAC_INT_EN 0x000000b4 +@@ -89,7 +90,6 @@ + #define XGMAC_INT_DEFAULT_EN (XGMAC_LPIIE | XGMAC_PMTIE) + #define XGMAC_Qx_TX_FLOW_CTRL(x) (0x00000070 + (x) * 4) + #define XGMAC_PT GENMASK(31, 16) +-#define XGMAC_PT_SHIFT 16 + #define XGMAC_TFE BIT(1) + #define XGMAC_RX_FLOW_CTRL 0x00000090 + #define XGMAC_RFE BIT(0) +@@ -173,16 +173,17 @@ + #define XGMAC_MDIO_ADDR 0x00000200 + #define XGMAC_MDIO_DATA 0x00000204 + #define XGMAC_MDIO_C22P 0x00000220 ++#define XGMAC_GPIO_STATUS 0x0000027c ++#define XGMAC_GPIO_GPO0 BIT(16) + #define XGMAC_ADDRx_HIGH(x) (0x00000300 + (x) * 0x8) + #define XGMAC_ADDR_MAX 32 + #define XGMAC_AE BIT(31) + #define XGMAC_DCS GENMASK(19, 16) +-#define XGMAC_DCS_SHIFT 16 + #define XGMAC_ADDRx_LOW(x) (0x00000304 + (x) * 0x8) + #define XGMAC_L3L4_ADDR_CTRL 0x00000c00 + #define XGMAC_IDDR GENMASK(16, 8) +-#define XGMAC_IDDR_SHIFT 8 +-#define XGMAC_IDDR_FNUM 4 ++#define XGMAC_IDDR_FNUM_MASK GENMASK(7, 4) /* FNUM within IDDR */ ++#define XGMAC_IDDR_REG_MASK GENMASK(3, 0) /* REG within IDDR */ + #define XGMAC_TT BIT(1) + #define XGMAC_XB BIT(0) + #define XGMAC_L3L4_DATA 0x00000c04 +@@ -201,7 +202,6 @@ + #define XGMAC_L3PEN0 BIT(0) + #define XGMAC_L4_ADDR 0x1 + #define XGMAC_L4DP0 GENMASK(31, 16) +-#define XGMAC_L4DP0_SHIFT 16 + #define XGMAC_L4SP0 GENMASK(15, 0) + #define XGMAC_L3_ADDR0 0x4 + #define XGMAC_L3_ADDR1 0x5 +@@ -220,6 +220,7 @@ + #define XGMAC_OB BIT(0) + #define XGMAC_RSS_DATA 0x00000c8c + #define XGMAC_TIMESTAMP_STATUS 0x00000d20 ++#define XGMAC_TIMESTAMP_ATSNS_MASK GENMASK(29, 25) + #define XGMAC_TXTSC BIT(15) + #define XGMAC_TXTIMESTAMP_NSEC 0x00000d30 + #define XGMAC_TXTSSTSLO GENMASK(30, 0) +@@ -285,13 +286,9 @@ + #define XGMAC_DPP_DISABLE BIT(0) + #define XGMAC_MTL_TXQ_OPMODE(x) (0x00001100 + (0x80 * (x))) + #define XGMAC_TQS GENMASK(25, 16) +-#define XGMAC_TQS_SHIFT 16 + #define XGMAC_Q2TCMAP GENMASK(10, 8) +-#define XGMAC_Q2TCMAP_SHIFT 8 + #define XGMAC_TTC GENMASK(6, 4) +-#define XGMAC_TTC_SHIFT 4 + #define XGMAC_TXQEN GENMASK(3, 2) +-#define XGMAC_TXQEN_SHIFT 2 + #define XGMAC_TSF BIT(1) + #define XGMAC_MTL_TCx_ETS_CONTROL(x) (0x00001110 + (0x80 * (x))) + #define XGMAC_MTL_TCx_QUANTUM_WEIGHT(x) (0x00001118 + (0x80 * (x))) +@@ -305,16 +302,12 @@ + #define XGMAC_ETS (0x2 << 0) + #define XGMAC_MTL_RXQ_OPMODE(x) (0x00001140 + (0x80 * (x))) + #define XGMAC_RQS GENMASK(25, 16) +-#define XGMAC_RQS_SHIFT 16 + #define XGMAC_EHFC BIT(7) + #define XGMAC_RSF BIT(5) + #define XGMAC_RTC GENMASK(1, 0) +-#define XGMAC_RTC_SHIFT 0 + #define XGMAC_MTL_RXQ_FLOW_CONTROL(x) (0x00001150 + (0x80 * (x))) + #define XGMAC_RFD GENMASK(31, 17) +-#define XGMAC_RFD_SHIFT 17 + #define XGMAC_RFA GENMASK(15, 1) +-#define XGMAC_RFA_SHIFT 1 + #define XGMAC_MTL_QINTEN(x) (0x00001170 + (0x80 * (x))) + #define XGMAC_RXOIE BIT(16) + #define XGMAC_MTL_QINT_STATUS(x) (0x00001174 + (0x80 * (x))) +@@ -328,9 +321,7 @@ + #define XGMAC_SWR BIT(0) + #define XGMAC_DMA_SYSBUS_MODE 0x00003004 + #define XGMAC_WR_OSR_LMT GENMASK(29, 24) +-#define XGMAC_WR_OSR_LMT_SHIFT 24 + #define XGMAC_RD_OSR_LMT GENMASK(21, 16) +-#define XGMAC_RD_OSR_LMT_SHIFT 16 + #define XGMAC_EN_LPI BIT(15) + #define XGMAC_LPI_XIT_PKT BIT(14) + #define XGMAC_AAL BIT(12) +@@ -372,15 +363,12 @@ + #define XGMAC_DMA_CH_TX_CONTROL(x) (0x00003104 + (0x80 * (x))) + #define XGMAC_EDSE BIT(28) + #define XGMAC_TxPBL GENMASK(21, 16) +-#define XGMAC_TxPBL_SHIFT 16 + #define XGMAC_TSE BIT(12) + #define XGMAC_OSP BIT(4) + #define XGMAC_TXST BIT(0) + #define XGMAC_DMA_CH_RX_CONTROL(x) (0x00003108 + (0x80 * (x))) + #define XGMAC_RxPBL GENMASK(21, 16) +-#define XGMAC_RxPBL_SHIFT 16 + #define XGMAC_RBSZ GENMASK(14, 1) +-#define XGMAC_RBSZ_SHIFT 1 + #define XGMAC_RXST BIT(0) + #define XGMAC_DMA_CH_TxDESC_HADDR(x) (0x00003110 + (0x80 * (x))) + #define XGMAC_DMA_CH_TxDESC_LADDR(x) (0x00003114 + (0x80 * (x))) +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +index 00e929bf280bae..ee41c77426f1ab 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +@@ -376,7 +376,7 @@ static void dwxgmac2_flow_ctrl(struct mac_device_info *hw, unsigned int duplex, + u32 value = XGMAC_TFE; + + if (duplex) +- value |= pause_time << XGMAC_PT_SHIFT; ++ value |= FIELD_PREP(XGMAC_PT, pause_time); + + writel(value, ioaddr + XGMAC_Qx_TX_FLOW_CTRL(i)); + } +@@ -1233,8 +1233,7 @@ static void dwxgmac2_sarc_configure(void __iomem *ioaddr, int val) + { + u32 value = readl(ioaddr + XGMAC_TX_CONFIG); + +- value &= ~XGMAC_CONFIG_SARC; +- value |= val << XGMAC_CONFIG_SARC_SHIFT; ++ value = u32_replace_bits(value, val, XGMAC_CONFIG_SARC); + + writel(value, ioaddr + XGMAC_TX_CONFIG); + } +@@ -1254,14 +1253,16 @@ static int dwxgmac2_filter_read(struct mac_device_info *hw, u32 filter_no, + u8 reg, u32 *data) + { + void __iomem *ioaddr = hw->pcsr; +- u32 value; ++ u32 value, iddr; + int ret; + + ret = dwxgmac2_filter_wait(hw); + if (ret) + return ret; + +- value = ((filter_no << XGMAC_IDDR_FNUM) | reg) << XGMAC_IDDR_SHIFT; ++ iddr = FIELD_PREP(XGMAC_IDDR_FNUM_MASK, filter_no) | ++ FIELD_PREP(XGMAC_IDDR_REG_MASK, reg); ++ value = FIELD_PREP(XGMAC_IDDR, iddr); + value |= XGMAC_TT | XGMAC_XB; + writel(value, ioaddr + XGMAC_L3L4_ADDR_CTRL); + +@@ -1277,7 +1278,7 @@ static int dwxgmac2_filter_write(struct mac_device_info *hw, u32 filter_no, + u8 reg, u32 data) + { + void __iomem *ioaddr = hw->pcsr; +- u32 value; ++ u32 value, iddr; + int ret; + + ret = dwxgmac2_filter_wait(hw); +@@ -1286,7 +1287,9 @@ static int dwxgmac2_filter_write(struct mac_device_info *hw, u32 filter_no, + + writel(data, ioaddr + XGMAC_L3L4_DATA); + +- value = ((filter_no << XGMAC_IDDR_FNUM) | reg) << XGMAC_IDDR_SHIFT; ++ iddr = FIELD_PREP(XGMAC_IDDR_FNUM_MASK, filter_no) | ++ FIELD_PREP(XGMAC_IDDR_REG_MASK, reg); ++ value = FIELD_PREP(XGMAC_IDDR, iddr); + value |= XGMAC_XB; + writel(value, ioaddr + XGMAC_L3L4_ADDR_CTRL); + +@@ -1378,36 +1381,40 @@ static int dwxgmac2_config_l4_filter(struct mac_device_info *hw, u32 filter_no, + value &= ~XGMAC_L4PEN0; + } + +- value &= ~(XGMAC_L4SPM0 | XGMAC_L4SPIM0); +- value &= ~(XGMAC_L4DPM0 | XGMAC_L4DPIM0); + if (sa) { + value |= XGMAC_L4SPM0; + if (inv) + value |= XGMAC_L4SPIM0; ++ else ++ value &= ~XGMAC_L4SPIM0; + } else { + value |= XGMAC_L4DPM0; + if (inv) + value |= XGMAC_L4DPIM0; ++ else ++ value &= ~XGMAC_L4DPIM0; + } + + ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, value); + if (ret) + return ret; + +- if (sa) { +- value = match & XGMAC_L4SP0; ++ ret = dwxgmac2_filter_read(hw, filter_no, XGMAC_L4_ADDR, &value); ++ if (ret) ++ return ret; + +- ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L4_ADDR, value); +- if (ret) +- return ret; ++ if (sa) { ++ value &= ~XGMAC_L4SP0; ++ value |= FIELD_PREP(XGMAC_L4SP0, match); + } else { +- value = (match << XGMAC_L4DP0_SHIFT) & XGMAC_L4DP0; +- +- ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L4_ADDR, value); +- if (ret) +- return ret; ++ value &= ~XGMAC_L4DP0; ++ value |= FIELD_PREP(XGMAC_L4DP0, match); + } + ++ ret = dwxgmac2_filter_write(hw, filter_no, XGMAC_L4_ADDR, value); ++ if (ret) ++ return ret; ++ + if (!en) + return dwxgmac2_filter_write(hw, filter_no, XGMAC_L3L4_CTRL, 0); + +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +index 4d6bb995d8d84c..964ce2d7331696 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +@@ -55,8 +55,7 @@ static void dwxgmac2_dma_init_rx_chan(struct stmmac_priv *priv, + u32 value; + + value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan)); +- value &= ~XGMAC_RxPBL; +- value |= (rxpbl << XGMAC_RxPBL_SHIFT) & XGMAC_RxPBL; ++ value = u32_replace_bits(value, rxpbl, XGMAC_RxPBL); + writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan)); + + writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_HADDR(chan)); +@@ -72,9 +71,7 @@ static void dwxgmac2_dma_init_tx_chan(struct stmmac_priv *priv, + u32 value; + + value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)); +- value &= ~XGMAC_TxPBL; +- value |= (txpbl << XGMAC_TxPBL_SHIFT) & XGMAC_TxPBL; +- value |= XGMAC_OSP; ++ value = u32_replace_bits(value, txpbl, XGMAC_TxPBL); + writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)); + + writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_HADDR(chan)); +@@ -91,13 +88,8 @@ static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi) + if (axi->axi_xit_frm) + value |= XGMAC_LPI_XIT_PKT; + +- value &= ~XGMAC_WR_OSR_LMT; +- value |= (axi->axi_wr_osr_lmt << XGMAC_WR_OSR_LMT_SHIFT) & +- XGMAC_WR_OSR_LMT; +- +- value &= ~XGMAC_RD_OSR_LMT; +- value |= (axi->axi_rd_osr_lmt << XGMAC_RD_OSR_LMT_SHIFT) & +- XGMAC_RD_OSR_LMT; ++ value = u32_replace_bits(value, axi->axi_wr_osr_lmt, XGMAC_WR_OSR_LMT); ++ value = u32_replace_bits(value, axi->axi_rd_osr_lmt, XGMAC_RD_OSR_LMT); + + if (!axi->axi_fb) + value |= XGMAC_UNDEF; +@@ -148,23 +140,24 @@ static void dwxgmac2_dma_rx_mode(struct stmmac_priv *priv, void __iomem *ioaddr, + { + u32 value = readl(ioaddr + XGMAC_MTL_RXQ_OPMODE(channel)); + unsigned int rqs = fifosz / 256 - 1; ++ unsigned int rtc; + + if (mode == SF_DMA_MODE) { + value |= XGMAC_RSF; + } else { + value &= ~XGMAC_RSF; +- value &= ~XGMAC_RTC; + + if (mode <= 64) +- value |= 0x0 << XGMAC_RTC_SHIFT; ++ rtc = 0x0; + else if (mode <= 96) +- value |= 0x2 << XGMAC_RTC_SHIFT; ++ rtc = 0x2; + else +- value |= 0x3 << XGMAC_RTC_SHIFT; ++ rtc = 0x3; ++ ++ value = u32_replace_bits(value, rtc, XGMAC_RTC); + } + +- value &= ~XGMAC_RQS; +- value |= (rqs << XGMAC_RQS_SHIFT) & XGMAC_RQS; ++ value = u32_replace_bits(value, rqs, XGMAC_RQS); + + if ((fifosz >= 4096) && (qmode != MTL_QUEUE_AVB)) { + u32 flow = readl(ioaddr + XGMAC_MTL_RXQ_FLOW_CONTROL(channel)); +@@ -193,11 +186,8 @@ static void dwxgmac2_dma_rx_mode(struct stmmac_priv *priv, void __iomem *ioaddr, + break; + } + +- flow &= ~XGMAC_RFD; +- flow |= rfd << XGMAC_RFD_SHIFT; +- +- flow &= ~XGMAC_RFA; +- flow |= rfa << XGMAC_RFA_SHIFT; ++ flow = u32_replace_bits(flow, rfd, XGMAC_RFD); ++ flow = u32_replace_bits(flow, rfa, XGMAC_RFA); + + writel(flow, ioaddr + XGMAC_MTL_RXQ_FLOW_CONTROL(channel)); + } +@@ -210,40 +200,41 @@ static void dwxgmac2_dma_tx_mode(struct stmmac_priv *priv, void __iomem *ioaddr, + { + u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(channel)); + unsigned int tqs = fifosz / 256 - 1; ++ unsigned int ttc, txqen; + + if (mode == SF_DMA_MODE) { + value |= XGMAC_TSF; + } else { + value &= ~XGMAC_TSF; +- value &= ~XGMAC_TTC; + + if (mode <= 64) +- value |= 0x0 << XGMAC_TTC_SHIFT; ++ ttc = 0x0; + else if (mode <= 96) +- value |= 0x2 << XGMAC_TTC_SHIFT; ++ ttc = 0x2; + else if (mode <= 128) +- value |= 0x3 << XGMAC_TTC_SHIFT; ++ ttc = 0x3; + else if (mode <= 192) +- value |= 0x4 << XGMAC_TTC_SHIFT; ++ ttc = 0x4; + else if (mode <= 256) +- value |= 0x5 << XGMAC_TTC_SHIFT; ++ ttc = 0x5; + else if (mode <= 384) +- value |= 0x6 << XGMAC_TTC_SHIFT; ++ ttc = 0x6; + else +- value |= 0x7 << XGMAC_TTC_SHIFT; ++ ttc = 0x7; ++ ++ value = u32_replace_bits(value, ttc, XGMAC_TTC); + } + + /* Use static TC to Queue mapping */ +- value |= (channel << XGMAC_Q2TCMAP_SHIFT) & XGMAC_Q2TCMAP; ++ value |= FIELD_PREP(XGMAC_Q2TCMAP, channel); + +- value &= ~XGMAC_TXQEN; + if (qmode != MTL_QUEUE_AVB) +- value |= 0x2 << XGMAC_TXQEN_SHIFT; ++ txqen = 0x2; + else +- value |= 0x1 << XGMAC_TXQEN_SHIFT; ++ txqen = 0x1; + +- value &= ~XGMAC_TQS; +- value |= (tqs << XGMAC_TQS_SHIFT) & XGMAC_TQS; ++ value = u32_replace_bits(value, txqen, XGMAC_TXQEN); ++ value = u32_replace_bits(value, tqs, XGMAC_TQS); + + writel(value, ioaddr + XGMAC_MTL_TXQ_OPMODE(channel)); + } +@@ -547,16 +538,17 @@ static void dwxgmac2_qmode(struct stmmac_priv *priv, void __iomem *ioaddr, + { + u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(channel)); + u32 flow = readl(ioaddr + XGMAC_RX_FLOW_CTRL); ++ unsigned int txqen; + +- value &= ~XGMAC_TXQEN; + if (qmode != MTL_QUEUE_AVB) { +- value |= 0x2 << XGMAC_TXQEN_SHIFT; ++ txqen = 0x2; + writel(0, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(channel)); + } else { +- value |= 0x1 << XGMAC_TXQEN_SHIFT; ++ txqen = 0x1; + writel(flow & (~XGMAC_RFE), ioaddr + XGMAC_RX_FLOW_CTRL); + } + ++ value = u32_replace_bits(value, txqen, XGMAC_TXQEN); + writel(value, ioaddr + XGMAC_MTL_TXQ_OPMODE(channel)); + } + +@@ -566,8 +558,7 @@ static void dwxgmac2_set_bfsize(struct stmmac_priv *priv, void __iomem *ioaddr, + u32 value; + + value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan)); +- value &= ~XGMAC_RBSZ; +- value |= bfsize << XGMAC_RBSZ_SHIFT; ++ value = u32_replace_bits(value, bfsize, XGMAC_RBSZ); + writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan)); + } + +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +index 1ceedd74e42908..3be0b795324964 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -892,63 +892,45 @@ static void stmmac_mac_link_up(struct phylink_config *config, + old_ctrl = readl(priv->ioaddr + MAC_CTRL_REG); + ctrl = old_ctrl & ~priv->hw->link.speed_mask; + +- if (interface == PHY_INTERFACE_MODE_USXGMII) { +- switch (speed) { +- case SPEED_10000: +- ctrl |= priv->hw->link.xgmii.speed10000; +- break; +- case SPEED_5000: +- ctrl |= priv->hw->link.xgmii.speed5000; +- break; +- case SPEED_2500: ++ switch (speed) { ++ case SPEED_100000: ++ ctrl |= priv->hw->link.xlgmii.speed100000; ++ break; ++ case SPEED_50000: ++ ctrl |= priv->hw->link.xlgmii.speed50000; ++ break; ++ case SPEED_40000: ++ ctrl |= priv->hw->link.xlgmii.speed40000; ++ break; ++ case SPEED_25000: ++ ctrl |= priv->hw->link.xlgmii.speed25000; ++ break; ++ case SPEED_10000: ++ ctrl |= priv->hw->link.xgmii.speed10000; ++ break; ++ case SPEED_5000: ++ ctrl |= priv->hw->link.xgmii.speed5000; ++ break; ++ case SPEED_2500: ++ if (interface == PHY_INTERFACE_MODE_USXGMII) + ctrl |= priv->hw->link.xgmii.speed2500; +- break; +- default: +- return; +- } +- } else if (interface == PHY_INTERFACE_MODE_XLGMII) { +- switch (speed) { +- case SPEED_100000: +- ctrl |= priv->hw->link.xlgmii.speed100000; +- break; +- case SPEED_50000: +- ctrl |= priv->hw->link.xlgmii.speed50000; +- break; +- case SPEED_40000: +- ctrl |= priv->hw->link.xlgmii.speed40000; +- break; +- case SPEED_25000: +- ctrl |= priv->hw->link.xlgmii.speed25000; +- break; +- case SPEED_10000: +- ctrl |= priv->hw->link.xgmii.speed10000; +- break; +- case SPEED_2500: +- ctrl |= priv->hw->link.speed2500; +- break; +- case SPEED_1000: +- ctrl |= priv->hw->link.speed1000; +- break; +- default: +- return; +- } +- } else { +- switch (speed) { +- case SPEED_2500: ++ else + ctrl |= priv->hw->link.speed2500; +- break; +- case SPEED_1000: +- ctrl |= priv->hw->link.speed1000; +- break; +- case SPEED_100: +- ctrl |= priv->hw->link.speed100; +- break; +- case SPEED_10: +- ctrl |= priv->hw->link.speed10; +- break; +- default: +- return; +- } ++ break; ++ case SPEED_1000: ++ ctrl |= priv->hw->link.speed1000; ++ break; ++ case SPEED_100: ++ ctrl |= priv->hw->link.speed100; ++ break; ++ case SPEED_10: ++ ctrl |= priv->hw->link.speed10; ++ break; ++ default: ++ netdev_err(priv->dev, ++ "unsupported speed %s on %s, leaving the MAC disabled\n", ++ phy_speed_to_str(speed), phy_modes(interface)); ++ return; + } + + if (priv->plat->fix_mac_speed) +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +index 3b4d4696afe96a..0119b4b89fc0a0 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +@@ -446,6 +446,7 @@ static int tc_parse_flow_actions(struct stmmac_priv *priv, + } + + #define ETHER_TYPE_FULL_MASK cpu_to_be16(~0) ++#define IP_PROTO_FULL_MASK 0xFF + + static int tc_add_basic_flow(struct stmmac_priv *priv, + struct flow_cls_offload *cls, +@@ -461,6 +462,37 @@ static int tc_add_basic_flow(struct stmmac_priv *priv, + + flow_rule_match_basic(rule, &match); + ++ /* Both network proto and transport proto not present in the key */ ++ if (!match.mask || !(match.mask->n_proto || match.mask->ip_proto)) { ++ NL_SET_ERR_MSG_MOD(cls->common.extack, ++ "filter must specify network or transport protocol"); ++ return -EOPNOTSUPP; ++ } ++ ++ /* If the proto is present in the key and is not full mask */ ++ if ((match.mask->n_proto && match.mask->n_proto != ETHER_TYPE_FULL_MASK) || ++ (match.mask->ip_proto && match.mask->ip_proto != IP_PROTO_FULL_MASK)) { ++ NL_SET_ERR_MSG_MOD(cls->common.extack, ++ "only full protocol mask is supported"); ++ return -EOPNOTSUPP; ++ } ++ ++ /* Network proto is present in the key and is not IPv4 */ ++ if (match.mask->n_proto && match.key->n_proto != cpu_to_be16(ETH_P_IP)) { ++ NL_SET_ERR_MSG_MOD(cls->common.extack, ++ "only IPv4 network protocol is supported"); ++ return -EOPNOTSUPP; ++ } ++ ++ /* Transport proto is present in the key and is not TCP or UDP */ ++ if (match.mask->ip_proto && ++ match.key->ip_proto != IPPROTO_TCP && ++ match.key->ip_proto != IPPROTO_UDP) { ++ NL_SET_ERR_MSG_MOD(cls->common.extack, ++ "only TCP and UDP transport protocols are supported"); ++ return -EOPNOTSUPP; ++ } ++ + entry->ip_proto = match.key->ip_proto; + return 0; + } +@@ -598,6 +630,8 @@ static int tc_add_flow(struct stmmac_priv *priv, + ret = tc_flow_parsers[i].fn(priv, cls, entry); + if (!ret) + entry->in_use = true; ++ else if (ret == -EOPNOTSUPP) ++ return ret; + } + + if (!entry->in_use) +@@ -627,6 +661,7 @@ static int tc_del_flow(struct stmmac_priv *priv, + entry->in_use = false; + entry->cookie = 0; + entry->is_l4 = false; ++ entry->action = 0; + return ret; + } + +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +index 4d20b178af236b..76d2940a49fae6 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +@@ -956,6 +956,7 @@ static void txgbe_remove(struct pci_dev *pdev) + netdev = wx->netdev; + wx_disable_sriov(wx); + unregister_netdev(netdev); ++ txgbe_fdir_filter_exit(wx); + + txgbe_remove_phy(txgbe); + wx_free_isb_resources(wx); +diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c +index 77b0c3d5204140..73e020270b989a 100644 +--- a/drivers/net/geneve.c ++++ b/drivers/net/geneve.c +@@ -1736,6 +1736,9 @@ static int geneve_changelink(struct net_device *dev, struct nlattr *tb[], + struct geneve_config cfg; + int err; + ++ if (!rtnl_dev_link_net_capable(dev, geneve->net)) ++ return -EPERM; ++ + /* If the geneve device is configured for metadata (or externally + * controlled, for example, OVS), then nothing can be changed. + */ +diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c +index 2f8626c3824d6b..98614d0b390b8c 100644 +--- a/drivers/net/gtp.c ++++ b/drivers/net/gtp.c +@@ -669,8 +669,9 @@ static int gtp1u_send_echo_resp(struct gtp_dev *gtp, struct sk_buff *skb) + return -1; + + /* pull GTP and UDP headers */ +- skb_pull_data(skb, +- sizeof(struct gtp1_header_long) + sizeof(struct udphdr)); ++ if (!skb_pull_data(skb, sizeof(struct gtp1_header_long) + ++ sizeof(struct udphdr))) ++ return -1; + + gtp_pkt = skb_push(skb, sizeof(struct gtp1u_packet)); + memset(gtp_pkt, 0, sizeof(struct gtp1u_packet)); +@@ -826,13 +827,17 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb) + if (!pskb_may_pull(skb, hdrlen)) + return -1; + ++ gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr)); ++ ++ if (gtp1->flags & GTP1_F_EXTHDR && ++ gtp_parse_exthdrs(skb, &hdrlen) < 0) ++ return -1; ++ + if (gtp_inner_proto(skb, hdrlen, &inner_proto) < 0) { + netdev_dbg(gtp->dev, "GTP packet does not encapsulate an IP packet\n"); + return -1; + } + +- gtp1 = (struct gtp1_header *)(skb->data + sizeof(struct udphdr)); +- + pctx = gtp1_pdp_find(gtp, ntohl(gtp1->tid), + gtp_proto_to_family(inner_proto)); + if (!pctx) { +@@ -840,10 +845,6 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb) + return 1; + } + +- if (gtp1->flags & GTP1_F_EXTHDR && +- gtp_parse_exthdrs(skb, &hdrlen) < 0) +- return -1; +- + return gtp_rx(pctx, skb, hdrlen, gtp->role, inner_proto); + } + +diff --git a/drivers/net/ipa/ipa_smp2p.c b/drivers/net/ipa/ipa_smp2p.c +index fcaadd111a8a30..0c184f6f91c6f2 100644 +--- a/drivers/net/ipa/ipa_smp2p.c ++++ b/drivers/net/ipa/ipa_smp2p.c +@@ -234,19 +234,27 @@ ipa_smp2p_init(struct ipa *ipa, struct platform_device *pdev, bool modem_init) + &valid_bit); + if (IS_ERR(valid_state)) + return PTR_ERR(valid_state); +- if (valid_bit >= 32) /* BITS_PER_U32 */ +- return -EINVAL; ++ if (valid_bit >= 32) { /* BITS_PER_U32 */ ++ ret = -EINVAL; ++ goto err_valid_state_put; ++ } + + enabled_state = qcom_smem_state_get(dev, "ipa-clock-enabled", + &enabled_bit); +- if (IS_ERR(enabled_state)) +- return PTR_ERR(enabled_state); +- if (enabled_bit >= 32) /* BITS_PER_U32 */ +- return -EINVAL; ++ if (IS_ERR(enabled_state)) { ++ ret = PTR_ERR(enabled_state); ++ goto err_valid_state_put; ++ } ++ if (enabled_bit >= 32) { /* BITS_PER_U32 */ ++ ret = -EINVAL; ++ goto err_enabled_state_put; ++ } + + smp2p = kzalloc(sizeof(*smp2p), GFP_KERNEL); +- if (!smp2p) +- return -ENOMEM; ++ if (!smp2p) { ++ ret = -ENOMEM; ++ goto err_enabled_state_put; ++ } + + smp2p->ipa = ipa; + +@@ -291,6 +299,10 @@ err_null_smp2p: + ipa->smp2p = NULL; + mutex_destroy(&smp2p->mutex); + kfree(smp2p); ++err_enabled_state_put: ++ qcom_smem_state_put(enabled_state); ++err_valid_state_put: ++ qcom_smem_state_put(valid_state); + + return ret; + } +@@ -307,6 +319,8 @@ void ipa_smp2p_exit(struct ipa *ipa) + ipa_smp2p_power_release(ipa); + ipa->smp2p = NULL; + mutex_destroy(&smp2p->mutex); ++ qcom_smem_state_put(smp2p->enabled_state); ++ qcom_smem_state_put(smp2p->valid_state); + kfree(smp2p); + } + +diff --git a/drivers/net/mctp/mctp-i3c.c b/drivers/net/mctp/mctp-i3c.c +index c678f79aa35611..c5d0bc517fea99 100644 +--- a/drivers/net/mctp/mctp-i3c.c ++++ b/drivers/net/mctp/mctp-i3c.c +@@ -731,18 +731,21 @@ static __init int mctp_i3c_mod_init(void) + int rc; + + rc = i3c_register_notifier(&mctp_i3c_notifier); +- if (rc < 0) { +- i3c_driver_unregister(&mctp_i3c_driver); ++ if (rc < 0) + return rc; +- } + + i3c_for_each_bus_locked(mctp_i3c_bus_add_new, NULL); + + rc = i3c_driver_register(&mctp_i3c_driver); + if (rc < 0) +- return rc; ++ goto err_unregister_notifier; + + return 0; ++ ++err_unregister_notifier: ++ i3c_unregister_notifier(&mctp_i3c_notifier); ++ mctp_i3c_bus_remove_all(); ++ return rc; + } + + static __exit void mctp_i3c_mod_exit(void) +diff --git a/drivers/net/mctp/mctp-serial.c b/drivers/net/mctp/mctp-serial.c +index 26c9a33fd63648..a5070ffa9a9559 100644 +--- a/drivers/net/mctp/mctp-serial.c ++++ b/drivers/net/mctp/mctp-serial.c +@@ -318,7 +318,7 @@ static void mctp_serial_push_header(struct mctp_serial *dev, u8 c) + } else { + dev->rxlen = c; + dev->rxpos = 0; +- dev->rxstate = STATE_DATA; ++ dev->rxstate = c > 0 ? STATE_DATA : STATE_TRAILER; + dev->rxfcs = crc_ccitt_byte(dev->rxfcs, c); + } + break; +diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c +index c03e58e28a860d..0008a3d30c198b 100644 +--- a/drivers/net/ovpn/io.c ++++ b/drivers/net/ovpn/io.c +@@ -137,7 +137,7 @@ void ovpn_decrypt_post(void *data, int ret) + } + + /* keep track of last received authenticated packet for keepalive */ +- WRITE_ONCE(peer->last_recv, ktime_get_real_seconds()); ++ WRITE_ONCE(peer->last_recv, ktime_get_boottime_seconds()); + + rcu_read_lock(); + sock = rcu_dereference(peer->sock); +@@ -291,7 +291,7 @@ void ovpn_encrypt_post(void *data, int ret) + + ovpn_peer_stats_increment_tx(&peer->link_stats, orig_len); + /* keep track of last sent packet for keepalive */ +- WRITE_ONCE(peer->last_sent, ktime_get_real_seconds()); ++ WRITE_ONCE(peer->last_sent, ktime_get_boottime_seconds()); + /* skb passed down the stack - don't free it */ + skb = NULL; + err_unlock: +diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c +index 87a83321f1dd5f..85fa9bd475f45a 100644 +--- a/drivers/net/ovpn/peer.c ++++ b/drivers/net/ovpn/peer.c +@@ -26,11 +26,12 @@ static void unlock_ovpn(struct ovpn_priv *ovpn, + struct llist_head *release_list) + __releases(&ovpn->lock) + { +- struct ovpn_peer *peer; ++ struct ovpn_peer *peer, *next; + + spin_unlock_bh(&ovpn->lock); + +- llist_for_each_entry(peer, release_list->first, release_entry) { ++ llist_for_each_entry_safe(peer, next, release_list->first, ++ release_entry) { + ovpn_socket_release(peer); + ovpn_peer_put(peer); + } +@@ -44,7 +45,7 @@ static void unlock_ovpn(struct ovpn_priv *ovpn, + */ + void ovpn_peer_keepalive_set(struct ovpn_peer *peer, u32 interval, u32 timeout) + { +- time64_t now = ktime_get_real_seconds(); ++ time64_t now = ktime_get_boottime_seconds(); + + netdev_dbg(peer->ovpn->dev, + "scheduling keepalive for peer %u: interval=%u timeout=%u\n", +@@ -1162,7 +1163,6 @@ static void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, struct sock *sk, + ovpn_sock = rcu_access_pointer(peer->sock); + if (!ovpn_sock || ovpn_sock->sk != sk) { + spin_unlock_bh(&ovpn->lock); +- ovpn_peer_put(peer); + return; + } + } +@@ -1280,8 +1280,10 @@ static time64_t ovpn_peer_keepalive_work_single(struct ovpn_peer *peer, + netdev_dbg(peer->ovpn->dev, + "sending keepalive to peer %u\n", + peer->id); +- if (schedule_work(&peer->keepalive_work)) +- ovpn_peer_hold(peer); ++ if (WARN_ON(!ovpn_peer_hold(peer))) ++ return 0; ++ if (!schedule_work(&peer->keepalive_work)) ++ ovpn_peer_put(peer); + } + + if (next_run1 < next_run2) +@@ -1352,7 +1354,7 @@ void ovpn_peer_keepalive_work(struct work_struct *work) + { + struct ovpn_priv *ovpn = container_of(work, struct ovpn_priv, + keepalive_work.work); +- time64_t next_run = 0, now = ktime_get_real_seconds(); ++ time64_t next_run = 0, now = ktime_get_boottime_seconds(); + LLIST_HEAD(release_list); + + spin_lock_bh(&ovpn->lock); +diff --git a/drivers/net/ovpn/tcp.c b/drivers/net/ovpn/tcp.c +index 433bd07a4f1be9..0af14055c39aad 100644 +--- a/drivers/net/ovpn/tcp.c ++++ b/drivers/net/ovpn/tcp.c +@@ -151,7 +151,8 @@ err: + /* take reference for deferred peer deletion. should never fail */ + if (WARN_ON(!ovpn_peer_hold(peer))) + goto err_nopeer; +- schedule_work(&peer->tcp.defer_del_work); ++ if (!schedule_work(&peer->tcp.defer_del_work)) ++ ovpn_peer_put(peer); + ovpn_dev_dstats_rx_dropped(peer->ovpn->dev); + err_nopeer: + kfree_skb(skb); +@@ -283,7 +284,8 @@ static void ovpn_tcp_send_sock(struct ovpn_peer *peer, struct sock *sk) + * stream therefore we abort the connection + */ + ovpn_peer_hold(peer); +- schedule_work(&peer->tcp.defer_del_work); ++ if (!schedule_work(&peer->tcp.defer_del_work)) ++ ovpn_peer_put(peer); + + /* we bail out immediately and keep tx_in_progress set + * to true. This way we prevent more TX attempts +diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c +index 3d1bd5aac09376..14c4b10fee74c6 100644 +--- a/drivers/net/pcs/pcs-xpcs.c ++++ b/drivers/net/pcs/pcs-xpcs.c +@@ -958,6 +958,7 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs, + + /* Reset link_state */ + state->link = false; ++ state->an_complete = false; + state->speed = SPEED_UNKNOWN; + state->duplex = DUPLEX_UNKNOWN; + state->pause = 0; +@@ -969,6 +970,8 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs, + if (ret < 0) + return ret; + ++ state->an_complete = ret & DW_VR_MII_AN_STS_C37_ANCMPLT_INTR; ++ + if (ret & DW_VR_MII_C37_ANSGM_SP_LNKSTS) { + int speed_value; + +@@ -986,34 +989,13 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs, + state->duplex = DUPLEX_FULL; + else + state->duplex = DUPLEX_HALF; +- } else if (ret == DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) { +- int speed, duplex; +- +- state->link = true; +- +- speed = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMCR); +- if (speed < 0) +- return speed; +- +- speed &= BMCR_SPEED100 | BMCR_SPEED1000; +- if (speed == BMCR_SPEED1000) +- state->speed = SPEED_1000; +- else if (speed == BMCR_SPEED100) +- state->speed = SPEED_100; +- else if (speed == 0) +- state->speed = SPEED_10; +- +- duplex = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_ADVERTISE); +- if (duplex < 0) +- return duplex; + +- if (duplex & ADVERTISE_1000XFULL) +- state->duplex = DUPLEX_FULL; +- else if (duplex & ADVERTISE_1000XHALF) +- state->duplex = DUPLEX_HALF; ++ return 0; ++ } + ++ /* Clear AN complete status or interrupt */ ++ if (state->an_complete) + xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0); +- } + + return 0; + } +diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c +index c248c90510ae51..f191b8c4321887 100644 +--- a/drivers/net/phy/marvell.c ++++ b/drivers/net/phy/marvell.c +@@ -753,7 +753,7 @@ static int m88e1111_config_inband(struct phy_device *phydev, unsigned int modes) + err = phy_modify(phydev, MII_M1111_PHY_EXT_SR, + MII_M1111_HWCFG_SERIAL_AN_BYPASS, extsr); + if (err < 0) +- return extsr; ++ return err; + + return phy_modify_paged(phydev, MII_MARVELL_FIBER_PAGE, MII_BMCR, + BMCR_ANENABLE, bmcr); +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index 507d216256c0dd..14fa87a8e08345 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -134,7 +134,6 @@ struct ppp { + int debug; /* debug flags 70 */ + struct slcompress *vj; /* state for VJ header compression */ + enum NPmode npmode[NUM_NP]; /* what to do with each net proto 78 */ +- struct sk_buff *xmit_pending; /* a packet ready to go out 88 */ + struct compressor *xcomp; /* transmit packet compressor 8c */ + void *xc_state; /* its internal state 90 */ + struct compressor *rcomp; /* receive decompressor 94 */ +@@ -185,6 +184,7 @@ struct channel { + struct list_head clist; /* link in list of channels per unit */ + spinlock_t upl; /* protects `ppp' and 'bridge' */ + struct channel __rcu *bridge; /* "bridged" ppp channel */ ++ struct rcu_head rcu; /* for RCU-deferred free of the channel */ + #ifdef CONFIG_PPP_MULTILINK + u8 avail; /* flag used in multilink stuff */ + u8 had_frag; /* >= 1 fragments have been sent */ +@@ -264,8 +264,8 @@ struct ppp_net { + static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, + struct file *file, unsigned int cmd, unsigned long arg); + static void ppp_xmit_process(struct ppp *ppp, struct sk_buff *skb); +-static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb); +-static void ppp_push(struct ppp *ppp); ++static int ppp_prepare_tx_skb(struct ppp *ppp, struct sk_buff **pskb); ++static int ppp_push(struct ppp *ppp, struct sk_buff *skb); + static void ppp_channel_push(struct channel *pch); + static void ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, + struct channel *pch); +@@ -818,7 +818,9 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + case PPPIOCSMRU: + if (get_user(val, p)) + break; ++ ppp_recv_lock(ppp); + ppp->mru = val; ++ ppp_recv_unlock(ppp); + err = 0; + break; + +@@ -839,7 +841,9 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + break; + + case PPPIOCGFLAGS: ++ ppp_lock(ppp); + val = ppp->flags | ppp->xstate | ppp->rstate; ++ ppp_unlock(ppp); + if (put_user(val, p)) + break; + err = 0; +@@ -863,7 +867,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + case PPPIOCSDEBUG: + if (get_user(val, p)) + break; +- ppp->debug = val; ++ WRITE_ONCE(ppp->debug, val); + err = 0; + break; + +@@ -874,16 +878,16 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + break; + + case PPPIOCGIDLE32: +- idle32.xmit_idle = (jiffies - ppp->last_xmit) / HZ; +- idle32.recv_idle = (jiffies - ppp->last_recv) / HZ; +- if (copy_to_user(argp, &idle32, sizeof(idle32))) ++ idle32.xmit_idle = max(0L, (long)(jiffies - READ_ONCE(ppp->last_xmit))) / HZ; ++ idle32.recv_idle = max(0L, (long)(jiffies - READ_ONCE(ppp->last_recv))) / HZ; ++ if (copy_to_user(argp, &idle32, sizeof(idle32))) + break; + err = 0; + break; + + case PPPIOCGIDLE64: +- idle64.xmit_idle = (jiffies - ppp->last_xmit) / HZ; +- idle64.recv_idle = (jiffies - ppp->last_recv) / HZ; ++ idle64.xmit_idle = max(0L, (long)(jiffies - READ_ONCE(ppp->last_xmit))) / HZ; ++ idle64.recv_idle = max(0L, (long)(jiffies - READ_ONCE(ppp->last_recv))) / HZ; + if (copy_to_user(argp, &idle64, sizeof(idle64))) + break; + err = 0; +@@ -924,7 +928,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + if (copy_to_user(argp, &npi, sizeof(npi))) + break; + } else { +- ppp->npmode[i] = npi.mode; ++ WRITE_ONCE(ppp->npmode[i], npi.mode); + /* we may be able to transmit more packets now (??) */ + netif_wake_queue(ppp->dev); + } +@@ -1462,7 +1466,7 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) + goto outf; + + /* Drop, accept or reject the packet */ +- switch (ppp->npmode[npi]) { ++ switch (READ_ONCE(ppp->npmode[npi])) { + case NPMODE_PASS: + break; + case NPMODE_QUEUE: +@@ -1490,7 +1494,7 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) + + outf: + kfree_skb(skb); +- ++dev->stats.tx_dropped; ++ DEV_STATS_INC(dev, tx_dropped); + return NETDEV_TX_OK; + } + +@@ -1540,11 +1544,11 @@ ppp_net_siocdevprivate(struct net_device *dev, struct ifreq *ifr, + static void + ppp_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats64) + { +- stats64->rx_errors = dev->stats.rx_errors; +- stats64->tx_errors = dev->stats.tx_errors; +- stats64->rx_dropped = dev->stats.rx_dropped; +- stats64->tx_dropped = dev->stats.tx_dropped; +- stats64->rx_length_errors = dev->stats.rx_length_errors; ++ stats64->rx_errors = DEV_STATS_READ(dev, rx_errors); ++ stats64->tx_errors = DEV_STATS_READ(dev, tx_errors); ++ stats64->rx_dropped = DEV_STATS_READ(dev, rx_dropped); ++ stats64->tx_dropped = DEV_STATS_READ(dev, tx_dropped); ++ stats64->rx_length_errors = DEV_STATS_READ(dev, rx_length_errors); + dev_fetch_sw_netstats(stats64, dev->tstats); + } + +@@ -1644,6 +1648,8 @@ static void ppp_setup(struct net_device *dev) + dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; + dev->priv_destructor = ppp_dev_priv_destructor; + dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; ++ dev->features = NETIF_F_SG | NETIF_F_FRAGLIST; ++ dev->hw_features = dev->features; + netif_keep_dst(dev); + } + +@@ -1652,26 +1658,44 @@ static void ppp_setup(struct net_device *dev) + */ + + /* Called to do any work queued up on the transmit side that can now be done */ ++static void ppp_xmit_flush(struct ppp *ppp) ++{ ++ struct sk_buff *skb; ++ ++ while ((skb = skb_dequeue(&ppp->file.xq))) { ++ if (unlikely(!ppp_push(ppp, skb))) { ++ skb_queue_head(&ppp->file.xq, skb); ++ return; ++ } ++ } ++ /* If there's no work left to do, tell the core net code that we can ++ * accept some more. ++ */ ++ netif_wake_queue(ppp->dev); ++} ++ + static void __ppp_xmit_process(struct ppp *ppp, struct sk_buff *skb) + { + ppp_xmit_lock(ppp); +- if (!ppp->closing) { +- ppp_push(ppp); +- +- if (skb) ++ if (unlikely(ppp->closing)) { ++ kfree_skb(skb); ++ goto out; ++ } ++ if (unlikely(ppp_prepare_tx_skb(ppp, &skb))) ++ goto out; ++ /* Fastpath: No backlog, just send the new skb. */ ++ if (likely(skb_queue_empty(&ppp->file.xq))) { ++ if (unlikely(!ppp_push(ppp, skb))) { + skb_queue_tail(&ppp->file.xq, skb); +- while (!ppp->xmit_pending && +- (skb = skb_dequeue(&ppp->file.xq))) +- ppp_send_frame(ppp, skb); +- /* If there's no work left to do, tell the core net +- code that we can accept some more. */ +- if (!ppp->xmit_pending && !skb_peek(&ppp->file.xq)) +- netif_wake_queue(ppp->dev); +- else + netif_stop_queue(ppp->dev); +- } else { +- kfree_skb(skb); ++ } ++ goto out; + } ++ ++ /* Slowpath: Enqueue the new skb and process backlog */ ++ skb_queue_tail(&ppp->file.xq, skb); ++ ppp_xmit_flush(ppp); ++out: + ppp_xmit_unlock(ppp); + } + +@@ -1713,6 +1737,10 @@ pad_compress_skb(struct ppp *ppp, struct sk_buff *skb) + ppp->xcomp->comp_extra + ppp->dev->hard_header_len; + int compressor_skb_size = ppp->dev->mtu + + ppp->xcomp->comp_extra + PPP_HDRLEN; ++ ++ if (skb_linearize(skb)) ++ return NULL; ++ + new_skb = alloc_skb(new_skb_size, GFP_ATOMIC); + if (!new_skb) { + if (net_ratelimit()) +@@ -1754,13 +1782,15 @@ pad_compress_skb(struct ppp *ppp, struct sk_buff *skb) + } + + /* +- * Compress and send a frame. +- * The caller should have locked the xmit path, +- * and xmit_pending should be 0. ++ * Compress and prepare to send a frame. ++ * The caller should have locked the xmit path. ++ * Returns 1 if the skb was consumed, 0 if it can be passed to ppp_push(). ++ * @pskb is updated if a compressor is in use. + */ +-static void +-ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) ++static int ++ppp_prepare_tx_skb(struct ppp *ppp, struct sk_buff **pskb) + { ++ struct sk_buff *skb = *pskb; + int proto = PPP_PROTO(skb); + struct sk_buff *new_skb; + int len; +@@ -1776,21 +1806,21 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) + *(__be16 *)skb_push(skb, 2) = htons(PPP_FILTER_OUTBOUND_TAG); + if (ppp->pass_filter && + bpf_prog_run(ppp->pass_filter, skb) == 0) { +- if (ppp->debug & 1) ++ if (READ_ONCE(ppp->debug) & 1) + netdev_printk(KERN_DEBUG, ppp->dev, + "PPP: outbound frame " + "not passed\n"); + kfree_skb(skb); +- return; ++ return 1; + } + /* if this packet passes the active filter, record the time */ + if (!(ppp->active_filter && + bpf_prog_run(ppp->active_filter, skb) == 0)) +- ppp->last_xmit = jiffies; ++ WRITE_ONCE(ppp->last_xmit, jiffies); + skb_pull(skb, 2); + #else + /* for data packets, record the time */ +- ppp->last_xmit = jiffies; ++ WRITE_ONCE(ppp->last_xmit, jiffies); + #endif /* CONFIG_PPP_FILTER */ + } + +@@ -1800,6 +1830,10 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) + case PPP_IP: + if (!ppp->vj || (ppp->flags & SC_COMP_TCP) == 0) + break; ++ ++ if (skb_linearize(skb)) ++ goto drop; ++ + /* try to do VJ TCP header compression */ + new_skb = alloc_skb(skb->len + ppp->dev->hard_header_len - 2, + GFP_ATOMIC); +@@ -1825,6 +1859,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) + } + consume_skb(skb); + skb = new_skb; ++ *pskb = skb; + cp = skb_put(skb, len + 2); + cp[0] = 0; + cp[1] = proto; +@@ -1851,6 +1886,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) + if (!new_skb) + goto drop; + skb = new_skb; ++ *pskb = skb; + } + + /* +@@ -1862,67 +1898,69 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) + goto drop; + skb_queue_tail(&ppp->file.rq, skb); + wake_up_interruptible(&ppp->file.rwait); +- return; ++ return 1; + } + +- ppp->xmit_pending = skb; +- ppp_push(ppp); +- return; ++ return 0; + + drop: + kfree_skb(skb); +- ++ppp->dev->stats.tx_errors; ++ DEV_STATS_INC(ppp->dev, tx_errors); ++ return 1; + } + + /* +- * Try to send the frame in xmit_pending. ++ * Try to send the frame. + * The caller should have the xmit path locked. ++ * Returns 1 if the skb was consumed, 0 if not. + */ +-static void +-ppp_push(struct ppp *ppp) ++static int ++ppp_push(struct ppp *ppp, struct sk_buff *skb) + { + struct list_head *list; + struct channel *pch; +- struct sk_buff *skb = ppp->xmit_pending; +- +- if (!skb) +- return; + + list = &ppp->channels; + if (list_empty(list)) { + /* nowhere to send the packet, just drop it */ +- ppp->xmit_pending = NULL; + kfree_skb(skb); +- return; ++ return 1; + } + + if ((ppp->flags & SC_MULTILINK) == 0) { ++ struct ppp_channel *chan; ++ int ret; + /* not doing multilink: send it down the first channel */ + list = list->next; + pch = list_entry(list, struct channel, clist); + + spin_lock(&pch->downl); +- if (pch->chan) { +- if (pch->chan->ops->start_xmit(pch->chan, skb)) +- ppp->xmit_pending = NULL; +- } else { +- /* channel got unregistered */ ++ chan = pch->chan; ++ if (unlikely(!chan || (!chan->direct_xmit && skb_linearize(skb)))) { ++ /* channel got unregistered, or it requires a linear ++ * skb but linearization failed ++ */ + kfree_skb(skb); +- ppp->xmit_pending = NULL; ++ ret = 1; ++ goto out; + } ++ ++ ret = chan->ops->start_xmit(chan, skb); ++ ++out: + spin_unlock(&pch->downl); +- return; ++ return ret; + } + + #ifdef CONFIG_PPP_MULTILINK + /* Multilink: fragment the packet over as many links + as can take the packet at the moment. */ + if (!ppp_mp_explode(ppp, skb)) +- return; ++ return 0; + #endif /* CONFIG_PPP_MULTILINK */ + +- ppp->xmit_pending = NULL; + kfree_skb(skb); ++ return 1; + } + + #ifdef CONFIG_PPP_MULTILINK +@@ -1991,9 +2029,11 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) + * performance if we have a lot of channels. + */ + if (nfree == 0 || nfree < navail / 2) +- return 0; /* can't take now, leave it in xmit_pending */ ++ return 0; /* can't take now, leave it in transmit queue */ + + /* Do protocol field compression */ ++ if (skb_linearize(skb)) ++ goto err_linearize; + p = skb->data; + len = skb->len; + if (*p == 0 && mp_protocol_compress) { +@@ -2152,9 +2192,10 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) + + noskb: + spin_unlock(&pch->downl); +- if (ppp->debug & 1) ++ err_linearize: ++ if (READ_ONCE(ppp->debug) & 1) + netdev_err(ppp->dev, "PPP: no memory (fragment)\n"); +- ++ppp->dev->stats.tx_errors; ++ DEV_STATS_INC(ppp->dev, tx_errors); + ++ppp->nxseq; + return 1; /* abandon the frame */ + } +@@ -2182,8 +2223,12 @@ static void __ppp_channel_push(struct channel *pch, struct ppp *ppp) + spin_unlock(&pch->downl); + /* see if there is anything from the attached unit to be sent */ + if (skb_queue_empty(&pch->file.xq)) { +- if (ppp) +- __ppp_xmit_process(ppp, NULL); ++ if (ppp) { ++ ppp_xmit_lock(ppp); ++ if (!ppp->closing) ++ ppp_xmit_flush(ppp); ++ ppp_xmit_unlock(ppp); ++ } + } + } + +@@ -2323,7 +2368,7 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb) + if (!ppp_decompress_proto(skb)) { + kfree_skb(skb); + if (ppp) { +- ++ppp->dev->stats.rx_length_errors; ++ DEV_STATS_INC(ppp->dev, rx_length_errors); + ppp_receive_error(ppp); + } + goto done; +@@ -2396,7 +2441,7 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) + static void + ppp_receive_error(struct ppp *ppp) + { +- ++ppp->dev->stats.rx_errors; ++ DEV_STATS_INC(ppp->dev, rx_errors); + if (ppp->vj) + slhc_toss(ppp->vj); + } +@@ -2507,7 +2552,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) + *(__be16 *)skb_push(skb, 2) = htons(PPP_FILTER_INBOUND_TAG); + if (ppp->pass_filter && + bpf_prog_run(ppp->pass_filter, skb) == 0) { +- if (ppp->debug & 1) ++ if (READ_ONCE(ppp->debug) & 1) + netdev_printk(KERN_DEBUG, ppp->dev, + "PPP: inbound frame " + "not passed\n"); +@@ -2516,14 +2561,14 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) + } + if (!(ppp->active_filter && + bpf_prog_run(ppp->active_filter, skb) == 0)) +- ppp->last_recv = jiffies; ++ WRITE_ONCE(ppp->last_recv, jiffies); + __skb_pull(skb, 2); + } else + #endif /* CONFIG_PPP_FILTER */ +- ppp->last_recv = jiffies; ++ WRITE_ONCE(ppp->last_recv, jiffies); + + if ((ppp->dev->flags & IFF_UP) == 0 || +- ppp->npmode[npi] != NPMODE_PASS) { ++ READ_ONCE(ppp->npmode[npi]) != NPMODE_PASS) { + kfree_skb(skb); + } else { + /* chop off protocol */ +@@ -2663,7 +2708,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) + */ + if (seq_before(seq, ppp->nextseq)) { + kfree_skb(skb); +- ++ppp->dev->stats.rx_dropped; ++ DEV_STATS_INC(ppp->dev, rx_dropped); + ppp_receive_error(ppp); + return; + } +@@ -2699,7 +2744,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) + if (pskb_may_pull(skb, 2)) + ppp_receive_nonmp_frame(ppp, skb); + else { +- ++ppp->dev->stats.rx_length_errors; ++ DEV_STATS_INC(ppp->dev, rx_length_errors); + kfree_skb(skb); + ppp_receive_error(ppp); + } +@@ -2776,7 +2821,7 @@ ppp_mp_reconstruct(struct ppp *ppp) + seq = seq_before(minseq, PPP_MP_CB(p)->sequence)? + minseq + 1: PPP_MP_CB(p)->sequence; + +- if (ppp->debug & 1) ++ if (READ_ONCE(ppp->debug) & 1) + netdev_printk(KERN_DEBUG, ppp->dev, + "lost frag %u..%u\n", + oldseq, seq-1); +@@ -2805,7 +2850,7 @@ ppp_mp_reconstruct(struct ppp *ppp) + if (lost == 0 && (PPP_MP_CB(p)->BEbits & E) && + (PPP_MP_CB(head)->BEbits & B)) { + if (len > ppp->mrru + 2) { +- ++ppp->dev->stats.rx_length_errors; ++ DEV_STATS_INC(ppp->dev, rx_length_errors); + netdev_printk(KERN_DEBUG, ppp->dev, + "PPP: reconstructed packet" + " is too long (%d)\n", len); +@@ -2825,7 +2870,7 @@ ppp_mp_reconstruct(struct ppp *ppp) + struct sk_buff *tmp2; + + skb_queue_reverse_walk_from_safe(list, p, tmp2) { +- if (ppp->debug & 1) ++ if (READ_ONCE(ppp->debug) & 1) + netdev_printk(KERN_DEBUG, ppp->dev, + "discarding frag %u\n", + PPP_MP_CB(p)->sequence); +@@ -2847,7 +2892,7 @@ ppp_mp_reconstruct(struct ppp *ppp) + skb_queue_walk_safe(list, p, tmp) { + if (p == head) + break; +- if (ppp->debug & 1) ++ if (READ_ONCE(ppp->debug) & 1) + netdev_printk(KERN_DEBUG, ppp->dev, + "discarding frag %u\n", + PPP_MP_CB(p)->sequence); +@@ -2855,12 +2900,12 @@ ppp_mp_reconstruct(struct ppp *ppp) + kfree_skb(p); + } + +- if (ppp->debug & 1) ++ if (READ_ONCE(ppp->debug) & 1) + netdev_printk(KERN_DEBUG, ppp->dev, + " missed pkts %u..%u\n", + ppp->nextseq, + PPP_MP_CB(head)->sequence-1); +- ++ppp->dev->stats.rx_dropped; ++ DEV_STATS_INC(ppp->dev, rx_dropped); + ppp_receive_error(ppp); + } + +@@ -3168,7 +3213,8 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound) + if (!ppp->rc_state) + break; + if (ppp->rcomp->decomp_init(ppp->rc_state, dp, len, +- ppp->file.index, 0, ppp->mru, ppp->debug)) { ++ ppp->file.index, 0, ppp->mru, ++ READ_ONCE(ppp->debug))) { + ppp->rstate |= SC_DECOMP_RUN; + ppp->rstate &= ~(SC_DC_ERROR | SC_DC_FERROR); + } +@@ -3177,7 +3223,8 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound) + if (!ppp->xc_state) + break; + if (ppp->xcomp->comp_init(ppp->xc_state, dp, len, +- ppp->file.index, 0, ppp->debug)) ++ ppp->file.index, 0, ++ READ_ONCE(ppp->debug))) + ppp->xstate |= SC_COMP_RUN; + } + break; +@@ -3329,8 +3376,8 @@ ppp_get_stats(struct ppp *ppp, struct ppp_stats *st) + st->p.ppp_opackets += tx_packets; + st->p.ppp_obytes += tx_bytes; + } +- st->p.ppp_ierrors = ppp->dev->stats.rx_errors; +- st->p.ppp_oerrors = ppp->dev->stats.tx_errors; ++ st->p.ppp_ierrors = DEV_STATS_READ(ppp->dev, rx_errors); ++ st->p.ppp_oerrors = DEV_STATS_READ(ppp->dev, tx_errors); + if (!vj) + return; + st->vj.vjs_packets = vj->sls_o_compressed + vj->sls_o_uncompressed; +@@ -3443,7 +3490,6 @@ static void ppp_destroy_interface(struct ppp *ppp) + } + #endif /* CONFIG_PPP_FILTER */ + +- kfree_skb(ppp->xmit_pending); + free_percpu(ppp->xmit_recursion); + + free_netdev(ppp->dev); +@@ -3570,6 +3616,18 @@ ppp_disconnect_channel(struct channel *pch) + return err; + } + ++/* Purge after the grace period: a late ppp_input() may still queue an ++ * skb on pch->file.rq before the last RCU reader drains. ++ */ ++static void ppp_release_channel_free(struct rcu_head *rcu) ++{ ++ struct channel *pch = container_of(rcu, struct channel, rcu); ++ ++ skb_queue_purge(&pch->file.xq); ++ skb_queue_purge(&pch->file.rq); ++ kfree(pch); ++} ++ + /* + * Free up the resources used by a ppp channel. + */ +@@ -3585,9 +3643,7 @@ static void ppp_destroy_channel(struct channel *pch) + pr_err("ppp: destroying undead channel %p !\n", pch); + return; + } +- skb_queue_purge(&pch->file.xq); +- skb_queue_purge(&pch->file.rq); +- kfree(pch); ++ call_rcu(&pch->rcu, ppp_release_channel_free); + } + + static void __exit ppp_cleanup(void) +@@ -3600,6 +3656,7 @@ static void __exit ppp_cleanup(void) + device_destroy(&ppp_class, MKDEV(PPP_MAJOR, 0)); + class_unregister(&ppp_class); + unregister_pernet_device(&ppp_net_ops); ++ rcu_barrier(); /* wait for RCU callbacks before module unload */ + } + + /* +diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c +index dc6d1394323878..7ee63051a16193 100644 +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -903,6 +903,7 @@ static int pppoe_sendmsg(struct socket *sock, struct msghdr *m, + dev_hard_header(skb, dev, ETH_P_PPP_SES, + po->pppoe_pa.remote, NULL, total_len); + ++ ph = pppoe_hdr(skb); + memcpy(ph, &hdr, sizeof(struct pppoe_hdr)); + + ph->length = htons(total_len); +diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c +index c889fb3747030b..bc84e2cc050222 100644 +--- a/drivers/net/slip/slip.c ++++ b/drivers/net/slip/slip.c +@@ -693,6 +693,8 @@ static void slip_receive_buf(struct tty_struct *tty, const u8 *cp, const u8 *fp, + if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev)) + return; + ++ spin_lock_bh(&sl->lock); ++ + /* Read the characters out of the buffer */ + while (count--) { + if (fp && *fp++) { +@@ -708,6 +710,8 @@ static void slip_receive_buf(struct tty_struct *tty, const u8 *cp, const u8 *fp, + #endif + slip_unesc(sl, *cp++); + } ++ ++ spin_unlock_bh(&sl->lock); + } + + /************************************ +diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c +index 0572f6a9bdb628..679208d587f853 100644 +--- a/drivers/net/vmxnet3/vmxnet3_drv.c ++++ b/drivers/net/vmxnet3/vmxnet3_drv.c +@@ -1530,7 +1530,11 @@ vmxnet3_get_hdr_len(struct vmxnet3_adapter *adapter, struct sk_buff *skb, + struct ipv6hdr *ipv6; + struct tcphdr *tcp; + } hdr; +- BUG_ON(gdesc->rcd.tcp == 0); ++ ++ /* v4/v6/tcp then describe the inner header, which we can't locate. */ ++ if ((le32_to_cpu(gdesc->dword[0]) & (1UL << VMXNET3_RCD_HDR_INNER_SHIFT)) || ++ gdesc->rcd.tcp == 0) ++ return 0; + + maplen = skb_headlen(skb); + if (unlikely(sizeof(struct iphdr) + sizeof(struct tcphdr) > maplen)) +@@ -1544,15 +1548,21 @@ vmxnet3_get_hdr_len(struct vmxnet3_adapter *adapter, struct sk_buff *skb, + + hdr.eth = eth_hdr(skb); + if (gdesc->rcd.v4) { +- BUG_ON(hdr.eth->h_proto != htons(ETH_P_IP) && +- hdr.veth->h_vlan_encapsulated_proto != htons(ETH_P_IP)); ++ if (hdr.eth->h_proto != htons(ETH_P_IP) && ++ hdr.veth->h_vlan_encapsulated_proto != htons(ETH_P_IP)) ++ return 0; ++ + hdr.ptr += hlen; +- BUG_ON(hdr.ipv4->protocol != IPPROTO_TCP); ++ if (hdr.ipv4->protocol != IPPROTO_TCP) ++ return 0; ++ + hlen = hdr.ipv4->ihl << 2; + hdr.ptr += hdr.ipv4->ihl << 2; + } else if (gdesc->rcd.v6) { +- BUG_ON(hdr.eth->h_proto != htons(ETH_P_IPV6) && +- hdr.veth->h_vlan_encapsulated_proto != htons(ETH_P_IPV6)); ++ if (hdr.eth->h_proto != htons(ETH_P_IPV6) && ++ hdr.veth->h_vlan_encapsulated_proto != htons(ETH_P_IPV6)) ++ return 0; ++ + hdr.ptr += hlen; + /* Use an estimated value, since we also need to handle + * TSO case. +diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c +index b706e1777354c0..cb7b01e492fa1f 100644 +--- a/drivers/net/vxlan/vxlan_core.c ++++ b/drivers/net/vxlan/vxlan_core.c +@@ -4415,6 +4415,9 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], + struct vxlan_rdst *dst; + int err; + ++ if (!rtnl_dev_link_net_capable(dev, vxlan->net)) ++ return -EPERM; ++ + dst = &vxlan->default_dst; + err = vxlan_nl2conf(tb, data, dev, &conf, true, extack); + if (err) +diff --git a/drivers/net/vxlan/vxlan_mdb.c b/drivers/net/vxlan/vxlan_mdb.c +index 816ab1aa05262d..4e02a669d045ae 100644 +--- a/drivers/net/vxlan/vxlan_mdb.c ++++ b/drivers/net/vxlan/vxlan_mdb.c +@@ -42,6 +42,7 @@ struct vxlan_mdb_remote { + }; + + #define VXLAN_SGRP_F_DELETE BIT(0) ++#define VXLAN_SGRP_F_NEW BIT(1) + + struct vxlan_mdb_src_entry { + struct hlist_node node; +@@ -844,6 +845,7 @@ vxlan_mdb_remote_src_add(const struct vxlan_mdb_config *cfg, + ent = vxlan_mdb_remote_src_entry_add(remote, &src->addr); + if (!ent) + return -ENOMEM; ++ ent->flags |= VXLAN_SGRP_F_NEW; + } else if (!(cfg->nlflags & NLM_F_REPLACE)) { + NL_SET_ERR_MSG_MOD(extack, "Source entry already exists"); + return -EEXIST; +@@ -853,15 +855,16 @@ vxlan_mdb_remote_src_add(const struct vxlan_mdb_config *cfg, + if (err) + goto err_src_del; + +- /* Clear flags in case source entry was marked for deletion as part of +- * replace flow. ++ /* Clear the deletion mark so the entry survives the replace sweep. ++ * The new mark is retained until the whole operation succeeds. + */ +- ent->flags = 0; ++ ent->flags &= ~VXLAN_SGRP_F_DELETE; + + return 0; + + err_src_del: +- vxlan_mdb_remote_src_entry_del(ent); ++ if (ent->flags & VXLAN_SGRP_F_NEW) ++ vxlan_mdb_remote_src_entry_del(ent); + return err; + } + +@@ -889,11 +892,19 @@ static int vxlan_mdb_remote_srcs_add(const struct vxlan_mdb_config *cfg, + goto err_src_del; + } + ++ hlist_for_each_entry(ent, &remote->src_list, node) ++ ent->flags &= ~VXLAN_SGRP_F_NEW; ++ + return 0; + + err_src_del: +- hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node) +- vxlan_mdb_remote_src_del(cfg->vxlan, &cfg->group, remote, ent); ++ hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node) { ++ if (ent->flags & VXLAN_SGRP_F_NEW) ++ vxlan_mdb_remote_src_del(cfg->vxlan, &cfg->group, remote, ++ ent); ++ else ++ ent->flags &= ~VXLAN_SGRP_F_DELETE; ++ } + return err; + } + +@@ -1069,7 +1080,7 @@ vxlan_mdb_remote_srcs_replace(const struct vxlan_mdb_config *cfg, + + err = vxlan_mdb_remote_srcs_add(cfg, remote, extack); + if (err) +- goto err_clear_delete; ++ return err; + + hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node) { + if (ent->flags & VXLAN_SGRP_F_DELETE) +@@ -1078,11 +1089,6 @@ vxlan_mdb_remote_srcs_replace(const struct vxlan_mdb_config *cfg, + } + + return 0; +- +-err_clear_delete: +- hlist_for_each_entry(ent, &remote->src_list, node) +- ent->flags &= ~VXLAN_SGRP_F_DELETE; +- return err; + } + + static int vxlan_mdb_remote_replace(const struct vxlan_mdb_config *cfg, +diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c +index 5a9e262188efe1..c38dd741401e13 100644 +--- a/drivers/net/wan/wanxl.c ++++ b/drivers/net/wan/wanxl.c +@@ -514,7 +514,8 @@ static void wanxl_pci_remove_one(struct pci_dev *pdev) + if (card->irq) + free_irq(card->irq, card); + +- wanxl_reset(card); ++ if (card->plx) ++ wanxl_reset(card); + + for (i = 0; i < RX_QUEUE_LENGTH; i++) + if (card->rx_skbs[i]) { +diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c +index 8dfe9b40c12626..b8437e23e51921 100644 +--- a/drivers/net/wireless/ath/ath11k/ahb.c ++++ b/drivers/net/wireless/ath/ath11k/ahb.c +@@ -998,6 +998,7 @@ static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab) + ret = ath11k_ahb_setup_msa_resources(ab); + if (ret) { + ath11k_err(ab, "failed to setup msa resources\n"); ++ of_node_put(node); + return ret; + } + +diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c +index 5666f66474455a..330446f279cd6d 100644 +--- a/drivers/net/wireless/ath/ath11k/dp_rx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c +@@ -4609,6 +4609,9 @@ static void ath11k_hal_rx_msdu_list_get(struct ath11k *ar, + msdu_details = &msdu_link->msdu_link[0]; + + for (i = 0; i < HAL_RX_NUM_MSDU_DESC; i++) { ++ if (!i && FIELD_GET(BUFFER_ADDR_INFO0_ADDR, ++ msdu_details[i].buf_addr_info.info0) == 0) ++ break; + if (FIELD_GET(BUFFER_ADDR_INFO0_ADDR, + msdu_details[i].buf_addr_info.info0) == 0) { + msdu_desc_info = &msdu_details[i - 1].rx_msdu_info; +diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c +index 7114eca8810dbf..c7048219f3e08a 100644 +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -199,6 +199,8 @@ static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) + val |= PCIE_SOC_GLOBAL_RESET_V; + + ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val); ++ /* Flush the posted write to the device */ ++ ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET); + + /* TODO: exact time to sleep is uncertain */ + delay = 10; +@@ -208,6 +210,8 @@ static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) + val &= ~PCIE_SOC_GLOBAL_RESET_V; + + ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val); ++ /* Flush the posted write to the device */ ++ ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET); + + mdelay(delay); + +diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c +index aea56c38bf8f38..f23d75c8ad6794 100644 +--- a/drivers/net/wireless/ath/ath11k/qmi.c ++++ b/drivers/net/wireless/ath/ath11k/qmi.c +@@ -3295,9 +3295,14 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work) + clear_bit(ATH11K_FLAG_CRASH_FLUSH, + &ab->dev_flags); + clear_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags); +- ath11k_core_qmi_firmware_ready(ab); +- set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags); +- ++ if (!test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) { ++ ret = ath11k_core_qmi_firmware_ready(ab); ++ if (ret) { ++ set_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags); ++ break; ++ } ++ set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags); ++ } + break; + case ATH11K_QMI_EVENT_COLD_BOOT_CAL_DONE: + break; +diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c +index 60b8f7361b7f63..37f41635d3b00e 100644 +--- a/drivers/net/wireless/ath/ath12k/pci.c ++++ b/drivers/net/wireless/ath/ath12k/pci.c +@@ -240,6 +240,8 @@ static void ath12k_pci_soc_global_reset(struct ath12k_base *ab) + val |= PCIE_SOC_GLOBAL_RESET_V; + + ath12k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); ++ /* Flush the posted write to the device */ ++ ath12k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); + + /* TODO: exact time to sleep is uncertain */ + delay = 10; +@@ -249,6 +251,8 @@ static void ath12k_pci_soc_global_reset(struct ath12k_base *ab) + val &= ~PCIE_SOC_GLOBAL_RESET_V; + + ath12k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); ++ /* Flush the posted write to the device */ ++ ath12k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); + + mdelay(delay); + +diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c +index c3b06b515c4f41..5fd9cfdb567172 100644 +--- a/drivers/net/wireless/ath/ath6kl/txrx.c ++++ b/drivers/net/wireless/ath/ath6kl/txrx.c +@@ -1723,13 +1723,15 @@ void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid_mux, u16 seq_no, + + rxtid = &aggr_conn->rx_tid[tid]; + +- if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX) +- ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n", +- __func__, win_sz, tid); +- + if (rxtid->aggr) + aggr_delete_tid_state(aggr_conn, tid); + ++ if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX) { ++ ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n", ++ __func__, win_sz, tid); ++ return; ++ } ++ + rxtid->seq_next = seq_no; + hold_q_size = TID_WINDOW_SZ(win_sz) * sizeof(struct skb_hold_q); + rxtid->hold_q = kzalloc(hold_q_size, GFP_KERNEL); +@@ -1828,7 +1830,7 @@ void aggr_reset_state(struct aggr_info_conn *aggr_conn) + return; + + if (aggr_conn->timer_scheduled) { +- timer_delete(&aggr_conn->timer); ++ timer_delete_sync(&aggr_conn->timer); + aggr_conn->timer_scheduled = false; + } + +diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c +index 08a154bce1396e..0cdcbc3c77966a 100644 +--- a/drivers/net/wireless/ath/ath6kl/wmi.c ++++ b/drivers/net/wireless/ath/ath6kl/wmi.c +@@ -484,6 +484,18 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len) + + evt = (struct wmi_tx_complete_event *) datap; + ++ if (len < sizeof(*evt)) { ++ ath6kl_dbg(ATH6KL_DBG_WMI, "tx complete: invalid len %d\n", ++ len); ++ return -EINVAL; ++ } ++ ++ if (len < sizeof(*evt) + evt->num_msg * sizeof(struct tx_complete_msg_v1)) { ++ ath6kl_dbg(ATH6KL_DBG_WMI, "tx complete: invalid len %d for %u msgs\n", ++ len, evt->num_msg); ++ return -EINVAL; ++ } ++ + ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n", + evt->num_msg, evt->msg_len, evt->msg_type); + +@@ -862,6 +874,14 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len, + + ev = (struct wmi_connect_event *) datap; + ++ if (len < sizeof(*ev) + ev->beacon_ie_len + ++ ev->assoc_req_len + ev->assoc_resp_len) { ++ ath6kl_dbg(ATH6KL_DBG_WMI, ++ "connect event: IE lengths %u+%u+%u exceed buffer %d\n", ++ ev->beacon_ie_len, ev->assoc_req_len, ++ ev->assoc_resp_len, len); ++ return -EINVAL; ++ } + if (vif->nw_type == AP_NETWORK) { + /* AP mode start/STA connected event */ + struct net_device *dev = vif->ndev; +diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c +index fe9abe8cd268fa..0a3d2190b9beec 100644 +--- a/drivers/net/wireless/ath/ath9k/hif_usb.c ++++ b/drivers/net/wireless/ath/ath9k/hif_usb.c +@@ -1225,15 +1225,10 @@ static int ath9k_hif_request_firmware(struct hif_device_usb *hif_dev, + ret = request_firmware_nowait(THIS_MODULE, true, hif_dev->fw_name, + &hif_dev->udev->dev, GFP_KERNEL, + hif_dev, ath9k_hif_usb_firmware_cb); +- if (ret) { ++ if (ret) + dev_err(&hif_dev->udev->dev, + "ath9k_htc: Async request for firmware %s failed\n", + hif_dev->fw_name); +- return ret; +- } +- +- dev_info(&hif_dev->udev->dev, "ath9k_htc: Firmware %s requested\n", +- hif_dev->fw_name); + + return ret; + } +diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c +index 6833430130f4ca..0383d5c9698bfa 100644 +--- a/drivers/net/wireless/ath/carl9170/rx.c ++++ b/drivers/net/wireless/ath/carl9170/rx.c +@@ -150,7 +150,8 @@ static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer) + spin_lock(&ar->cmd_lock); + if (ar->readbuf) { + if (len >= 4) +- memcpy(ar->readbuf, buffer + 4, len - 4); ++ memcpy(ar->readbuf, buffer + 4, ++ min_t(u32, len - 4, ar->readlen)); + + ar->readbuf = NULL; + } +@@ -917,7 +918,9 @@ static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len) + } + } + +- skb_put_data(ar->rx_failover, tbuf, tlen); ++ skb_put_data(ar->rx_failover, tbuf, ++ min_t(unsigned int, tlen, ++ ar->rx_failover_missing)); + ar->rx_failover_missing -= tlen; + + if (ar->rx_failover_missing <= 0) { +diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c +index b7717f9e1e9b92..b0eee8f892af70 100644 +--- a/drivers/net/wireless/ath/carl9170/tx.c ++++ b/drivers/net/wireless/ath/carl9170/tx.c +@@ -692,7 +692,7 @@ void carl9170_tx_process_status(struct ar9170 *ar, + unsigned int i; + + for (i = 0; i < cmd->hdr.ext; i++) { +- if (WARN_ON(i > ((cmd->hdr.len / 2) + 1))) { ++ if (WARN_ON(i >= (cmd->hdr.len / 2))) { + print_hex_dump_bytes("UU:", DUMP_PREFIX_NONE, + (void *) cmd, cmd->hdr.len + 4); + break; +diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c +index aa683eacaf38ea..b983b51ffee71b 100644 +--- a/drivers/net/wireless/atmel/at76c50x-usb.c ++++ b/drivers/net/wireless/atmel/at76c50x-usb.c +@@ -1521,13 +1521,16 @@ static inline int at76_guess_freq(struct at76_priv *priv) + + if (ieee80211_is_probe_resp(hdr->frame_control)) { + el_off = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); +- el = ((struct ieee80211_mgmt *)hdr)->u.probe_resp.variable; + } else if (ieee80211_is_beacon(hdr->frame_control)) { + el_off = offsetof(struct ieee80211_mgmt, u.beacon.variable); +- el = ((struct ieee80211_mgmt *)hdr)->u.beacon.variable; + } else { + goto exit; + } ++ ++ if (len < el_off) ++ goto exit; ++ ++ el = priv->rx_skb->data + el_off; + len -= el_off; + + el = cfg80211_find_ie(WLAN_EID_DS_PARAMS, el, len); +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +index 13952dfeb3e30c..0beb38047df516 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +@@ -911,6 +911,7 @@ int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) + return ret; + } + switch (sdiodev->func2->device) { ++ case SDIO_DEVICE_ID_BROADCOM_43752: + case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373: + f2_blksz = SDIO_4373_FUNC2_BLOCKSIZE; + break; +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +index bb96b87b2a6e56..1fc9ecd86d5d9d 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -2146,7 +2146,7 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) + sme->crypto.akm_suites[0]); + return -EINVAL; + } +- } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { ++ } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_1X_SHA256)) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + val = WPA2_AUTH_UNSPECIFIED; +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +index 6327f4eca50078..fe4f23decc7057 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +@@ -1383,16 +1383,20 @@ fail: + static void + brcmf_pcie_release_scratchbuffers(struct brcmf_pciedev_info *devinfo) + { +- if (devinfo->shared.scratch) ++ if (devinfo->shared.scratch) { + dma_free_coherent(&devinfo->pdev->dev, + BRCMF_DMA_D2H_SCRATCH_BUF_LEN, + devinfo->shared.scratch, + devinfo->shared.scratch_dmahandle); +- if (devinfo->shared.ringupd) ++ devinfo->shared.scratch = NULL; ++ } ++ if (devinfo->shared.ringupd) { + dma_free_coherent(&devinfo->pdev->dev, + BRCMF_DMA_D2H_RINGUPD_BUF_LEN, + devinfo->shared.ringupd, + devinfo->shared.ringupd_dmahandle); ++ devinfo->shared.ringupd = NULL; ++ } + } + + static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo) +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +index a0e88dbaaebe67..9ab62a2667c7b6 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +@@ -4465,6 +4465,7 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) + bus->sdiodev = sdiodev; + sdiodev->bus = bus; + skb_queue_head_init(&bus->glom); ++ INIT_WORK(&bus->datawork, brcmf_sdio_dataworker); + bus->txbound = BRCMF_TXBOUND; + bus->rxbound = BRCMF_RXBOUND; + bus->txminmax = BRCMF_TXMINMAX; +@@ -4479,7 +4480,6 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) + goto fail; + } + brcmf_sdiod_freezer_count(sdiodev); +- INIT_WORK(&bus->datawork, brcmf_sdio_dataworker); + bus->brcmf_wq = wq; + + /* attempt to attach to the dongle */ +diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c +index 215814861cbda5..0808e69c3c1786 100644 +--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c ++++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c +@@ -6162,6 +6162,8 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, + if (err) { + printk(KERN_WARNING DRV_NAME + "Error calling pci_enable_device.\n"); ++ free_libipw(dev, 0); ++ pci_iounmap(pci_dev, ioaddr); + return err; + } + +@@ -6174,16 +6176,14 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, + if (err) { + printk(KERN_WARNING DRV_NAME + "Error calling pci_set_dma_mask.\n"); +- pci_disable_device(pci_dev); +- return err; ++ goto fail; + } + + err = pci_request_regions(pci_dev, DRV_NAME); + if (err) { + printk(KERN_WARNING DRV_NAME + "Error calling pci_request_regions.\n"); +- pci_disable_device(pci_dev); +- return err; ++ goto fail; + } + + /* We disable the RETRY_TIMEOUT register (0x41) to keep +diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +index f297e82d63d234..5de3a9c0b3ef09 100644 +--- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c ++++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + /* +- * Copyright(c) 2020-2025 Intel Corporation ++ * Copyright(c) 2020-2026 Intel Corporation + */ + + #include "iwl-drv.h" +@@ -12,6 +12,7 @@ + #include "fw/api/alive.h" + #include "fw/uefi.h" + #include "fw/img.h" ++#include "fw/dbg.h" + + #define IWL_PNVM_REDUCED_CAP_BIT BIT(25) + +@@ -26,6 +27,12 @@ static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait, + struct iwl_trans *trans = (struct iwl_trans *)data; + struct iwl_pnvm_init_complete_ntfy *pnvm_ntf = (void *)pkt->data; + ++ if (IWL_FW_CHECK(trans, ++ iwl_rx_packet_payload_len(pkt) < sizeof(*pnvm_ntf), ++ "Bad notif len: %d\n", ++ iwl_rx_packet_payload_len(pkt))) ++ return true; ++ + IWL_DEBUG_FW(trans, + "PNVM complete notification received with status 0x%0x\n", + le32_to_cpu(pnvm_ntf->status)); +diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +index e1f28b0532530a..818eb1c4b158f1 100644 +--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c ++++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +@@ -483,7 +483,7 @@ bool iwl_add_mcc_to_tas_block_list(u16 *list, u8 *size, u16 mcc) + if (*size >= IWL_WTAS_BLACK_LIST_MAX) + return false; + +- list[*size++] = mcc; ++ list[(*size)++] = mcc; + return true; + } + IWL_EXPORT_SYMBOL(iwl_add_mcc_to_tas_block_list); +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +index 11afe373961f3d..46e95e25dcd44e 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +@@ -2783,7 +2783,7 @@ static int iwl_mvm_wowlan_store_wake_pkt(struct iwl_mvm *mvm, + struct iwl_wowlan_status_data *status, + u32 len) + { +- u32 data_size, packet_len = le32_to_cpu(notif->wake_packet_length); ++ u32 data_size, packet_len; + + if (len < sizeof(*notif)) { + IWL_ERR(mvm, "Invalid WoWLAN wake packet notification!\n"); +@@ -2802,6 +2802,7 @@ static int iwl_mvm_wowlan_store_wake_pkt(struct iwl_mvm *mvm, + return -EIO; + } + ++ packet_len = le32_to_cpu(notif->wake_packet_length); + data_size = len - offsetof(struct iwl_wowlan_wake_pkt_notif, wake_packet); + + /* data_size got the padding from the notification, remove it. */ +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +index aa517978fc7a35..cfca5a3ee78ec8 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +@@ -955,12 +955,22 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) + return ret; + } + ++ if (IWL_FW_CHECK(mvm, ++ iwl_rx_packet_payload_len(cmd.resp_pkt) != ++ sizeof(*resp), ++ "Wrong size for iwl_geo_tx_power_profiles_resp: %d\n", ++ iwl_rx_packet_payload_len(cmd.resp_pkt))) { ++ ret = -EIO; ++ goto out; ++ } ++ + resp = (void *)cmd.resp_pkt->data; + ret = le32_to_cpu(resp->profile_idx); + + if (WARN_ON(ret > BIOS_GEO_MAX_PROFILE_NUM)) + ret = -EIO; + ++out: + iwl_free_resp(&cmd); + return ret; + } +diff --git a/drivers/net/wireless/intersil/p54/txrx.c b/drivers/net/wireless/intersil/p54/txrx.c +index 1294a1d6528e2c..9f491334c8d043 100644 +--- a/drivers/net/wireless/intersil/p54/txrx.c ++++ b/drivers/net/wireless/intersil/p54/txrx.c +@@ -499,11 +499,19 @@ static void p54_rx_eeprom_readback(struct p54_common *priv, + if (le16_to_cpu(eeprom->v2.len) != priv->eeprom_slice_size) + return; + ++ if (eeprom->v2.data + priv->eeprom_slice_size > ++ skb_tail_pointer(skb)) ++ return; ++ + memcpy(priv->eeprom, eeprom->v2.data, priv->eeprom_slice_size); + } else { + if (le16_to_cpu(eeprom->v1.len) != priv->eeprom_slice_size) + return; + ++ if (eeprom->v1.data + priv->eeprom_slice_size > ++ skb_tail_pointer(skb)) ++ return; ++ + memcpy(priv->eeprom, eeprom->v1.data, priv->eeprom_slice_size); + } + +diff --git a/drivers/net/wireless/marvell/libertas/firmware.c b/drivers/net/wireless/marvell/libertas/firmware.c +index f124110944b7e9..9bf7d4c207b9ed 100644 +--- a/drivers/net/wireless/marvell/libertas/firmware.c ++++ b/drivers/net/wireless/marvell/libertas/firmware.c +@@ -78,6 +78,7 @@ static void helper_firmware_cb(const struct firmware *firmware, void *context) + } else { + /* No main firmware needed for this helper --> success! */ + lbs_fw_loaded(priv, 0, firmware, NULL); ++ release_firmware(firmware); + } + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +index ef6722ffdc74d8..358de94eeb5ed9 100644 +--- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c ++++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +@@ -196,6 +196,7 @@ static int mwifiex_request_rgpower_table(struct mwifiex_private *priv) + struct mwifiex_adapter *adapter = priv->adapter; + char rgpower_table_name[30]; + char country_code[3]; ++ int ret; + + strscpy(country_code, domain_info->country_code, sizeof(country_code)); + +@@ -214,16 +215,17 @@ static int mwifiex_request_rgpower_table(struct mwifiex_private *priv) + adapter->rgpower_data = NULL; + } + +- if ((request_firmware(&adapter->rgpower_data, rgpower_table_name, +- adapter->dev))) { ++ ret = request_firmware_direct(&adapter->rgpower_data, rgpower_table_name, ++ adapter->dev); ++ ++ if (ret) { + mwifiex_dbg( + adapter, INFO, +- "info: %s: failed to request regulatory power table\n", +- __func__); +- return -EIO; ++ "info: %s: failed to request regulatory power table: %d\n", ++ __func__, ret); + } + +- return 0; ++ return ret; + } + + static int mwifiex_dnld_rgpower_table(struct mwifiex_private *priv) +diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c +index 77a9a6de636d1f..b94ca13086d679 100644 +--- a/drivers/net/wireless/marvell/mwifiex/tdls.c ++++ b/drivers/net/wireless/marvell/mwifiex/tdls.c +@@ -215,7 +215,7 @@ mwifiex_tdls_add_ht_oper(struct mwifiex_private *priv, const u8 *mac, + + /* follow AP's channel bandwidth */ + if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) && +- bss_desc->bcn_ht_cap && ++ bss_desc->bcn_ht_oper && + ISALLOWED_CHANWIDTH40(bss_desc->bcn_ht_oper->ht_param)) + ht_oper->ht_param = bss_desc->bcn_ht_oper->ht_param; + +diff --git a/drivers/net/wireless/marvell/mwifiex/uap_event.c b/drivers/net/wireless/marvell/mwifiex/uap_event.c +index 245cb99a3daad2..fc9da9006a782c 100644 +--- a/drivers/net/wireless/marvell/mwifiex/uap_event.c ++++ b/drivers/net/wireless/marvell/mwifiex/uap_event.c +@@ -123,11 +123,31 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) + len = ETH_ALEN; + + if (len != -1) { ++ u16 evt_len = le16_to_cpu(event->len); ++ + sinfo->assoc_req_ies = &event->data[len]; + len = (u8 *)sinfo->assoc_req_ies - + (u8 *)&event->frame_control; +- sinfo->assoc_req_ies_len = +- le16_to_cpu(event->len) - (u16)len; ++ ++ /* ++ * event->len is reported by the device firmware ++ * and is not otherwise validated. Reject a ++ * length that underflows the header, or that ++ * would place the association request IEs ++ * outside the fixed-size event_body[] buffer the ++ * event was copied into; otherwise the IE walk ++ * in mwifiex_set_sta_ht_cap() reads past ++ * event_body and out of the adapter slab object. ++ */ ++ if (evt_len < len || ++ (u8 *)&event->frame_control + evt_len > ++ adapter->event_body + MAX_EVENT_SIZE) { ++ mwifiex_dbg(adapter, ERROR, ++ "invalid STA assoc event length\n"); ++ kfree(sinfo); ++ return -1; ++ } ++ sinfo->assoc_req_ies_len = evt_len - (u16)len; + } + } + cfg80211_new_sta(priv->netdev, event->sta_addr, sinfo, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +index 13c9dbeaee84e8..6c7debe439b6c3 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +@@ -1601,6 +1601,8 @@ bool mt7615_rx_check(struct mt76_dev *mdev, void *data, int len) + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: ++ if (!mt76_is_mmio(mdev)) ++ return false; + mt7615_mac_tx_free(dev, data, len); + return false; + case PKT_TYPE_TXS: +@@ -1634,6 +1636,10 @@ void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + dev_kfree_skb(skb); + break; + case PKT_TYPE_TXRX_NOTIFY: ++ if (!mt76_is_mmio(mdev)) { ++ dev_kfree_skb(skb); ++ break; ++ } + mt7615_mac_tx_free(dev, skb->data, skb->len); + dev_kfree_skb(skb); + break; +diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +index fc3e6728fcfbfb..2aa7b711c774e0 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +@@ -1441,6 +1441,8 @@ mt76_connac_mcu_uni_bss_he_tlv(struct mt76_phy *phy, struct ieee80211_vif *vif, + struct bss_info_uni_he *he; + + cap = mt76_connac_get_he_phy_cap(phy, vif); ++ if (!cap) ++ return; + + he = (struct bss_info_uni_he *)tlv; + he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext; +diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +index 79e021ac0bdbcc..f60e2eaea2af4a 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +@@ -595,6 +595,8 @@ mt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct tlv *tlv; + + cap = mt76_connac_get_he_phy_cap(phy->mt76, vif); ++ if (!cap) ++ return; + + tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HE_BASIC, sizeof(*he)); + +@@ -1177,13 +1179,12 @@ mt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy, + } + + static void +-mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, +- struct mt7915_phy *phy, struct sta_rec_bf *bf) ++mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, ++ const struct ieee80211_sta_he_cap *vc, ++ struct sta_rec_bf *bf) + { + struct ieee80211_sta_he_cap *pc = &sta->deflink.he_cap; + struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem; +- const struct ieee80211_sta_he_cap *vc = +- mt76_connac_get_he_phy_cap(phy->mt76, vif); + const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem; + u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80); + u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); +@@ -1242,6 +1243,7 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb, + { + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_phy *phy = mvif->phy; ++ const struct ieee80211_sta_he_cap *vc = NULL; + int tx_ant = hweight8(phy->mt76->chainmask) - 1; + struct sta_rec_bf *bf; + struct tlv *tlv; +@@ -1260,6 +1262,12 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb, + if (!ebf && !dev->ibf) + return; + ++ if (sta->deflink.he_cap.has_he && ebf) { ++ vc = mt76_connac_get_he_phy_cap(phy->mt76, vif); ++ if (!vc) ++ return; ++ } ++ + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf)); + bf = (struct sta_rec_bf *)tlv; + +@@ -1268,7 +1276,7 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb, + * ht: iBF only, since mac80211 lacks of eBF support + */ + if (sta->deflink.he_cap.has_he && ebf) +- mt7915_mcu_sta_bfer_he(sta, vif, phy, bf); ++ mt7915_mcu_sta_bfer_he(sta, vc, bf); + else if (sta->deflink.vht_cap.vht_supported) + mt7915_mcu_sta_bfer_vht(sta, phy, bf, ebf); + else if (sta->deflink.ht_cap.ht_supported) +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +index d2731e9953bf84..251a9a1f664d5d 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +@@ -569,8 +569,9 @@ bool mt7921_rx_check(struct mt76_dev *mdev, void *data, int len) + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: +- /* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */ +- mt7921_mac_tx_free(dev, data, len); /* mmio */ ++ if (!mt76_is_mmio(mdev)) ++ return false; ++ mt7921_mac_tx_free(dev, data, len); + return false; + case PKT_TYPE_TXS: + for (rxd += 2; rxd + 8 <= end; rxd += 8) +@@ -599,7 +600,10 @@ void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: +- /* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */ ++ if (!mt76_is_mmio(mdev)) { ++ napi_consume_skb(skb, 1); ++ break; ++ } + mt7921_mac_tx_free(dev, skb->data, skb->len); + napi_consume_skb(skb, 1); + break; +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +index d951a46e9d48ce..6a74779430916e 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +@@ -1193,8 +1193,9 @@ bool mt7925_rx_check(struct mt76_dev *mdev, void *data, int len) + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: +- /* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */ +- mt7925_mac_tx_free(dev, data, len); /* mmio */ ++ if (!mt76_is_mmio(mdev)) ++ return false; ++ mt7925_mac_tx_free(dev, data, len); + return false; + case PKT_TYPE_TXS: + for (rxd += 4; rxd + 12 <= end; rxd += 12) +@@ -1230,7 +1231,10 @@ void mt7925_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: +- /* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */ ++ if (!mt76_is_mmio(mdev)) { ++ napi_consume_skb(skb, 1); ++ break; ++ } + mt7925_mac_tx_free(dev, skb->data, skb->len); + napi_consume_skb(skb, 1); + break; +@@ -1274,6 +1278,9 @@ mt7925_vif_connect_iter(void *priv, u8 *mac, + + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + bss_conf = mt792x_vif_to_bss_conf(vif, i); ++ if (!bss_conf) ++ continue; ++ + mconf = mt792x_vif_to_link(mvif, i); + + mt76_connac_mcu_uni_add_dev(&dev->mphy, bss_conf, &mconf->mt76, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +index 6c0dc72efc3928..910713e62e14a5 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +@@ -1573,6 +1573,9 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw, + + mlink = mt792x_sta_to_link(msta, i); + ++ if (!mlink) ++ continue; ++ + if (enabled) + set_bit(MT_WCID_FLAG_HDR_TRANS, &mlink->wcid.flags); + else +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +index d887aa9a3dff72..647efa963db48d 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +@@ -2706,6 +2706,8 @@ mt7925_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf, + struct tlv *tlv; + + cap = mt76_connac_get_he_phy_cap(phy->mt76, link_conf->vif); ++ if (!cap) ++ return; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_HE_BASIC, sizeof(*he)); + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +index a3f813be107df7..72851399575f9d 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -860,6 +860,8 @@ mt7996_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct tlv *tlv; + + cap = mt76_connac_get_he_phy_cap(phy->mt76, vif); ++ if (!cap) ++ return; + + tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_HE_BASIC, sizeof(*he)); + +@@ -1659,17 +1661,18 @@ mt7996_mcu_sta_bfer_he(struct ieee80211_link_sta *link_sta, + { + struct ieee80211_sta_he_cap *pc = &link_sta->he_cap; + struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem; +- const struct ieee80211_sta_he_cap *vc = +- mt76_connac_get_he_phy_cap(phy->mt76, vif); +- const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem; + u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80); + u8 nss_mcs = mt7996_mcu_get_sta_nss(mcs_map); ++ const struct ieee80211_he_cap_elem *ve; ++ const struct ieee80211_sta_he_cap *vc; + u8 snd_dim, sts; + ++ vc = mt76_connac_get_he_phy_cap(phy->mt76, vif); + if (!vc) + return; + + bf->tx_mode = MT_PHY_TYPE_HE_SU; ++ ve = &vc->he_cap_elem; + + mt7996_mcu_sta_sounding_rate(bf, phy); + +@@ -1725,14 +1728,18 @@ mt7996_mcu_sta_bfer_eht(struct ieee80211_link_sta *link_sta, + struct ieee80211_sta_eht_cap *pc = &link_sta->eht_cap; + struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem; + struct ieee80211_eht_mcs_nss_supp *eht_nss = &pc->eht_mcs_nss_supp; +- const struct ieee80211_sta_eht_cap *vc = +- mt76_connac_get_eht_phy_cap(phy->mt76, vif); +- const struct ieee80211_eht_cap_elem_fixed *ve = &vc->eht_cap_elem; + u8 nss_mcs = u8_get_bits(eht_nss->bw._80.rx_tx_mcs9_max_nss, + IEEE80211_EHT_MCS_NSS_RX) - 1; ++ const struct ieee80211_eht_cap_elem_fixed *ve; ++ const struct ieee80211_sta_eht_cap *vc; + u8 snd_dim, sts; + ++ vc = mt76_connac_get_eht_phy_cap(phy->mt76, vif); ++ if (!vc) ++ return; ++ + bf->tx_mode = MT_PHY_TYPE_EHT_MU; ++ ve = &vc->eht_cap_elem; + + mt7996_mcu_sta_sounding_rate(bf, phy); + +diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c +index d795ca05729abe..f08426ca51135b 100644 +--- a/drivers/net/wireless/microchip/wilc1000/hif.c ++++ b/drivers/net/wireless/microchip/wilc1000/hif.c +@@ -600,6 +600,11 @@ static s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len, + u16 ies_len; + struct wilc_assoc_resp *res = (struct wilc_assoc_resp *)buffer; + ++ if (buffer_len < sizeof(*res)) { ++ ret_conn_info->status = WLAN_STATUS_UNSPECIFIED_FAILURE; ++ return -EINVAL; ++ } ++ + ret_conn_info->status = le16_to_cpu(res->status_code); + if (ret_conn_info->status == WLAN_STATUS_SUCCESS) { + ies = &buffer[sizeof(*res)]; +diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c +index 20815fdc9d3764..a0724e1c530709 100644 +--- a/drivers/net/wireless/virtual/mac80211_hwsim.c ++++ b/drivers/net/wireless/virtual/mac80211_hwsim.c +@@ -6898,6 +6898,7 @@ static void hwsim_virtio_rx_work(struct work_struct *work) + + skb->data = skb->head; + skb_reset_tail_pointer(skb); ++ len = min(len, skb_end_offset(skb)); + skb_put(skb, len); + hwsim_virtio_handle_cmd(skb); + +diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c +index aaa783c79e6dd6..e8cc83029db339 100644 +--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c ++++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c +@@ -1097,7 +1097,7 @@ static int rzg2l_read_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin) + int bit; + + if (!pctrl->data->pin_to_oen_bit) +- return -EOPNOTSUPP; ++ return -ENOTSUPP; + + bit = pctrl->data->pin_to_oen_bit(pctrl, _pin); + if (bit < 0) +@@ -1115,7 +1115,7 @@ static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, unsigned int _pin, u8 oe + int bit; + + if (!pctrl->data->pin_to_oen_bit) +- return -EOPNOTSUPP; ++ return -ENOTSUPP; + + bit = pctrl->data->pin_to_oen_bit(pctrl, _pin); + if (bit < 0) +@@ -1552,7 +1552,7 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev, + break; + + default: +- return -EOPNOTSUPP; ++ return -ENOTSUPP; + } + } + +@@ -1634,7 +1634,7 @@ static int rzg2l_pinctrl_pinconf_group_get(struct pinctrl_dev *pctldev, + + /* Check config matching between to pin */ + if (i && prev_config != *config) +- return -EOPNOTSUPP; ++ return -ENOTSUPP; + + prev_config = *config; + } +diff --git a/drivers/platform/loongarch/loongson-laptop.c b/drivers/platform/loongarch/loongson-laptop.c +index 61b18ac206c9ee..dc8142f4fa9541 100644 +--- a/drivers/platform/loongarch/loongson-laptop.c ++++ b/drivers/platform/loongarch/loongson-laptop.c +@@ -189,6 +189,7 @@ static int __init setup_acpi_notify(struct generic_sub_driver *sub_driver) + + static int loongson_hotkey_suspend(struct device *dev) + { ++ bl_powered = false; + return 0; + } + +diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c +index 65897fae17dfba..6091b617480ff6 100644 +--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c ++++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c +@@ -274,15 +274,20 @@ int uncore_freq_add_entry(struct uncore_data *data, int cpu) + sprintf(data->name, "package_%02d_die_%02d", data->package_id, data->die_id); + } + ++ /* ++ * Set the control CPU before any read path so entry recreation after CPU ++ * hotplug can populate read-only attributes from the new online CPU. ++ */ ++ data->control_cpu = cpu; + uncore_read(data, &data->initial_min_freq_khz, UNCORE_INDEX_MIN_FREQ); + uncore_read(data, &data->initial_max_freq_khz, UNCORE_INDEX_MAX_FREQ); + + ret = create_attr_group(data, data->name); + if (ret) { ++ data->control_cpu = -1; + if (data->domain_id != UNCORE_DOMAIN_ID_INVALID) + ida_free(&intel_uncore_ida, data->instance_id); + } else { +- data->control_cpu = cpu; + data->valid = true; + } + +diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c +index e094fe5a42bf64..28688ca46517aa 100644 +--- a/drivers/pmdomain/imx/imx93-blk-ctrl.c ++++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c +@@ -47,6 +47,8 @@ + + #define PRIO(X) (X) + ++#define BLK_CTRL_NO_PARENT UINT_MAX ++ + struct imx93_blk_ctrl_domain; + + struct imx93_blk_ctrl { +@@ -67,12 +69,18 @@ struct imx93_blk_ctrl_qos { + u32 cfg_prio; + }; + ++struct imx93_blk_ctrl_subdomain_link { ++ struct generic_pm_domain *parent; ++ struct generic_pm_domain *subdomain; ++}; ++ + struct imx93_blk_ctrl_domain_data { + const char *name; + const char * const *clk_names; + int num_clks; + u32 rst_mask; + u32 clk_mask; ++ u32 parent; + int num_qos; + struct imx93_blk_ctrl_qos qos[DOMAIN_MAX_QOS]; + }; +@@ -188,6 +196,27 @@ static int imx93_blk_ctrl_power_off(struct generic_pm_domain *genpd) + return 0; + } + ++static void imx93_release_genpd_provider(void *data) ++{ ++ struct device_node *of_node = data; ++ ++ of_genpd_del_provider(of_node); ++} ++ ++static void imx93_release_pm_genpd(void *data) ++{ ++ struct generic_pm_domain *genpd = data; ++ ++ pm_genpd_remove(genpd); ++} ++ ++static void imx93_release_subdomain(void *data) ++{ ++ struct imx93_blk_ctrl_subdomain_link *link = data; ++ ++ pm_genpd_remove_subdomain(link->parent, link->subdomain); ++} ++ + static struct lock_class_key blk_ctrl_genpd_lock_class; + + static int imx93_blk_ctrl_probe(struct platform_device *pdev) +@@ -258,10 +287,8 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev) + domain->clks[j].id = data->clk_names[j]; + + ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks); +- if (ret) { +- dev_err_probe(dev, ret, "failed to get clock\n"); +- goto cleanup_pds; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to get clock\n"); + + domain->genpd.name = data->name; + domain->genpd.power_on = imx93_blk_ctrl_power_on; +@@ -269,11 +296,12 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev) + domain->bc = bc; + + ret = pm_genpd_init(&domain->genpd, NULL, true); +- if (ret) { +- dev_err_probe(dev, ret, "failed to init power domain\n"); +- goto cleanup_pds; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to init power domain\n"); + ++ ret = devm_add_action_or_reset(dev, imx93_release_pm_genpd, &domain->genpd); ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to add pm_genpd release callback\n"); + /* + * We use runtime PM to trigger power on/off of the upstream GPC + * domain, as a strict hierarchical parent/child power domain +@@ -290,39 +318,47 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev) + bc->onecell_data.domains[i] = &domain->genpd; + } + +- pm_runtime_enable(dev); +- +- ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data); +- if (ret) { +- dev_err_probe(dev, ret, "failed to add power domain provider\n"); +- goto cleanup_pds; +- } ++ for (i = 0; i < bc_data->num_domains; i++) { ++ struct imx93_blk_ctrl_domain *domain = &bc->domains[i]; ++ const struct imx93_blk_ctrl_domain_data *data = domain->data; ++ struct imx93_blk_ctrl_subdomain_link *link; + +- dev_set_drvdata(dev, bc); ++ if (bc_data->skip_mask & BIT(i) || ++ data->parent == BLK_CTRL_NO_PARENT) ++ continue; + +- return 0; ++ link = devm_kzalloc(dev, sizeof(*link), GFP_KERNEL); ++ if (!link) ++ return -ENOMEM; + +-cleanup_pds: +- for (i--; i >= 0; i--) +- pm_genpd_remove(&bc->domains[i].genpd); ++ link->parent = &bc->domains[data->parent].genpd; ++ link->subdomain = &domain->genpd; + +- return ret; +-} ++ ret = pm_genpd_add_subdomain(&bc->domains[data->parent].genpd, ++ &domain->genpd); ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to add subdomain %s\n", ++ domain->genpd.name); + +-static void imx93_blk_ctrl_remove(struct platform_device *pdev) +-{ +- struct imx93_blk_ctrl *bc = dev_get_drvdata(&pdev->dev); +- int i; ++ ret = devm_add_action_or_reset(dev, imx93_release_subdomain, link); ++ if (ret) ++ return dev_err_probe(dev, ret, ++ "failed to add subdomain release callback\n"); ++ } + +- of_genpd_del_provider(pdev->dev.of_node); ++ ret = devm_pm_runtime_enable(dev); ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to enable pm-runtime\n"); + +- pm_runtime_disable(&pdev->dev); ++ ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data); ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to add power domain provider\n"); + +- for (i = 0; i < bc->onecell_data.num_domains; i++) { +- struct imx93_blk_ctrl_domain *domain = &bc->domains[i]; ++ ret = devm_add_action_or_reset(dev, imx93_release_genpd_provider, dev->of_node); ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to add genpd_provider release callback\n"); + +- pm_genpd_remove(&domain->genpd); +- } ++ return 0; + } + + static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] = { +@@ -330,8 +366,9 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] + .name = "mediablk-mipi-dsi", + .clk_names = (const char *[]){ "dsi" }, + .num_clks = 1, +- .rst_mask = BIT(11) | BIT(12), +- .clk_mask = BIT(11) | BIT(12), ++ .rst_mask = BIT(11), ++ .clk_mask = BIT(11), ++ .parent = IMX93_MEDIABLK_PD_MIPI_PHY, + }, + [IMX93_MEDIABLK_PD_MIPI_CSI] = { + .name = "mediablk-mipi-csi", +@@ -339,6 +376,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] + .num_clks = 2, + .rst_mask = BIT(9) | BIT(10), + .clk_mask = BIT(9) | BIT(10), ++ .parent = IMX93_MEDIABLK_PD_MIPI_PHY, + }, + [IMX93_MEDIABLK_PD_PXP] = { + .name = "mediablk-pxp", +@@ -346,6 +384,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] + .num_clks = 1, + .rst_mask = BIT(7) | BIT(8), + .clk_mask = BIT(7) | BIT(8), ++ .parent = BLK_CTRL_NO_PARENT, + .num_qos = 2, + .qos = { + { +@@ -367,6 +406,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] + .num_clks = 2, + .rst_mask = BIT(4) | BIT(5) | BIT(6), + .clk_mask = BIT(4) | BIT(5) | BIT(6), ++ .parent = BLK_CTRL_NO_PARENT, + .num_qos = 1, + .qos = { + { +@@ -383,6 +423,7 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] + .num_clks = 1, + .rst_mask = BIT(2) | BIT(3), + .clk_mask = BIT(2) | BIT(3), ++ .parent = BLK_CTRL_NO_PARENT, + .num_qos = 4, + .qos = { + { +@@ -408,6 +449,14 @@ static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] + } + } + }, ++ [IMX93_MEDIABLK_PD_MIPI_PHY] = { ++ .name = "mediablk-mipi-phy", ++ .clk_names = NULL, ++ .num_clks = 0, ++ .rst_mask = BIT(12), ++ .clk_mask = BIT(12), ++ .parent = BLK_CTRL_NO_PARENT, ++ }, + }; + + static const struct regmap_range imx93_media_blk_ctl_yes_ranges[] = { +@@ -457,7 +506,6 @@ MODULE_DEVICE_TABLE(of, imx93_blk_ctrl_of_match); + + static struct platform_driver imx93_blk_ctrl_driver = { + .probe = imx93_blk_ctrl_probe, +- .remove = imx93_blk_ctrl_remove, + .driver = { + .name = "imx93-blk-ctrl", + .of_match_table = imx93_blk_ctrl_of_match, +diff --git a/drivers/ptp/ptp_netc.c b/drivers/ptp/ptp_netc.c +index 94e952ee69902e..5e381c354d746a 100644 +--- a/drivers/ptp/ptp_netc.c ++++ b/drivers/ptp/ptp_netc.c +@@ -779,6 +779,7 @@ static void netc_timer_init(struct netc_timer *priv) + netc_timer_wr(priv, NETC_TMR_FIPER_CTRL, fiper_ctrl); + netc_timer_wr(priv, NETC_TMR_ECTRL, NETC_TMR_DEFAULT_ETTF_THR); + ++ netc_timer_offset_write(priv, 0); + ktime_get_real_ts64(&now); + ns = timespec64_to_ns(&now); + netc_timer_cnt_write(priv, ns); +diff --git a/drivers/ptp/ptp_s390.c b/drivers/ptp/ptp_s390.c +index 29618eb9bf442c..02d624d89a0abf 100644 +--- a/drivers/ptp/ptp_s390.c ++++ b/drivers/ptp/ptp_s390.c +@@ -107,6 +107,9 @@ static __init int ptp_s390_init(void) + if (IS_ERR(ptp_stcke_clock)) + return PTR_ERR(ptp_stcke_clock); + ++ if (!test_facility(28) || !ptff_query(PTFF_QPT)) ++ return 0; ++ + ptp_qpt_clock = ptp_clock_register(&ptp_s390_qpt_info, NULL); + if (IS_ERR(ptp_qpt_clock)) { + ptp_clock_unregister(ptp_stcke_clock); +@@ -117,7 +120,8 @@ static __init int ptp_s390_init(void) + + static __exit void ptp_s390_exit(void) + { +- ptp_clock_unregister(ptp_qpt_clock); ++ if (ptp_qpt_clock) ++ ptp_clock_unregister(ptp_qpt_clock); + ptp_clock_unregister(ptp_stcke_clock); + } + +diff --git a/drivers/regulator/mt6358-regulator.c b/drivers/regulator/mt6358-regulator.c +index e4745f616cea3b..44bef0bdfdbe35 100644 +--- a/drivers/regulator/mt6358-regulator.c ++++ b/drivers/regulator/mt6358-regulator.c +@@ -492,7 +492,7 @@ static const struct regulator_ops mt6358_volt_fixed_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, +- .get_voltage_sel = mt6358_get_buck_voltage_sel, ++ .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, +diff --git a/drivers/remoteproc/xlnx_r5_remoteproc.c b/drivers/remoteproc/xlnx_r5_remoteproc.c +index 5ef586fd37bca3..a238b45bf2f2c6 100644 +--- a/drivers/remoteproc/xlnx_r5_remoteproc.c ++++ b/drivers/remoteproc/xlnx_r5_remoteproc.c +@@ -959,16 +959,6 @@ static struct zynqmp_r5_core *zynqmp_r5_add_rproc_core(struct device *cdev) + goto free_rproc; + } + +- /* +- * If firmware is already available in the memory then move rproc state +- * to DETACHED. Firmware can be preloaded via debugger or by any other +- * agent (processors) in the system. +- * If firmware isn't available in the memory and resource table isn't +- * found, then rproc state remains OFFLINE. +- */ +- if (!zynqmp_r5_get_rsc_table_va(r5_core)) +- r5_rproc->state = RPROC_DETACHED; +- + r5_core->rproc = r5_rproc; + return r5_core; + +@@ -1221,6 +1211,7 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster, + { + struct device *dev = cluster->dev; + struct zynqmp_r5_core *r5_core; ++ u32 payload[PAYLOAD_ARG_CNT]; + int ret = -EINVAL, i; + + r5_core = cluster->r5_cores[0]; +@@ -1266,6 +1257,45 @@ static int zynqmp_r5_core_init(struct zynqmp_r5_cluster *cluster, + ret = zynqmp_r5_get_sram_banks(r5_core); + if (ret) + return ret; ++ ++ /* ++ * It is possible that firmware is loaded into the memory, but ++ * RPU (remote) is not running. In such case, RPU state will be ++ * moved to RPROC_DETACHED wrongfully. To avoid it first make ++ * sure RPU is power-on and out of reset before parsing for the ++ * resource table. ++ */ ++ ret = zynqmp_pm_feature(PM_GET_NODE_STATUS); ++ if (ret < PM_API_VERSION_2) ++ ret = -EOPNOTSUPP; ++ else ++ ret = zynqmp_pm_invoke_fn(PM_GET_NODE_STATUS, payload, 1, ++ r5_core->pm_domain_id); ++ if (ret) { ++ dev_warn(r5_core->dev, ++ "failed to get rpu node status, err %d\n", ret); ++ continue; ++ } ++ ++ /* ++ * If RPU state is power on and out of reset i.e. running, then ++ * assign RPROC_DETACHED state. If the RPU is not out of reset ++ * then do not attempt to attach to the remote processor. ++ */ ++ if (payload[1] == PM_NODE_RUNNING) { ++ /* ++ * Not all the firmware that is running on the remote ++ * core is expected to have the resource table. The ++ * firmware might not use RPMsg at all, and in that case ++ * resource table becomes irrelevant. However, we still ++ * need to make sure that running core is not reported ++ * as offline. so do not decide remote core state based ++ * on the resource table availability ++ */ ++ if (zynqmp_r5_get_rsc_table_va(r5_core)) ++ dev_dbg(r5_core->dev, "rsc tbl not found\n"); ++ r5_core->rproc->state = RPROC_DETACHED; ++ } + } + + return 0; +diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c +index 17173239301e61..a1055fe4922f64 100644 +--- a/drivers/scsi/hosts.c ++++ b/drivers/scsi/hosts.c +@@ -343,6 +343,7 @@ static void scsi_host_dev_release(struct device *dev) + /* Wait for functions invoked through call_rcu(&scmd->rcu, ...) */ + rcu_barrier(); + ++ cancel_work_sync(&shost->eh_work); + if (shost->tmf_work_q) + destroy_workqueue(shost->tmf_work_q); + if (shost->ehandler) +@@ -408,6 +409,7 @@ struct Scsi_Host *scsi_host_alloc(const struct scsi_host_template *sht, int priv + INIT_LIST_HEAD(&shost->starved_list); + init_waitqueue_head(&shost->host_wait); + mutex_init(&shost->scan_mutex); ++ INIT_WORK(&shost->eh_work, scsi_rcu_eh_wakeup); + + index = ida_alloc(&host_index_ida, GFP_KERNEL); + if (index < 0) { +diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c +index 2fd4ca96b3089d..13d46b6e0359e2 100644 +--- a/drivers/scsi/scsi_error.c ++++ b/drivers/scsi/scsi_error.c +@@ -73,6 +73,26 @@ void scsi_eh_wakeup(struct Scsi_Host *shost, unsigned int busy) + } + } + ++void scsi_rcu_eh_wakeup(struct work_struct *work) ++{ ++ struct Scsi_Host *shost = container_of(work, struct Scsi_Host, eh_work); ++ unsigned long flags; ++ unsigned int busy; ++ ++ /* ++ * Ensure any running scsi_dec_host_busy has completed its rcu section ++ * so changes to host state and host_eh_scheduled are visible to all ++ * future calls of scsi_dec_host_busy ++ */ ++ synchronize_rcu(); ++ ++ busy = scsi_host_busy(shost); ++ ++ spin_lock_irqsave(shost->host_lock, flags); ++ scsi_eh_wakeup(shost, busy); ++ spin_unlock_irqrestore(shost->host_lock, flags); ++} ++ + /** + * scsi_schedule_eh - schedule EH for SCSI host + * @shost: SCSI host to invoke error handling on. +@@ -88,7 +108,7 @@ void scsi_schedule_eh(struct Scsi_Host *shost) + if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 || + scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) { + shost->host_eh_scheduled++; +- scsi_eh_wakeup(shost, scsi_host_busy(shost)); ++ queue_work(shost->tmf_work_q, &shost->eh_work); + } + + spin_unlock_irqrestore(shost->host_lock, flags); +diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h +index 5b2b19f5e8ec8a..68866b18a60058 100644 +--- a/drivers/scsi/scsi_priv.h ++++ b/drivers/scsi/scsi_priv.h +@@ -91,6 +91,7 @@ extern enum blk_eh_timer_return scsi_timeout(struct request *req); + extern int scsi_error_handler(void *host); + extern enum scsi_disposition scsi_decide_disposition(struct scsi_cmnd *cmd); + extern void scsi_eh_wakeup(struct Scsi_Host *shost, unsigned int busy); ++extern void scsi_rcu_eh_wakeup(struct work_struct *work); + extern void scsi_eh_scmd_add(struct scsi_cmnd *); + void scsi_eh_ready_devs(struct Scsi_Host *shost, + struct list_head *work_q, +diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c +index 49e497a32973b8..8545d62683eb56 100644 +--- a/drivers/staging/media/meson/vdec/vdec.c ++++ b/drivers/staging/media/meson/vdec/vdec.c +@@ -889,7 +889,7 @@ static int vdec_open(struct file *file) + + ret = vdec_init_ctrls(sess); + if (ret) +- goto err_m2m_release; ++ goto err_m2m_ctx_release; + + sess->pixfmt_cap = formats[0].pixfmts_cap[0]; + sess->fmt_out = &formats[0]; +@@ -913,6 +913,8 @@ static int vdec_open(struct file *file) + + return 0; + ++err_m2m_ctx_release: ++ v4l2_m2m_ctx_release(sess->m2m_ctx); + err_m2m_release: + v4l2_m2m_release(sess->m2m_dev); + err_free_sess: +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c +index 1c7191bb0d8fca..6de345b4ed1700 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus.c +@@ -391,6 +391,7 @@ static int cedrus_open(struct file *file) + err_m2m_release: + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + err_free: ++ v4l2_fh_exit(&ctx->fh); + kfree(ctx); + mutex_unlock(&dev->dev_mutex); + +@@ -507,7 +508,7 @@ static int cedrus_probe(struct platform_device *pdev) + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); +- goto err_m2m; ++ goto err_media; + } + + v4l2_info(&dev->v4l2_dev, +@@ -533,7 +534,8 @@ err_m2m_mc: + v4l2_m2m_unregister_media_controller(dev->m2m_dev); + err_video: + video_unregister_device(&dev->vfd); +-err_m2m: ++err_media: ++ media_device_cleanup(&dev->mdev); + v4l2_m2m_release(dev->m2m_dev); + err_v4l2: + v4l2_device_unregister(&dev->v4l2_dev); +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +index 3e2843ef6ccec8..fc54d993b11f2a 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +@@ -210,6 +210,9 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx, + u8 dpb_idx; + + dpb_idx = ref_list[i].index; ++ if (dpb_idx >= V4L2_H264_NUM_DPB_ENTRIES) ++ continue; ++ + dpb = &decode->dpb[dpb_idx]; + + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) +diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c +index 14b327afe045e6..46f16934678248 100644 +--- a/drivers/staging/media/tegra-video/vi.c ++++ b/drivers/staging/media/tegra-video/vi.c +@@ -80,8 +80,8 @@ static int tegra_get_format_idx_by_code(struct tegra_vi *vi, + static u32 tegra_get_format_fourcc_by_idx(struct tegra_vi *vi, + unsigned int index) + { +- if (index >= vi->soc->nformats) +- return -EINVAL; ++ if (WARN_ON_ONCE(index >= vi->soc->nformats)) ++ return vi->soc->video_formats[0].fourcc; + + return vi->soc->video_formats[index].fourcc; + } +diff --git a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c +index 01ab7fb5e5bc66..e61bc9c6bb21e8 100644 +--- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c ++++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c +@@ -679,7 +679,14 @@ u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen) + while (cnt < in_len) { + eid = in_ie[cnt]; + +- if ((eid == WLAN_EID_VENDOR_SPECIFIC) && (!memcmp(&in_ie[cnt + 2], wps_oui, 4))) { ++ if (cnt + 2 > in_len) ++ break; ++ ++ if (in_ie[cnt + 1] + 2 > in_len - cnt) ++ break; ++ ++ if ((eid == WLAN_EID_VENDOR_SPECIFIC) && (in_ie[cnt + 1] >= 4) && ++ (!memcmp(&in_ie[cnt + 2], wps_oui, 4))) { + wpsie_ptr = &in_ie[cnt]; + + if (wps_ie) +diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +index 73fc1d4f92e6c6..1bc60be309dd6e 100644 +--- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c ++++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +@@ -1958,7 +1958,7 @@ static u8 rtw_get_chan_type(struct adapter *adapter) + else + return NL80211_CHAN_NO_HT; + case CHANNEL_WIDTH_40: +- if (mlme_ext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) ++ if (mlme_ext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) + return NL80211_CHAN_HT40PLUS; + else + return NL80211_CHAN_HT40MINUS; +diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c +index f88809ff370b73..82656645b8a64b 100644 +--- a/drivers/tty/serial/8250/8250_mid.c ++++ b/drivers/tty/serial/8250/8250_mid.c +@@ -318,9 +318,11 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) + if (!uart.port.membase) + return -ENOMEM; + +- ret = mid->board->setup(mid, &uart.port); +- if (ret) +- return ret; ++ if (mid->board->setup) { ++ ret = mid->board->setup(mid, &uart.port); ++ if (ret) ++ return ret; ++ } + + ret = mid8250_dma_setup(mid, &uart); + if (ret) +@@ -336,7 +338,8 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) + return 0; + + err: +- mid->board->exit(mid); ++ if (mid->board->exit) ++ mid->board->exit(mid); + return ret; + } + +@@ -346,7 +349,8 @@ static void mid8250_remove(struct pci_dev *pdev) + + serial8250_unregister_port(mid->line); + +- mid->board->exit(mid); ++ if (mid->board->exit) ++ mid->board->exit(mid); + } + + static const struct mid8250_board pnw_board = { +diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c +index c7435595dce13d..13a86f0c2d9b4d 100644 +--- a/drivers/tty/serial/sc16is7xx.c ++++ b/drivers/tty/serial/sc16is7xx.c +@@ -1328,6 +1328,17 @@ static int sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned int offset, + return 0; + } + ++static int sc16is7xx_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) ++{ ++ struct sc16is7xx_port *s = gpiochip_get_data(chip); ++ struct uart_port *port = &s->p[0].port; ++ unsigned int val; ++ ++ val = sc16is7xx_port_read(port, SC16IS7XX_IODIR_REG); ++ ++ return val & BIT(offset) ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; ++} ++ + static int sc16is7xx_gpio_direction_input(struct gpio_chip *chip, + unsigned offset) + { +@@ -1405,6 +1416,7 @@ static int sc16is7xx_setup_gpio_chip(struct sc16is7xx_port *s) + s->gpio.parent = dev; + s->gpio.label = dev_name(dev); + s->gpio.init_valid_mask = sc16is7xx_gpio_init_valid_mask; ++ s->gpio.get_direction = sc16is7xx_gpio_get_direction; + s->gpio.direction_input = sc16is7xx_gpio_direction_input; + s->gpio.get = sc16is7xx_gpio_get; + s->gpio.direction_output = sc16is7xx_gpio_direction_output; +diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c +index 3f8e2e27697fbe..c47d46334a7c00 100644 +--- a/drivers/uio/uio_hv_generic.c ++++ b/drivers/uio/uio_hv_generic.c +@@ -395,9 +395,15 @@ hv_uio_remove(struct hv_device *dev) + vmbus_free_ring(dev->channel); + } + ++static const struct hv_vmbus_device_id hv_uio_id_table[] = { ++ { HV_FCOPY_GUID }, ++ {} ++}; ++MODULE_DEVICE_TABLE(vmbus, hv_uio_id_table); ++ + static struct hv_driver hv_uio_drv = { + .name = "uio_hv_generic", +- .id_table = NULL, /* only dynamic id's */ ++ .id_table = hv_uio_id_table, + .probe = hv_uio_probe, + .remove = hv_uio_remove, + }; +diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c +index a943a5257a59fb..f1f1fc16a4711f 100644 +--- a/drivers/usb/atm/ueagle-atm.c ++++ b/drivers/usb/atm/ueagle-atm.c +@@ -2550,6 +2550,7 @@ static struct usbatm_driver uea_usbatm_driver = { + static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id) + { + struct usb_device *usb = interface_to_usbdev(intf); ++ bool single_iface = usb->config->desc.bNumInterfaces == 1; + int ret; + + uea_dbg(usb, "ADSL device found with vid (%#X) pid (%#X) Rev (%#X): %s\n", +@@ -2558,6 +2559,22 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id) + le16_to_cpu(usb->descriptor.bcdDevice), + chip_name[UEA_CHIP_VERSION(id)]); + ++ /* ++ * uea_probe() decides between the pre-firmware and post-firmware case ++ * from the USB id and stores a different object as interface data in ++ * each case: a struct completion for a pre-firmware device, a struct ++ * usbatm_data for a post-firmware one. uea_disconnect() instead tells ++ * the two apart by the number of interfaces (a pre-firmware device ++ * exposes a single interface, ADI930 has 2 and eagle has 3). A crafted ++ * device advertising a pre-firmware id together with a multi-interface ++ * descriptor (or the other way around) makes the two disagree, so that ++ * usbatm_usb_disconnect() treats the small completion object as a ++ * struct usbatm_data and reads out of bounds. Reject such inconsistent ++ * descriptors so both paths make the same decision. ++ */ ++ if (UEA_IS_PREFIRM(id) != single_iface) ++ return -ENODEV; ++ + usb_reset_device(usb); + + if (UEA_IS_PREFIRM(id)) { +diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c +index 4d3a89b9d38603..628b83099764a9 100644 +--- a/drivers/usb/chipidea/core.c ++++ b/drivers/usb/chipidea/core.c +@@ -1265,6 +1265,7 @@ static void ci_hdrc_remove(struct platform_device *pdev) + usb_role_switch_unregister(ci->role_switch); + + if (ci->supports_runtime_pm) { ++ pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); +diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c +index a47df5d32f7c4e..7cae194843556a 100644 +--- a/drivers/usb/core/port.c ++++ b/drivers/usb/core/port.c +@@ -726,6 +726,8 @@ static void connector_unbind(struct device *dev, struct device *connector, void + + sysfs_remove_link(&connector->kobj, dev_name(dev)); + sysfs_remove_link(&dev->kobj, "connector"); ++ if (port_dev->child) ++ typec_deattach(port_dev->connector, &port_dev->child->dev); + port_dev->connector = NULL; + } + +diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c +index a07866f1060cf4..d22dc78457d791 100644 +--- a/drivers/usb/core/sysfs.c ++++ b/drivers/usb/core/sysfs.c +@@ -899,10 +899,15 @@ bos_descriptors_read(struct file *filp, struct kobject *kobj, + { + struct device *dev = kobj_to_dev(kobj); + struct usb_device *udev = to_usb_device(dev); +- struct usb_host_bos *bos = udev->bos; ++ struct usb_host_bos *bos; + struct usb_bos_descriptor *desc; + size_t desclen, n = 0; ++ int rc; + ++ rc = usb_lock_device_interruptible(udev); ++ if (rc < 0) ++ return -EINTR; ++ bos = udev->bos; + if (bos) { + desc = bos->desc; + desclen = le16_to_cpu(desc->wTotalLength); +@@ -911,6 +916,7 @@ bos_descriptors_read(struct file *filp, struct kobject *kobj, + memcpy(buf, (void *) desc + off, n); + } + } ++ usb_unlock_device(udev); + return n; + } + static const BIN_ATTR_RO(bos_descriptors, 65535); /* max-size BOS */ +diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c +index da82598fcef8a8..28eca6698adaa9 100644 +--- a/drivers/usb/gadget/function/f_midi.c ++++ b/drivers/usb/gadget/function/f_midi.c +@@ -1302,6 +1302,7 @@ static void f_midi_free(struct usb_function *f) + opts = container_of(f->fi, struct f_midi_opts, func_inst); + mutex_lock(&opts->lock); + if (!--midi->free_ref) { ++ cancel_work_sync(&midi->work); + kfree(midi->id); + kfifo_free(&midi->in_req_fifo); + kfree(midi); +diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c +index 04be7047aa3d2c..fb57d57781ddb5 100644 +--- a/drivers/usb/gadget/function/f_ncm.c ++++ b/drivers/usb/gadget/function/f_ncm.c +@@ -1189,6 +1189,10 @@ static int ncm_unwrap_ntb(struct gether *port, + frame_max = ncm_opts->max_segment_size; + + parse_ntb: ++ if (to_process < (int)opts->nth_size) { ++ INFO(port->func.config->cdev, "Packet too small for headers\n"); ++ goto err; ++ } + tmp = (__le16 *)ntb_ptr; + + /* dwSignature */ +@@ -1209,8 +1213,12 @@ parse_ntb: + tmp++; /* skip wSequence */ + + block_len = get_ncm(&tmp, opts->block_length); ++ if (block_len == 0) ++ block_len = to_process; ++ + /* (d)wBlockLength */ +- if ((block_len < opts->nth_size + opts->ndp_size) || (block_len > ntb_max)) { ++ if ((block_len < opts->nth_size + opts->ndp_size) || (block_len > ntb_max) || ++ (block_len > to_process)) { + INFO(port->func.config->cdev, "Bad block length: %#X\n", block_len); + goto err; + } +@@ -1273,7 +1281,7 @@ parse_ntb: + index = index2; + /* wDatagramIndex[0] */ + if ((index < opts->nth_size) || +- (index > block_len - opts->dpe_size)) { ++ (index > block_len)) { + INFO(port->func.config->cdev, + "Bad index: %#X\n", index); + goto err; +@@ -1285,7 +1293,8 @@ parse_ntb: + * ethernet hdr + crc or larger than max frame size + */ + if ((dg_len < 14 + crc_len) || +- (dg_len > frame_max)) { ++ (dg_len > frame_max) || ++ (dg_len > block_len - index)) { + INFO(port->func.config->cdev, + "Bad dgram length: %#X\n", dg_len); + goto err; +@@ -1310,7 +1319,7 @@ parse_ntb: + dg_len2 = get_ncm(&tmp, opts->dgram_item_len); + + /* wDatagramIndex[1] */ +- if (index2 > block_len - opts->dpe_size) { ++ if (index2 > block_len) { + INFO(port->func.config->cdev, + "Bad index: %#X\n", index2); + goto err; +diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c +index a3884afa42b4bc..3db07d0fba89c8 100644 +--- a/drivers/usb/gadget/function/f_printer.c ++++ b/drivers/usb/gadget/function/f_printer.c +@@ -431,7 +431,7 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr) + { + struct printer_dev *dev = fd->private_data; + unsigned long flags; +- size_t size; ++ size_t size, not_copied, copied; + size_t bytes_copied; + struct usb_request *req; + /* This is a pointer to the current USB rx request. */ +@@ -524,10 +524,12 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr) + else + size = len; + +- size -= copy_to_user(buf, current_rx_buf, size); +- bytes_copied += size; +- len -= size; +- buf += size; ++ not_copied = copy_to_user(buf, current_rx_buf, size); ++ copied = size - not_copied; ++ ++ bytes_copied += copied; ++ len -= copied; ++ buf += copied; + + spin_lock_irqsave(&dev->lock, flags); + +@@ -542,6 +544,17 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr) + if (dev->interface < 0) + goto out_disabled; + ++ if (!copied) { ++ dev->current_rx_req = current_rx_req; ++ dev->current_rx_bytes = current_rx_bytes; ++ dev->current_rx_buf = current_rx_buf; ++ spin_unlock_irqrestore(&dev->lock, flags); ++ mutex_unlock(&dev->lock_printer_io); ++ return bytes_copied ? bytes_copied : -EFAULT; ++ } ++ ++ size = copied; ++ + /* If we not returning all the data left in this RX request + * buffer then adjust the amount of data left in the buffer. + * Othewise if we are done with this RX request buffer then +diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c +index 7b27f8082ace66..5753c83f557846 100644 +--- a/drivers/usb/gadget/function/f_tcm.c ++++ b/drivers/usb/gadget/function/f_tcm.c +@@ -2361,31 +2361,158 @@ ep_fail: + return -ENOTSUPP; + } + +-struct guas_setup_wq { +- struct work_struct work; +- struct f_uas *fu; +- unsigned int alt; +-}; ++static void tcm_cleanup_old_alt(struct f_uas *fu) ++{ ++ if (fu->flags & USBG_IS_UAS) ++ uasp_cleanup_old_alt(fu); ++ else if (fu->flags & USBG_IS_BOT) ++ bot_cleanup_old_alt(fu); ++ fu->flags = 0; ++} ++ ++static void tcm_delayed_set_alt_done(struct f_uas *fu) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&fu->delayed_set_alt_lock, flags); ++ fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_IDLE; ++ fu->delayed_set_alt_cancel = false; ++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags); ++} ++ ++static bool tcm_delayed_set_alt_cancelled(struct f_uas *fu) ++{ ++ bool cancelled; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&fu->delayed_set_alt_lock, flags); ++ cancelled = fu->delayed_set_alt_cancel; ++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags); ++ ++ return cancelled; ++} ++ ++static bool tcm_complete_delayed_status(struct f_uas *fu) ++{ ++ struct usb_composite_dev *cdev = fu->function.config->cdev; ++ struct usb_request *req = cdev->req; ++ unsigned long cdev_flags; ++ bool cancelled; ++ int ret; ++ ++ spin_lock_irqsave(&cdev->lock, cdev_flags); ++ spin_lock(&fu->delayed_set_alt_lock); ++ cancelled = fu->delayed_set_alt_cancel; ++ if (!cancelled) { ++ fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_IDLE; ++ fu->delayed_set_alt_cancel = false; ++ } ++ spin_unlock(&fu->delayed_set_alt_lock); ++ ++ if (cancelled) { ++ spin_unlock_irqrestore(&cdev->lock, cdev_flags); ++ return false; ++ } ++ ++ if (cdev->delayed_status == 0) { ++ WARN(cdev, "%s: Unexpected call\n", __func__); ++ } else if (--cdev->delayed_status == 0) { ++ req->length = 0; ++ req->context = cdev; ++ ret = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); ++ if (ret == 0) { ++ cdev->setup_pending = true; ++ } else { ++ req->status = 0; ++ req->complete(cdev->gadget->ep0, req); ++ } ++ } ++ ++ spin_unlock_irqrestore(&cdev->lock, cdev_flags); ++ ++ return true; ++} ++ ++static bool tcm_cancel_delayed_set_alt(struct f_uas *fu) ++{ ++ bool cleanup = false; ++ bool cancel = false; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&fu->delayed_set_alt_lock, flags); ++ switch (fu->delayed_set_alt_state) { ++ case USBG_DELAYED_SET_ALT_IDLE: ++ cleanup = true; ++ break; ++ case USBG_DELAYED_SET_ALT_QUEUED: ++ case USBG_DELAYED_SET_ALT_RUNNING: ++ fu->delayed_set_alt_cancel = true; ++ cancel = true; ++ break; ++ } ++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags); ++ ++ if (cancel && cancel_work(&fu->delayed_set_alt)) { ++ spin_lock_irqsave(&fu->delayed_set_alt_lock, flags); ++ if (fu->delayed_set_alt_state == USBG_DELAYED_SET_ALT_QUEUED) { ++ fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_IDLE; ++ fu->delayed_set_alt_cancel = false; ++ cleanup = true; ++ } ++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags); ++ } ++ ++ return cleanup; ++} ++ ++static void tcm_cancel_delayed_set_alt_sync(struct f_uas *fu) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&fu->delayed_set_alt_lock, flags); ++ if (fu->delayed_set_alt_state != USBG_DELAYED_SET_ALT_IDLE) ++ fu->delayed_set_alt_cancel = true; ++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags); ++ ++ cancel_work_sync(&fu->delayed_set_alt); ++ ++ spin_lock_irqsave(&fu->delayed_set_alt_lock, flags); ++ fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_IDLE; ++ fu->delayed_set_alt_cancel = false; ++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags); ++} + + static void tcm_delayed_set_alt(struct work_struct *wq) + { +- struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq, +- work); +- struct f_uas *fu = work->fu; +- int alt = work->alt; ++ struct f_uas *fu = container_of(wq, struct f_uas, delayed_set_alt); ++ unsigned long flags; ++ unsigned int alt; + +- kfree(work); ++ spin_lock_irqsave(&fu->delayed_set_alt_lock, flags); ++ if (fu->delayed_set_alt_state != USBG_DELAYED_SET_ALT_QUEUED) { ++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags); ++ return; ++ } ++ fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_RUNNING; ++ alt = fu->delayed_alt; ++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags); + +- if (fu->flags & USBG_IS_BOT) +- bot_cleanup_old_alt(fu); +- if (fu->flags & USBG_IS_UAS) +- uasp_cleanup_old_alt(fu); ++ tcm_cleanup_old_alt(fu); ++ ++ if (tcm_delayed_set_alt_cancelled(fu)) ++ goto out_done; + + if (alt == USB_G_ALT_INT_BBB) + bot_set_alt(fu); + else if (alt == USB_G_ALT_INT_UAS) + uasp_set_alt(fu); +- usb_composite_setup_continue(fu->function.config->cdev); ++ ++ if (tcm_complete_delayed_status(fu)) ++ return; ++ ++ tcm_cleanup_old_alt(fu); ++out_done: ++ tcm_delayed_set_alt_done(fu); + } + + static int tcm_get_alt(struct usb_function *f, unsigned intf) +@@ -2411,15 +2538,20 @@ static int tcm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) + return -EOPNOTSUPP; + + if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) { +- struct guas_setup_wq *work; ++ unsigned long flags; + +- work = kmalloc(sizeof(*work), GFP_ATOMIC); +- if (!work) +- return -ENOMEM; +- INIT_WORK(&work->work, tcm_delayed_set_alt); +- work->fu = fu; +- work->alt = alt; +- schedule_work(&work->work); ++ spin_lock_irqsave(&fu->delayed_set_alt_lock, flags); ++ if (fu->delayed_set_alt_state != USBG_DELAYED_SET_ALT_IDLE) { ++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, ++ flags); ++ return -EBUSY; ++ } ++ fu->delayed_alt = alt; ++ fu->delayed_set_alt_cancel = false; ++ fu->delayed_set_alt_state = USBG_DELAYED_SET_ALT_QUEUED; ++ spin_unlock_irqrestore(&fu->delayed_set_alt_lock, flags); ++ ++ schedule_work(&fu->delayed_set_alt); + return USB_GADGET_DELAYED_STATUS; + } + return -EOPNOTSUPP; +@@ -2429,11 +2561,8 @@ static void tcm_disable(struct usb_function *f) + { + struct f_uas *fu = to_f_uas(f); + +- if (fu->flags & USBG_IS_UAS) +- uasp_cleanup_old_alt(fu); +- else if (fu->flags & USBG_IS_BOT) +- bot_cleanup_old_alt(fu); +- fu->flags = 0; ++ if (tcm_cancel_delayed_set_alt(fu)) ++ tcm_cleanup_old_alt(fu); + } + + static int tcm_setup(struct usb_function *f, +@@ -2581,11 +2710,16 @@ static void tcm_free(struct usb_function *f) + { + struct f_uas *tcm = to_f_uas(f); + ++ tcm_cancel_delayed_set_alt_sync(tcm); + kfree(tcm); + } + + static void tcm_unbind(struct usb_configuration *c, struct usb_function *f) + { ++ struct f_uas *fu = to_f_uas(f); ++ ++ tcm_cancel_delayed_set_alt_sync(fu); ++ tcm_cleanup_old_alt(fu); + usb_free_all_descriptors(f); + } + +@@ -2618,6 +2752,8 @@ static struct usb_function *tcm_alloc(struct usb_function_instance *fi) + fu->function.disable = tcm_disable; + fu->function.free_func = tcm_free; + fu->tpg = tpg_instances[i].tpg; ++ INIT_WORK(&fu->delayed_set_alt, tcm_delayed_set_alt); ++ spin_lock_init(&fu->delayed_set_alt_lock); + + hash_init(fu->stream_hash); + mutex_unlock(&tpg_instances_lock); +diff --git a/drivers/usb/gadget/function/tcm.h b/drivers/usb/gadget/function/tcm.h +index 009974d81d66bb..e1d5a939161273 100644 +--- a/drivers/usb/gadget/function/tcm.h ++++ b/drivers/usb/gadget/function/tcm.h +@@ -3,6 +3,7 @@ + #define __TARGET_USB_GADGET_H__ + + #include <linux/kref.h> ++#include <linux/spinlock.h> + /* #include <linux/usb/uas.h> */ + #include <linux/hashtable.h> + #include <linux/usb/composite.h> +@@ -29,6 +30,12 @@ enum { + + #define USB_G_DEFAULT_SESSION_TAGS USBG_NUM_CMDS + ++enum { ++ USBG_DELAYED_SET_ALT_IDLE = 0, ++ USBG_DELAYED_SET_ALT_QUEUED, ++ USBG_DELAYED_SET_ALT_RUNNING, ++}; ++ + struct tcm_usbg_nexus { + struct se_session *tvn_se_sess; + }; +@@ -132,6 +139,12 @@ struct f_uas { + #define USBG_BOT_CMD_PEND (1 << 4) + #define USBG_BOT_WEDGED (1 << 5) + ++ struct work_struct delayed_set_alt; ++ spinlock_t delayed_set_alt_lock; /* protects delayed_set_alt_* */ ++ unsigned int delayed_alt; ++ unsigned int delayed_set_alt_state; ++ bool delayed_set_alt_cancel; ++ + struct usbg_cdb cmd[USBG_NUM_CMDS]; + struct usb_ep *ep_in; + struct usb_ep *ep_out; +diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c +index 23bafb07133f25..b5384c88b84c94 100644 +--- a/drivers/usb/gadget/function/uvc_v4l2.c ++++ b/drivers/usb/gadget/function/uvc_v4l2.c +@@ -200,6 +200,8 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data) + return usb_ep_set_halt(cdev->gadget->ep0); + + req->length = min_t(unsigned int, uvc->event_length, data->length); ++ if (req->length > sizeof(data->data)) ++ req->length = sizeof(data->data); + req->zero = data->length < uvc->event_length; + + memcpy(req->buf, data->data, req->length); +diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c +index f47aac078f6be6..de44cda273fb2a 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_core.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_core.c +@@ -586,9 +586,29 @@ disable_clk: + static void bdc_remove(struct platform_device *pdev) + { + struct bdc *bdc; ++ unsigned long flags; ++ u32 temp; + + bdc = platform_get_drvdata(pdev); + dev_dbg(bdc->dev, "%s ()\n", __func__); ++ /* ++ * Disable the device interrupt source before freeing the IRQ: ++ * clear BDC_GIE so the controller stops asserting interrupts, ++ * then free_irq drains any in-flight handler. ++ */ ++ spin_lock_irqsave(&bdc->lock, flags); ++ temp = bdc_readl(bdc->regs, BDC_BDCSC); ++ temp &= ~BDC_GIE; ++ bdc_writel(bdc->regs, BDC_BDCSC, temp); ++ spin_unlock_irqrestore(&bdc->lock, flags); ++ free_irq(bdc->irq, bdc); ++ /* ++ * Drain func_wake_notify after free_irq: the IRQ handler arms this ++ * delayed_work via bdc_sr_uspc -> handle_link_state_change -> ++ * schedule_delayed_work (self-rearmed in bdc_func_wake_timer), so ++ * the IRQ must be released first to prevent re-arm after cancel. ++ */ ++ cancel_delayed_work_sync(&bdc->func_wake_notify); + bdc_udc_exit(bdc); + bdc_hw_exit(bdc); + bdc_phy_exit(bdc); +diff --git a/drivers/usb/gadget/udc/bdc/bdc_udc.c b/drivers/usb/gadget/udc/bdc/bdc_udc.c +index 23826fd7a8e693..7a12219edac6fd 100644 +--- a/drivers/usb/gadget/udc/bdc/bdc_udc.c ++++ b/drivers/usb/gadget/udc/bdc/bdc_udc.c +@@ -530,8 +530,8 @@ int bdc_udc_init(struct bdc *bdc) + + + bdc->gadget.name = BRCM_BDC_NAME; +- ret = devm_request_irq(bdc->dev, bdc->irq, bdc_udc_interrupt, +- IRQF_SHARED, BRCM_BDC_NAME, bdc); ++ ret = request_irq(bdc->irq, bdc_udc_interrupt, IRQF_SHARED, ++ BRCM_BDC_NAME, bdc); + if (ret) { + dev_err(bdc->dev, + "failed to request irq #%d %d\n", +@@ -542,7 +542,7 @@ int bdc_udc_init(struct bdc *bdc) + ret = bdc_init_ep(bdc); + if (ret) { + dev_err(bdc->dev, "bdc init ep fail: %d\n", ret); +- return ret; ++ goto err0; + } + + ret = usb_add_gadget_udc(bdc->dev, &bdc->gadget); +@@ -571,6 +571,7 @@ int bdc_udc_init(struct bdc *bdc) + err1: + usb_del_gadget_udc(&bdc->gadget); + err0: ++ free_irq(bdc->irq, bdc); + bdc_free_ep(bdc); + + return ret; +diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c +index 4a78536644ba1b..5e3cbe0338bffc 100644 +--- a/drivers/usb/gadget/udc/dummy_hcd.c ++++ b/drivers/usb/gadget/udc/dummy_hcd.c +@@ -278,6 +278,7 @@ struct dummy { + unsigned ints_enabled:1; + unsigned udc_suspended:1; + unsigned pullup:1; ++ unsigned fifo_req_busy:1; + + /* + * HOST side support +@@ -329,6 +330,26 @@ static inline struct dummy *gadget_dev_to_dummy(struct device *dev) + + /* DEVICE/GADGET SIDE UTILITY ROUTINES */ + ++/* ++ * Give back a gadget request with dum->lock dropped around the callback. ++ * If @req is the shared fifo_req, clear fifo_req_busy afterward: the flag ++ * was set in dummy_queue() when the shared request was taken and must stay ++ * set until its completion callback has returned; list_del_init() alone ++ * makes the request look idle while the callback is still running. ++ * Caller holds dum->lock and has already done list_del_init() + status. ++ */ ++static void dummy_giveback(struct dummy *dum, struct usb_ep *_ep, ++ struct dummy_request *req) ++{ ++ bool fifo = req == &dum->fifo_req; ++ ++ spin_unlock(&dum->lock); ++ usb_gadget_giveback_request(_ep, &req->req); ++ spin_lock(&dum->lock); ++ if (fifo) ++ dum->fifo_req_busy = 0; ++} ++ + /* called with spinlock held */ + static void nuke(struct dummy *dum, struct dummy_ep *ep) + { +@@ -339,9 +360,7 @@ static void nuke(struct dummy *dum, struct dummy_ep *ep) + list_del_init(&req->queue); + req->req.status = -ESHUTDOWN; + +- spin_unlock(&dum->lock); +- usb_gadget_giveback_request(&ep->ep, &req->req); +- spin_lock(&dum->lock); ++ dummy_giveback(dum, &ep->ep, req); + } + } + +@@ -728,10 +747,11 @@ static int dummy_queue(struct usb_ep *_ep, struct usb_request *_req, + + /* implement an emulated single-request FIFO */ + if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) && +- list_empty(&dum->fifo_req.queue) && ++ !dum->fifo_req_busy && + list_empty(&ep->queue) && + _req->length <= FIFO_SIZE) { + req = &dum->fifo_req; ++ dum->fifo_req_busy = 1; + req->req = *_req; + req->req.buf = dum->fifo_buf; + memcpy(dum->fifo_buf, _req->buf, _req->length); +@@ -785,9 +805,7 @@ static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req) + dev_dbg(udc_dev(dum), + "dequeued req %p from %s, len %d buf %p\n", + req, _ep->name, _req->length, _req->buf); +- spin_unlock(&dum->lock); +- usb_gadget_giveback_request(_ep, _req); +- spin_lock(&dum->lock); ++ dummy_giveback(dum, _ep, req); + } + spin_unlock_irqrestore(&dum->lock, flags); + return retval; +@@ -1523,9 +1541,7 @@ top: + if (req->req.status != -EINPROGRESS) { + list_del_init(&req->queue); + +- spin_unlock(&dum->lock); +- usb_gadget_giveback_request(&ep->ep, &req->req); +- spin_lock(&dum->lock); ++ dummy_giveback(dum, &ep->ep, req); + + /* requests might have been unlinked... */ + rescan = 1; +@@ -1910,9 +1926,7 @@ restart: + dev_dbg(udc_dev(dum), "stale req = %p\n", + req); + +- spin_unlock(&dum->lock); +- usb_gadget_giveback_request(&ep->ep, &req->req); +- spin_lock(&dum->lock); ++ dummy_giveback(dum, &ep->ep, req); + ep->already_seen = 0; + goto restart; + } +diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c +index 4dea8bc30cf6d6..ed311f0d74b5eb 100644 +--- a/drivers/usb/gadget/udc/fsl_udc_core.c ++++ b/drivers/usb/gadget/udc/fsl_udc_core.c +@@ -184,7 +184,7 @@ __acquires(ep->udc->lock) + usb_gadget_unmap_request(&ep->udc->gadget, &req->req, ep_is_in(ep)); + + if (status && (status != -ESHUTDOWN)) +- dev_vdbg(&udc->gadget.dev, "complete %s req %p stat %d len %u/%u\n", ++ dev_vdbg(udc->dev, "complete %s req %p stat %d len %u/%u\n", + ep->ep.name, &req->req, status, + req->req.actual, req->req.length); + +@@ -286,7 +286,7 @@ static int dr_controller_setup(struct fsl_udc *udc) + timeout = jiffies + FSL_UDC_RESET_TIMEOUT; + while (fsl_readl(&dr_regs->usbcmd) & USB_CMD_CTRL_RESET) { + if (time_after(jiffies, timeout)) { +- dev_err(&udc->gadget.dev, "udc reset timeout!\n"); ++ dev_err(udc->dev, "udc reset timeout!\n"); + return -ETIMEDOUT; + } + cpu_relax(); +@@ -309,7 +309,7 @@ static int dr_controller_setup(struct fsl_udc *udc) + tmp &= USB_EP_LIST_ADDRESS_MASK; + fsl_writel(tmp, &dr_regs->endpointlistaddr); + +- dev_vdbg(&udc->gadget.dev, ++ dev_vdbg(udc->dev, + "vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x\n", + udc->ep_qh, (int)tmp, + fsl_readl(&dr_regs->endpointlistaddr)); +@@ -500,7 +500,7 @@ static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num, + tmp = max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS; + break; + default: +- dev_vdbg(&udc->gadget.dev, "error ep type is %d\n", ep_type); ++ dev_vdbg(udc->dev, "error ep type is %d\n", ep_type); + return; + } + if (zlt) +@@ -613,7 +613,7 @@ static int fsl_ep_enable(struct usb_ep *_ep, + spin_unlock_irqrestore(&udc->lock, flags); + retval = 0; + +- dev_vdbg(&udc->gadget.dev, "enabled %s (ep%d%s) maxpacket %d\n", ++ dev_vdbg(udc->dev, "enabled %s (ep%d%s) maxpacket %d\n", + ep->ep.name, ep->ep.desc->bEndpointAddress & 0x0f, + (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", + max); +@@ -634,13 +634,8 @@ static int fsl_ep_disable(struct usb_ep *_ep) + int ep_num; + + ep = container_of(_ep, struct fsl_ep, ep); +- if (!_ep || !ep->ep.desc) { +- /* +- * dev_vdbg(&udc->gadget.dev, "%s not enabled\n", +- * _ep ? ep->ep.name : NULL); +- */ ++ if (!_ep || !ep->ep.desc) + return -EINVAL; +- } + + /* disable ep on controller */ + ep_num = ep_index(ep); +@@ -664,7 +659,7 @@ static int fsl_ep_disable(struct usb_ep *_ep) + ep->stopped = 1; + spin_unlock_irqrestore(&udc->lock, flags); + +- dev_vdbg(&udc->gadget.dev, "disabled %s OK\n", _ep->name); ++ dev_vdbg(udc->dev, "disabled %s OK\n", _ep->name); + return 0; + } + +@@ -724,9 +719,6 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) + { + u32 temp, bitmask, tmp_stat; + +- /* dev_vdbg(&udc->gadget.dev, "QH addr Register 0x%8x\n", dr_regs->endpointlistaddr); +- dev_vdbg(&udc->gadget.dev, "ep_qh[%d] addr is 0x%8x\n", i, (u32)&(ep->udc->ep_qh[i])); */ +- + bitmask = ep_is_in(ep) + ? (1 << (ep_index(ep) + 16)) + : (1 << (ep_index(ep))); +@@ -813,7 +805,7 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length, + *is_last = 0; + + if ((*is_last) == 0) +- dev_vdbg(&udc_controller->gadget.dev, "multi-dtd request!\n"); ++ dev_vdbg(udc_controller->dev, "multi-dtd request!\n"); + /* Fill in the transfer size; set active bit */ + swap_temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE); + +@@ -825,7 +817,7 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length, + + mb(); + +- dev_vdbg(&udc_controller->gadget.dev, "length = %d address= 0x%x\n", *length, (int)*dma); ++ dev_vdbg(udc_controller->dev, "length = %d address= 0x%x\n", *length, (int)*dma); + + return dtd; + } +@@ -876,11 +868,11 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) + /* catch various bogus parameters */ + if (!_req || !req->req.complete || !req->req.buf + || !list_empty(&req->queue)) { +- dev_vdbg(&udc->gadget.dev, "%s, bad params\n", __func__); ++ dev_vdbg(udc->dev, "%s, bad params\n", __func__); + return -EINVAL; + } + if (unlikely(!ep->ep.desc)) { +- dev_vdbg(&udc->gadget.dev, "%s, bad ep\n", __func__); ++ dev_vdbg(udc->dev, "%s, bad ep\n", __func__); + return -EINVAL; + } + if (usb_endpoint_xfer_isoc(ep->ep.desc)) { +@@ -1040,7 +1032,7 @@ static int fsl_ep_set_halt(struct usb_ep *_ep, int value) + udc->ep0_dir = 0; + } + out: +- dev_vdbg(&udc->gadget.dev, "%s %s halt stat %d\n", ep->ep.name, ++ dev_vdbg(udc->dev, "%s %s halt stat %d\n", ep->ep.name, + value ? "set" : "clear", status); + + return status; +@@ -1109,7 +1101,7 @@ static void fsl_ep_fifo_flush(struct usb_ep *_ep) + /* Wait until flush complete */ + while (fsl_readl(&dr_regs->endptflush)) { + if (time_after(jiffies, timeout)) { +- dev_err(&udc_controller->gadget.dev, ++ dev_err(udc_controller->dev, + "ep flush timeout\n"); + return; + } +@@ -1182,7 +1174,7 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active) + + udc = container_of(gadget, struct fsl_udc, gadget); + spin_lock_irqsave(&udc->lock, flags); +- dev_vdbg(&gadget->dev, "VBUS %s\n", str_on_off(is_active)); ++ dev_vdbg(udc->dev, "VBUS %s\n", str_on_off(is_active)); + udc->vbus_active = (is_active != 0); + if (can_pullup(udc)) + fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP), +@@ -1548,7 +1540,7 @@ static void ep0_req_complete(struct fsl_udc *udc, struct fsl_ep *ep0, + udc->ep0_state = WAIT_FOR_SETUP; + break; + case WAIT_FOR_SETUP: +- dev_err(&udc->gadget.dev, "Unexpected ep0 packets\n"); ++ dev_err(udc->dev, "Unexpected ep0 packets\n"); + break; + default: + ep0stall(udc); +@@ -1617,7 +1609,7 @@ static int process_ep_req(struct fsl_udc *udc, int pipe, + errors = hc32_to_cpu(curr_td->size_ioc_sts); + if (errors & DTD_ERROR_MASK) { + if (errors & DTD_STATUS_HALTED) { +- dev_err(&udc->gadget.dev, "dTD error %08x QH=%d\n", errors, pipe); ++ dev_err(udc->dev, "dTD error %08x QH=%d\n", errors, pipe); + /* Clear the errors and Halt condition */ + tmp = hc32_to_cpu(curr_qh->size_ioc_int_sts); + tmp &= ~errors; +@@ -1628,26 +1620,26 @@ static int process_ep_req(struct fsl_udc *udc, int pipe, + break; + } + if (errors & DTD_STATUS_DATA_BUFF_ERR) { +- dev_vdbg(&udc->gadget.dev, "Transfer overflow\n"); ++ dev_vdbg(udc->dev, "Transfer overflow\n"); + status = -EPROTO; + break; + } else if (errors & DTD_STATUS_TRANSACTION_ERR) { +- dev_vdbg(&udc->gadget.dev, "ISO error\n"); ++ dev_vdbg(udc->dev, "ISO error\n"); + status = -EILSEQ; + break; + } else +- dev_err(&udc->gadget.dev, ++ dev_err(udc->dev, + "Unknown error has occurred (0x%x)!\n", + errors); + + } else if (hc32_to_cpu(curr_td->size_ioc_sts) + & DTD_STATUS_ACTIVE) { +- dev_vdbg(&udc->gadget.dev, "Request not complete\n"); ++ dev_vdbg(udc->dev, "Request not complete\n"); + status = REQ_UNCOMPLETE; + return status; + } else if (remaining_length) { + if (direction) { +- dev_vdbg(&udc->gadget.dev, ++ dev_vdbg(udc->dev, + "Transmit dTD remaining length not zero\n"); + status = -EPROTO; + break; +@@ -1655,8 +1647,7 @@ static int process_ep_req(struct fsl_udc *udc, int pipe, + break; + } + } else { +- dev_vdbg(&udc->gadget.dev, +- "dTD transmitted successful\n"); ++ dev_vdbg(udc->dev, "dTD transmitted successful\n"); + } + + if (j != curr_req->dtd_count - 1) +@@ -1699,7 +1690,7 @@ static void dtd_complete_irq(struct fsl_udc *udc) + + /* If the ep is configured */ + if (!curr_ep->ep.name) { +- dev_warn(&udc->gadget.dev, "Invalid EP?\n"); ++ dev_warn(udc->dev, "Invalid EP?\n"); + continue; + } + +@@ -1708,7 +1699,7 @@ static void dtd_complete_irq(struct fsl_udc *udc) + queue) { + status = process_ep_req(udc, i, curr_req); + +- dev_vdbg(&udc->gadget.dev, ++ dev_vdbg(udc->dev, + "status of process_ep_req= %d, ep = %d\n", + status, ep_num); + if (status == REQ_UNCOMPLETE) +@@ -1829,7 +1820,7 @@ static void reset_irq(struct fsl_udc *udc) + while (fsl_readl(&dr_regs->endpointprime)) { + /* Wait until all endptprime bits cleared */ + if (time_after(jiffies, timeout)) { +- dev_err(&udc->gadget.dev, "Timeout for reset\n"); ++ dev_err(udc->dev, "Timeout for reset\n"); + break; + } + cpu_relax(); +@@ -1839,7 +1830,7 @@ static void reset_irq(struct fsl_udc *udc) + fsl_writel(0xffffffff, &dr_regs->endptflush); + + if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) { +- dev_vdbg(&udc->gadget.dev, "Bus reset\n"); ++ dev_vdbg(udc->dev, "Bus reset\n"); + /* Bus is reseting */ + udc->bus_reset = 1; + /* Reset all the queues, include XD, dTD, EP queue +@@ -1847,7 +1838,7 @@ static void reset_irq(struct fsl_udc *udc) + reset_queues(udc, true); + udc->usb_state = USB_STATE_DEFAULT; + } else { +- dev_vdbg(&udc->gadget.dev, "Controller reset\n"); ++ dev_vdbg(udc->dev, "Controller reset\n"); + /* initialize usb hw reg except for regs for EP, not + * touch usbintr reg */ + dr_controller_setup(udc); +@@ -1881,7 +1872,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) + /* Clear notification bits */ + fsl_writel(irq_src, &dr_regs->usbsts); + +- /* dev_vdbg(&udc->gadget.dev, "irq_src [0x%8x]", irq_src); */ ++ /* dev_vdbg(udc->dev, "irq_src [0x%8x]", irq_src); */ + + /* Need to resume? */ + if (udc->usb_state == USB_STATE_SUSPENDED) +@@ -1890,7 +1881,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) + + /* USB Interrupt */ + if (irq_src & USB_STS_INT) { +- dev_vdbg(&udc->gadget.dev, "Packet int\n"); ++ dev_vdbg(udc->dev, "Packet int\n"); + /* Setup package, we only support ep0 as control ep */ + if (fsl_readl(&dr_regs->endptsetupstat) & EP_SETUP_STATUS_EP0) { + tripwire_handler(udc, 0, +@@ -1919,7 +1910,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) + + /* Reset Received */ + if (irq_src & USB_STS_RESET) { +- dev_vdbg(&udc->gadget.dev, "reset int\n"); ++ dev_vdbg(udc->dev, "reset int\n"); + reset_irq(udc); + status = IRQ_HANDLED; + } +@@ -1931,7 +1922,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) + } + + if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) { +- dev_vdbg(&udc->gadget.dev, "Error IRQ %x\n", irq_src); ++ dev_vdbg(udc->dev, "Error IRQ %x\n", irq_src); + } + + spin_unlock_irqrestore(&udc->lock, flags); +@@ -1967,7 +1958,7 @@ static int fsl_udc_start(struct usb_gadget *g, + udc_controller->transceiver->otg, + &udc_controller->gadget); + if (retval < 0) { +- dev_err(&udc_controller->gadget.dev, "can't bind to transceiver\n"); ++ dev_err(udc_controller->dev, "can't bind to transceiver\n"); + udc_controller->driver = NULL; + return retval; + } +@@ -2252,7 +2243,7 @@ static int struct_udc_setup(struct fsl_udc *udc, + + udc->eps = kcalloc(udc->max_ep, sizeof(struct fsl_ep), GFP_KERNEL); + if (!udc->eps) { +- dev_err(&udc->gadget.dev, "kmalloc udc endpoint status failed\n"); ++ dev_err(udc->dev, "kmalloc udc endpoint status failed\n"); + goto eps_alloc_failed; + } + +@@ -2267,7 +2258,7 @@ static int struct_udc_setup(struct fsl_udc *udc, + udc->ep_qh = dma_alloc_coherent(&pdev->dev, size, + &udc->ep_qh_dma, GFP_KERNEL); + if (!udc->ep_qh) { +- dev_err(&udc->gadget.dev, "malloc QHs for udc failed\n"); ++ dev_err(udc->dev, "malloc QHs for udc failed\n"); + goto ep_queue_alloc_failed; + } + +@@ -2278,14 +2269,14 @@ static int struct_udc_setup(struct fsl_udc *udc, + udc->status_req = container_of(fsl_alloc_request(NULL, GFP_KERNEL), + struct fsl_req, req); + if (!udc->status_req) { +- dev_err(&udc->gadget.dev, "kzalloc for udc status request failed\n"); ++ dev_err(udc->dev, "kzalloc for udc status request failed\n"); + goto udc_status_alloc_failed; + } + + /* allocate a small amount of memory to get valid address */ + udc->status_req->req.buf = kmalloc(8, GFP_KERNEL); + if (!udc->status_req->req.buf) { +- dev_err(&udc->gadget.dev, "kzalloc for udc request buffer failed\n"); ++ dev_err(udc->dev, "kzalloc for udc request buffer failed\n"); + goto udc_req_buf_alloc_failed; + } + +@@ -2373,6 +2364,7 @@ static int fsl_udc_probe(struct platform_device *pdev) + if (udc_controller == NULL) + return -ENOMEM; + ++ udc_controller->dev = &pdev->dev; + pdata = dev_get_platdata(&pdev->dev); + udc_controller->pdata = pdata; + spin_lock_init(&udc_controller->lock); +@@ -2382,7 +2374,7 @@ static int fsl_udc_probe(struct platform_device *pdev) + if (pdata->operating_mode == FSL_USB2_DR_OTG) { + udc_controller->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); + if (IS_ERR_OR_NULL(udc_controller->transceiver)) { +- dev_err(&udc_controller->gadget.dev, "Can't find OTG driver!\n"); ++ dev_err(&pdev->dev, "Can't find OTG driver!\n"); + ret = -ENODEV; + goto err_kfree; + } +@@ -2398,7 +2390,7 @@ static int fsl_udc_probe(struct platform_device *pdev) + if (pdata->operating_mode == FSL_USB2_DR_DEVICE) { + if (!request_mem_region(res->start, resource_size(res), + driver_name)) { +- dev_err(&udc_controller->gadget.dev, "request mem region for %s failed\n", pdev->name); ++ dev_err(&pdev->dev, "failed to request mem region\n"); + ret = -EBUSY; + goto err_kfree; + } +@@ -2429,7 +2421,7 @@ static int fsl_udc_probe(struct platform_device *pdev) + /* Read Device Controller Capability Parameters register */ + dccparams = fsl_readl(&dr_regs->dccparams); + if (!(dccparams & DCCPARAMS_DC)) { +- dev_err(&udc_controller->gadget.dev, "This SOC doesn't support device role\n"); ++ dev_err(&pdev->dev, "This SOC doesn't support device role\n"); + ret = -ENODEV; + goto err_exit; + } +@@ -2447,14 +2439,14 @@ static int fsl_udc_probe(struct platform_device *pdev) + ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED, + driver_name, udc_controller); + if (ret != 0) { +- dev_err(&udc_controller->gadget.dev, "cannot request irq %d err %d\n", ++ dev_err(&pdev->dev, "cannot request irq %d err %d\n", + udc_controller->irq, ret); + goto err_exit; + } + + /* Initialize the udc structure including QH member and other member */ + if (struct_udc_setup(udc_controller, pdev)) { +- dev_err(&udc_controller->gadget.dev, "Can't initialize udc data structure\n"); ++ dev_err(&pdev->dev, "Can't initialize udc data structure\n"); + ret = -ENOMEM; + goto err_free_irq; + } +@@ -2474,7 +2466,6 @@ static int fsl_udc_probe(struct platform_device *pdev) + udc_controller->gadget.name = driver_name; + + /* Setup gadget.dev and register with kernel */ +- dev_set_name(&udc_controller->gadget.dev, "gadget"); + udc_controller->gadget.dev.of_node = pdev->dev.of_node; + + if (!IS_ERR_OR_NULL(udc_controller->transceiver)) +diff --git a/drivers/usb/gadget/udc/fsl_usb2_udc.h b/drivers/usb/gadget/udc/fsl_usb2_udc.h +index cc1756f3e89d13..53922bc58ca014 100644 +--- a/drivers/usb/gadget/udc/fsl_usb2_udc.h ++++ b/drivers/usb/gadget/udc/fsl_usb2_udc.h +@@ -470,6 +470,7 @@ struct fsl_ep { + #define EP_DIR_OUT 0 + + struct fsl_udc { ++ struct device *dev; + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct fsl_usb2_platform_data *pdata; +diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c +index 373942ceb07699..2f790cc65257b8 100644 +--- a/drivers/usb/gadget/udc/snps_udc_core.c ++++ b/drivers/usb/gadget/udc/snps_udc_core.c +@@ -3133,7 +3133,6 @@ int udc_probe(struct udc *dev) + /* device struct setup */ + dev->gadget.ops = &udc_ops; + +- dev_set_name(&dev->gadget.dev, "gadget"); + dev->gadget.name = name; + dev->gadget.max_speed = USB_SPEED_HIGH; + +diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c +index f67a4d9562046f..734f7e74158354 100644 +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -448,6 +448,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == PCI_DEVICE_ID_VIA_VL805) { + xhci->quirks |= XHCI_LPM_SUPPORT; + xhci->quirks |= XHCI_TRB_OVERFETCH; ++ xhci->dma_mask_bits = 36; + } + + if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && +diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c +index a06758addbf823..23b104c2956c7c 100644 +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -5459,6 +5459,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) + if (xhci->hci_version > 0x100) + xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2); + ++ xhci->dma_mask_bits = 64; + /* xhci-plat or xhci-pci might have set max_interrupters already */ + if ((!xhci->max_interrupters) || + xhci->max_interrupters > HCS_MAX_INTRS(xhci->hcs_params1)) +@@ -5505,12 +5506,16 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) + if (xhci->quirks & XHCI_NO_64BIT_SUPPORT) + xhci->hcc_params &= ~BIT(0); + +- /* Set dma_mask and coherent_dma_mask to 64-bits, +- * if xHC supports 64-bit addressing */ ++ /* ++ * Set dma_mask and coherent_dma_mask to 64-bits if xHC supports ++ * 64-bit addressing, unless a controller-specific quirk callback ++ * limits the usable address width. ++ */ + if (HCC_64BIT_ADDR(xhci->hcc_params) && +- !dma_set_mask(dev, DMA_BIT_MASK(64))) { +- xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); +- dma_set_coherent_mask(dev, DMA_BIT_MASK(64)); ++ !dma_set_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits))) { ++ xhci_dbg(xhci, "Enabling %u-bit DMA addresses.\n", ++ xhci->dma_mask_bits); ++ dma_set_coherent_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits)); + } else { + /* + * This is to avoid error in cases where a 32-bit USB +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index 58a51f09cceb8f..4cd4cb0e431d17 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1524,6 +1524,7 @@ struct xhci_hcd { + /* imod_interval in ns (I * 250ns) */ + u32 imod_interval; + u32 page_size; ++ unsigned int dma_mask_bits; + /* MSI-X/MSI vectors */ + int nvecs; + /* optional clocks */ +diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c +index aadabc415145bb..77133ee77063cc 100644 +--- a/drivers/usb/musb/omap2430.c ++++ b/drivers/usb/musb/omap2430.c +@@ -455,7 +455,6 @@ static int omap2430_probe(struct platform_device *pdev) + dev_err(&pdev->dev, "failed to register musb device\n"); + goto err_disable_rpm; + } +- of_node_put(np); + + return 0; + +@@ -465,7 +464,6 @@ err_put_control_otghs: + if (!IS_ERR(glue->control_otghs)) + put_device(glue->control_otghs); + err_put_musb: +- of_node_put(np); + platform_device_put(musb); + + return ret; +diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c +index ceddfb1852e165..8eb50640e8b734 100644 +--- a/drivers/usb/serial/ftdi_sio.c ++++ b/drivers/usb/serial/ftdi_sio.c +@@ -1075,6 +1075,8 @@ static const struct usb_device_id id_table_combined[] = { + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602E_PID, 3) }, + /* Abacus Electrics */ + { USB_DEVICE(FTDI_VID, ABACUS_OPTICAL_PROBE_PID) }, ++ /* Endress+Hauser AG devices */ ++ { USB_DEVICE(FTDI_VID, FTDI_EH_FXA291_PID) }, + { } /* Terminating entry */ + }; + +diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h +index 6c76cfebfd0e42..9c83c17853c871 100644 +--- a/drivers/usb/serial/ftdi_sio_ids.h ++++ b/drivers/usb/serial/ftdi_sio_ids.h +@@ -313,6 +313,11 @@ + #define FTDI_ELV_UDF77_PID 0xFB5E /* USB DCF Funkuhr (UDF 77) */ + #define FTDI_ELV_UIO88_PID 0xFB5F /* USB-I/O Interface (UIO 88) */ + ++/* ++ * Endress+Hauser AG product ids (FTDI_VID) ++ */ ++#define FTDI_EH_FXA291_PID 0xE510 ++ + /* + * EVER Eco Pro UPS (http://www.ever.com.pl/) + */ +diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c +index ad73040b30c8d7..9b8fb8467b5378 100644 +--- a/drivers/usb/serial/io_edgeport.c ++++ b/drivers/usb/serial/io_edgeport.c +@@ -646,7 +646,8 @@ static void edge_interrupt_callback(struct urb *urb) + if (edge_port && edge_port->open) { + spin_lock_irqsave(&edge_port->ep_lock, + flags); +- edge_port->txCredits += txCredits; ++ edge_port->txCredits = min(edge_port->txCredits + txCredits, ++ edge_port->maxTxCredits); + spin_unlock_irqrestore(&edge_port->ep_lock, + flags); + dev_dbg(dev, "%s - txcredits for port%d = %d\n", +diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c +index f800bf5ac1de95..e500ffd150854a 100644 +--- a/drivers/usb/serial/keyspan_pda.c ++++ b/drivers/usb/serial/keyspan_pda.c +@@ -35,6 +35,8 @@ struct keyspan_pda_private { + struct work_struct unthrottle_work; + struct usb_serial *serial; + struct usb_serial_port *port; ++ bool throttled; ++ bool throttle_req; + }; + + static int keyspan_pda_write_start(struct usb_serial_port *port); +@@ -150,6 +152,7 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) + int retval; + int status = urb->status; + struct keyspan_pda_private *priv; ++ bool throttled = false; + unsigned long flags; + + priv = usb_get_serial_port_data(port); +@@ -211,16 +214,24 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) + } + + exit: +- retval = usb_submit_urb(urb, GFP_ATOMIC); +- if (retval) +- dev_err(&port->dev, +- "%s - usb_submit_urb failed with result %d\n", +- __func__, retval); ++ spin_lock_irqsave(&port->lock, flags); ++ if (priv->throttle_req) { ++ priv->throttled = true; ++ throttled = true; ++ } ++ spin_unlock_irqrestore(&port->lock, flags); ++ ++ if (!throttled) { ++ retval = usb_submit_urb(urb, GFP_ATOMIC); ++ if (retval) ++ dev_err(&port->dev, "failed to resubmit in urb: %d\n", retval); ++ } + } + + static void keyspan_pda_rx_throttle(struct tty_struct *tty) + { + struct usb_serial_port *port = tty->driver_data; ++ struct keyspan_pda_private *priv = usb_get_serial_port_data(port); + + /* + * Stop receiving characters. We just turn off the URB request, and +@@ -230,16 +241,29 @@ static void keyspan_pda_rx_throttle(struct tty_struct *tty) + * send an XOFF, although it might make sense to foist that off upon + * the device too. + */ +- usb_kill_urb(port->interrupt_in_urb); ++ spin_lock_irq(&port->lock); ++ priv->throttle_req = true; ++ spin_unlock_irq(&port->lock); + } + + static void keyspan_pda_rx_unthrottle(struct tty_struct *tty) + { + struct usb_serial_port *port = tty->driver_data; ++ struct keyspan_pda_private *priv = usb_get_serial_port_data(port); ++ bool throttled; ++ int ret; + +- /* just restart the receive interrupt URB */ +- if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL)) +- dev_dbg(&port->dev, "usb_submit_urb(read urb) failed\n"); ++ spin_lock_irq(&port->lock); ++ throttled = priv->throttled; ++ priv->throttled = false; ++ priv->throttle_req = false; ++ spin_unlock_irq(&port->lock); ++ ++ if (throttled) { ++ ret = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); ++ if (ret) ++ dev_err(&port->dev, "failed to submit in urb: %d\n", ret); ++ } + } + + static speed_t keyspan_pda_setbaud(struct usb_serial *serial, speed_t baud) +@@ -579,6 +603,8 @@ static int keyspan_pda_open(struct tty_struct *tty, + + spin_lock_irq(&port->lock); + priv->tx_room = rc; ++ priv->throttled = false; ++ priv->throttle_req = false; + spin_unlock_irq(&port->lock); + + rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); +diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c +index b4b58e48e2253d..89624f38fec2eb 100644 +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -2497,6 +2497,7 @@ static const struct usb_device_id option_ids[] = { + .driver_info = RSVD(5) }, + { USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x1003, 0xff), /* Rolling RW135R-GL (laptop MBIM) */ + .driver_info = RSVD(5) }, ++ { USB_DEVICE_INTERFACE_CLASS(0x3466, 0x3301, 0xff) }, /* TDTECH MT5710-CN */ + { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x30) }, /* NetPrisma LCUK54-WWD for Global */ + { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0x00, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x40) }, +diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h +index 255968f9ca42ae..ac22fa31873439 100644 +--- a/drivers/usb/storage/unusual_devs.h ++++ b/drivers/usb/storage/unusual_devs.h +@@ -395,6 +395,13 @@ UNUSUAL_DEV( 0x04b3, 0x4001, 0x0110, 0x0110, + USB_SC_DEVICE, USB_PR_CB, NULL, + US_FL_MAX_SECTORS_MIN), + ++/* Reported by Ai Chao <aichao-UOlijcLmZ/[email protected]> */ ++UNUSUAL_DEV( 0x04b4, 0xb708, 0x0000, 0xffff, ++ "Longmai Technologies", ++ "USB Key", ++ USB_SC_SCSI, USB_PR_BULK, NULL, ++ US_FL_NO_ATA_1X), ++ + /* + * Reported by Simon Levitt <simon-V/[email protected]> + * This entry needs Sub and Proto fields +diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c +index b4b0c46d2fa44f..01a15ab5a734ac 100644 +--- a/drivers/usb/typec/ucsi/ucsi.c ++++ b/drivers/usb/typec/ucsi/ucsi.c +@@ -487,6 +487,129 @@ err: + return ret; + } + ++static void ucsi_dump_duplicate_altmode(struct ucsi_connector *con, ++ u8 recipient, u16 svid, ++ u32 existing_vdo, u32 new_vdo, ++ int offset) ++{ ++ static const char * const recipient_names[] = { ++ [UCSI_RECIPIENT_CON] = "port", ++ [UCSI_RECIPIENT_SOP] = "partner", ++ [UCSI_RECIPIENT_SOP_P] = "plug", ++ [UCSI_RECIPIENT_SOP_PP] = "cable plug prime", ++ }; ++ ++ dev_warn(con->ucsi->dev, ++ "con%d: Firmware bug: duplicate %s altmode SVID 0x%04x at offset %d, ignoring but please contact the BIOS vendor to fix this issue.\n", ++ con->num, recipient_names[recipient], svid, offset); ++ ++ if (existing_vdo != new_vdo) ++ dev_warn(con->ucsi->dev, ++ "con%d: VDO mismatch: 0x%08x vs 0x%08x\n", ++ con->num, existing_vdo, new_vdo); ++} ++ ++/* Count altmodes in @altmodes that advertise @svid. */ ++static int ucsi_altmode_count_svid(struct typec_altmode **altmodes, u16 svid) ++{ ++ int count = 0; ++ int k; ++ ++ for (k = 0; k < UCSI_MAX_ALTMODES; k++) { ++ if (!altmodes[k]) ++ break; ++ if (altmodes[k]->svid == svid) ++ count++; ++ } ++ ++ return count; ++} ++ ++/* ++ * Check if an altmode is a duplicate. Some firmware implementations ++ * incorrectly return the same altmode multiple times, causing sysfs errors. ++ * Returns true if the altmode should be skipped. ++ * ++ * The matching rules differ by recipient: ++ * ++ * - UCSI_RECIPIENT_CON (port) and UCSI_RECIPIENT_SOP_P (plug): ++ * Two altmodes with identical SVID and VDO are byte-for-byte duplicates ++ * and the second has no observable function. Drop them. ++ * ++ * - UCSI_RECIPIENT_SOP (partner): ++ * The typec class binds each partner altmode to a port altmode of the ++ * same SVID via altmode_match()/device_find_child(), which returns the ++ * first port altmode with a matching SVID. If the partner advertises ++ * more altmodes for SVID X than the port advertises, the surplus ++ * partner altmode(s) collapse onto an already-paired port altmode and ++ * trigger a "duplicate filename .../partner" sysfs error during ++ * typec_altmode_create_links(). Use the port-side altmode count for ++ * SVID X as the authoritative cap and reject any partner altmode that ++ * would exceed it. This preserves legitimate multi-Mode partner ++ * altmodes (e.g. vendor SVIDs that the port really does advertise ++ * twice) while filtering the firmware-generated duplicates that have ++ * no port counterpart. ++ */ ++static bool ucsi_altmode_is_duplicate(struct ucsi_connector *con, u8 recipient, ++ const struct ucsi_altmode *alt_batch, int batch_idx, ++ u16 svid, u32 vdo, int offset) ++{ ++ struct typec_altmode **altmodes; ++ int port_count, partner_count; ++ int k; ++ ++ /* Check for duplicates within the current batch first */ ++ for (k = 0; k < batch_idx; k++) { ++ if (alt_batch[k].svid == svid && alt_batch[k].mid == vdo) { ++ ucsi_dump_duplicate_altmode(con, recipient, svid, ++ vdo, vdo, offset); ++ return true; ++ } ++ } ++ ++ switch (recipient) { ++ case UCSI_RECIPIENT_SOP: ++ /* ++ * Cap partner altmodes per SVID by the port-side count: ++ * any further partner altmode for that SVID would alias an ++ * already-paired port altmode and break typec sysfs. ++ */ ++ port_count = ucsi_altmode_count_svid(con->port_altmode, svid); ++ partner_count = ucsi_altmode_count_svid(con->partner_altmode, ++ svid); ++ if (port_count && partner_count >= port_count) { ++ ucsi_dump_duplicate_altmode(con, recipient, svid, ++ con->partner_altmode[partner_count - 1]->vdo, ++ vdo, offset); ++ return true; ++ } ++ return false; ++ case UCSI_RECIPIENT_CON: ++ altmodes = con->port_altmode; ++ break; ++ case UCSI_RECIPIENT_SOP_P: ++ altmodes = con->plug_altmode; ++ break; ++ default: ++ return false; ++ } ++ ++ /* CON and SOP_P: drop only exact SVID+VDO duplicates. */ ++ for (k = 0; k < UCSI_MAX_ALTMODES; k++) { ++ if (!altmodes[k]) ++ break; ++ ++ if (altmodes[k]->svid != svid || altmodes[k]->vdo != vdo) ++ continue; ++ ++ ucsi_dump_duplicate_altmode(con, recipient, svid, ++ altmodes[k]->vdo, vdo, offset); ++ return true; ++ } ++ ++ return false; ++} ++ + static int + ucsi_register_altmodes_nvidia(struct ucsi_connector *con, u8 recipient) + { +@@ -541,19 +664,25 @@ ucsi_register_altmodes_nvidia(struct ucsi_connector *con, u8 recipient) + + /* now register altmodes */ + for (i = 0; i < max_altmodes; i++) { +- memset(&desc, 0, sizeof(desc)); +- if (multi_dp) { +- desc.svid = updated[i].svid; +- desc.vdo = updated[i].mid; +- } else { +- desc.svid = orig[i].svid; +- desc.vdo = orig[i].mid; +- } +- desc.roles = TYPEC_PORT_DRD; ++ struct ucsi_altmode *altmode_array = multi_dp ? updated : orig; + +- if (!desc.svid) ++ if (!altmode_array[i].svid) + return 0; + ++ /* ++ * Check for duplicates in current array and already ++ * registered altmodes. Skip if duplicate found. ++ */ ++ if (ucsi_altmode_is_duplicate(con, recipient, altmode_array, i, ++ altmode_array[i].svid, ++ altmode_array[i].mid, i)) ++ continue; ++ ++ memset(&desc, 0, sizeof(desc)); ++ desc.svid = altmode_array[i].svid; ++ desc.vdo = altmode_array[i].mid; ++ desc.roles = TYPEC_PORT_DRD; ++ + ret = ucsi_register_altmode(con, &desc, recipient); + if (ret) + return ret; +@@ -611,6 +740,15 @@ static int ucsi_register_altmodes(struct ucsi_connector *con, u8 recipient) + if (!alt[j].svid) + return 0; + ++ /* ++ * Check for duplicates in current batch and already ++ * registered altmodes. Skip if duplicate found. ++ */ ++ if (ucsi_altmode_is_duplicate(con, recipient, alt, j, ++ alt[j].svid, alt[j].mid, ++ i - num + j)) ++ continue; ++ + memset(&desc, 0, sizeof(desc)); + desc.vdo = alt[j].mid; + desc.svid = alt[j].svid; +diff --git a/drivers/vdpa/vdpa_user/iova_domain.c b/drivers/vdpa/vdpa_user/iova_domain.c +index 4352b5cf74f078..ec743bed361c17 100644 +--- a/drivers/vdpa/vdpa_user/iova_domain.c ++++ b/drivers/vdpa/vdpa_user/iova_domain.c +@@ -124,7 +124,7 @@ static int vduse_domain_map_bounce_page(struct vduse_iova_domain *domain, + if (!map->bounce_page) { + head_map = &domain->bounce_maps[(iova & PAGE_MASK) >> BOUNCE_MAP_SHIFT]; + if (!head_map->bounce_page) { +- tmp_page = alloc_page(GFP_ATOMIC); ++ tmp_page = alloc_page(GFP_ATOMIC | __GFP_ZERO); + if (!tmp_page) + return -ENOMEM; + if (cmpxchg(&head_map->bounce_page, NULL, tmp_page)) +@@ -493,17 +493,15 @@ void vduse_domain_unmap_page(struct vduse_iova_domain *domain, + vduse_domain_free_iova(iovad, dma_addr, size); + } + +-void *vduse_domain_alloc_coherent(struct vduse_iova_domain *domain, +- size_t size, dma_addr_t *dma_addr, +- gfp_t flag) ++dma_addr_t vduse_domain_alloc_coherent(struct vduse_iova_domain *domain, ++ size_t size, void *orig) + { + struct iova_domain *iovad = &domain->consistent_iovad; + unsigned long limit = domain->iova_limit; + dma_addr_t iova = vduse_domain_alloc_iova(iovad, size, limit); +- void *orig = alloc_pages_exact(size, flag); + +- if (!iova || !orig) +- goto err; ++ if (!iova) ++ return DMA_MAPPING_ERROR; + + spin_lock(&domain->iotlb_lock); + if (vduse_iotlb_add_range(domain, (u64)iova, (u64)iova + size - 1, +@@ -514,27 +512,20 @@ void *vduse_domain_alloc_coherent(struct vduse_iova_domain *domain, + } + spin_unlock(&domain->iotlb_lock); + +- *dma_addr = iova; ++ return iova; + +- return orig; + err: +- *dma_addr = DMA_MAPPING_ERROR; +- if (orig) +- free_pages_exact(orig, size); +- if (iova) +- vduse_domain_free_iova(iovad, iova, size); ++ vduse_domain_free_iova(iovad, iova, size); + +- return NULL; ++ return DMA_MAPPING_ERROR; + } + + void vduse_domain_free_coherent(struct vduse_iova_domain *domain, size_t size, +- void *vaddr, dma_addr_t dma_addr, +- unsigned long attrs) ++ dma_addr_t dma_addr, unsigned long attrs) + { + struct iova_domain *iovad = &domain->consistent_iovad; + struct vhost_iotlb_map *map; + struct vdpa_map_file *map_file; +- phys_addr_t pa; + + spin_lock(&domain->iotlb_lock); + map = vhost_iotlb_itree_first(domain->iotlb, (u64)dma_addr, +@@ -546,12 +537,10 @@ void vduse_domain_free_coherent(struct vduse_iova_domain *domain, size_t size, + map_file = (struct vdpa_map_file *)map->opaque; + fput(map_file->file); + kfree(map_file); +- pa = map->addr; + vhost_iotlb_map_free(domain->iotlb, map); + spin_unlock(&domain->iotlb_lock); + + vduse_domain_free_iova(iovad, dma_addr, size); +- free_pages_exact(phys_to_virt(pa), size); + } + + static vm_fault_t vduse_domain_mmap_fault(struct vm_fault *vmf) +diff --git a/drivers/vdpa/vdpa_user/iova_domain.h b/drivers/vdpa/vdpa_user/iova_domain.h +index 775cad5238f3aa..ead5ab477079b6 100644 +--- a/drivers/vdpa/vdpa_user/iova_domain.h ++++ b/drivers/vdpa/vdpa_user/iova_domain.h +@@ -67,13 +67,11 @@ void vduse_domain_unmap_page(struct vduse_iova_domain *domain, + dma_addr_t dma_addr, size_t size, + enum dma_data_direction dir, unsigned long attrs); + +-void *vduse_domain_alloc_coherent(struct vduse_iova_domain *domain, +- size_t size, dma_addr_t *dma_addr, +- gfp_t flag); ++dma_addr_t vduse_domain_alloc_coherent(struct vduse_iova_domain *domain, ++ size_t size, void *orig); + + void vduse_domain_free_coherent(struct vduse_iova_domain *domain, size_t size, +- void *vaddr, dma_addr_t dma_addr, +- unsigned long attrs); ++ dma_addr_t dma_addr, unsigned long attrs); + + void vduse_domain_reset_bounce_map(struct vduse_iova_domain *domain); + +diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c +index db7af4b3fd4ad9..1cc826742ac9cd 100644 +--- a/drivers/vdpa/vdpa_user/vduse_dev.c ++++ b/drivers/vdpa/vdpa_user/vduse_dev.c +@@ -22,6 +22,7 @@ + #include <linux/uio.h> + #include <linux/vdpa.h> + #include <linux/nospec.h> ++#include <linux/virtio.h> + #include <linux/vmalloc.h> + #include <linux/sched/mm.h> + #include <uapi/linux/vduse.h> +@@ -83,6 +84,10 @@ struct vduse_umem { + struct mm_struct *mm; + }; + ++struct vduse_vq_group { ++ struct vduse_dev *dev; ++}; ++ + struct vduse_dev { + struct vduse_vdpa *vdev; + struct device *dev; +@@ -115,6 +120,7 @@ struct vduse_dev { + u32 vq_num; + u32 vq_align; + struct vduse_umem *umem; ++ struct vduse_vq_group *groups; + struct mutex mem_lock; + unsigned int bounce_size; + struct mutex domain_lock; +@@ -615,6 +621,16 @@ static int vduse_vdpa_set_vq_state(struct vdpa_device *vdpa, u16 idx, + return 0; + } + ++static union virtio_map vduse_get_vq_map(struct vdpa_device *vdpa, u16 idx) ++{ ++ struct vduse_dev *dev = vdpa_to_vduse(vdpa); ++ union virtio_map ret = { ++ .group = &dev->groups[0], ++ }; ++ ++ return ret; ++} ++ + static int vduse_vdpa_get_vq_state(struct vdpa_device *vdpa, u16 idx, + struct vdpa_vq_state *state) + { +@@ -834,6 +850,7 @@ static const struct vdpa_config_ops vduse_vdpa_config_ops = { + .get_vq_affinity = vduse_vdpa_get_vq_affinity, + .reset = vduse_vdpa_reset, + .set_map = vduse_vdpa_set_map, ++ .get_vq_map = vduse_get_vq_map, + .free = vduse_vdpa_free, + }; + +@@ -841,7 +858,14 @@ static void vduse_dev_sync_single_for_device(union virtio_map token, + dma_addr_t dma_addr, size_t size, + enum dma_data_direction dir) + { +- struct vduse_iova_domain *domain = token.iova_domain; ++ struct vduse_dev *vdev; ++ struct vduse_iova_domain *domain; ++ ++ if (!token.group) ++ return; ++ ++ vdev = token.group->dev; ++ domain = vdev->domain; + + vduse_domain_sync_single_for_device(domain, dma_addr, size, dir); + } +@@ -850,7 +874,14 @@ static void vduse_dev_sync_single_for_cpu(union virtio_map token, + dma_addr_t dma_addr, size_t size, + enum dma_data_direction dir) + { +- struct vduse_iova_domain *domain = token.iova_domain; ++ struct vduse_dev *vdev; ++ struct vduse_iova_domain *domain; ++ ++ if (!token.group) ++ return; ++ ++ vdev = token.group->dev; ++ domain = vdev->domain; + + vduse_domain_sync_single_for_cpu(domain, dma_addr, size, dir); + } +@@ -860,7 +891,14 @@ static dma_addr_t vduse_dev_map_page(union virtio_map token, struct page *page, + enum dma_data_direction dir, + unsigned long attrs) + { +- struct vduse_iova_domain *domain = token.iova_domain; ++ struct vduse_dev *vdev; ++ struct vduse_iova_domain *domain; ++ ++ if (!token.group) ++ return DMA_MAPPING_ERROR; ++ ++ vdev = token.group->dev; ++ domain = vdev->domain; + + return vduse_domain_map_page(domain, page, offset, size, dir, attrs); + } +@@ -869,7 +907,14 @@ static void vduse_dev_unmap_page(union virtio_map token, dma_addr_t dma_addr, + size_t size, enum dma_data_direction dir, + unsigned long attrs) + { +- struct vduse_iova_domain *domain = token.iova_domain; ++ struct vduse_dev *vdev; ++ struct vduse_iova_domain *domain; ++ ++ if (!token.group) ++ return; ++ ++ vdev = token.group->dev; ++ domain = vdev->domain; + + return vduse_domain_unmap_page(domain, dma_addr, size, dir, attrs); + } +@@ -877,33 +922,58 @@ static void vduse_dev_unmap_page(union virtio_map token, dma_addr_t dma_addr, + static void *vduse_dev_alloc_coherent(union virtio_map token, size_t size, + dma_addr_t *dma_addr, gfp_t flag) + { +- struct vduse_iova_domain *domain = token.iova_domain; +- unsigned long iova; ++ struct vduse_dev *vdev; ++ struct vduse_iova_domain *domain; + void *addr; + + *dma_addr = DMA_MAPPING_ERROR; +- addr = vduse_domain_alloc_coherent(domain, size, +- (dma_addr_t *)&iova, flag); ++ if (!token.group) ++ return NULL; ++ ++ addr = alloc_pages_exact(size, flag | __GFP_ZERO); + if (!addr) + return NULL; + +- *dma_addr = (dma_addr_t)iova; ++ vdev = token.group->dev; ++ domain = vdev->domain; ++ *dma_addr = vduse_domain_alloc_coherent(domain, size, addr); ++ if (*dma_addr == DMA_MAPPING_ERROR) ++ goto err; + + return addr; ++ ++err: ++ free_pages_exact(addr, size); ++ return NULL; + } + + static void vduse_dev_free_coherent(union virtio_map token, size_t size, + void *vaddr, dma_addr_t dma_addr, + unsigned long attrs) + { +- struct vduse_iova_domain *domain = token.iova_domain; ++ struct vduse_dev *vdev; ++ struct vduse_iova_domain *domain; ++ ++ if (!token.group) ++ return; ++ ++ vdev = token.group->dev; ++ domain = vdev->domain; + +- vduse_domain_free_coherent(domain, size, vaddr, dma_addr, attrs); ++ vduse_domain_free_coherent(domain, size, dma_addr, attrs); ++ free_pages_exact(vaddr, size); + } + + static bool vduse_dev_need_sync(union virtio_map token, dma_addr_t dma_addr) + { +- struct vduse_iova_domain *domain = token.iova_domain; ++ struct vduse_dev *vdev; ++ struct vduse_iova_domain *domain; ++ ++ if (!token.group) ++ return false; ++ ++ vdev = token.group->dev; ++ domain = vdev->domain; + + return dma_addr < domain->bounce_size; + } +@@ -917,7 +987,14 @@ static int vduse_dev_mapping_error(union virtio_map token, dma_addr_t dma_addr) + + static size_t vduse_dev_max_mapping_size(union virtio_map token) + { +- struct vduse_iova_domain *domain = token.iova_domain; ++ struct vduse_dev *vdev; ++ struct vduse_iova_domain *domain; ++ ++ if (!token.group) ++ return 0; ++ ++ vdev = token.group->dev; ++ domain = vdev->domain; + + return domain->bounce_size; + } +@@ -1716,6 +1793,7 @@ static int vduse_destroy_dev(char *name) + if (dev->domain) + vduse_domain_destroy(dev->domain); + kfree(dev->name); ++ kfree(dev->groups); + vduse_dev_destroy(dev); + module_put(THIS_MODULE); + +@@ -1874,6 +1952,11 @@ static int vduse_create_dev(struct vduse_dev_config *config, + dev->device_features = config->features; + dev->device_id = config->device_id; + dev->vendor_id = config->vendor_id; ++ dev->groups = kcalloc(1, sizeof(dev->groups[0]), GFP_KERNEL); ++ if (!dev->groups) ++ goto err_vq_groups; ++ dev->groups[0].dev = dev; ++ + dev->name = kstrdup(config->name, GFP_KERNEL); + if (!dev->name) + goto err_str; +@@ -1910,6 +1993,8 @@ err_dev: + err_idr: + kfree(dev->name); + err_str: ++ kfree(dev->groups); ++err_vq_groups: + vduse_dev_destroy(dev); + err: + return ret; +@@ -2071,7 +2156,6 @@ static int vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, + return -ENOMEM; + } + +- dev->vdev->vdpa.vmap.iova_domain = dev->domain; + ret = _vdpa_register_device(&dev->vdev->vdpa, dev->vq_num); + if (ret) { + put_device(&dev->vdev->vdpa.dev); +diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c +index b2b90732b1d595..89d5438ba7af97 100644 +--- a/drivers/vhost/net.c ++++ b/drivers/vhost/net.c +@@ -724,10 +724,12 @@ static int vhost_net_build_xdp(struct vhost_net_virtqueue *nvq, + goto err; + } + +- gso = buf + pad - sock_hlen; +- +- if (!sock_hlen) ++ if (!sock_hlen) { + memset(buf, 0, pad); ++ gso = buf; ++ } else { ++ gso = buf + pad - sock_hlen; ++ } + + if ((gso->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && + vhost16_to_cpu(vq, gso->csum_start) + +diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig +index d51777df12d164..0adb1e2fa53382 100644 +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -37,6 +37,7 @@ source "drivers/char/agp/Kconfig" + + source "drivers/gpu/vga/Kconfig" + ++source "drivers/gpu/Kconfig" + source "drivers/gpu/host1x/Kconfig" + source "drivers/gpu/ipu-v3/Kconfig" + source "drivers/gpu/nova-core/Kconfig" +diff --git a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c +index 4230b817a80bd8..d66291def0f408 100644 +--- a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c ++++ b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c +@@ -82,8 +82,8 @@ static int mmio_guard_ioremap_hook(phys_addr_t phys, size_t size, + if (protval != PROT_DEVICE_nGnRE && protval != PROT_DEVICE_nGnRnE) + return 0; + ++ end = PAGE_ALIGN(phys + size); + phys = PAGE_ALIGN_DOWN(phys); +- end = phys + PAGE_ALIGN(size); + + while (phys < end) { + const int func_id = ARM_SMCCC_VENDOR_HYP_KVM_MMIO_GUARD_FUNC_ID; +diff --git a/drivers/watchdog/airoha_wdt.c b/drivers/watchdog/airoha_wdt.c +index dc8ca11c14d81a..4bd333189b87ec 100644 +--- a/drivers/watchdog/airoha_wdt.c ++++ b/drivers/watchdog/airoha_wdt.c +@@ -147,6 +147,9 @@ static int airoha_wdt_probe(struct platform_device *pdev) + + /* Watchdog ticks at half the bus rate */ + airoha_wdt->wdt_freq = clk_get_rate(bus_clk) / 2; ++ if (!airoha_wdt->wdt_freq) ++ return dev_err_probe(dev, -EINVAL, ++ "invalid clock frequency\n"); + + /* Initialize struct watchdog device */ + wdog_dev = &airoha_wdt->wdog_dev; +diff --git a/drivers/watchdog/s32g_wdt.c b/drivers/watchdog/s32g_wdt.c +index ad55063060af60..6422a694fc65ff 100644 +--- a/drivers/watchdog/s32g_wdt.c ++++ b/drivers/watchdog/s32g_wdt.c +@@ -56,8 +56,7 @@ MODULE_PARM_DESC(early_enable, + + static const struct watchdog_info s32g_wdt_info = { + .identity = "s32g watchdog", +- .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | +- WDIOC_GETTIMEOUT | WDIOC_GETTIMELEFT, ++ .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, + }; + + static struct s32g_wdt_device *wdd_to_s32g_wdt(struct watchdog_device *wdd) +diff --git a/drivers/watchdog/watchdog_pretimeout.c b/drivers/watchdog/watchdog_pretimeout.c +index 2526436dc74dd8..ea05f84f07e184 100644 +--- a/drivers/watchdog/watchdog_pretimeout.c ++++ b/drivers/watchdog/watchdog_pretimeout.c +@@ -167,6 +167,8 @@ void watchdog_unregister_governor(struct watchdog_governor *gov) + } + + spin_lock_irq(&pretimeout_lock); ++ if (default_gov == gov) ++ default_gov = NULL; + list_for_each_entry(p, &pretimeout_list, entry) + if (p->wdd->gov == gov) + p->wdd->gov = default_gov; +diff --git a/fs/afs/dir_edit.c b/fs/afs/dir_edit.c +index fd3aa9f97ce64c..3ead36a070487a 100644 +--- a/fs/afs/dir_edit.c ++++ b/fs/afs/dir_edit.c +@@ -415,7 +415,7 @@ void afs_edit_dir_remove(struct afs_vnode *vnode, + if (!afs_dir_init_iter(&iter, name)) + return; + +- meta = afs_dir_find_block(&iter, 0); ++ meta = afs_dir_get_block(&iter, 0); + if (!meta) + return; + +diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c +index a3d4e6973b299b..7834ca77877db7 100644 +--- a/fs/binfmt_elf_fdpic.c ++++ b/fs/binfmt_elf_fdpic.c +@@ -231,6 +231,10 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm) + for (i = 0; i < exec_params.hdr.e_phnum; i++, phdr++) { + switch (phdr->p_type) { + case PT_INTERP: ++ /* elf ABI allows only one interpreter */ ++ if (interpreter_name) ++ continue; ++ + retval = -ENOMEM; + if (phdr->p_filesz > PATH_MAX) + goto error; +diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c +index a8b1d79e4af074..d44529d5ecf5f4 100644 +--- a/fs/binfmt_misc.c ++++ b/fs/binfmt_misc.c +@@ -227,9 +227,6 @@ static int load_misc_binary(struct linux_binprm *bprm) + goto ret; + } + +- if (fmt->flags & MISC_FMT_OPEN_BINARY) +- bprm->have_execfd = 1; +- + /* make argv[1] be the path to the binary */ + retval = copy_string_kernel(bprm->interp, bprm); + if (retval < 0) +@@ -259,6 +256,8 @@ static int load_misc_binary(struct linux_binprm *bprm) + goto ret; + + bprm->interpreter = interp_file; ++ if (fmt->flags & MISC_FMT_OPEN_BINARY) ++ bprm->have_execfd = 1; + if (fmt->flags & MISC_FMT_CREDENTIALS) + bprm->execfd_creds = 1; + +diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c +index e050d0938dc45f..0c47b4570a7bf8 100644 +--- a/fs/btrfs/backref.c ++++ b/fs/btrfs/backref.c +@@ -1408,12 +1408,12 @@ static int find_parent_nodes(struct btrfs_backref_walk_ctx *ctx, + if (!path) + return -ENOMEM; + if (!ctx->trans) { +- path->search_commit_root = 1; +- path->skip_locking = 1; ++ path->search_commit_root = true; ++ path->skip_locking = true; + } + + if (ctx->time_seq == BTRFS_SEQ_LAST) +- path->skip_locking = 1; ++ path->skip_locking = true; + + again: + head = NULL; +@@ -1560,7 +1560,7 @@ again: + + btrfs_release_path(path); + +- ret = add_missing_keys(ctx->fs_info, &preftrees, path->skip_locking == 0); ++ ret = add_missing_keys(ctx->fs_info, &preftrees, !path->skip_locking); + if (ret) + goto out; + +@@ -2833,8 +2833,8 @@ struct btrfs_backref_iter *btrfs_backref_iter_alloc(struct btrfs_fs_info *fs_inf + } + + /* Current backref iterator only supports iteration in commit root */ +- ret->path->search_commit_root = 1; +- ret->path->skip_locking = 1; ++ ret->path->search_commit_root = true; ++ ret->path->skip_locking = true; + ret->fs_info = fs_info; + + return ret; +@@ -3307,8 +3307,8 @@ static int handle_indirect_tree_backref(struct btrfs_trans_handle *trans, + level = cur->level + 1; + + /* Search the tree to find parent blocks referring to the block */ +- path->search_commit_root = 1; +- path->skip_locking = 1; ++ path->search_commit_root = true; ++ path->skip_locking = true; + path->lowest_level = level; + ret = btrfs_search_slot(NULL, root, tree_key, path, 0, 0); + path->lowest_level = 0; +diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c +index 1e57f7d04c47ec..e6bac34ebe83d6 100644 +--- a/fs/btrfs/block-group.c ++++ b/fs/btrfs/block-group.c +@@ -613,8 +613,8 @@ static int sample_block_group_extent_item(struct btrfs_caching_control *caching_ + extent_root = btrfs_extent_root(fs_info, max_t(u64, block_group->start, + BTRFS_SUPER_INFO_OFFSET)); + +- path->skip_locking = 1; +- path->search_commit_root = 1; ++ path->skip_locking = true; ++ path->search_commit_root = true; + path->reada = READA_FORWARD; + + search_offset = index * div_u64(block_group->length, max_index); +@@ -744,8 +744,8 @@ static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl) + * root to add free space. So we skip locking and search the commit + * root, since its read-only + */ +- path->skip_locking = 1; +- path->search_commit_root = 1; ++ path->skip_locking = true; ++ path->search_commit_root = true; + path->reada = READA_FORWARD; + + key.objectid = last; +diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c +index 27e2adc2ee717b..0f2e9f33dd0cbc 100644 +--- a/fs/btrfs/ctree.c ++++ b/fs/btrfs/ctree.c +@@ -1709,9 +1709,9 @@ static struct extent_buffer *btrfs_search_slot_get_root(struct btrfs_root *root, + level = btrfs_header_level(b); + /* + * Ensure that all callers have set skip_locking when +- * p->search_commit_root = 1. ++ * p->search_commit_root is true. + */ +- ASSERT(p->skip_locking == 1); ++ ASSERT(p->skip_locking); + + goto out; + } +@@ -3858,10 +3858,10 @@ static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans, + } + btrfs_release_path(path); + +- path->keep_locks = 1; +- path->search_for_split = 1; ++ path->keep_locks = true; ++ path->search_for_split = true; + ret = btrfs_search_slot(trans, root, &key, path, 0, 1); +- path->search_for_split = 0; ++ path->search_for_split = false; + if (ret > 0) + ret = -EAGAIN; + if (ret < 0) +@@ -3888,11 +3888,11 @@ static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans, + if (ret) + goto err; + +- path->keep_locks = 0; ++ path->keep_locks = false; + btrfs_unlock_up_safe(path, 1); + return 0; + err: +- path->keep_locks = 0; ++ path->keep_locks = false; + return ret; + } + +@@ -4610,11 +4610,11 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, + u32 nritems; + int level; + int ret = 1; +- int keep_locks = path->keep_locks; ++ const bool keep_locks = path->keep_locks; + + ASSERT(!path->nowait); + ASSERT(path->lowest_level == 0); +- path->keep_locks = 1; ++ path->keep_locks = true; + again: + cur = btrfs_read_lock_root_node(root); + level = btrfs_header_level(cur); +@@ -4704,7 +4704,7 @@ out: + * 0 is returned if another key is found, < 0 if there are any errors + * and 1 is returned if there are no higher keys in the tree + * +- * path->keep_locks should be set to 1 on the search made before ++ * path->keep_locks should be set to true on the search made before + * calling this function. + */ + int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, +@@ -4803,13 +4803,13 @@ again: + next = NULL; + btrfs_release_path(path); + +- path->keep_locks = 1; ++ path->keep_locks = true; + + if (time_seq) { + ret = btrfs_search_old_slot(root, &key, path, time_seq); + } else { + if (path->need_commit_sem) { +- path->need_commit_sem = 0; ++ path->need_commit_sem = false; + need_commit_sem = true; + if (path->nowait) { + if (!down_read_trylock(&fs_info->commit_root_sem)) { +@@ -4822,7 +4822,7 @@ again: + } + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + } +- path->keep_locks = 0; ++ path->keep_locks = false; + + if (ret < 0) + goto done; +@@ -4961,7 +4961,7 @@ done: + if (need_commit_sem) { + int ret2; + +- path->need_commit_sem = 1; ++ path->need_commit_sem = true; + ret2 = finish_need_commit_sem_search(path); + up_read(&fs_info->commit_root_sem); + if (ret2) +diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h +index 16dd11c4853130..692370fc07b280 100644 +--- a/fs/btrfs/ctree.h ++++ b/fs/btrfs/ctree.h +@@ -65,21 +65,21 @@ struct btrfs_path { + * set by btrfs_split_item, tells search_slot to keep all locks + * and to force calls to keep space in the nodes + */ +- unsigned int search_for_split:1; ++ bool search_for_split:1; + /* Keep some upper locks as we walk down. */ +- unsigned int keep_locks:1; +- unsigned int skip_locking:1; +- unsigned int search_commit_root:1; +- unsigned int need_commit_sem:1; +- unsigned int skip_release_on_error:1; ++ bool keep_locks:1; ++ bool skip_locking:1; ++ bool search_commit_root:1; ++ bool need_commit_sem:1; ++ bool skip_release_on_error:1; + /* + * Indicate that new item (btrfs_search_slot) is extending already + * existing item and ins_len contains only the data size and not item + * header (ie. sizeof(struct btrfs_item) is not included). + */ +- unsigned int search_for_extension:1; ++ bool search_for_extension:1; + /* Stop search if any locks need to be taken (for read) */ +- unsigned int nowait:1; ++ bool nowait:1; + }; + + #define BTRFS_PATH_AUTO_FREE(path_name) \ +diff --git a/fs/btrfs/defrag.c b/fs/btrfs/defrag.c +index a4cc1bc6356227..2e3c011d410a6f 100644 +--- a/fs/btrfs/defrag.c ++++ b/fs/btrfs/defrag.c +@@ -472,7 +472,7 @@ static int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, + memcpy(&key, &root->defrag_progress, sizeof(key)); + } + +- path->keep_locks = 1; ++ path->keep_locks = true; + + ret = btrfs_search_forward(root, &key, path, BTRFS_OLDEST_GENERATION); + if (ret < 0) +@@ -515,7 +515,7 @@ static int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, + /* + * Now that we reallocated the node we can find the next key. Note that + * btrfs_find_next_key() can release our path and do another search +- * without COWing, this is because even with path->keep_locks = 1, ++ * without COWing, this is because even with path->keep_locks == true, + * btrfs_search_slot() / ctree.c:unlock_up() does not keeps a lock on a + * node when path->slots[node_level - 1] does not point to the last + * item or a slot beyond the last item (ctree.c:unlock_up()). Therefore +diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c +index a4eaef60549eed..b6c7da8e1bc8b1 100644 +--- a/fs/btrfs/dev-replace.c ++++ b/fs/btrfs/dev-replace.c +@@ -489,8 +489,8 @@ static int mark_block_group_to_copy(struct btrfs_fs_info *fs_info, + } + + path->reada = READA_FORWARD; +- path->search_commit_root = 1; +- path->skip_locking = 1; ++ path->search_commit_root = true; ++ path->skip_locking = true; + + key.objectid = src_dev->devid; + key.type = BTRFS_DEV_EXTENT_KEY; +diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c +index 6ef7cc116bfcca..d2d96f366dac31 100644 +--- a/fs/btrfs/extent-tree.c ++++ b/fs/btrfs/extent-tree.c +@@ -788,7 +788,7 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans, + want = extent_ref_type(parent, owner); + if (insert) { + extra_size = btrfs_extent_inline_ref_size(want); +- path->search_for_extension = 1; ++ path->search_for_extension = true; + } else + extra_size = -1; + +@@ -954,7 +954,7 @@ again: + + if (!path->keep_locks) { + btrfs_release_path(path); +- path->keep_locks = 1; ++ path->keep_locks = true; + goto again; + } + +@@ -975,11 +975,11 @@ out_no_entry: + *ref_ret = (struct btrfs_extent_inline_ref *)ptr; + out: + if (path->keep_locks) { +- path->keep_locks = 0; ++ path->keep_locks = false; + btrfs_unlock_up_safe(path, 1); + } + if (insert) +- path->search_for_extension = 0; ++ path->search_for_extension = false; + return ret; + } + +diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c +index f955b4003d4246..80fc2d59bfeb86 100644 +--- a/fs/btrfs/extent_io.c ++++ b/fs/btrfs/extent_io.c +@@ -1949,7 +1949,7 @@ static noinline_for_stack bool lock_extent_buffer_for_io(struct extent_buffer *e + + btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN); + percpu_counter_add_batch(&fs_info->dirty_metadata_bytes, +- -eb->len, ++ -(s64)eb->len, + fs_info->dirty_metadata_batch); + ret = true; + } else { +@@ -3731,7 +3731,7 @@ void btrfs_clear_buffer_dirty(struct btrfs_trans_handle *trans, + return; + + buffer_tree_clear_mark(eb, PAGECACHE_TAG_DIRTY); +- percpu_counter_add_batch(&fs_info->dirty_metadata_bytes, -eb->len, ++ percpu_counter_add_batch(&fs_info->dirty_metadata_bytes, -(s64)eb->len, + fs_info->dirty_metadata_batch); + + for (int i = 0; i < num_extent_folios(eb); i++) { +diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c +index 7e38c23a0c1cb6..21eb104ee2aefb 100644 +--- a/fs/btrfs/extent_map.c ++++ b/fs/btrfs/extent_map.c +@@ -854,13 +854,13 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, u64 start, u64 end, + goto next; + } + +- flags = em->flags; + /* + * In case we split the extent map, we want to preserve the + * EXTENT_FLAG_LOGGING flag on our extent map, but we don't want + * it on the new extent maps. + */ +- em->flags &= ~(EXTENT_FLAG_PINNED | EXTENT_FLAG_LOGGING); ++ flags = em->flags & ~EXTENT_FLAG_LOGGING; ++ em->flags &= ~EXTENT_FLAG_PINNED; + modified = !list_empty(&em->list); + + /* +diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c +index 4b7c40f05e8f9e..9b19b33e85b687 100644 +--- a/fs/btrfs/file-item.c ++++ b/fs/btrfs/file-item.c +@@ -350,6 +350,7 @@ int btrfs_lookup_bio_sums(struct btrfs_bio *bbio) + const unsigned int nblocks = orig_len >> fs_info->sectorsize_bits; + int ret = 0; + u32 bio_offset = 0; ++ bool using_commit_root = false; + + if ((inode->flags & BTRFS_INODE_NODATASUM) || + test_bit(BTRFS_FS_STATE_NO_DATA_CSUMS, &fs_info->fs_state)) +@@ -394,8 +395,8 @@ int btrfs_lookup_bio_sums(struct btrfs_bio *bbio) + * between reading the free space cache and updating the csum tree. + */ + if (btrfs_is_free_space_inode(inode)) { +- path->search_commit_root = 1; +- path->skip_locking = 1; ++ path->search_commit_root = true; ++ path->skip_locking = true; + } + + /* +@@ -423,8 +424,9 @@ int btrfs_lookup_bio_sums(struct btrfs_bio *bbio) + * from across transactions. + */ + if (bbio->csum_search_commit_root) { +- path->search_commit_root = 1; +- path->skip_locking = 1; ++ using_commit_root = true; ++ path->search_commit_root = true; ++ path->skip_locking = true; + down_read(&fs_info->commit_root_sem); + } + +@@ -455,6 +457,28 @@ int btrfs_lookup_bio_sums(struct btrfs_bio *bbio) + * assume this is the case. + */ + if (count == 0) { ++ /* ++ * If an extent is relocated in the current transaction ++ * then relocation writes a new csum without updating ++ * the extent map generation. Until the next commit, we ++ * will see a hole in that case, so we need to fallback ++ * to searching the transaction csum root. ++ * ++ * Note that a commit root lookup of a referenced extent can ++ * only miss, not return a stale csum. A freed extent's csum ++ * is deleted in the same transaction and its bytenr is not ++ * reusable until that transaction has committed and the ++ * extent is unpinned. ++ */ ++ if (using_commit_root) { ++ up_read(&fs_info->commit_root_sem); ++ using_commit_root = false; ++ path->search_commit_root = false; ++ path->skip_locking = false; ++ btrfs_release_path(path); ++ continue; ++ } ++ + memset(csum_dst, 0, csum_size); + count = 1; + +@@ -473,7 +497,7 @@ int btrfs_lookup_bio_sums(struct btrfs_bio *bbio) + bio_offset += count * sectorsize; + } + +- if (bbio->csum_search_commit_root) ++ if (using_commit_root) + up_read(&fs_info->commit_root_sem); + return ret; + } +@@ -1168,10 +1192,10 @@ again: + } + + btrfs_release_path(path); +- path->search_for_extension = 1; ++ path->search_for_extension = true; + ret = btrfs_search_slot(trans, root, &file_key, path, + csum_size, 1); +- path->search_for_extension = 0; ++ path->search_for_extension = false; + if (ret < 0) + goto out; + +diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c +index ab873bd6719209..7ee3d8f05c1a21 100644 +--- a/fs/btrfs/free-space-cache.c ++++ b/fs/btrfs/free-space-cache.c +@@ -554,6 +554,9 @@ static int io_ctl_check_crc(struct btrfs_io_ctl *io_ctl, int index) + u32 crc = ~(u32)0; + unsigned offset = 0; + ++ if (index >= io_ctl->num_pages) ++ return -EIO; ++ + if (index == 0) + offset = sizeof(u32) * io_ctl->num_pages; + +@@ -968,8 +971,8 @@ int load_free_space_cache(struct btrfs_block_group *block_group) + path = btrfs_alloc_path(); + if (!path) + return 0; +- path->search_commit_root = 1; +- path->skip_locking = 1; ++ path->search_commit_root = true; ++ path->skip_locking = true; + + /* + * We must pass a path with search_commit_root set to btrfs_iget in +diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c +index c3734892d6548b..f9ffb1c8988d90 100644 +--- a/fs/btrfs/free-space-tree.c ++++ b/fs/btrfs/free-space-tree.c +@@ -1699,8 +1699,8 @@ int btrfs_load_free_space_tree(struct btrfs_caching_control *caching_ctl) + * Just like caching_thread() doesn't want to deadlock on the extent + * tree, we don't want to deadlock on the free space tree. + */ +- path->skip_locking = 1; +- path->search_commit_root = 1; ++ path->skip_locking = true; ++ path->search_commit_root = true; + path->reada = READA_FORWARD; + + info = btrfs_search_free_space_info(NULL, block_group, path, 0); +diff --git a/fs/btrfs/inode-item.c b/fs/btrfs/inode-item.c +index 7e14e1bbcf389b..b73e1dd97208a8 100644 +--- a/fs/btrfs/inode-item.c ++++ b/fs/btrfs/inode-item.c +@@ -312,7 +312,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, + if (!path) + return -ENOMEM; + +- path->skip_release_on_error = 1; ++ path->skip_release_on_error = true; + ret = btrfs_insert_empty_item(trans, root, path, &key, + ins_len); + if (ret == -EEXIST) { +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index 30a34cd905ba48..36f75c6a8344d4 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -7170,8 +7170,8 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, + * point the commit_root has everything we need. + */ + if (btrfs_is_free_space_inode(inode)) { +- path->search_commit_root = 1; +- path->skip_locking = 1; ++ path->search_commit_root = true; ++ path->skip_locking = true; + } + + ret = btrfs_lookup_file_extent(NULL, root, path, objectid, start, 0); +diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c +index 261aa65019207f..b4c6cbbcd168e6 100644 +--- a/fs/btrfs/qgroup.c ++++ b/fs/btrfs/qgroup.c +@@ -3882,8 +3882,8 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) + * Rescan should only search for commit root, and any later difference + * should be recorded by qgroup + */ +- path->search_commit_root = 1; +- path->skip_locking = 1; ++ path->search_commit_root = true; ++ path->skip_locking = true; + + while (!ret && !(stopped = rescan_should_stop(fs_info))) { + trans = btrfs_start_transaction(fs_info->fs_root, 0); +diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c +index cc6f6095cc9fd0..f6f02463dd1a9b 100644 +--- a/fs/btrfs/raid-stripe-tree.c ++++ b/fs/btrfs/raid-stripe-tree.c +@@ -394,8 +394,8 @@ int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info, + return -ENOMEM; + + if (stripe->rst_search_commit_root) { +- path->skip_locking = 1; +- path->search_commit_root = 1; ++ path->skip_locking = true; ++ path->search_commit_root = true; + } + + ret = btrfs_search_slot(NULL, stripe_root, &stripe_key, path, 0, 0); +diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c +index fc76013b1a3e01..80e5de6736e829 100644 +--- a/fs/btrfs/relocation.c ++++ b/fs/btrfs/relocation.c +@@ -496,6 +496,7 @@ static int __add_reloc_root(struct btrfs_root *root) + btrfs_err(fs_info, + "Duplicate root found for start=%llu while inserting into relocation tree", + node->bytenr); ++ kfree(node); + return -EEXIST; + } + +@@ -1857,6 +1858,7 @@ again: + * corruption, e.g. bad reloc tree key offset. + */ + ret = -EINVAL; ++ btrfs_put_root(root); + goto out; + } + ret = merge_reloc_root(rc, root); +@@ -3175,8 +3177,8 @@ again: + key.offset = blocksize; + } + +- path->search_commit_root = 1; +- path->skip_locking = 1; ++ path->search_commit_root = true; ++ path->skip_locking = true; + ret = btrfs_search_slot(NULL, rc->extent_root, &key, path, 0, 0); + if (ret < 0) + return ret; +@@ -3368,8 +3370,8 @@ int find_next_extent(struct reloc_control *rc, struct btrfs_path *path, + key.type = BTRFS_EXTENT_ITEM_KEY; + key.offset = 0; + +- path->search_commit_root = 1; +- path->skip_locking = 1; ++ path->search_commit_root = true; ++ path->skip_locking = true; + ret = btrfs_search_slot(NULL, rc->extent_root, &key, path, + 0, 0); + if (ret < 0) +diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c +index 16936d17166eef..368f1d44449351 100644 +--- a/fs/btrfs/scrub.c ++++ b/fs/btrfs/scrub.c +@@ -463,10 +463,10 @@ static noinline_for_stack struct scrub_ctx *scrub_setup_ctx( + refcount_set(&sctx->refs, 1); + sctx->is_dev_replace = is_dev_replace; + sctx->fs_info = fs_info; +- sctx->extent_path.search_commit_root = 1; +- sctx->extent_path.skip_locking = 1; +- sctx->csum_path.search_commit_root = 1; +- sctx->csum_path.skip_locking = 1; ++ sctx->extent_path.search_commit_root = true; ++ sctx->extent_path.skip_locking = true; ++ sctx->csum_path.search_commit_root = true; ++ sctx->csum_path.skip_locking = true; + for (i = 0; i < SCRUB_TOTAL_STRIPES; i++) { + int ret; + +@@ -2103,10 +2103,10 @@ static int scrub_raid56_parity_stripe(struct scrub_ctx *sctx, + * as the data stripe bytenr may be smaller than previous extent. Thus + * we have to use our own extent/csum paths. + */ +- extent_path.search_commit_root = 1; +- extent_path.skip_locking = 1; +- csum_path.search_commit_root = 1; +- csum_path.skip_locking = 1; ++ extent_path.search_commit_root = true; ++ extent_path.skip_locking = true; ++ csum_path.search_commit_root = true; ++ csum_path.skip_locking = true; + + for (int i = 0; i < data_stripes; i++) { + int stripe_index; +@@ -2630,8 +2630,8 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, + return -ENOMEM; + + path->reada = READA_FORWARD; +- path->search_commit_root = 1; +- path->skip_locking = 1; ++ path->search_commit_root = true; ++ path->skip_locking = true; + + key.objectid = scrub_dev->devid; + key.type = BTRFS_DEV_EXTENT_KEY; +diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c +index 04473387ee8bf0..34a57f11e4bb9c 100644 +--- a/fs/btrfs/send.c ++++ b/fs/btrfs/send.c +@@ -633,9 +633,9 @@ static struct btrfs_path *alloc_path_for_send(void) + path = btrfs_alloc_path(); + if (!path) + return NULL; +- path->search_commit_root = 1; +- path->skip_locking = 1; +- path->need_commit_sem = 1; ++ path->search_commit_root = true; ++ path->skip_locking = true; ++ path->need_commit_sem = true; + return path; + } + +@@ -7643,10 +7643,10 @@ static int btrfs_compare_trees(struct btrfs_root *left_root, + goto out; + } + +- left_path->search_commit_root = 1; +- left_path->skip_locking = 1; +- right_path->search_commit_root = 1; +- right_path->skip_locking = 1; ++ left_path->search_commit_root = true; ++ left_path->skip_locking = true; ++ right_path->search_commit_root = true; ++ right_path->skip_locking = true; + + /* + * Strategy: Go to the first items of both trees. Then do +diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c +index a0e12b4fb95614..f84065b69464c7 100644 +--- a/fs/btrfs/tree-log.c ++++ b/fs/btrfs/tree-log.c +@@ -602,9 +602,9 @@ static int overwrite_item(struct walk_control *wc) + insert: + btrfs_release_path(wc->subvol_path); + /* try to insert the key into the destination tree */ +- wc->subvol_path->skip_release_on_error = 1; ++ wc->subvol_path->skip_release_on_error = true; + ret = btrfs_insert_empty_item(trans, root, wc->subvol_path, &wc->log_key, item_size); +- wc->subvol_path->skip_release_on_error = 0; ++ wc->subvol_path->skip_release_on_error = false; + + dst_eb = wc->subvol_path->nodes[0]; + dst_slot = wc->subvol_path->slots[0]; +@@ -5734,8 +5734,8 @@ static int btrfs_check_ref_name_override(struct extent_buffer *eb, + search_path = btrfs_alloc_path(); + if (!search_path) + return -ENOMEM; +- search_path->search_commit_root = 1; +- search_path->skip_locking = 1; ++ search_path->search_commit_root = true; ++ search_path->skip_locking = true; + + while (cur_offset < item_size) { + u64 parent; +@@ -6052,8 +6052,8 @@ static int conflicting_inode_is_dir(struct btrfs_root *root, u64 ino, + key.type = BTRFS_INODE_ITEM_KEY; + key.offset = 0; + +- path->search_commit_root = 1; +- path->skip_locking = 1; ++ path->search_commit_root = true; ++ path->skip_locking = true; + + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (WARN_ON_ONCE(ret > 0)) { +@@ -6073,8 +6073,8 @@ static int conflicting_inode_is_dir(struct btrfs_root *root, u64 ino, + } + + btrfs_release_path(path); +- path->search_commit_root = 0; +- path->skip_locking = 0; ++ path->search_commit_root = false; ++ path->skip_locking = false; + + return ret; + } +@@ -7232,8 +7232,8 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans, + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; +- path->skip_locking = 1; +- path->search_commit_root = 1; ++ path->skip_locking = true; ++ path->search_commit_root = true; + + key.objectid = ino; + key.type = BTRFS_INODE_REF_KEY; +diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c +index 630fb5885692b1..863f69b9cf14bd 100644 +--- a/fs/btrfs/volumes.c ++++ b/fs/btrfs/volumes.c +@@ -1839,8 +1839,8 @@ static int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, + } + + path->reada = READA_FORWARD; +- path->search_commit_root = 1; +- path->skip_locking = 1; ++ path->search_commit_root = true; ++ path->skip_locking = true; + + key.objectid = device->devid; + key.type = BTRFS_DEV_EXTENT_KEY; +@@ -7627,7 +7627,7 @@ int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info) + * chunk tree, to keep it simple, just skip locking on the chunk tree. + */ + ASSERT(!test_bit(BTRFS_FS_OPEN, &fs_info->flags)); +- path->skip_locking = 1; ++ path->skip_locking = true; + + /* + * Read all device items, and then all the chunk items. All +diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c +index b6f01d6c79e7f3..b6e91e8fb7e388 100644 +--- a/fs/btrfs/xattr.c ++++ b/fs/btrfs/xattr.c +@@ -97,7 +97,7 @@ int btrfs_setxattr(struct btrfs_trans_handle *trans, struct inode *inode, + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; +- path->skip_release_on_error = 1; ++ path->skip_release_on_error = true; + + if (!value) { + di = btrfs_lookup_xattr(trans, root, path, +diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c +index 3af6795cb3c15d..ea31c892a1fb19 100644 +--- a/fs/ceph/addr.c ++++ b/fs/ceph/addr.c +@@ -785,6 +785,9 @@ static int write_folio_nounlock(struct folio *folio, + ceph_wbc.truncate_size, true); + if (IS_ERR(req)) { + folio_redirty_for_writepage(wbc, folio); ++ if (atomic_long_dec_return(&fsc->writeback_count) < ++ CONGESTION_OFF_THRESH(fsc->mount_options->congestion_kb)) ++ fsc->write_congested = false; + return PTR_ERR(req); + } + +@@ -804,6 +807,9 @@ static int write_folio_nounlock(struct folio *folio, + folio_redirty_for_writepage(wbc, folio); + folio_end_writeback(folio); + ceph_osdc_put_request(req); ++ if (atomic_long_dec_return(&fsc->writeback_count) < ++ CONGESTION_OFF_THRESH(fsc->mount_options->congestion_kb)) ++ fsc->write_congested = false; + return PTR_ERR(bounce_page); + } + } +@@ -838,6 +844,9 @@ static int write_folio_nounlock(struct folio *folio, + ceph_vinop(inode), folio); + folio_redirty_for_writepage(wbc, folio); + folio_end_writeback(folio); ++ if (atomic_long_dec_return(&fsc->writeback_count) < ++ CONGESTION_OFF_THRESH(fsc->mount_options->congestion_kb)) ++ fsc->write_congested = false; + return err; + } + if (err == -EBLOCKLISTED) +diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c +index b1a8ff612c41dc..d9924ef55f4a21 100644 +--- a/fs/ceph/caps.c ++++ b/fs/ceph/caps.c +@@ -4364,6 +4364,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, + + snaptrace = h + 1; + snaptrace_len = le32_to_cpu(h->snap_trace_len); ++ ceph_decode_need(&snaptrace, end, snaptrace_len, bad); + p = snaptrace + snaptrace_len; + + if (msg_version >= 2) { +diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c +index 66e592c47e57a9..c30510bdae3a5e 100644 +--- a/fs/ceph/dir.c ++++ b/fs/ceph/dir.c +@@ -546,11 +546,16 @@ more: + pr_warn_client(cl, + "%p %llx.%llx rde->offset 0x%llx ctx->pos 0x%llx\n", + inode, ceph_vinop(inode), rde->offset, ctx->pos); ++ ceph_mdsc_put_request(dfi->last_readdir); ++ dfi->last_readdir = NULL; + return -EIO; + } + +- if (WARN_ON_ONCE(!rde->inode.in)) ++ if (WARN_ON_ONCE(!rde->inode.in)) { ++ ceph_mdsc_put_request(dfi->last_readdir); ++ dfi->last_readdir = NULL; + return -EIO; ++ } + + ctx->pos = rde->offset; + doutc(cl, "%p %llx.%llx (%d/%d) -> %llx '%.*s' %p\n", inode, +diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c +index 645cc493607294..500397ca8a26fa 100644 +--- a/fs/crypto/inline_crypt.c ++++ b/fs/crypto/inline_crypt.c +@@ -22,22 +22,14 @@ + + #include "fscrypt_private.h" + +-static struct block_device **fscrypt_get_devices(struct super_block *sb, +- unsigned int *num_devs) ++static unsigned int ++fscrypt_get_devices(struct super_block *sb, ++ struct block_device *devs[FSCRYPT_MAX_DEVICES]) + { +- struct block_device **devs; +- +- if (sb->s_cop->get_devices) { +- devs = sb->s_cop->get_devices(sb, num_devs); +- if (devs) +- return devs; +- } +- devs = kmalloc(sizeof(*devs), GFP_KERNEL); +- if (!devs) +- return ERR_PTR(-ENOMEM); ++ if (sb->s_cop->get_devices) ++ return sb->s_cop->get_devices(sb, devs); + devs[0] = sb->s_bdev; +- *num_devs = 1; +- return devs; ++ return 1; + } + + static unsigned int fscrypt_get_dun_bytes(const struct fscrypt_inode_info *ci) +@@ -96,7 +88,7 @@ int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci, + const struct inode *inode = ci->ci_inode; + struct super_block *sb = inode->i_sb; + struct blk_crypto_config crypto_cfg; +- struct block_device **devs; ++ struct block_device *devs[FSCRYPT_MAX_DEVICES]; + unsigned int num_devs; + unsigned int i; + +@@ -135,20 +127,15 @@ int fscrypt_select_encryption_impl(struct fscrypt_inode_info *ci, + crypto_cfg.key_type = is_hw_wrapped_key ? + BLK_CRYPTO_KEY_TYPE_HW_WRAPPED : BLK_CRYPTO_KEY_TYPE_RAW; + +- devs = fscrypt_get_devices(sb, &num_devs); +- if (IS_ERR(devs)) +- return PTR_ERR(devs); +- ++ num_devs = fscrypt_get_devices(sb, devs); + for (i = 0; i < num_devs; i++) { + if (!blk_crypto_config_supported(devs[i], &crypto_cfg)) +- goto out_free_devs; ++ return 0; + } + + fscrypt_log_blk_crypto_impl(ci->ci_mode, devs, num_devs, &crypto_cfg); + + ci->ci_inlinecrypt = true; +-out_free_devs: +- kfree(devs); + + return 0; + } +@@ -164,7 +151,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, + enum blk_crypto_key_type key_type = is_hw_wrapped ? + BLK_CRYPTO_KEY_TYPE_HW_WRAPPED : BLK_CRYPTO_KEY_TYPE_RAW; + struct blk_crypto_key *blk_key; +- struct block_device **devs; ++ struct block_device *devs[FSCRYPT_MAX_DEVICES]; + unsigned int num_devs; + unsigned int i; + int err; +@@ -182,17 +169,12 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, + } + + /* Start using blk-crypto on all the filesystem's block devices. */ +- devs = fscrypt_get_devices(sb, &num_devs); +- if (IS_ERR(devs)) { +- err = PTR_ERR(devs); +- goto fail; +- } ++ num_devs = fscrypt_get_devices(sb, devs); + for (i = 0; i < num_devs; i++) { + err = blk_crypto_start_using_key(devs[i], blk_key); + if (err) + break; + } +- kfree(devs); + if (err) { + fscrypt_err(inode, "error %d starting to use blk-crypto", err); + goto fail; +@@ -210,20 +192,21 @@ void fscrypt_destroy_inline_crypt_key(struct super_block *sb, + struct fscrypt_prepared_key *prep_key) + { + struct blk_crypto_key *blk_key = prep_key->blk_key; +- struct block_device **devs; ++ struct block_device *devs[FSCRYPT_MAX_DEVICES]; + unsigned int num_devs; + unsigned int i; + + if (!blk_key) + return; + +- /* Evict the key from all the filesystem's block devices. */ +- devs = fscrypt_get_devices(sb, &num_devs); +- if (!IS_ERR(devs)) { +- for (i = 0; i < num_devs; i++) +- blk_crypto_evict_key(devs[i], blk_key); +- kfree(devs); +- } ++ /* ++ * Evict the key from all the filesystem's block devices. ++ * This *must* be done before the key is freed. ++ */ ++ num_devs = fscrypt_get_devices(sb, devs); ++ for (i = 0; i < num_devs; i++) ++ blk_crypto_evict_key(devs[i], blk_key); ++ + kfree_sensitive(blk_key); + } + +diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c +index c4d05168522b0c..7b2ee3c14d31c6 100644 +--- a/fs/crypto/keysetup_v1.c ++++ b/fs/crypto/keysetup_v1.c +@@ -190,13 +190,19 @@ find_or_insert_direct_key(struct fscrypt_direct_key *to_insert, + if (memcmp(ci->ci_policy.v1.master_key_descriptor, + dk->dk_descriptor, FSCRYPT_KEY_DESCRIPTOR_SIZE) != 0) + continue; ++ /* The sb is used at eviction time, so it must be the same. */ ++ if (ci->ci_inode->i_sb != dk->dk_sb) ++ continue; + if (ci->ci_mode != dk->dk_mode) + continue; + if (!fscrypt_is_key_prepared(&dk->dk_key, ci)) + continue; + if (crypto_memneq(raw_key, dk->dk_raw, ci->ci_mode->keysize)) + continue; +- /* using existing tfm with same (descriptor, mode, raw_key) */ ++ /* ++ * Use an existing prepared key with the same (descriptor, sb, ++ * mode, inlinecrypt, raw_key) combination. ++ */ + refcount_inc(&dk->dk_refcount); + spin_unlock(&fscrypt_direct_keys_lock); + free_direct_key(to_insert); +diff --git a/fs/exec.c b/fs/exec.c +index 4298e7e08d5d78..6eb1c8da2c7dbb 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -736,7 +736,7 @@ int transfer_args_to_stack(struct linux_binprm *bprm, + stop = bprm->p >> PAGE_SHIFT; + sp = *sp_location; + +- for (index = MAX_ARG_PAGES - 1; index >= stop; index--) { ++ for (index = MAX_ARG_PAGES; index-- > stop; ) { + unsigned int offset = index == stop ? bprm->p & ~PAGE_MASK : 0; + char *src = kmap_local_page(bprm->page[index]) + offset; + sp -= PAGE_SIZE - offset; +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +index f6b75ce11d1c1a..6f787cbeefd096 100644 +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -3659,24 +3659,27 @@ static bool f2fs_has_stable_inodes(struct super_block *sb) + return true; + } + +-static struct block_device **f2fs_get_devices(struct super_block *sb, +- unsigned int *num_devs) ++static unsigned int ++f2fs_get_devices(struct super_block *sb, ++ struct block_device *devs[FSCRYPT_MAX_DEVICES]) + { + struct f2fs_sb_info *sbi = F2FS_SB(sb); +- struct block_device **devs; ++ int ndevs; + int i; + +- if (!f2fs_is_multi_device(sbi)) +- return NULL; ++ static_assert(MAX_DEVICES <= FSCRYPT_MAX_DEVICES); + +- devs = kmalloc_array(sbi->s_ndevs, sizeof(*devs), GFP_KERNEL); +- if (!devs) +- return ERR_PTR(-ENOMEM); ++ if (!f2fs_is_multi_device(sbi)) { ++ devs[0] = sb->s_bdev; ++ return 1; ++ } ++ ndevs = sbi->s_ndevs; ++ if (WARN_ON_ONCE(ndevs > FSCRYPT_MAX_DEVICES)) ++ ndevs = FSCRYPT_MAX_DEVICES; + +- for (i = 0; i < sbi->s_ndevs; i++) ++ for (i = 0; i < ndevs; i++) + devs[i] = FDEV(i).bdev; +- *num_devs = sbi->s_ndevs; +- return devs; ++ return ndevs; + } + + static const struct fscrypt_operations f2fs_cryptops = { +diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c +index 42c82b54765934..6f74c345080f47 100644 +--- a/fs/fuse/dev_uring.c ++++ b/fs/fuse/dev_uring.c +@@ -998,15 +998,26 @@ static bool is_ring_ready(struct fuse_ring *ring, int current_qid) + /* + * fuse_uring_req_fetch command handling + */ +-static void fuse_uring_do_register(struct fuse_ring_ent *ent, +- struct io_uring_cmd *cmd, +- unsigned int issue_flags) ++static int fuse_uring_do_register(struct fuse_ring_ent *ent, ++ struct io_uring_cmd *cmd, ++ unsigned int issue_flags) + { + struct fuse_ring_queue *queue = ent->queue; + struct fuse_ring *ring = queue->ring; + struct fuse_conn *fc = ring->fc; + struct fuse_iqueue *fiq = &fc->iq; + ++ spin_lock(&fc->lock); ++ /* abort teardown path is running or has run */ ++ if (!fc->connected) { ++ spin_unlock(&fc->lock); ++ if (atomic_dec_and_test(&ring->queue_refs)) ++ wake_up_all(&ring->stop_waitq); ++ kfree(ent); ++ return -ECONNABORTED; ++ } ++ spin_unlock(&fc->lock); ++ + fuse_uring_prepare_cancel(cmd, issue_flags, ent); + + spin_lock(&queue->lock); +@@ -1023,6 +1034,7 @@ static void fuse_uring_do_register(struct fuse_ring_ent *ent, + wake_up_all(&fc->blocked_waitq); + } + } ++ return 0; + } + + /* +@@ -1138,9 +1150,7 @@ static int fuse_uring_register(struct io_uring_cmd *cmd, + if (IS_ERR(ent)) + return PTR_ERR(ent); + +- fuse_uring_do_register(ent, cmd, issue_flags); +- +- return 0; ++ return fuse_uring_do_register(ent, cmd, issue_flags); + } + + /* +diff --git a/fs/fuse/file.c b/fs/fuse/file.c +index 79d1b502e73195..585dd90361b654 100644 +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -2140,7 +2140,10 @@ static bool fuse_writepage_need_send(struct fuse_conn *fc, loff_t pos, + + WARN_ON(!ap->num_folios); + +- /* Reached max pages */ ++ /* Reached max pages or max folio slots */ ++ if (ap->num_folios >= fc->max_pages) ++ return true; ++ + if ((bytes + PAGE_SIZE - 1) >> PAGE_SHIFT > fc->max_pages) + return true; + +diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c +index c0fa6acf19375b..c9ece378687b9a 100644 +--- a/fs/iomap/buffered-io.c ++++ b/fs/iomap/buffered-io.c +@@ -47,11 +47,13 @@ static bool ifs_set_range_uptodate(struct folio *folio, + struct iomap_folio_state *ifs, size_t off, size_t len) + { + struct inode *inode = folio->mapping->host; +- unsigned int first_blk = off >> inode->i_blkbits; +- unsigned int last_blk = (off + len - 1) >> inode->i_blkbits; +- unsigned int nr_blks = last_blk - first_blk + 1; ++ unsigned int first_blk, last_blk; + +- bitmap_set(ifs->state, first_blk, nr_blks); ++ if (len) { ++ first_blk = off >> inode->i_blkbits; ++ last_blk = (off + len - 1) >> inode->i_blkbits; ++ bitmap_set(ifs->state, first_blk, last_blk - first_blk + 1); ++ } + return ifs_is_fully_uptodate(folio, ifs); + } + +@@ -127,13 +129,17 @@ static void ifs_clear_range_dirty(struct folio *folio, + { + struct inode *inode = folio->mapping->host; + unsigned int blks_per_folio = i_blocks_per_folio(inode, folio); +- unsigned int first_blk = (off >> inode->i_blkbits); +- unsigned int last_blk = (off + len - 1) >> inode->i_blkbits; +- unsigned int nr_blks = last_blk - first_blk + 1; ++ unsigned int first_blk = round_up(off, i_blocksize(inode)) >> ++ inode->i_blkbits; ++ unsigned int last_blk = (off + len) >> inode->i_blkbits; + unsigned long flags; + ++ if (first_blk >= last_blk) ++ return; ++ + spin_lock_irqsave(&ifs->state_lock, flags); +- bitmap_clear(ifs->state, first_blk + blks_per_folio, nr_blks); ++ bitmap_clear(ifs->state, first_blk + blks_per_folio, ++ last_blk - first_blk); + spin_unlock_irqrestore(&ifs->state_lock, flags); + } + +@@ -150,13 +156,17 @@ static void ifs_set_range_dirty(struct folio *folio, + { + struct inode *inode = folio->mapping->host; + unsigned int blks_per_folio = i_blocks_per_folio(inode, folio); +- unsigned int first_blk = (off >> inode->i_blkbits); +- unsigned int last_blk = (off + len - 1) >> inode->i_blkbits; +- unsigned int nr_blks = last_blk - first_blk + 1; ++ unsigned int first_blk, last_blk; + unsigned long flags; + ++ if (!len) ++ return; ++ ++ first_blk = off >> inode->i_blkbits; ++ last_blk = (off + len - 1) >> inode->i_blkbits; + spin_lock_irqsave(&ifs->state_lock, flags); +- bitmap_set(ifs->state, first_blk + blks_per_folio, nr_blks); ++ bitmap_set(ifs->state, first_blk + blks_per_folio, ++ last_blk - first_blk + 1); + spin_unlock_irqrestore(&ifs->state_lock, flags); + } + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index a96029c967e6bd..1e158881c1af9e 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -4478,7 +4478,7 @@ out_err: + + static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, + struct nfsd4_read *read, +- struct file *file, unsigned long maxcount) ++ unsigned long maxcount) + { + struct xdr_stream *xdr = resp->xdr; + unsigned int base = xdr->buf->page_len & ~PAGE_MASK; +@@ -4489,7 +4489,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, + if (xdr_reserve_space_vec(xdr, maxcount) < 0) + return nfserr_resource; + +- nfserr = nfsd_iter_read(resp->rqstp, read->rd_fhp, file, ++ nfserr = nfsd_iter_read(resp->rqstp, read->rd_fhp, read->rd_nf, + read->rd_offset, &maxcount, base, + &read->rd_eof); + read->rd_length = maxcount; +@@ -4536,7 +4536,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, + if (file->f_op->splice_read && splice_ok) + nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount); + else +- nfserr = nfsd4_encode_readv(resp, read, file, maxcount); ++ nfserr = nfsd4_encode_readv(resp, read, maxcount); + if (nfserr) { + xdr_truncate_encode(xdr, eof_offset); + return nfserr; +@@ -5432,7 +5432,7 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, + if (file->f_op->splice_read && splice_ok) + nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount); + else +- nfserr = nfsd4_encode_readv(resp, read, file, maxcount); ++ nfserr = nfsd4_encode_readv(resp, read, maxcount); + if (nfserr) + return nfserr; + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 20330372387801..ba882a4ea9cb9d 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1078,7 +1078,7 @@ __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp, + * nfsd_iter_read - Perform a VFS read using an iterator + * @rqstp: RPC transaction context + * @fhp: file handle of file to be read +- * @file: opened struct file of file to be read ++ * @nf: opened struct nfsd_file of file to be read + * @offset: starting byte offset + * @count: IN: requested number of bytes; OUT: number of bytes read + * @base: offset in first page of read buffer +@@ -1091,9 +1091,10 @@ __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp, + * returned. + */ + __be32 nfsd_iter_read(struct svc_rqst *rqstp, struct svc_fh *fhp, +- struct file *file, loff_t offset, unsigned long *count, ++ struct nfsd_file *nf, loff_t offset, unsigned long *count, + unsigned int base, u32 *eof) + { ++ struct file *file = nf->nf_file; + unsigned long v, total; + struct iov_iter iter; + struct kiocb kiocb; +@@ -1202,7 +1203,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned long exp_op_flags = 0; + unsigned int pflags = current->flags; + bool restore_flags = false; +- unsigned int nvecs; ++ int nvecs; + + trace_nfsd_write_opened(rqstp, fhp, offset, *cnt); + +@@ -1242,7 +1243,13 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, + } + + nvecs = xdr_buf_to_bvec(rqstp->rq_bvec, rqstp->rq_maxpages, payload); ++ if (nvecs < 0) { ++ host_err = nvecs; ++ goto out_nfserr; ++ } ++ + iov_iter_bvec(&iter, ITER_SOURCE, rqstp->rq_bvec, nvecs, *cnt); ++ + since = READ_ONCE(file->f_wb_err); + if (verf) + nfsd_copy_write_verifier(verf, nn); +@@ -1346,7 +1353,7 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (file->f_op->splice_read && nfsd_read_splice_ok(rqstp)) + err = nfsd_splice_read(rqstp, fhp, file, offset, count, eof); + else +- err = nfsd_iter_read(rqstp, fhp, file, offset, count, 0, eof); ++ err = nfsd_iter_read(rqstp, fhp, nf, offset, count, 0, eof); + + nfsd_file_put(nf); + trace_nfsd_read_done(rqstp, fhp, offset, *count); +diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h +index 9652c1de53ec13..1dd3ae3ceb3a8e 100644 +--- a/fs/nfsd/vfs.h ++++ b/fs/nfsd/vfs.h +@@ -122,7 +122,7 @@ __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned long *count, + u32 *eof); + __be32 nfsd_iter_read(struct svc_rqst *rqstp, struct svc_fh *fhp, +- struct file *file, loff_t offset, ++ struct nfsd_file *nf, loff_t offset, + unsigned long *count, unsigned int base, + u32 *eof); + bool nfsd_read_splice_ok(struct svc_rqst *rqstp); +diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c +index 97f373fd98797d..89317e1e7361b8 100644 +--- a/fs/overlayfs/copy_up.c ++++ b/fs/overlayfs/copy_up.c +@@ -864,7 +864,7 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c) + { + struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb); + struct inode *udir = d_inode(c->destdir); +- struct dentry *temp, *upper; ++ struct dentry *temp, *upper, *newdentry = NULL; + struct file *tmpfile; + struct ovl_cu_creds cc; + int err; +@@ -901,6 +901,14 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c) + err = PTR_ERR(upper); + if (!IS_ERR(upper)) { + err = ovl_do_link(ofs, temp, udir, upper); ++ if (!err) { ++ /* ++ * Record the linked dentry -- not the disconnected ++ * O_TMPFILE dentry -- so that ->d_revalidate() on ++ * the upper fs sees the real parent/name. ++ */ ++ newdentry = dget(upper); ++ } + dput(upper); + } + inode_unlock(udir); +@@ -916,7 +924,7 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c) + + if (!c->metacopy) + ovl_set_upperdata(d_inode(c->dentry)); +- ovl_inode_update(d_inode(c->dentry), dget(temp)); ++ ovl_inode_update(d_inode(c->dentry), newdentry); + + out: + ovl_end_write(c->dentry); +diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c +index 3fedfdddfa7584..a857ce377b0cfb 100644 +--- a/fs/overlayfs/file.c ++++ b/fs/overlayfs/file.c +@@ -541,9 +541,9 @@ static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in, + struct file *file_out, loff_t pos_out, + loff_t len, unsigned int flags, enum ovl_copyop op) + { ++ struct inode *inode_in = file_inode(file_in); + struct inode *inode_out = file_inode(file_out); + struct file *realfile_in, *realfile_out; +- const struct cred *old_cred; + loff_t ret; + + inode_lock(inode_out); +@@ -565,25 +565,38 @@ static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in, + if (IS_ERR(realfile_in)) + goto out_unlock; + +- old_cred = ovl_override_creds(file_inode(file_out)->i_sb); +- switch (op) { +- case OVL_COPY: +- ret = vfs_copy_file_range(realfile_in, pos_in, +- realfile_out, pos_out, len, flags); +- break; +- +- case OVL_CLONE: +- ret = vfs_clone_file_range(realfile_in, pos_in, +- realfile_out, pos_out, len, flags); +- break; +- +- case OVL_DEDUPE: +- ret = vfs_dedupe_file_range_one(realfile_in, pos_in, +- realfile_out, pos_out, len, +- flags); +- break; ++ /* ++ * For cross-sb copy, vfs_copy_file_range() will verify read access with ++ * the mounter creds of the dest fs mounter, so we need to explicitly ++ * verify read access with the source mounter creds. ++ */ ++ if (unlikely(inode_in->i_sb != inode_out->i_sb)) { ++ with_ovl_creds(inode_in->i_sb) { ++ ret = rw_verify_area(READ, realfile_in, &pos_in, len); ++ if (unlikely(ret)) ++ goto out_unlock; ++ } ++ } ++ ++ with_ovl_creds(inode_out->i_sb) { ++ switch (op) { ++ case OVL_COPY: ++ ret = vfs_copy_file_range(realfile_in, pos_in, ++ realfile_out, pos_out, len, flags); ++ break; ++ ++ case OVL_CLONE: ++ ret = vfs_clone_file_range(realfile_in, pos_in, ++ realfile_out, pos_out, len, flags); ++ break; ++ ++ case OVL_DEDUPE: ++ ret = vfs_dedupe_file_range_one(realfile_in, pos_in, ++ realfile_out, pos_out, len, ++ flags); ++ break; ++ } + } +- ovl_revert_creds(old_cred); + + /* Update size */ + ovl_file_modified(file_out); +diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h +index d1eb1cbe7a4561..696b13d9e1f102 100644 +--- a/fs/overlayfs/overlayfs.h ++++ b/fs/overlayfs/overlayfs.h +@@ -445,6 +445,11 @@ struct dentry *ovl_workdir(struct dentry *dentry); + const struct cred *ovl_override_creds(struct super_block *sb); + void ovl_revert_creds(const struct cred *old_cred); + ++EXTEND_CLASS(override_creds, _ovl, ovl_override_creds(sb), struct super_block *sb) ++ ++#define with_ovl_creds(sb) \ ++ scoped_class(override_creds_ovl, __UNIQUE_ID(label), sb) ++ + static inline const struct cred *ovl_creds(struct super_block *sb) + { + return OVL_FS(sb)->creator_cred; +diff --git a/fs/overlayfs/xattrs.c b/fs/overlayfs/xattrs.c +index 88055deca9360f..c86f1a6c8b937a 100644 +--- a/fs/overlayfs/xattrs.c ++++ b/fs/overlayfs/xattrs.c +@@ -13,7 +13,7 @@ static bool ovl_is_escaped_xattr(struct super_block *sb, const char *name) + OVL_XATTR_ESCAPE_USER_PREFIX_LEN) == 0; + else + return strncmp(name, OVL_XATTR_ESCAPE_TRUSTED_PREFIX, +- OVL_XATTR_ESCAPE_TRUSTED_PREFIX_LEN - 1) == 0; ++ OVL_XATTR_ESCAPE_TRUSTED_PREFIX_LEN) == 0; + } + + static bool ovl_is_own_xattr(struct super_block *sb, const char *name) +diff --git a/fs/posix_acl.c b/fs/posix_acl.c +index 4050942ab52f95..0d92d6a631e1d4 100644 +--- a/fs/posix_acl.c ++++ b/fs/posix_acl.c +@@ -93,6 +93,13 @@ static void __forget_cached_acl(struct posix_acl **p) + { + struct posix_acl *old; + ++ /* ++ * ACL_DONT_CACHE is expected to be a "const" value and xchg it with ++ * ACL_NOT_CACHED would enable acl caching for the inode - ++ * clearly not what the caller has intended. ++ */ ++ if (READ_ONCE(*p) == ACL_DONT_CACHE) ++ return; + old = xchg(p, ACL_NOT_CACHED); + if (!is_uncached_acl(old)) + posix_acl_release(old); +diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c +index 2f46f13967445c..ea6ec61a0430b9 100644 +--- a/fs/proc/namespaces.c ++++ b/fs/proc/namespaces.c +@@ -46,7 +46,7 @@ static const char *proc_ns_get_link(struct dentry *dentry, + const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops; + struct task_struct *task; + struct path ns_path; +- int error = -EACCES; ++ int error; + + if (!dentry) + return ERR_PTR(-ECHILD); +@@ -59,6 +59,7 @@ static const char *proc_ns_get_link(struct dentry *dentry, + if (error) + goto out_put_task; + ++ error = -EACCES; + if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) + goto out; + +@@ -90,6 +91,7 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int bufl + if (res) + goto out_put_task; + ++ res = -EACCES; + if (ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) { + res = ns_get_name(name, sizeof(name), task, ns_ops); + if (res >= 0) +diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index 38b9d47426ca99..858b11009c269e 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -2485,15 +2485,19 @@ static void make_uffd_wp_huge_pte(struct vm_area_struct *vma, + + psize = huge_page_size(hstate_vma(vma)); + +- if (is_hugetlb_entry_migration(ptent)) ++ if (is_hugetlb_entry_migration(ptent)) { + set_huge_pte_at(vma->vm_mm, addr, ptep, + pte_swp_mkuffd_wp(ptent), psize); +- else if (!huge_pte_none(ptent)) +- huge_ptep_modify_prot_commit(vma, addr, ptep, ptent, +- huge_pte_mkuffd_wp(ptent)); +- else ++ } else if (!huge_pte_none(ptent)) { ++ pte_t old_pte, new_pte; ++ ++ old_pte = huge_ptep_modify_prot_start(vma, addr, ptep); ++ new_pte = huge_pte_mkuffd_wp(old_pte); ++ huge_ptep_modify_prot_commit(vma, addr, ptep, old_pte, new_pte); ++ } else { + set_huge_pte_at(vma->vm_mm, addr, ptep, + make_pte_marker(PTE_MARKER_UFFD_WP), psize); ++ } + } + #endif /* CONFIG_HUGETLB_PAGE */ + +diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c +index 0d0ef54fc4de1f..eeb12ec594c7b4 100644 +--- a/fs/resctrl/ctrlmondata.c ++++ b/fs/resctrl/ctrlmondata.c +@@ -547,7 +547,7 @@ struct rdt_domain_hdr *resctrl_find_domain(struct list_head *h, int id, + } + + void mon_event_read(struct rmid_read *rr, struct rdt_resource *r, +- struct rdt_mon_domain *d, struct rdtgroup *rdtgrp, ++ struct rdt_l3_mon_domain *d, struct rdtgroup *rdtgrp, + cpumask_t *cpumask, int evtid, int first) + { + int cpu; +@@ -596,9 +596,9 @@ int rdtgroup_mondata_show(struct seq_file *m, void *arg) + struct kernfs_open_file *of = m->private; + enum resctrl_res_level resid; + enum resctrl_event_id evtid; ++ struct rdt_l3_mon_domain *d; + struct rdt_domain_hdr *hdr; + struct rmid_read rr = {0}; +- struct rdt_mon_domain *d; + struct rdtgroup *rdtgrp; + int domid, cpu, ret = 0; + struct rdt_resource *r; +@@ -653,7 +653,7 @@ int rdtgroup_mondata_show(struct seq_file *m, void *arg) + ret = -ENOENT; + goto out; + } +- d = container_of(hdr, struct rdt_mon_domain, hdr); ++ d = container_of(hdr, struct rdt_l3_mon_domain, hdr); + mon_event_read(&rr, r, d, rdtgrp, &d->hdr.cpu_mask, evtid, false); + } + +diff --git a/fs/resctrl/internal.h b/fs/resctrl/internal.h +index cf1fd82dc5a99e..77f6e531e261b9 100644 +--- a/fs/resctrl/internal.h ++++ b/fs/resctrl/internal.h +@@ -123,7 +123,7 @@ struct mon_data { + struct rmid_read { + struct rdtgroup *rgrp; + struct rdt_resource *r; +- struct rdt_mon_domain *d; ++ struct rdt_l3_mon_domain *d; + enum resctrl_event_id evtid; + bool first; + struct cacheinfo *ci; +@@ -351,23 +351,27 @@ int closids_supported(void); + + void closid_free(int closid); + ++int setup_rmid_lru_list(void); ++ ++void free_rmid_lru_list(void); ++ + int alloc_rmid(u32 closid); + + void free_rmid(u32 closid, u32 rmid); + +-void resctrl_mon_resource_exit(void); ++int resctrl_l3_mon_resource_init(void); ++ ++void resctrl_l3_mon_resource_exit(void); + + void mon_event_count(void *info); + + int rdtgroup_mondata_show(struct seq_file *m, void *arg); + + void mon_event_read(struct rmid_read *rr, struct rdt_resource *r, +- struct rdt_mon_domain *d, struct rdtgroup *rdtgrp, ++ struct rdt_l3_mon_domain *d, struct rdtgroup *rdtgrp, + cpumask_t *cpumask, int evtid, int first); + +-int resctrl_mon_resource_init(void); +- +-void mbm_setup_overflow_handler(struct rdt_mon_domain *dom, ++void mbm_setup_overflow_handler(struct rdt_l3_mon_domain *dom, + unsigned long delay_ms, + int exclude_cpu); + +@@ -375,14 +379,14 @@ void mbm_handle_overflow(struct work_struct *work); + + bool is_mba_sc(struct rdt_resource *r); + +-void cqm_setup_limbo_handler(struct rdt_mon_domain *dom, unsigned long delay_ms, ++void cqm_setup_limbo_handler(struct rdt_l3_mon_domain *dom, unsigned long delay_ms, + int exclude_cpu); + + void cqm_handle_limbo(struct work_struct *work); + +-bool has_busy_rmid(struct rdt_mon_domain *d); ++bool has_busy_rmid(struct rdt_l3_mon_domain *d); + +-void __check_limbo(struct rdt_mon_domain *d, bool force_free); ++void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free); + + void resctrl_file_fflags_init(const char *config, unsigned long fflags); + +diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c +index 7012a75814ac36..55db47e969ce6d 100644 +--- a/fs/resctrl/monitor.c ++++ b/fs/resctrl/monitor.c +@@ -130,7 +130,7 @@ static void limbo_release_entry(struct rmid_entry *entry) + * decrement the count. If the busy count gets to zero on an RMID, we + * free the RMID + */ +-void __check_limbo(struct rdt_mon_domain *d, bool force_free) ++void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free) + { + struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3); + u32 idx_limit = resctrl_arch_system_num_rmid_idx(); +@@ -193,7 +193,7 @@ void __check_limbo(struct rdt_mon_domain *d, bool force_free) + resctrl_arch_mon_ctx_free(r, QOS_L3_OCCUP_EVENT_ID, arch_mon_ctx); + } + +-bool has_busy_rmid(struct rdt_mon_domain *d) ++bool has_busy_rmid(struct rdt_l3_mon_domain *d) + { + u32 idx_limit = resctrl_arch_system_num_rmid_idx(); + +@@ -294,7 +294,7 @@ int alloc_rmid(u32 closid) + static void add_rmid_to_limbo(struct rmid_entry *entry) + { + struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3); +- struct rdt_mon_domain *d; ++ struct rdt_l3_mon_domain *d; + u32 idx; + + lockdep_assert_held(&rdtgroup_mutex); +@@ -347,7 +347,7 @@ void free_rmid(u32 closid, u32 rmid) + list_add_tail(&entry->list, &rmid_free_lru); + } + +-static struct mbm_state *get_mbm_state(struct rdt_mon_domain *d, u32 closid, ++static struct mbm_state *get_mbm_state(struct rdt_l3_mon_domain *d, u32 closid, + u32 rmid, enum resctrl_event_id evtid) + { + u32 idx = resctrl_arch_rmid_idx_encode(closid, rmid); +@@ -367,7 +367,7 @@ static struct mbm_state *get_mbm_state(struct rdt_mon_domain *d, u32 closid, + * Return: + * Valid counter ID on success, or -ENOENT on failure. + */ +-static int mbm_cntr_get(struct rdt_resource *r, struct rdt_mon_domain *d, ++static int mbm_cntr_get(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + struct rdtgroup *rdtgrp, enum resctrl_event_id evtid) + { + int cntr_id; +@@ -394,7 +394,7 @@ static int mbm_cntr_get(struct rdt_resource *r, struct rdt_mon_domain *d, + * Return: + * Valid counter ID on success, or -ENOSPC on failure. + */ +-static int mbm_cntr_alloc(struct rdt_resource *r, struct rdt_mon_domain *d, ++static int mbm_cntr_alloc(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + struct rdtgroup *rdtgrp, enum resctrl_event_id evtid) + { + int cntr_id; +@@ -413,17 +413,17 @@ static int mbm_cntr_alloc(struct rdt_resource *r, struct rdt_mon_domain *d, + /* + * mbm_cntr_free() - Clear the counter ID configuration details in the domain @d. + */ +-static void mbm_cntr_free(struct rdt_mon_domain *d, int cntr_id) ++static void mbm_cntr_free(struct rdt_l3_mon_domain *d, int cntr_id) + { + memset(&d->cntr_cfg[cntr_id], 0, sizeof(*d->cntr_cfg)); + } + +-static int __mon_event_count(struct rdtgroup *rdtgrp, struct rmid_read *rr) ++static int __l3_mon_event_count(struct rdtgroup *rdtgrp, struct rmid_read *rr) + { + int cpu = smp_processor_id(); + u32 closid = rdtgrp->closid; + u32 rmid = rdtgrp->mon.rmid; +- struct rdt_mon_domain *d; ++ struct rdt_l3_mon_domain *d; + int cntr_id = -ENOENT; + struct mbm_state *m; + int err, ret; +@@ -499,6 +499,17 @@ static int __mon_event_count(struct rdtgroup *rdtgrp, struct rmid_read *rr) + return ret; + } + ++static int __mon_event_count(struct rdtgroup *rdtgrp, struct rmid_read *rr) ++{ ++ switch (rr->r->rid) { ++ case RDT_RESOURCE_L3: ++ return __l3_mon_event_count(rdtgrp, rr); ++ default: ++ rr->err = -EINVAL; ++ return -EINVAL; ++ } ++} ++ + /* + * mbm_bw_count() - Update bw count from values previously read by + * __mon_event_count(). +@@ -617,7 +628,7 @@ static struct rdt_ctrl_domain *get_ctrl_domain_from_cpu(int cpu, + * throttle MSRs already have low percentage values. To avoid + * unnecessarily restricting such rdtgroups, we also increase the bandwidth. + */ +-static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_mon_domain *dom_mbm) ++static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_l3_mon_domain *dom_mbm) + { + u32 closid, rmid, cur_msr_val, new_msr_val; + struct mbm_state *pmbm_data, *cmbm_data; +@@ -685,7 +696,7 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_mon_domain *dom_mbm) + resctrl_arch_update_one(r_mba, dom_mba, closid, CDP_NONE, new_msr_val); + } + +-static void mbm_update_one_event(struct rdt_resource *r, struct rdt_mon_domain *d, ++static void mbm_update_one_event(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + struct rdtgroup *rdtgrp, enum resctrl_event_id evtid) + { + struct rmid_read rr = {0}; +@@ -717,7 +728,7 @@ static void mbm_update_one_event(struct rdt_resource *r, struct rdt_mon_domain * + resctrl_arch_mon_ctx_free(rr.r, rr.evtid, rr.arch_mon_ctx); + } + +-static void mbm_update(struct rdt_resource *r, struct rdt_mon_domain *d, ++static void mbm_update(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + struct rdtgroup *rdtgrp) + { + /* +@@ -738,12 +749,12 @@ static void mbm_update(struct rdt_resource *r, struct rdt_mon_domain *d, + void cqm_handle_limbo(struct work_struct *work) + { + unsigned long delay = msecs_to_jiffies(CQM_LIMBOCHECK_INTERVAL); +- struct rdt_mon_domain *d; ++ struct rdt_l3_mon_domain *d; + + cpus_read_lock(); + mutex_lock(&rdtgroup_mutex); + +- d = container_of(work, struct rdt_mon_domain, cqm_limbo.work); ++ d = container_of(work, struct rdt_l3_mon_domain, cqm_limbo.work); + + __check_limbo(d, false); + +@@ -766,7 +777,7 @@ void cqm_handle_limbo(struct work_struct *work) + * @exclude_cpu: Which CPU the handler should not run on, + * RESCTRL_PICK_ANY_CPU to pick any CPU. + */ +-void cqm_setup_limbo_handler(struct rdt_mon_domain *dom, unsigned long delay_ms, ++void cqm_setup_limbo_handler(struct rdt_l3_mon_domain *dom, unsigned long delay_ms, + int exclude_cpu) + { + unsigned long delay = msecs_to_jiffies(delay_ms); +@@ -783,7 +794,7 @@ void mbm_handle_overflow(struct work_struct *work) + { + unsigned long delay = msecs_to_jiffies(MBM_OVERFLOW_INTERVAL); + struct rdtgroup *prgrp, *crgrp; +- struct rdt_mon_domain *d; ++ struct rdt_l3_mon_domain *d; + struct list_head *head; + struct rdt_resource *r; + +@@ -798,7 +809,7 @@ void mbm_handle_overflow(struct work_struct *work) + goto out_unlock; + + r = resctrl_arch_get_resource(RDT_RESOURCE_L3); +- d = container_of(work, struct rdt_mon_domain, mbm_over.work); ++ d = container_of(work, struct rdt_l3_mon_domain, mbm_over.work); + + list_for_each_entry(prgrp, &rdt_all_groups, rdtgroup_list) { + mbm_update(r, d, prgrp); +@@ -832,7 +843,7 @@ out_unlock: + * @exclude_cpu: Which CPU the handler should not run on, + * RESCTRL_PICK_ANY_CPU to pick any CPU. + */ +-void mbm_setup_overflow_handler(struct rdt_mon_domain *dom, unsigned long delay_ms, ++void mbm_setup_overflow_handler(struct rdt_l3_mon_domain *dom, unsigned long delay_ms, + int exclude_cpu) + { + unsigned long delay = msecs_to_jiffies(delay_ms); +@@ -851,42 +862,29 @@ void mbm_setup_overflow_handler(struct rdt_mon_domain *dom, unsigned long delay_ + schedule_delayed_work_on(cpu, &dom->mbm_over, delay); + } + +-static int dom_data_init(struct rdt_resource *r) ++int setup_rmid_lru_list(void) + { +- u32 idx_limit = resctrl_arch_system_num_rmid_idx(); +- u32 num_closid = resctrl_arch_get_num_closid(r); + struct rmid_entry *entry = NULL; +- int err = 0, i; ++ u32 idx_limit; + u32 idx; ++ int i; + +- mutex_lock(&rdtgroup_mutex); +- if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID)) { +- u32 *tmp; +- +- /* +- * If the architecture hasn't provided a sanitised value here, +- * this may result in larger arrays than necessary. Resctrl will +- * use a smaller system wide value based on the resources in +- * use. +- */ +- tmp = kcalloc(num_closid, sizeof(*tmp), GFP_KERNEL); +- if (!tmp) { +- err = -ENOMEM; +- goto out_unlock; +- } ++ if (!resctrl_arch_mon_capable()) ++ return 0; + +- closid_num_dirty_rmid = tmp; +- } ++ /* ++ * Called on every mount, but the number of RMIDs cannot change ++ * after the first mount, so keep using the same set of rmid_ptrs[] ++ * until resctrl_exit(). Note that the limbo handler continues to ++ * access rmid_ptrs[] after resctrl is unmounted. ++ */ ++ if (rmid_ptrs) ++ return 0; + ++ idx_limit = resctrl_arch_system_num_rmid_idx(); + rmid_ptrs = kcalloc(idx_limit, sizeof(struct rmid_entry), GFP_KERNEL); +- if (!rmid_ptrs) { +- if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID)) { +- kfree(closid_num_dirty_rmid); +- closid_num_dirty_rmid = NULL; +- } +- err = -ENOMEM; +- goto out_unlock; +- } ++ if (!rmid_ptrs) ++ return -ENOMEM; + + for (i = 0; i < idx_limit; i++) { + entry = &rmid_ptrs[i]; +@@ -899,35 +897,24 @@ static int dom_data_init(struct rdt_resource *r) + /* + * RESCTRL_RESERVED_CLOSID and RESCTRL_RESERVED_RMID are special and + * are always allocated. These are used for the rdtgroup_default +- * control group, which will be setup later in resctrl_init(). ++ * control group, which was setup earlier in rdtgroup_setup_default(). + */ + idx = resctrl_arch_rmid_idx_encode(RESCTRL_RESERVED_CLOSID, + RESCTRL_RESERVED_RMID); + entry = __rmid_entry(idx); + list_del(&entry->list); + +-out_unlock: +- mutex_unlock(&rdtgroup_mutex); +- +- return err; ++ return 0; + } + +-static void dom_data_exit(struct rdt_resource *r) ++void free_rmid_lru_list(void) + { +- mutex_lock(&rdtgroup_mutex); +- +- if (!r->mon_capable) +- goto out_unlock; +- +- if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID)) { +- kfree(closid_num_dirty_rmid); +- closid_num_dirty_rmid = NULL; +- } ++ if (!resctrl_arch_mon_capable()) ++ return; + ++ mutex_lock(&rdtgroup_mutex); + kfree(rmid_ptrs); + rmid_ptrs = NULL; +- +-out_unlock: + mutex_unlock(&rdtgroup_mutex); + } + +@@ -1087,7 +1074,7 @@ out_unlock: + * mbm_cntr_free_all() - Clear all the counter ID configuration details in the + * domain @d. Called when mbm_assign_mode is changed. + */ +-static void mbm_cntr_free_all(struct rdt_resource *r, struct rdt_mon_domain *d) ++static void mbm_cntr_free_all(struct rdt_resource *r, struct rdt_l3_mon_domain *d) + { + memset(d->cntr_cfg, 0, sizeof(*d->cntr_cfg) * r->mon.num_mbm_cntrs); + } +@@ -1096,7 +1083,7 @@ static void mbm_cntr_free_all(struct rdt_resource *r, struct rdt_mon_domain *d) + * resctrl_reset_rmid_all() - Reset all non-architecture states for all the + * supported RMIDs. + */ +-static void resctrl_reset_rmid_all(struct rdt_resource *r, struct rdt_mon_domain *d) ++static void resctrl_reset_rmid_all(struct rdt_resource *r, struct rdt_l3_mon_domain *d) + { + u32 idx_limit = resctrl_arch_system_num_rmid_idx(); + enum resctrl_event_id evt; +@@ -1117,7 +1104,7 @@ static void resctrl_reset_rmid_all(struct rdt_resource *r, struct rdt_mon_domain + * Assign the counter if @assign is true else unassign the counter. Reset the + * associated non-architectural state. + */ +-static void rdtgroup_assign_cntr(struct rdt_resource *r, struct rdt_mon_domain *d, ++static void rdtgroup_assign_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + enum resctrl_event_id evtid, u32 rmid, u32 closid, + u32 cntr_id, bool assign) + { +@@ -1137,7 +1124,7 @@ static void rdtgroup_assign_cntr(struct rdt_resource *r, struct rdt_mon_domain * + * Return: + * 0 on success, < 0 on failure. + */ +-static int rdtgroup_alloc_assign_cntr(struct rdt_resource *r, struct rdt_mon_domain *d, ++static int rdtgroup_alloc_assign_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + struct rdtgroup *rdtgrp, struct mon_evt *mevt) + { + int cntr_id; +@@ -1172,7 +1159,7 @@ static int rdtgroup_alloc_assign_cntr(struct rdt_resource *r, struct rdt_mon_dom + * Return: + * 0 on success, < 0 on failure. + */ +-static int rdtgroup_assign_cntr_event(struct rdt_mon_domain *d, struct rdtgroup *rdtgrp, ++static int rdtgroup_assign_cntr_event(struct rdt_l3_mon_domain *d, struct rdtgroup *rdtgrp, + struct mon_evt *mevt) + { + struct rdt_resource *r = resctrl_arch_get_resource(mevt->rid); +@@ -1222,7 +1209,7 @@ void rdtgroup_assign_cntrs(struct rdtgroup *rdtgrp) + * rdtgroup_free_unassign_cntr() - Unassign and reset the counter ID configuration + * for the event pointed to by @mevt within the domain @d and resctrl group @rdtgrp. + */ +-static void rdtgroup_free_unassign_cntr(struct rdt_resource *r, struct rdt_mon_domain *d, ++static void rdtgroup_free_unassign_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + struct rdtgroup *rdtgrp, struct mon_evt *mevt) + { + int cntr_id; +@@ -1243,7 +1230,7 @@ static void rdtgroup_free_unassign_cntr(struct rdt_resource *r, struct rdt_mon_d + * the event structure @mevt from the domain @d and the group @rdtgrp. Unassign + * the counters from all the domains if @d is NULL else unassign from @d. + */ +-static void rdtgroup_unassign_cntr_event(struct rdt_mon_domain *d, struct rdtgroup *rdtgrp, ++static void rdtgroup_unassign_cntr_event(struct rdt_l3_mon_domain *d, struct rdtgroup *rdtgrp, + struct mon_evt *mevt) + { + struct rdt_resource *r = resctrl_arch_get_resource(mevt->rid); +@@ -1318,7 +1305,7 @@ next_config: + static void rdtgroup_update_cntr_event(struct rdt_resource *r, struct rdtgroup *rdtgrp, + enum resctrl_event_id evtid) + { +- struct rdt_mon_domain *d; ++ struct rdt_l3_mon_domain *d; + int cntr_id; + + list_for_each_entry(d, &r->mon_domains, hdr.list) { +@@ -1424,7 +1411,7 @@ ssize_t resctrl_mbm_assign_mode_write(struct kernfs_open_file *of, char *buf, + size_t nbytes, loff_t off) + { + struct rdt_resource *r = rdt_kn_parent_priv(of->kn); +- struct rdt_mon_domain *d; ++ struct rdt_l3_mon_domain *d; + int ret = 0; + bool enable; + +@@ -1497,7 +1484,7 @@ int resctrl_num_mbm_cntrs_show(struct kernfs_open_file *of, + struct seq_file *s, void *v) + { + struct rdt_resource *r = rdt_kn_parent_priv(of->kn); +- struct rdt_mon_domain *dom; ++ struct rdt_l3_mon_domain *dom; + bool sep = false; + + cpus_read_lock(); +@@ -1521,7 +1508,7 @@ int resctrl_available_mbm_cntrs_show(struct kernfs_open_file *of, + struct seq_file *s, void *v) + { + struct rdt_resource *r = rdt_kn_parent_priv(of->kn); +- struct rdt_mon_domain *dom; ++ struct rdt_l3_mon_domain *dom; + bool sep = false; + u32 cntrs, i; + int ret = 0; +@@ -1562,7 +1549,7 @@ out_unlock: + int mbm_L3_assignments_show(struct kernfs_open_file *of, struct seq_file *s, void *v) + { + struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3); +- struct rdt_mon_domain *d; ++ struct rdt_l3_mon_domain *d; + struct rdtgroup *rdtgrp; + struct mon_evt *mevt; + int ret = 0; +@@ -1625,7 +1612,7 @@ static struct mon_evt *mbm_get_mon_event_by_name(struct rdt_resource *r, char *n + return NULL; + } + +-static int rdtgroup_modify_assign_state(char *assign, struct rdt_mon_domain *d, ++static int rdtgroup_modify_assign_state(char *assign, struct rdt_l3_mon_domain *d, + struct rdtgroup *rdtgrp, struct mon_evt *mevt) + { + int ret = 0; +@@ -1651,7 +1638,7 @@ static int rdtgroup_modify_assign_state(char *assign, struct rdt_mon_domain *d, + static int resctrl_parse_mbm_assignment(struct rdt_resource *r, struct rdtgroup *rdtgrp, + char *event, char *tok) + { +- struct rdt_mon_domain *d; ++ struct rdt_l3_mon_domain *d; + unsigned long dom_id = 0; + char *dom_str, *id_str; + struct mon_evt *mevt; +@@ -1746,19 +1733,59 @@ ssize_t mbm_L3_assignments_write(struct kernfs_open_file *of, char *buf, + return ret ?: nbytes; + } + ++static int closid_num_dirty_rmid_alloc(struct rdt_resource *r) ++{ ++ if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID)) { ++ u32 num_closid = resctrl_arch_get_num_closid(r); ++ u32 *tmp; ++ ++ /* For ARM memory ordering access to closid_num_dirty_rmid */ ++ mutex_lock(&rdtgroup_mutex); ++ ++ /* ++ * If the architecture hasn't provided a sanitised value here, ++ * this may result in larger arrays than necessary. Resctrl will ++ * use a smaller system wide value based on the resources in ++ * use. ++ */ ++ tmp = kcalloc(num_closid, sizeof(*tmp), GFP_KERNEL); ++ if (!tmp) { ++ mutex_unlock(&rdtgroup_mutex); ++ return -ENOMEM; ++ } ++ ++ closid_num_dirty_rmid = tmp; ++ ++ mutex_unlock(&rdtgroup_mutex); ++ } ++ ++ return 0; ++} ++ ++static void closid_num_dirty_rmid_free(void) ++{ ++ if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID)) { ++ mutex_lock(&rdtgroup_mutex); ++ kfree(closid_num_dirty_rmid); ++ closid_num_dirty_rmid = NULL; ++ mutex_unlock(&rdtgroup_mutex); ++ } ++} ++ + /** +- * resctrl_mon_resource_init() - Initialise global monitoring structures. ++ * resctrl_l3_mon_resource_init() - Initialise global monitoring structures. + * + * Allocate and initialise global monitor resources that do not belong to a +- * specific domain. i.e. the rmid_ptrs[] used for the limbo and free lists. ++ * specific domain. i.e. the closid_num_dirty_rmid[] used to find the CLOSID ++ * with the cleanest set of RMIDs. + * Called once during boot after the struct rdt_resource's have been configured + * but before the filesystem is mounted. + * Resctrl's cpuhp callbacks may be called before this point to bring a domain + * online. + * +- * Returns 0 for success, or -ENOMEM. ++ * Return: 0 for success, or -ENOMEM. + */ +-int resctrl_mon_resource_init(void) ++int resctrl_l3_mon_resource_init(void) + { + struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3); + int ret; +@@ -1766,7 +1793,7 @@ int resctrl_mon_resource_init(void) + if (!r->mon_capable) + return 0; + +- ret = dom_data_init(r); ++ ret = closid_num_dirty_rmid_alloc(r); + if (ret) + return ret; + +@@ -1808,9 +1835,12 @@ int resctrl_mon_resource_init(void) + return 0; + } + +-void resctrl_mon_resource_exit(void) ++void resctrl_l3_mon_resource_exit(void) + { + struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3); + +- dom_data_exit(r); ++ if (!r->mon_capable) ++ return; ++ ++ closid_num_dirty_rmid_free(); + } +diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c +index 7cfb0086451c5f..08e26c0c9fb9cf 100644 +--- a/fs/resctrl/rdtgroup.c ++++ b/fs/resctrl/rdtgroup.c +@@ -581,14 +581,20 @@ unlock: + * + * On resource group creation via a mkdir, an extra kernfs_node reference is + * taken to ensure that the rdtgroup structure remains accessible for the +- * rdtgroup_kn_unlock() calls where it is removed. ++ * rdtgroup_kn_unlock() calls where it is removed. The default group is ++ * statically allocated: it does not have an extra reference but will have ++ * RDT_DELETED set on unmount to support safe access to its associated files ++ * via rdtgroup_kn_lock_live/rdtgroup_kn_unlock(). + * +- * Drop the extra reference here, then free the rdtgroup structure. ++ * For all but the default group: drop the extra reference, then free the ++ * rdtgroup structure. + * + * Return: void + */ + static void rdtgroup_remove(struct rdtgroup *rdtgrp) + { ++ if (rdtgrp == &rdtgroup_default) ++ return; + kernfs_put(rdtgrp->kn); + kfree(rdtgrp); + } +@@ -1620,7 +1626,7 @@ static void mondata_config_read(struct resctrl_mon_config_info *mon_info) + static int mbm_config_show(struct seq_file *s, struct rdt_resource *r, u32 evtid) + { + struct resctrl_mon_config_info mon_info; +- struct rdt_mon_domain *dom; ++ struct rdt_l3_mon_domain *dom; + bool sep = false; + + cpus_read_lock(); +@@ -1668,7 +1674,7 @@ static int mbm_local_bytes_config_show(struct kernfs_open_file *of, + } + + static void mbm_config_write_domain(struct rdt_resource *r, +- struct rdt_mon_domain *d, u32 evtid, u32 val) ++ struct rdt_l3_mon_domain *d, u32 evtid, u32 val) + { + struct resctrl_mon_config_info mon_info = {0}; + +@@ -1710,7 +1716,7 @@ static int mon_config_write(struct rdt_resource *r, char *tok, u32 evtid) + { + char *dom_str = NULL, *id_str; + unsigned long dom_id, val; +- struct rdt_mon_domain *d; ++ struct rdt_l3_mon_domain *d; + + /* Walking r->domains, ensure it can't race with cpuhp */ + lockdep_assert_cpus_held(); +@@ -2718,7 +2724,7 @@ static int rdt_get_tree(struct fs_context *fc) + { + struct rdt_fs_context *ctx = rdt_fc2context(fc); + unsigned long flags = RFTYPE_CTRL_BASE; +- struct rdt_mon_domain *dom; ++ struct rdt_l3_mon_domain *dom; + struct rdt_resource *r; + int ret; + +@@ -2732,6 +2738,16 @@ static int rdt_get_tree(struct fs_context *fc) + goto out; + } + ++ /* Avoid races from pending operations from a previous mount */ ++ if (atomic_read(&rdtgroup_default.waitcount) != 0) { ++ ret = -EBUSY; ++ goto out; ++ } ++ ++ ret = setup_rmid_lru_list(); ++ if (ret) ++ goto out; ++ + ret = rdtgroup_setup_root(ctx); + if (ret) + goto out; +@@ -3090,6 +3106,7 @@ static void resctrl_fs_teardown(void) + mon_put_kn_priv(); + rdt_pseudo_lock_release(); + rdtgroup_default.mode = RDT_MODE_SHAREABLE; ++ rdtgroup_default.flags = RDT_DELETED; + closid_exit(); + schemata_list_destroy(); + rdtgroup_destroy_root(); +@@ -3169,7 +3186,7 @@ static void mon_rmdir_one_subdir(struct kernfs_node *pkn, char *name, char *subn + * when last domain being summed is removed. + */ + static void rmdir_mondata_subdir_allrdtgrp(struct rdt_resource *r, +- struct rdt_mon_domain *d) ++ struct rdt_l3_mon_domain *d) + { + struct rdtgroup *prgrp, *crgrp; + char subname[32]; +@@ -3189,7 +3206,7 @@ static void rmdir_mondata_subdir_allrdtgrp(struct rdt_resource *r, + } + } + +-static int mon_add_all_files(struct kernfs_node *kn, struct rdt_mon_domain *d, ++static int mon_add_all_files(struct kernfs_node *kn, struct rdt_l3_mon_domain *d, + struct rdt_resource *r, struct rdtgroup *prgrp, + bool do_sum) + { +@@ -3218,7 +3235,7 @@ static int mon_add_all_files(struct kernfs_node *kn, struct rdt_mon_domain *d, + } + + static int mkdir_mondata_subdir(struct kernfs_node *parent_kn, +- struct rdt_mon_domain *d, ++ struct rdt_l3_mon_domain *d, + struct rdt_resource *r, struct rdtgroup *prgrp) + { + struct kernfs_node *kn, *ckn; +@@ -3280,7 +3297,7 @@ out_destroy: + * and "monitor" groups with given domain id. + */ + static void mkdir_mondata_subdir_allrdtgrp(struct rdt_resource *r, +- struct rdt_mon_domain *d) ++ struct rdt_l3_mon_domain *d) + { + struct kernfs_node *parent_kn; + struct rdtgroup *prgrp, *crgrp; +@@ -3302,7 +3319,7 @@ static int mkdir_mondata_subdir_alldom(struct kernfs_node *parent_kn, + struct rdt_resource *r, + struct rdtgroup *prgrp) + { +- struct rdt_mon_domain *dom; ++ struct rdt_l3_mon_domain *dom; + int ret; + + /* Walking r->domains, ensure it can't race with cpuhp */ +@@ -4144,6 +4161,7 @@ static int rdtgroup_setup_root(struct rdt_fs_context *ctx) + + ctx->kfc.root = rdt_root; + rdtgroup_default.kn = kernfs_root_to_node(rdt_root); ++ rdtgroup_default.flags = 0; + + return 0; + } +@@ -4170,7 +4188,7 @@ static void rdtgroup_setup_default(void) + mutex_unlock(&rdtgroup_mutex); + } + +-static void domain_destroy_mon_state(struct rdt_mon_domain *d) ++static void domain_destroy_l3_mon_state(struct rdt_l3_mon_domain *d) + { + int idx; + +@@ -4192,7 +4210,7 @@ void resctrl_offline_ctrl_domain(struct rdt_resource *r, struct rdt_ctrl_domain + mutex_unlock(&rdtgroup_mutex); + } + +-void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_mon_domain *d) ++void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_l3_mon_domain *d) + { + mutex_lock(&rdtgroup_mutex); + +@@ -4218,13 +4236,13 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_mon_domain *d + cancel_delayed_work(&d->cqm_limbo); + } + +- domain_destroy_mon_state(d); ++ domain_destroy_l3_mon_state(d); + + mutex_unlock(&rdtgroup_mutex); + } + + /** +- * domain_setup_mon_state() - Initialise domain monitoring structures. ++ * domain_setup_l3_mon_state() - Initialise domain monitoring structures. + * @r: The resource for the newly online domain. + * @d: The newly online domain. + * +@@ -4232,11 +4250,11 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_mon_domain *d + * Called when the first CPU of a domain comes online, regardless of whether + * the filesystem is mounted. + * During boot this may be called before global allocations have been made by +- * resctrl_mon_resource_init(). ++ * resctrl_l3_mon_resource_init(). + * +- * Returns 0 for success, or -ENOMEM. ++ * Return: 0 for success, or -ENOMEM. + */ +-static int domain_setup_mon_state(struct rdt_resource *r, struct rdt_mon_domain *d) ++static int domain_setup_l3_mon_state(struct rdt_resource *r, struct rdt_l3_mon_domain *d) + { + u32 idx_limit = resctrl_arch_system_num_rmid_idx(); + size_t tsize = sizeof(*d->mbm_states[0]); +@@ -4292,13 +4310,13 @@ int resctrl_online_ctrl_domain(struct rdt_resource *r, struct rdt_ctrl_domain *d + return err; + } + +-int resctrl_online_mon_domain(struct rdt_resource *r, struct rdt_mon_domain *d) ++int resctrl_online_mon_domain(struct rdt_resource *r, struct rdt_l3_mon_domain *d) + { + int err; + + mutex_lock(&rdtgroup_mutex); + +- err = domain_setup_mon_state(r, d); ++ err = domain_setup_l3_mon_state(r, d); + if (err) + goto out_unlock; + +@@ -4344,10 +4362,10 @@ static void clear_childcpus(struct rdtgroup *r, unsigned int cpu) + } + } + +-static struct rdt_mon_domain *get_mon_domain_from_cpu(int cpu, ++static struct rdt_l3_mon_domain *get_mon_domain_from_cpu(int cpu, + struct rdt_resource *r) + { +- struct rdt_mon_domain *d; ++ struct rdt_l3_mon_domain *d; + + lockdep_assert_cpus_held(); + +@@ -4363,7 +4381,7 @@ static struct rdt_mon_domain *get_mon_domain_from_cpu(int cpu, + void resctrl_offline_cpu(unsigned int cpu) + { + struct rdt_resource *l3 = resctrl_arch_get_resource(RDT_RESOURCE_L3); +- struct rdt_mon_domain *d; ++ struct rdt_l3_mon_domain *d; + struct rdtgroup *rdtgrp; + + mutex_lock(&rdtgroup_mutex); +@@ -4413,13 +4431,13 @@ int resctrl_init(void) + + thread_throttle_mode_init(); + +- ret = resctrl_mon_resource_init(); ++ ret = resctrl_l3_mon_resource_init(); + if (ret) + return ret; + + ret = sysfs_create_mount_point(fs_kobj, "resctrl"); + if (ret) { +- resctrl_mon_resource_exit(); ++ resctrl_l3_mon_resource_exit(); + return ret; + } + +@@ -4454,7 +4472,7 @@ int resctrl_init(void) + + cleanup_mountpoint: + sysfs_remove_mount_point(fs_kobj, "resctrl"); +- resctrl_mon_resource_exit(); ++ resctrl_l3_mon_resource_exit(); + + return ret; + } +@@ -4490,7 +4508,7 @@ static bool resctrl_online_domains_exist(void) + * When called by the architecture code, all CPUs and resctrl domains must be + * offline. This ensures the limbo and overflow handlers are not scheduled to + * run, meaning the data structures they access can be freed by +- * resctrl_mon_resource_exit(). ++ * resctrl_l3_mon_resource_exit(). + * + * After resctrl_exit() returns, the architecture code should return an + * error from all resctrl_arch_ functions that can do this. +@@ -4517,5 +4535,6 @@ void resctrl_exit(void) + * it can be used to umount resctrl. + */ + +- resctrl_mon_resource_exit(); ++ resctrl_l3_mon_resource_exit(); ++ free_rmid_lru_list(); + } +diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c +index f378437113129a..d9771d224527d7 100644 +--- a/fs/smb/client/misc.c ++++ b/fs/smb/client/misc.c +@@ -957,6 +957,8 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, + int i, rc = 0; + char *data_end; + struct dfs_referral_level_3 *ref; ++ unsigned int path_consumed; ++ size_t search_name_len; + + if (rsp_size < sizeof(*rsp)) { + cifs_dbg(VFS | ONCE, +@@ -1004,6 +1006,7 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, + rc = -ENOMEM; + goto parse_DFS_referrals_exit; + } ++ search_name_len = strlen(searchName); + + /* collect necessary data from referrals */ + for (i = 0; i < *num_of_nodes; i++) { +@@ -1012,21 +1015,34 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, + struct dfs_info3_param *node = (*target_nodes)+i; + + node->flags = le32_to_cpu(rsp->DFSFlags); ++ path_consumed = le16_to_cpu(rsp->PathConsumed); + if (is_unicode) { +- __le16 *tmp = kmalloc(strlen(searchName)*2 + 2, +- GFP_KERNEL); +- if (tmp == NULL) { ++ size_t search_name_utf16_len = search_name_len * 2 + 2; ++ __le16 *tmp; ++ ++ if (path_consumed > search_name_utf16_len) { ++ rc = -EINVAL; ++ goto parse_DFS_referrals_exit; ++ } ++ ++ tmp = kmalloc(search_name_utf16_len, GFP_KERNEL); ++ if (!tmp) { + rc = -ENOMEM; + goto parse_DFS_referrals_exit; + } +- cifsConvertToUTF16((__le16 *) tmp, searchName, ++ cifsConvertToUTF16((__le16 *)tmp, searchName, + PATH_MAX, nls_codepage, remap); +- node->path_consumed = cifs_utf16_bytes(tmp, +- le16_to_cpu(rsp->PathConsumed), +- nls_codepage); ++ node->path_consumed = cifs_utf16_bytes(tmp, path_consumed, ++ nls_codepage); + kfree(tmp); +- } else +- node->path_consumed = le16_to_cpu(rsp->PathConsumed); ++ } else { ++ if (path_consumed > search_name_len) { ++ rc = -EINVAL; ++ goto parse_DFS_referrals_exit; ++ } ++ ++ node->path_consumed = path_consumed; ++ } + + node->server_type = le16_to_cpu(ref->ServerType); + node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags); +diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c +index cc1ff2461b0030..9bab3c57b3a4fd 100644 +--- a/fs/smb/client/smb2file.c ++++ b/fs/smb/client/smb2file.c +@@ -30,6 +30,19 @@ static struct smb2_symlink_err_rsp *symlink_data(const struct kvec *iov) + u8 *end = (u8 *)err + iov->iov_len; + u32 len; + ++ /* ++ * Per [MS-SMB2] section 2.2.2, a STATUS_STOPPED_ON_SYMLINK response has to ++ * carry a Symbolic Link Error Response, so ByteCount cannot be zero. Some ++ * servers (e.g. the macOS built-in SMB server) violate this and return an ++ * empty error response, with both ErrorContextCount and ByteCount set to ++ * zero, i.e. without the symlink target. Detect this and return -ENODATA ++ * so that callers can tell "server did not send the target" apart from a ++ * malformed response, and retrieve the target with FSCTL_GET_REPARSE_POINT ++ * instead. ++ */ ++ if (!err->ErrorContextCount && !le32_to_cpu(err->ByteCount)) ++ return ERR_PTR(-ENODATA); ++ + if (err->ErrorContextCount) { + struct smb2_error_context_rsp *p; + +@@ -200,6 +213,14 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 + rc = smb2_parse_symlink_response(oparms->cifs_sb, &err_iov, + oparms->path, + &data->symlink_target); ++ /* ++ * If smb2_parse_symlink_response returned -ENODATA then the ++ * symlink_target was not sent. Treat this as if the SMB2_open() ++ * failed with STATUS_IO_REPARSE_TAG_NOT_HANDLED status, which is ++ * indicated by the -EIO errno. ++ */ ++ if (rc == -ENODATA) ++ rc = -EIO; + if (!rc) { + memset(smb2_data, 0, sizeof(*smb2_data)); + oparms->create_options |= OPEN_REPARSE_POINT; +diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c +index e13bc8a97c4497..f1de84990aedb6 100644 +--- a/fs/smb/client/smb2inode.c ++++ b/fs/smb/client/smb2inode.c +@@ -896,9 +896,19 @@ static int parse_create_response(struct cifs_open_info_data *data, + rc = smb2_parse_symlink_response(cifs_sb, iov, + full_path, + &data->symlink_target); +- if (rc) ++ if (rc != 0 && rc != -ENODATA) + return rc; +- tag = IO_REPARSE_TAG_SYMLINK; ++ /* ++ * -ENODATA means that the response was parsed but did not contain ++ * the symlink target at all (see symlink_data()). Treat it like ++ * STATUS_IO_REPARSE_TAG_NOT_HANDLED, which does not contain it ++ * either: leave the tag unset and clear rc, so that the caller ++ * retrieves the target with SMB2_OP_GET_REPARSE. ++ */ ++ if (rc == -ENODATA) ++ rc = 0; ++ else ++ tag = IO_REPARSE_TAG_SYMLINK; + reparse_point = true; + break; + case STATUS_SUCCESS: +@@ -1091,7 +1101,14 @@ int smb2_query_path_info(const unsigned int xid, + rc = -EOPNOTSUPP; + } + +- if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK && !rc) { ++ /* ++ * If the symlink was already parsed in create response then it is needed to fix ++ * its type now (after the second call with OPEN_REPARSE_POINT which filled the ++ * data->fi.Attributes). If the symlink was not parsed in create response then ++ * the data->symlink_target was not filled yet and then the type will be fixed ++ * later after data->symlink_target is filled. ++ */ ++ if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK && !rc && data->symlink_target) { + bool directory = le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY; + rc = smb2_fix_symlink_target_type(&data->symlink_target, directory, cifs_sb); + } +diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c +index 786a7e963f1ff4..5bbe98dc0529b9 100644 +--- a/fs/smb/client/smb2ops.c ++++ b/fs/smb/client/smb2ops.c +@@ -3546,6 +3546,7 @@ static int smb3_simple_fallocate_range(unsigned int xid, + struct file_allocated_range_buffer in_data, *out_data = NULL, *tmp_data; + u32 out_data_len; + char *buf = NULL; ++ u64 range_start, range_len, range_end; + loff_t l; + int rc; + +@@ -3582,13 +3583,21 @@ static int smb3_simple_fallocate_range(unsigned int xid, + goto out; + } + +- if (off < le64_to_cpu(tmp_data->file_offset)) { ++ range_start = le64_to_cpu(tmp_data->file_offset); ++ range_len = le64_to_cpu(tmp_data->length); ++ if (check_add_overflow(range_start, range_len, &range_end) || ++ range_end > S64_MAX) { ++ rc = -EINVAL; ++ goto out; ++ } ++ ++ if (off < range_start) { + /* + * We are at a hole. Write until the end of the region + * or until the next allocated data, + * whichever comes next. + */ +- l = le64_to_cpu(tmp_data->file_offset) - off; ++ l = range_start - off; + if (len < l) + l = len; + rc = smb3_simple_fallocate_write_range(xid, tcon, +@@ -3605,11 +3614,13 @@ static int smb3_simple_fallocate_range(unsigned int xid, + * until the end of the data or the end of the region + * we are supposed to fallocate, whichever comes first. + */ +- l = le64_to_cpu(tmp_data->length); +- if (len < l) +- l = len; +- off += l; +- len -= l; ++ if (off < range_end) { ++ l = range_end - off; ++ if (len < l) ++ l = len; ++ off += l; ++ len -= l; ++ } + + tmp_data = &tmp_data[1]; + out_data_len -= sizeof(struct file_allocated_range_buffer); +diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c +index a019c4496ae433..ff0dbf3f8cbf49 100644 +--- a/fs/smb/server/oplock.c ++++ b/fs/smb/server/oplock.c +@@ -705,6 +705,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk) + out: + ksmbd_free_work_struct(work); + ksmbd_conn_r_count_dec(conn); ++ ksmbd_conn_put(conn); + } + + /** +@@ -740,7 +741,7 @@ static int smb2_oplock_break_noti(struct oplock_info *opinfo) + br_info->open_trunc = opinfo->open_trunc; + + work->request_buf = (char *)br_info; +- work->conn = conn; ++ work->conn = ksmbd_conn_get(conn); + work->sess = opinfo->sess; + + ksmbd_conn_r_count_inc(conn); +@@ -814,6 +815,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk) + out: + ksmbd_free_work_struct(work); + ksmbd_conn_r_count_dec(conn); ++ ksmbd_conn_put(conn); + } + + /** +@@ -853,7 +855,7 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo) + memcpy(br_info->lease_key, lease->lease_key, SMB2_LEASE_KEY_SIZE); + + work->request_buf = (char *)br_info; +- work->conn = conn; ++ work->conn = ksmbd_conn_get(conn); + work->sess = opinfo->sess; + + ksmbd_conn_r_count_inc(conn); +diff --git a/fs/smb/server/smb2misc.c b/fs/smb/server/smb2misc.c +index 67a2d7a793f6ed..b11d854d3fcfba 100644 +--- a/fs/smb/server/smb2misc.c ++++ b/fs/smb/server/smb2misc.c +@@ -400,6 +400,11 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work) + return 1; + } + ++ if (len < __SMB2_HEADER_STRUCTURE_SIZE + sizeof(__le16)) { ++ ksmbd_debug(SMB, "Message is too small for StructureSize2\n"); ++ return 1; ++ } ++ + if (smb2_req_struct_sizes[command] != pdu->StructureSize2) { + if (!(command == SMB2_OPLOCK_BREAK_HE && + (le16_to_cpu(pdu->StructureSize2) == OP_BREAK_STRUCT_SIZE_20 || +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index a69bc75c85ad0c..64a1cfc4e80990 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -1492,11 +1492,6 @@ static int ntlm_authenticate(struct ksmbd_work *work, + return -EPERM; + } + +- /* Check for previous session */ +- prev_id = le64_to_cpu(req->PreviousSessionId); +- if (prev_id && prev_id != sess->id) +- destroy_previous_session(conn, user, prev_id); +- + if (sess->state == SMB2_SESSION_VALID) { + /* + * Reuse session if anonymous try to connect +@@ -1534,6 +1529,10 @@ static int ntlm_authenticate(struct ksmbd_work *work, + } + } + ++ prev_id = le64_to_cpu(req->PreviousSessionId); ++ if (prev_id && prev_id != sess->id) ++ destroy_previous_session(conn, sess->user, prev_id); ++ + /* + * If session state is SMB2_SESSION_VALID, We can assume + * that it is reauthentication. And the user/password +diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c +index b09bc8d9389a2a..d3d0a22620f96d 100644 +--- a/fs/smb/server/smbacl.c ++++ b/fs/smb/server/smbacl.c +@@ -595,7 +595,8 @@ static void parse_dacl(struct mnt_idmap *idmap, + static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, + struct smb_ace *pndace, + struct smb_fattr *fattr, u16 *num_aces, +- u16 *size, u32 nt_aces_num) ++ u16 *size, u16 existing_nt_aces, ++ bool had_nt_aces) + { + struct posix_acl_entry *pace; + struct smb_sid *sid; +@@ -627,14 +628,14 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, + + gid = posix_acl_gid_translate(idmap, pace); + id_to_sid(gid, SIDUNIX_GROUP, sid); +- } else if (pace->e_tag == ACL_OTHER && !nt_aces_num) { ++ } else if (pace->e_tag == ACL_OTHER && !had_nt_aces) { + smb_copy_sid(sid, &sid_everyone); + } else { + kfree(sid); + continue; + } + ntace = pndace; +- for (j = 0; j < nt_aces_num; j++) { ++ for (j = 0; j < existing_nt_aces; j++) { + if (ntace->sid.sub_auth[ntace->sid.num_subauth - 1] == + sid->sub_auth[sid->num_subauth - 1]) + goto pass_same_sid; +@@ -649,6 +650,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, + ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, flags, + pace->e_perm, 0777); + if (check_add_overflow(*size, ace_sz, size)) { ++ *size -= ace_sz; + kfree(sid); + break; + } +@@ -663,6 +665,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, + ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, + 0x03, pace->e_perm, 0777); + if (check_add_overflow(*size, ace_sz, size)) { ++ *size -= ace_sz; + kfree(sid); + break; + } +@@ -676,7 +679,7 @@ pass_same_sid: + kfree(sid); + } + +- if (nt_aces_num) ++ if (had_nt_aces) + return; + + posix_default_acl: +@@ -708,6 +711,7 @@ posix_default_acl: + ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x0b, + pace->e_perm, 0777); + if (check_add_overflow(*size, ace_sz, size)) { ++ *size -= ace_sz; + kfree(sid); + break; + } +@@ -729,6 +733,7 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap, + { + struct smb_ace *ntace, *pndace; + u16 nt_num_aces = le16_to_cpu(nt_dacl->num_aces), num_aces = 0; ++ u16 copied_nt_aces; + unsigned short size = 0; + int i; + +@@ -738,24 +743,41 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap, + for (i = 0; i < nt_num_aces; i++) { + unsigned short nt_ace_size; + +- if (offsetof(struct smb_ace, access_req) > aces_size) ++ if (aces_size < offsetof(struct smb_ace, sid) + ++ CIFS_SID_BASE_SIZE) + break; + + nt_ace_size = le16_to_cpu(ntace->size); +- if (nt_ace_size > aces_size) ++ if (nt_ace_size > aces_size || ++ nt_ace_size < offsetof(struct smb_ace, sid) + ++ CIFS_SID_BASE_SIZE) + break; + ++ if (ntace->sid.num_subauth == 0 || ++ ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES || ++ nt_ace_size < offsetof(struct smb_ace, sid) + ++ CIFS_SID_BASE_SIZE + ++ sizeof(__le32) * ++ ntace->sid.num_subauth) ++ goto next_ace; ++ + memcpy((char *)pndace + size, ntace, nt_ace_size); +- if (check_add_overflow(size, nt_ace_size, &size)) ++ if (check_add_overflow(size, nt_ace_size, &size)) { ++ size -= nt_ace_size; + break; ++ } ++ num_aces++; ++ ++next_ace: + aces_size -= nt_ace_size; + ntace = (struct smb_ace *)((char *)ntace + nt_ace_size); +- num_aces++; + } + } + ++ copied_nt_aces = num_aces; + set_posix_acl_entries_dacl(idmap, pndace, fattr, +- &num_aces, &size, nt_num_aces); ++ &num_aces, &size, copied_nt_aces, ++ nt_num_aces != 0); + pndacl->num_aces = cpu_to_le16(num_aces); + pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size); + } +@@ -773,7 +795,7 @@ static void set_mode_dacl(struct mnt_idmap *idmap, + + if (fattr->cf_acls) { + set_posix_acl_entries_dacl(idmap, pndace, fattr, +- &num_aces, &size, num_aces); ++ &num_aces, &size, num_aces, false); + goto out; + } + +diff --git a/fs/super.c b/fs/super.c +index ce6e5b4ff3c5f6..8af2ee9395bccf 100644 +--- a/fs/super.c ++++ b/fs/super.c +@@ -1139,18 +1139,35 @@ void emergency_remount(void) + } + } + ++static inline bool get_active_super(struct super_block *sb) ++{ ++ bool active = false; ++ ++ if (super_lock_excl(sb)) { ++ active = atomic_inc_not_zero(&sb->s_active); ++ super_unlock_excl(sb); ++ } ++ return active; ++} ++ + static void do_thaw_all_callback(struct super_block *sb, void *unused) + { ++ if (!get_active_super(sb)) ++ return; ++ ++ /* fs_bdev_thaw() acquires s_umount so it must not be held here */ + if (IS_ENABLED(CONFIG_BLOCK)) + while (sb->s_bdev && !bdev_thaw(sb->s_bdev)) + pr_warn("Emergency Thaw on %pg\n", sb->s_bdev); +- thaw_super_locked(sb, FREEZE_HOLDER_USERSPACE, NULL); +- return; ++ ++ if (super_lock_excl(sb)) ++ thaw_super_locked(sb, FREEZE_HOLDER_USERSPACE, NULL); ++ deactivate_super(sb); + } + + static void do_thaw_all(struct work_struct *work) + { +- __iterate_supers(do_thaw_all_callback, NULL, SUPER_ITER_EXCL); ++ __iterate_supers(do_thaw_all_callback, NULL, SUPER_ITER_UNLOCKED); + kfree(work); + printk(KERN_WARNING "Emergency Thaw complete\n"); + } +@@ -1171,17 +1188,6 @@ void emergency_thaw_all(void) + } + } + +-static inline bool get_active_super(struct super_block *sb) +-{ +- bool active = false; +- +- if (super_lock_excl(sb)) { +- active = atomic_inc_not_zero(&sb->s_active); +- super_unlock_excl(sb); +- } +- return active; +-} +- + static const char *filesystems_freeze_ptr = "filesystems_freeze"; + + static void filesystems_freeze_callback(struct super_block *sb, void *freeze_all_ptr) +diff --git a/fs/xfs/scrub/cow_repair.c b/fs/xfs/scrub/cow_repair.c +index fc70fd5b975a3a..87627ab8943c13 100644 +--- a/fs/xfs/scrub/cow_repair.c ++++ b/fs/xfs/scrub/cow_repair.c +@@ -80,12 +80,6 @@ struct xrep_cow { + unsigned int next_bno; + }; + +-/* CoW staging extent. */ +-struct xrep_cow_extent { +- xfs_fsblock_t fsbno; +- xfs_extlen_t len; +-}; +- + /* + * Mark the part of the file range that corresponds to the given physical + * space. Caller must ensure that the physical range is within xc->irec. +@@ -401,22 +395,21 @@ out_rtg: + STATIC int + xrep_cow_alloc( + struct xfs_scrub *sc, +- xfs_extlen_t maxlen, +- struct xrep_cow_extent *repl) ++ struct xfs_bmbt_irec *del) + { + struct xfs_alloc_arg args = { + .tp = sc->tp, + .mp = sc->mp, + .oinfo = XFS_RMAP_OINFO_SKIP_UPDATE, + .minlen = 1, +- .maxlen = maxlen, ++ .maxlen = del->br_blockcount, + .prod = 1, + .resv = XFS_AG_RESV_NONE, + .datatype = XFS_ALLOC_USERDATA, + }; + int error; + +- error = xfs_trans_reserve_more(sc->tp, maxlen, 0); ++ error = xfs_trans_reserve_more(sc->tp, del->br_blockcount, 0); + if (error) + return error; + +@@ -429,8 +422,8 @@ xrep_cow_alloc( + + xfs_refcount_alloc_cow_extent(sc->tp, false, args.fsbno, args.len); + +- repl->fsbno = args.fsbno; +- repl->len = args.len; ++ del->br_startblock = args.fsbno; ++ del->br_blockcount = args.len; + return 0; + } + +@@ -441,10 +434,12 @@ xrep_cow_alloc( + STATIC int + xrep_cow_alloc_rt( + struct xfs_scrub *sc, +- xfs_extlen_t maxlen, +- struct xrep_cow_extent *repl) ++ struct xfs_bmbt_irec *del) + { +- xfs_rtxlen_t maxrtx = xfs_rtb_to_rtx(sc->mp, maxlen); ++ xfs_fsblock_t fsbno; ++ xfs_rtxlen_t maxrtx = ++ min(U32_MAX, xfs_blen_to_rtbxlen(sc->mp, del->br_blockcount)); ++ xfs_extlen_t len; + int error; + + error = xfs_trans_reserve_more(sc->tp, 0, maxrtx); +@@ -452,11 +447,14 @@ xrep_cow_alloc_rt( + return error; + + error = xfs_rtallocate_rtgs(sc->tp, NULLRTBLOCK, 1, maxrtx, 1, false, +- false, &repl->fsbno, &repl->len); ++ false, &fsbno, &len); + if (error) + return error; + +- xfs_refcount_alloc_cow_extent(sc->tp, true, repl->fsbno, repl->len); ++ xfs_refcount_alloc_cow_extent(sc->tp, true, fsbno, len); ++ ++ del->br_startblock = fsbno; ++ del->br_blockcount = len; + return 0; + } + +@@ -470,19 +468,19 @@ static inline int + xrep_cow_find_mapping( + struct xrep_cow *xc, + struct xfs_iext_cursor *icur, +- xfs_fileoff_t startoff, +- struct xfs_bmbt_irec *got) ++ xfs_fileoff_t badoff, ++ xfs_extlen_t badlen, ++ struct xfs_bmbt_irec *got, ++ struct xfs_bmbt_irec *rep) + { + struct xfs_inode *ip = xc->sc->ip; + struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_COW_FORK); + +- if (!xfs_iext_lookup_extent(ip, ifp, startoff, icur, got)) ++ if (!xfs_iext_lookup_extent(ip, ifp, badoff, icur, got)) + goto bad; ++ memcpy(rep, got, sizeof(*rep)); + +- if (got->br_startoff > startoff) +- goto bad; +- +- if (got->br_blockcount == 0) ++ if (got->br_startoff > badoff) + goto bad; + + if (isnullstartblock(got->br_startblock)) +@@ -491,6 +489,24 @@ xrep_cow_find_mapping( + if (xfs_bmap_is_written_extent(got)) + goto bad; + ++ if (got->br_startoff < badoff) { ++ const int64_t delta = badoff - got->br_startoff; ++ ++ rep->br_blockcount -= delta; ++ rep->br_startoff += delta; ++ rep->br_startblock += delta; ++ } ++ ++ if (got->br_startoff + got->br_blockcount > badoff + badlen) { ++ const int64_t delta = (got->br_startoff + got->br_blockcount) - ++ (badoff + badlen); ++ ++ rep->br_blockcount -= delta; ++ } ++ ++ if (got->br_blockcount == 0) ++ goto bad; ++ + return 0; + bad: + ASSERT(0); +@@ -501,46 +517,92 @@ bad: + #define REPLACE_RIGHT_SIDE (1U << 1) + + /* +- * Given a CoW fork mapping @got and a replacement mapping @repl, remap the +- * beginning of @got with the space described by @rep. ++ * Given a CoW fork mapping @got and a replacement mapping @rep, map the space ++ * described by @rep into the cow fork, pushing aside @got as necessary. @icur ++ * must point to iext tree leaf containing @got. + */ + static inline void + xrep_cow_replace_mapping( +- struct xfs_inode *ip, +- struct xfs_iext_cursor *icur, +- const struct xfs_bmbt_irec *got, +- const struct xrep_cow_extent *repl) ++ struct xfs_inode *ip, ++ struct xfs_iext_cursor *icur, ++ struct xfs_bmbt_irec *got, ++ struct xfs_bmbt_irec *rep) + { +- struct xfs_bmbt_irec new = *got; /* struct copy */ ++ struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_COW_FORK); ++ xfs_fileoff_t rep_endoff = ++ rep->br_startoff + rep->br_blockcount; ++ xfs_fileoff_t got_endoff = ++ got->br_startoff + got->br_blockcount; ++ uint32_t state = BMAP_COWFORK; + +- ASSERT(repl->len > 0); ++ ASSERT(rep->br_blockcount > 0); + ASSERT(!isnullstartblock(got->br_startblock)); ++ ASSERT(got->br_startoff <= rep->br_startoff); ++ ASSERT(got_endoff >= rep_endoff); ++ ++ trace_xrep_cow_replace_mapping(ip, got, rep); + +- trace_xrep_cow_replace_mapping(ip, got, repl->fsbno, repl->len); ++ if (got->br_startoff == rep->br_startoff) ++ state |= BMAP_LEFT_FILLING; ++ if (got_endoff == rep_endoff) ++ state |= BMAP_RIGHT_FILLING; + +- if (got->br_blockcount == repl->len) { ++ switch (state & (BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING)) { ++ case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING: + /* +- * The new extent is a complete replacement for the existing +- * extent. Update the COW fork record. ++ * Replacement matches the whole mapping, update the record. + */ +- new.br_startblock = repl->fsbno; +- xfs_iext_update_extent(ip, BMAP_COWFORK, icur, &new); +- return; +- } ++ xfs_iext_update_extent(ip, state, icur, rep); ++ break; ++ case BMAP_LEFT_FILLING: ++ /* ++ * Replace the first part of the mapping: Update the cursor ++ * position with the new mapping, then add a record with the ++ * tail of the old mapping. ++ */ ++ got->br_startoff = rep_endoff; ++ got->br_blockcount -= rep->br_blockcount; ++ got->br_startblock += rep->br_blockcount; ++ ++ xfs_iext_update_extent(ip, state, icur, rep); ++ xfs_iext_next(ifp, icur); ++ xfs_iext_insert(ip, icur, got, state); ++ break; ++ case BMAP_RIGHT_FILLING: ++ /* ++ * Replacing the last part of the mapping. Shorten the current ++ * mapping then add a record with the new mapping. ++ */ ++ got->br_blockcount -= rep->br_blockcount; + +- /* +- * The new extent can replace the beginning of the COW fork record. +- * Move the left side of @got upwards, then insert the new record. +- */ +- new.br_startoff += repl->len; +- new.br_startblock += repl->len; +- new.br_blockcount -= repl->len; +- xfs_iext_update_extent(ip, BMAP_COWFORK, icur, &new); +- +- new.br_startoff = got->br_startoff; +- new.br_startblock = repl->fsbno; +- new.br_blockcount = repl->len; +- xfs_iext_insert(ip, icur, &new, BMAP_COWFORK); ++ xfs_iext_update_extent(ip, state, icur, got); ++ xfs_iext_next(ifp, icur); ++ xfs_iext_insert(ip, icur, rep, state); ++ break; ++ case 0: ++ /* ++ * Replacing the middle of the extent. Shorten the current ++ * mapping, add a new record with the new mapping, and add a ++ * second new record with the tail of the old mapping. ++ */ ++ got->br_blockcount = rep->br_startoff - got->br_startoff; ++ ++ struct xfs_bmbt_irec new = { ++ .br_startoff = rep_endoff, ++ .br_blockcount = got_endoff - rep_endoff, ++ .br_state = got->br_state, ++ .br_startblock = got->br_startblock + ++ rep->br_blockcount + ++ got->br_blockcount, ++ }; ++ ++ xfs_iext_update_extent(ip, state, icur, got); ++ xfs_iext_next(ifp, icur); ++ xfs_iext_insert(ip, icur, rep, state); ++ xfs_iext_next(ifp, icur); ++ xfs_iext_insert(ip, icur, &new, state); ++ break; ++ } + } + + /* +@@ -554,33 +616,30 @@ xrep_cow_replace_range( + xfs_extlen_t *blockcount) + { + struct xfs_iext_cursor icur; +- struct xrep_cow_extent repl; +- struct xfs_bmbt_irec got; ++ struct xfs_bmbt_irec got, rep; + struct xfs_scrub *sc = xc->sc; +- xfs_fileoff_t nextoff; +- xfs_extlen_t alloc_len; ++ xfs_fsblock_t old_fsbno; + int error; + + /* +- * Put the existing CoW fork mapping in @got. If @got ends before +- * @rep, truncate @rep so we only replace one extent mapping at a time. ++ * Put the existing CoW fork mapping in @got, and put in @rep the ++ * contents of @got trimmed to @startoff/@blockcount. We only want ++ * to replace the bad region, and only one mapping at a time. + */ +- error = xrep_cow_find_mapping(xc, &icur, startoff, &got); ++ error = xrep_cow_find_mapping(xc, &icur, startoff, *blockcount, &got, ++ &rep); + if (error) + return error; +- nextoff = min(startoff + *blockcount, +- got.br_startoff + got.br_blockcount); ++ old_fsbno = rep.br_startblock; + + /* + * Allocate a replacement extent. If we don't fill all the blocks, + * shorten the quantity that will be deleted in this step. + */ +- alloc_len = min_t(xfs_fileoff_t, XFS_MAX_BMBT_EXTLEN, +- nextoff - startoff); + if (XFS_IS_REALTIME_INODE(sc->ip)) +- error = xrep_cow_alloc_rt(sc, alloc_len, &repl); ++ error = xrep_cow_alloc_rt(sc, &rep); + else +- error = xrep_cow_alloc(sc, alloc_len, &repl); ++ error = xrep_cow_alloc(sc, &rep); + if (error) + return error; + +@@ -588,7 +647,7 @@ xrep_cow_replace_range( + * Replace the old mapping with the new one, and commit the metadata + * changes made so far. + */ +- xrep_cow_replace_mapping(sc->ip, &icur, &got, &repl); ++ xrep_cow_replace_mapping(sc->ip, &icur, &got, &rep); + + xfs_inode_set_cowblocks_tag(sc->ip); + error = xfs_defer_finish(&sc->tp); +@@ -597,15 +656,15 @@ xrep_cow_replace_range( + + /* Note the old CoW staging extents; we'll reap them all later. */ + if (XFS_IS_REALTIME_INODE(sc->ip)) +- error = xrtb_bitmap_set(&xc->old_cowfork_rtblocks, +- got.br_startblock, repl.len); ++ error = xrtb_bitmap_set(&xc->old_cowfork_rtblocks, old_fsbno, ++ rep.br_blockcount); + else +- error = xfsb_bitmap_set(&xc->old_cowfork_fsblocks, +- got.br_startblock, repl.len); ++ error = xfsb_bitmap_set(&xc->old_cowfork_fsblocks, old_fsbno, ++ rep.br_blockcount); + if (error) + return error; + +- *blockcount = repl.len; ++ *blockcount = rep.br_blockcount; + return 0; + } + +diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h +index 286c5f5e054449..fab3ce323e4c78 100644 +--- a/fs/xfs/scrub/trace.h ++++ b/fs/xfs/scrub/trace.h +@@ -2672,9 +2672,9 @@ TRACE_EVENT(xrep_cow_mark_file_range, + ); + + TRACE_EVENT(xrep_cow_replace_mapping, +- TP_PROTO(struct xfs_inode *ip, const struct xfs_bmbt_irec *irec, +- xfs_fsblock_t new_startblock, xfs_extlen_t new_blockcount), +- TP_ARGS(ip, irec, new_startblock, new_blockcount), ++ TP_PROTO(struct xfs_inode *ip, const struct xfs_bmbt_irec *got, ++ const struct xfs_bmbt_irec *rep), ++ TP_ARGS(ip, got, rep), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(xfs_ino_t, ino) +@@ -2682,28 +2682,34 @@ TRACE_EVENT(xrep_cow_replace_mapping, + __field(xfs_fileoff_t, startoff) + __field(xfs_filblks_t, blockcount) + __field(xfs_exntst_t, state) ++ __field(xfs_fileoff_t, new_startoff) + __field(xfs_fsblock_t, new_startblock) + __field(xfs_extlen_t, new_blockcount) ++ __field(xfs_exntst_t, new_state) + ), + TP_fast_assign( + __entry->dev = ip->i_mount->m_super->s_dev; + __entry->ino = ip->i_ino; +- __entry->startoff = irec->br_startoff; +- __entry->startblock = irec->br_startblock; +- __entry->blockcount = irec->br_blockcount; +- __entry->state = irec->br_state; +- __entry->new_startblock = new_startblock; +- __entry->new_blockcount = new_blockcount; ++ __entry->startoff = got->br_startoff; ++ __entry->startblock = got->br_startblock; ++ __entry->blockcount = got->br_blockcount; ++ __entry->state = got->br_state; ++ __entry->new_startoff = rep->br_startoff; ++ __entry->new_startblock = rep->br_startblock; ++ __entry->new_blockcount = rep->br_blockcount; ++ __entry->new_state = rep->br_state; + ), +- TP_printk("dev %d:%d ino 0x%llx startoff 0x%llx startblock 0x%llx fsbcount 0x%llx state 0x%x new_startblock 0x%llx new_fsbcount 0x%x", ++ TP_printk("dev %d:%d ino 0x%llx startoff 0x%llx startblock 0x%llx fsbcount 0x%llx state 0x%x new_startoff 0x%llx new_startblock 0x%llx new_fsbcount 0x%x new_state 0x%x", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->ino, + __entry->startoff, + __entry->startblock, + __entry->blockcount, + __entry->state, ++ __entry->new_startoff, + __entry->new_startblock, +- __entry->new_blockcount) ++ __entry->new_blockcount, ++ __entry->new_state) + ); + + TRACE_EVENT(xrep_cow_free_staging, +diff --git a/include/drm/drm_buddy.h b/include/drm/drm_buddy.h +index c2e05a28125224..3054369bebffbb 100644 +--- a/include/drm/drm_buddy.h ++++ b/include/drm/drm_buddy.h +@@ -6,166 +6,13 @@ + #ifndef __DRM_BUDDY_H__ + #define __DRM_BUDDY_H__ + +-#include <linux/bitops.h> +-#include <linux/list.h> +-#include <linux/slab.h> +-#include <linux/sched.h> +-#include <linux/rbtree.h> ++#include <linux/gpu_buddy.h> + +-#include <drm/drm_print.h> ++struct drm_printer; + +-#define DRM_BUDDY_RANGE_ALLOCATION BIT(0) +-#define DRM_BUDDY_TOPDOWN_ALLOCATION BIT(1) +-#define DRM_BUDDY_CONTIGUOUS_ALLOCATION BIT(2) +-#define DRM_BUDDY_CLEAR_ALLOCATION BIT(3) +-#define DRM_BUDDY_CLEARED BIT(4) +-#define DRM_BUDDY_TRIM_DISABLE BIT(5) +- +-struct drm_buddy_block { +-#define DRM_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12) +-#define DRM_BUDDY_HEADER_STATE GENMASK_ULL(11, 10) +-#define DRM_BUDDY_ALLOCATED (1 << 10) +-#define DRM_BUDDY_FREE (2 << 10) +-#define DRM_BUDDY_SPLIT (3 << 10) +-#define DRM_BUDDY_HEADER_CLEAR GENMASK_ULL(9, 9) +-/* Free to be used, if needed in the future */ +-#define DRM_BUDDY_HEADER_UNUSED GENMASK_ULL(8, 6) +-#define DRM_BUDDY_HEADER_ORDER GENMASK_ULL(5, 0) +- u64 header; +- +- struct drm_buddy_block *left; +- struct drm_buddy_block *right; +- struct drm_buddy_block *parent; +- +- void *private; /* owned by creator */ +- +- /* +- * While the block is allocated by the user through drm_buddy_alloc*, +- * the user has ownership of the link, for example to maintain within +- * a list, if so desired. As soon as the block is freed with +- * drm_buddy_free* ownership is given back to the mm. +- */ +- union { +- struct rb_node rb; +- struct list_head link; +- }; +- +- struct list_head tmp_link; +-}; +- +-/* Order-zero must be at least SZ_4K */ +-#define DRM_BUDDY_MAX_ORDER (63 - 12) +- +-/* +- * Binary Buddy System. +- * +- * Locking should be handled by the user, a simple mutex around +- * drm_buddy_alloc* and drm_buddy_free* should suffice. +- */ +-struct drm_buddy { +- /* Maintain a free list for each order. */ +- struct rb_root **free_trees; +- +- /* +- * Maintain explicit binary tree(s) to track the allocation of the +- * address space. This gives us a simple way of finding a buddy block +- * and performing the potentially recursive merge step when freeing a +- * block. Nodes are either allocated or free, in which case they will +- * also exist on the respective free list. +- */ +- struct drm_buddy_block **roots; +- +- /* +- * Anything from here is public, and remains static for the lifetime of +- * the mm. Everything above is considered do-not-touch. +- */ +- unsigned int n_roots; +- unsigned int max_order; +- +- /* Must be at least SZ_4K */ +- u64 chunk_size; +- u64 size; +- u64 avail; +- u64 clear_avail; +-}; +- +-static inline u64 +-drm_buddy_block_offset(const struct drm_buddy_block *block) +-{ +- return block->header & DRM_BUDDY_HEADER_OFFSET; +-} +- +-static inline unsigned int +-drm_buddy_block_order(struct drm_buddy_block *block) +-{ +- return block->header & DRM_BUDDY_HEADER_ORDER; +-} +- +-static inline unsigned int +-drm_buddy_block_state(struct drm_buddy_block *block) +-{ +- return block->header & DRM_BUDDY_HEADER_STATE; +-} +- +-static inline bool +-drm_buddy_block_is_allocated(struct drm_buddy_block *block) +-{ +- return drm_buddy_block_state(block) == DRM_BUDDY_ALLOCATED; +-} +- +-static inline bool +-drm_buddy_block_is_clear(struct drm_buddy_block *block) +-{ +- return block->header & DRM_BUDDY_HEADER_CLEAR; +-} +- +-static inline bool +-drm_buddy_block_is_free(struct drm_buddy_block *block) +-{ +- return drm_buddy_block_state(block) == DRM_BUDDY_FREE; +-} +- +-static inline bool +-drm_buddy_block_is_split(struct drm_buddy_block *block) +-{ +- return drm_buddy_block_state(block) == DRM_BUDDY_SPLIT; +-} +- +-static inline u64 +-drm_buddy_block_size(struct drm_buddy *mm, +- struct drm_buddy_block *block) +-{ +- return mm->chunk_size << drm_buddy_block_order(block); +-} +- +-int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size); +- +-void drm_buddy_fini(struct drm_buddy *mm); +- +-struct drm_buddy_block * +-drm_get_buddy(struct drm_buddy_block *block); +- +-int drm_buddy_alloc_blocks(struct drm_buddy *mm, +- u64 start, u64 end, u64 size, +- u64 min_page_size, +- struct list_head *blocks, +- unsigned long flags); +- +-int drm_buddy_block_trim(struct drm_buddy *mm, +- u64 *start, +- u64 new_size, +- struct list_head *blocks); +- +-void drm_buddy_reset_clear(struct drm_buddy *mm, bool is_clear); +- +-void drm_buddy_free_block(struct drm_buddy *mm, struct drm_buddy_block *block); +- +-void drm_buddy_free_list(struct drm_buddy *mm, +- struct list_head *objects, +- unsigned int flags); +- +-void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p); +-void drm_buddy_block_print(struct drm_buddy *mm, +- struct drm_buddy_block *block, ++/* DRM-specific GPU Buddy Allocator print helpers */ ++void drm_buddy_print(struct gpu_buddy *mm, struct drm_printer *p); ++void drm_buddy_block_print(struct gpu_buddy *mm, ++ struct gpu_buddy_block *block, + struct drm_printer *p); + #endif +diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h +index 8f34f4b8183d83..d5e6f4b832a77e 100644 +--- a/include/drm/drm_connector.h ++++ b/include/drm/drm_connector.h +@@ -2502,13 +2502,13 @@ struct drm_tile_group { + struct kref refcount; + struct drm_device *dev; + int id; +- u8 group_data[8]; ++ u8 group_data[9]; + }; + + struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, +- const char topology[8]); ++ const char topology_id[9]); + struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, +- const char topology[8]); ++ const char topology_id[9]); + void drm_mode_put_tile_group(struct drm_device *dev, + struct drm_tile_group *tg); + +diff --git a/include/drm/drm_utils.h b/include/drm/drm_utils.h +index 6a46f755daba0d..7e077484c5bbfc 100644 +--- a/include/drm/drm_utils.h ++++ b/include/drm/drm_utils.h +@@ -19,6 +19,7 @@ int drm_get_panel_orientation_quirk(int width, int height); + struct drm_panel_backlight_quirk { + u16 min_brightness; + u32 brightness_mask; ++ bool force_pwm; + }; + + const struct drm_panel_backlight_quirk * +diff --git a/include/linux/arm_ffa.h b/include/linux/arm_ffa.h +index 81e603839c4a51..62d67dae8b7033 100644 +--- a/include/linux/arm_ffa.h ++++ b/include/linux/arm_ffa.h +@@ -445,7 +445,7 @@ ffa_mem_desc_offset(struct ffa_mem_region *buf, int count, u32 ffa_version) + if (!FFA_MEM_REGION_HAS_EP_MEM_OFFSET(ffa_version)) + offset += offsetof(struct ffa_mem_region, ep_mem_offset); + else +- offset += sizeof(struct ffa_mem_region); ++ offset += buf->ep_mem_offset; + + return offset; + } +diff --git a/include/linux/audit.h b/include/linux/audit.h +index b8d8029c6c480c..09d06684174bae 100644 +--- a/include/linux/audit.h ++++ b/include/linux/audit.h +@@ -16,7 +16,7 @@ + #include <uapi/linux/netfilter/nf_tables.h> + #include <uapi/linux/fanotify.h> + +-#define AUDIT_INO_UNSET ((unsigned long)-1) ++#define AUDIT_INO_UNSET ((u64)-1) + #define AUDIT_DEV_UNSET ((dev_t)-1) + + struct audit_sig_info { +@@ -125,8 +125,8 @@ enum audit_nfcfgop { + AUDIT_NFT_OP_INVALID, + }; + +-extern int __init audit_register_class(int class, unsigned *list); +-extern int audit_classify_syscall(int abi, unsigned syscall); ++extern int __init audit_register_class(int class, unsigned int *list); ++extern int audit_classify_syscall(int abi, unsigned int syscall); + extern int audit_classify_arch(int arch); + + /* audit_names->type values */ +diff --git a/include/linux/audit_arch.h b/include/linux/audit_arch.h +index 2b8153791e6a5d..a35069a6c15de2 100644 +--- a/include/linux/audit_arch.h ++++ b/include/linux/audit_arch.h +@@ -21,13 +21,13 @@ enum auditsc_class_t { + AUDITSC_NVALS /* count */ + }; + +-extern int audit_classify_compat_syscall(int abi, unsigned syscall); ++extern int audit_classify_compat_syscall(int abi, unsigned int syscall); + + /* only for compat system calls */ +-extern unsigned compat_write_class[]; +-extern unsigned compat_read_class[]; +-extern unsigned compat_dir_class[]; +-extern unsigned compat_chattr_class[]; +-extern unsigned compat_signal_class[]; ++extern unsigned int compat_write_class[]; ++extern unsigned int compat_read_class[]; ++extern unsigned int compat_dir_class[]; ++extern unsigned int compat_chattr_class[]; ++extern unsigned int compat_signal_class[]; + + #endif +diff --git a/include/linux/bootconfig.h b/include/linux/bootconfig.h +index 25df9260d206da..1f6e9c54a2a5ef 100644 +--- a/include/linux/bootconfig.h ++++ b/include/linux/bootconfig.h +@@ -265,6 +265,9 @@ static inline struct xbc_node * __init xbc_node_get_subkey(struct xbc_node *node + int __init xbc_node_compose_key_after(struct xbc_node *root, + struct xbc_node *node, char *buf, size_t size); + ++/* Render key/value pairs under @root as a flat cmdline string */ ++int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root); ++ + /** + * xbc_node_compose_key() - Compose full key string of the XBC node + * @node: An XBC node. +diff --git a/include/linux/cred.h b/include/linux/cred.h +index 89ae50ad2acea9..be2cd07b174c5e 100644 +--- a/include/linux/cred.h ++++ b/include/linux/cred.h +@@ -20,6 +20,8 @@ + struct cred; + struct inode; + ++extern struct task_struct init_task; ++ + /* + * COW Supplementary groups list + */ +@@ -156,6 +158,11 @@ extern struct cred *prepare_exec_creds(void); + extern int commit_creds(struct cred *); + extern void abort_creds(struct cred *); + extern struct cred *prepare_kernel_cred(struct task_struct *); ++static inline const struct cred *kernel_cred(void) ++{ ++ /* shut up sparse */ ++ return rcu_dereference_raw(init_task.cred); ++} + extern int set_security_override(struct cred *, u32); + extern int set_security_override_from_ctx(struct cred *, const char *); + extern int set_create_files_as(struct cred *, struct inode *); +@@ -180,6 +187,14 @@ static inline const struct cred *revert_creds(const struct cred *revert_cred) + return rcu_replace_pointer(current->cred, revert_cred, 1); + } + ++DEFINE_CLASS(override_creds, ++ const struct cred *, ++ revert_creds(_T), ++ override_creds(override_cred), const struct cred *override_cred) ++ ++#define scoped_with_kernel_creds() \ ++ scoped_class(override_creds, __UNIQUE_ID(cred), kernel_cred()) ++ + /** + * get_cred_many - Get references on a set of credentials + * @cred: The credentials to reference +diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h +index ae48d619c4e0ac..2f1c71f0cea76c 100644 +--- a/include/linux/firmware/xlnx-zynqmp.h ++++ b/include/linux/firmware/xlnx-zynqmp.h +@@ -164,6 +164,7 @@ enum pm_api_cb_id { + enum pm_api_id { + PM_API_FEATURES = 0, + PM_GET_API_VERSION = 1, ++ PM_GET_NODE_STATUS = 3, + PM_REGISTER_NOTIFIER = 5, + PM_FORCE_POWERDOWN = 8, + PM_REQUEST_WAKEUP = 10, +@@ -544,6 +545,18 @@ enum pm_gem_config_type { + GEM_CONFIG_FIXED = 2, + }; + ++/** ++ * enum pm_node_status - Device node status provided by xilpm fw ++ * @PM_NODE_UNUSED: Device is not used ++ * @PM_NODE_RUNNING: Device is power-on and out of reset ++ * @PM_NODE_HALT: Device is power-on but in the reset state ++ */ ++enum pm_node_status { ++ PM_NODE_UNUSED = 0, ++ PM_NODE_RUNNING = 1, ++ PM_NODE_HALT = 12, ++}; ++ + /** + * struct zynqmp_pm_query_data - PM query data + * @qid: query ID +diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h +index 516aba5b858b54..c009d4afe91857 100644 +--- a/include/linux/fscrypt.h ++++ b/include/linux/fscrypt.h +@@ -57,6 +57,9 @@ struct fscrypt_name { + /* Maximum value for the third parameter of fscrypt_operations.set_context(). */ + #define FSCRYPT_SET_CONTEXT_MAX_SIZE 40 + ++/* Maximum supported number of block devices per filesystem */ ++#define FSCRYPT_MAX_DEVICES 8 ++ + #ifdef CONFIG_FS_ENCRYPTION + + /* Crypto operations for filesystems */ +@@ -181,21 +184,20 @@ struct fscrypt_operations { + bool (*has_stable_inodes)(struct super_block *sb); + + /* +- * Return an array of pointers to the block devices to which the +- * filesystem may write encrypted file contents, NULL if the filesystem +- * only has a single such block device, or an ERR_PTR() on error. ++ * Retrieve the list of block devices to which the filesystem may write ++ * encrypted file contents. + * +- * On successful non-NULL return, *num_devs is set to the number of +- * devices in the returned array. The caller must free the returned +- * array using kfree(). ++ * This writes the block_device pointers to @devs and returns the count ++ * (between 1 and FSCRYPT_MAX_DEVICES inclusively). + * + * If the filesystem can use multiple block devices (other than block + * devices that aren't used for encrypted file contents, such as + * external journal devices), and wants to support inline encryption, + * then it must implement this function. Otherwise it's not needed. + */ +- struct block_device **(*get_devices)(struct super_block *sb, +- unsigned int *num_devs); ++ unsigned int (*get_devices)( ++ struct super_block *sb, ++ struct block_device *devs[FSCRYPT_MAX_DEVICES]); + }; + + int fscrypt_d_revalidate(struct inode *dir, const struct qstr *name, +diff --git a/include/linux/gpu_buddy.h b/include/linux/gpu_buddy.h +new file mode 100644 +index 00000000000000..07ac65db6d2e89 +--- /dev/null ++++ b/include/linux/gpu_buddy.h +@@ -0,0 +1,177 @@ ++/* SPDX-License-Identifier: MIT */ ++/* ++ * Copyright © 2021 Intel Corporation ++ */ ++ ++#ifndef __GPU_BUDDY_H__ ++#define __GPU_BUDDY_H__ ++ ++#include <linux/bitops.h> ++#include <linux/list.h> ++#include <linux/slab.h> ++#include <linux/sched.h> ++#include <linux/rbtree.h> ++ ++#define GPU_BUDDY_RANGE_ALLOCATION BIT(0) ++#define GPU_BUDDY_TOPDOWN_ALLOCATION BIT(1) ++#define GPU_BUDDY_CONTIGUOUS_ALLOCATION BIT(2) ++#define GPU_BUDDY_CLEAR_ALLOCATION BIT(3) ++#define GPU_BUDDY_CLEARED BIT(4) ++#define GPU_BUDDY_TRIM_DISABLE BIT(5) ++ ++enum gpu_buddy_free_tree { ++ GPU_BUDDY_CLEAR_TREE = 0, ++ GPU_BUDDY_DIRTY_TREE, ++ GPU_BUDDY_MAX_FREE_TREES, ++}; ++ ++#define for_each_free_tree(tree) \ ++ for ((tree) = 0; (tree) < GPU_BUDDY_MAX_FREE_TREES; (tree)++) ++ ++struct gpu_buddy_block { ++#define GPU_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12) ++#define GPU_BUDDY_HEADER_STATE GENMASK_ULL(11, 10) ++#define GPU_BUDDY_ALLOCATED (1 << 10) ++#define GPU_BUDDY_FREE (2 << 10) ++#define GPU_BUDDY_SPLIT (3 << 10) ++#define GPU_BUDDY_HEADER_CLEAR GENMASK_ULL(9, 9) ++/* Free to be used, if needed in the future */ ++#define GPU_BUDDY_HEADER_UNUSED GENMASK_ULL(8, 6) ++#define GPU_BUDDY_HEADER_ORDER GENMASK_ULL(5, 0) ++ u64 header; ++ ++ struct gpu_buddy_block *left; ++ struct gpu_buddy_block *right; ++ struct gpu_buddy_block *parent; ++ ++ void *private; /* owned by creator */ ++ ++ /* ++ * While the block is allocated by the user through gpu_buddy_alloc*, ++ * the user has ownership of the link, for example to maintain within ++ * a list, if so desired. As soon as the block is freed with ++ * gpu_buddy_free* ownership is given back to the mm. ++ */ ++ union { ++ struct rb_node rb; ++ struct list_head link; ++ }; ++ ++ struct list_head tmp_link; ++}; ++ ++/* Order-zero must be at least SZ_4K */ ++#define GPU_BUDDY_MAX_ORDER (63 - 12) ++ ++/* ++ * Binary Buddy System. ++ * ++ * Locking should be handled by the user, a simple mutex around ++ * gpu_buddy_alloc* and gpu_buddy_free* should suffice. ++ */ ++struct gpu_buddy { ++ /* Maintain a free list for each order. */ ++ struct rb_root **free_trees; ++ ++ /* ++ * Maintain explicit binary tree(s) to track the allocation of the ++ * address space. This gives us a simple way of finding a buddy block ++ * and performing the potentially recursive merge step when freeing a ++ * block. Nodes are either allocated or free, in which case they will ++ * also exist on the respective free list. ++ */ ++ struct gpu_buddy_block **roots; ++ ++ /* ++ * Anything from here is public, and remains static for the lifetime of ++ * the mm. Everything above is considered do-not-touch. ++ */ ++ unsigned int n_roots; ++ unsigned int max_order; ++ ++ /* Must be at least SZ_4K */ ++ u64 chunk_size; ++ u64 size; ++ u64 avail; ++ u64 clear_avail; ++}; ++ ++static inline u64 ++gpu_buddy_block_offset(const struct gpu_buddy_block *block) ++{ ++ return block->header & GPU_BUDDY_HEADER_OFFSET; ++} ++ ++static inline unsigned int ++gpu_buddy_block_order(struct gpu_buddy_block *block) ++{ ++ return block->header & GPU_BUDDY_HEADER_ORDER; ++} ++ ++static inline unsigned int ++gpu_buddy_block_state(struct gpu_buddy_block *block) ++{ ++ return block->header & GPU_BUDDY_HEADER_STATE; ++} ++ ++static inline bool ++gpu_buddy_block_is_allocated(struct gpu_buddy_block *block) ++{ ++ return gpu_buddy_block_state(block) == GPU_BUDDY_ALLOCATED; ++} ++ ++static inline bool ++gpu_buddy_block_is_clear(struct gpu_buddy_block *block) ++{ ++ return block->header & GPU_BUDDY_HEADER_CLEAR; ++} ++ ++static inline bool ++gpu_buddy_block_is_free(struct gpu_buddy_block *block) ++{ ++ return gpu_buddy_block_state(block) == GPU_BUDDY_FREE; ++} ++ ++static inline bool ++gpu_buddy_block_is_split(struct gpu_buddy_block *block) ++{ ++ return gpu_buddy_block_state(block) == GPU_BUDDY_SPLIT; ++} ++ ++static inline u64 ++gpu_buddy_block_size(struct gpu_buddy *mm, ++ struct gpu_buddy_block *block) ++{ ++ return mm->chunk_size << gpu_buddy_block_order(block); ++} ++ ++int gpu_buddy_init(struct gpu_buddy *mm, u64 size, u64 chunk_size); ++ ++void gpu_buddy_fini(struct gpu_buddy *mm); ++ ++struct gpu_buddy_block * ++gpu_get_buddy(struct gpu_buddy_block *block); ++ ++int gpu_buddy_alloc_blocks(struct gpu_buddy *mm, ++ u64 start, u64 end, u64 size, ++ u64 min_page_size, ++ struct list_head *blocks, ++ unsigned long flags); ++ ++int gpu_buddy_block_trim(struct gpu_buddy *mm, ++ u64 *start, ++ u64 new_size, ++ struct list_head *blocks); ++ ++void gpu_buddy_reset_clear(struct gpu_buddy *mm, bool is_clear); ++ ++void gpu_buddy_free_block(struct gpu_buddy *mm, struct gpu_buddy_block *block); ++ ++void gpu_buddy_free_list(struct gpu_buddy *mm, ++ struct list_head *objects, ++ unsigned int flags); ++ ++void gpu_buddy_print(struct gpu_buddy *mm); ++void gpu_buddy_block_print(struct gpu_buddy *mm, ++ struct gpu_buddy_block *block); ++#endif +diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h +index 1b0b36aa2a767a..61257b866fb24e 100644 +--- a/include/linux/mlx5/mlx5_ifc.h ++++ b/include/linux/mlx5/mlx5_ifc.h +@@ -12141,18 +12141,7 @@ struct mlx5_ifc_mcia_reg_bits { + + u8 reserved_at_60[0x20]; + +- u8 dword_0[0x20]; +- u8 dword_1[0x20]; +- u8 dword_2[0x20]; +- u8 dword_3[0x20]; +- u8 dword_4[0x20]; +- u8 dword_5[0x20]; +- u8 dword_6[0x20]; +- u8 dword_7[0x20]; +- u8 dword_8[0x20]; +- u8 dword_9[0x20]; +- u8 dword_10[0x20]; +- u8 dword_11[0x20]; ++ u8 dwords[0x400]; + }; + + struct mlx5_ifc_dcbx_param_bits { +diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h +index a7d92718b653f5..f9bed457fc5f1e 100644 +--- a/include/linux/resctrl.h ++++ b/include/linux/resctrl.h +@@ -169,7 +169,7 @@ struct mbm_cntr_cfg { + }; + + /** +- * struct rdt_mon_domain - group of CPUs sharing a resctrl monitor resource ++ * struct rdt_l3_mon_domain - group of CPUs sharing RDT_RESOURCE_L3 monitoring + * @hdr: common header for different domain types + * @ci_id: cache info id for this domain + * @rmid_busy_llc: bitmap of which limbo RMIDs are above threshold +@@ -183,7 +183,7 @@ struct mbm_cntr_cfg { + * @cntr_cfg: array of assignable counters' configuration (indexed + * by counter ID) + */ +-struct rdt_mon_domain { ++struct rdt_l3_mon_domain { + struct rdt_domain_hdr hdr; + unsigned int ci_id; + unsigned long *rmid_busy_llc; +@@ -355,10 +355,10 @@ struct resctrl_cpu_defaults { + }; + + struct resctrl_mon_config_info { +- struct rdt_resource *r; +- struct rdt_mon_domain *d; +- u32 evtid; +- u32 mon_config; ++ struct rdt_resource *r; ++ struct rdt_l3_mon_domain *d; ++ u32 evtid; ++ u32 mon_config; + }; + + /** +@@ -495,9 +495,9 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d, + u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d, + u32 closid, enum resctrl_conf_type type); + int resctrl_online_ctrl_domain(struct rdt_resource *r, struct rdt_ctrl_domain *d); +-int resctrl_online_mon_domain(struct rdt_resource *r, struct rdt_mon_domain *d); ++int resctrl_online_mon_domain(struct rdt_resource *r, struct rdt_l3_mon_domain *d); + void resctrl_offline_ctrl_domain(struct rdt_resource *r, struct rdt_ctrl_domain *d); +-void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_mon_domain *d); ++void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_l3_mon_domain *d); + void resctrl_online_cpu(unsigned int cpu); + void resctrl_offline_cpu(unsigned int cpu); + +@@ -526,7 +526,7 @@ void resctrl_offline_cpu(unsigned int cpu); + * Return: + * 0 on success, or -EIO, -EINVAL etc on error. + */ +-int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_mon_domain *d, ++int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + u32 closid, u32 rmid, enum resctrl_event_id eventid, + u64 *val, void *arch_mon_ctx); + +@@ -573,7 +573,7 @@ struct rdt_domain_hdr *resctrl_find_domain(struct list_head *h, int id, + * + * This can be called from any CPU. + */ +-void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_mon_domain *d, ++void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + u32 closid, u32 rmid, + enum resctrl_event_id eventid); + +@@ -586,7 +586,7 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_mon_domain *d, + * + * This can be called from any CPU. + */ +-void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_mon_domain *d); ++void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_l3_mon_domain *d); + + /** + * resctrl_arch_reset_all_ctrls() - Reset the control for each CLOSID to its +@@ -612,7 +612,7 @@ void resctrl_arch_reset_all_ctrls(struct rdt_resource *r); + * + * This can be called from any CPU. + */ +-void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_mon_domain *d, ++void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + enum resctrl_event_id evtid, u32 rmid, u32 closid, + u32 cntr_id, bool assign); + +@@ -635,7 +635,7 @@ void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_mon_domain *d, + * Return: + * 0 on success, or -EIO, -EINVAL etc on error. + */ +-int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_mon_domain *d, ++int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + u32 closid, u32 rmid, int cntr_id, + enum resctrl_event_id eventid, u64 *val); + +@@ -650,7 +650,7 @@ int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_mon_domain *d, + * + * This can be called from any CPU. + */ +-void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_mon_domain *d, ++void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d, + u32 closid, u32 rmid, int cntr_id, + enum resctrl_event_id eventid); + +diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h +index 6ab7924f33f59d..6729245aa15438 100644 +--- a/include/linux/seqlock.h ++++ b/include/linux/seqlock.h +@@ -1224,7 +1224,7 @@ struct ss_tmp { + spinlock_t *lock_irqsave; + }; + +-static inline void __scoped_seqlock_cleanup(struct ss_tmp *sst) ++static __always_inline void __scoped_seqlock_cleanup(struct ss_tmp *sst) + { + if (sst->lock) + spin_unlock(sst->lock); +@@ -1234,11 +1234,15 @@ static inline void __scoped_seqlock_cleanup(struct ss_tmp *sst) + + extern void __scoped_seqlock_invalid_target(void); + +-#if defined(CONFIG_CC_IS_GCC) && CONFIG_GCC_VERSION < 90000 ++#if (defined(CONFIG_CC_IS_GCC) && CONFIG_GCC_VERSION < 90000) || \ ++ defined(CONFIG_KASAN) || defined(CONFIG_UBSAN_ALIGNMENT) + /* + * For some reason some GCC-8 architectures (nios2, alpha) have trouble + * determining that the ss_done state is impossible in __scoped_seqlock_next() + * below. ++ * ++ * Similarly KASAN and UBSAN_ALIGNMENT are known to confuse compilers enough ++ * to break this. But we don't care about code quality for such builds anyway. + */ + static inline void __scoped_seqlock_bug(void) { } + #else +@@ -1249,7 +1253,7 @@ static inline void __scoped_seqlock_bug(void) { } + extern void __scoped_seqlock_bug(void); + #endif + +-static inline void ++static __always_inline void + __scoped_seqlock_next(struct ss_tmp *sst, seqlock_t *lock, enum ss_state target) + { + switch (sst->state) { +diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h +index 963bbe251e5210..de37069aba9089 100644 +--- a/include/linux/sunrpc/svcsock.h ++++ b/include/linux/sunrpc/svcsock.h +@@ -26,6 +26,9 @@ struct svc_sock { + void (*sk_odata)(struct sock *); + void (*sk_owspace)(struct sock *); + ++ /* For sends (protected by xpt_mutex) */ ++ struct bio_vec *sk_bvec; ++ + /* private TCP part */ + /* On-the-wire fragment header: */ + __be32 sk_marker; +diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h +index 152597750f55b3..656e0ad323af1b 100644 +--- a/include/linux/sunrpc/xdr.h ++++ b/include/linux/sunrpc/xdr.h +@@ -138,8 +138,23 @@ void xdr_terminate_string(const struct xdr_buf *, const u32); + size_t xdr_buf_pagecount(const struct xdr_buf *buf); + int xdr_alloc_bvec(struct xdr_buf *buf, gfp_t gfp); + void xdr_free_bvec(struct xdr_buf *buf); +-unsigned int xdr_buf_to_bvec(struct bio_vec *bvec, unsigned int bvec_size, +- const struct xdr_buf *xdr); ++int xdr_buf_to_bvec(struct bio_vec *bvec, unsigned int bvec_size, ++ const struct xdr_buf *xdr); ++int xdr_buf_to_sg(const struct xdr_buf *buf, unsigned int offset, ++ unsigned int len, struct scatterlist *sg, unsigned int nsg); ++int xdr_buf_to_sg_alloc(const struct xdr_buf *buf, unsigned int offset, ++ unsigned int len, struct scatterlist *sg_head, ++ unsigned int sg_head_nents, ++ struct scatterlist **sg_overflow, gfp_t gfp); ++ ++/* ++ * Inline scatterlist entries for xdr_buf_to_sg_alloc(). Sized to cover the ++ * head kvec, tail kvec, and a few page fragments without any heap allocation. ++ */ ++enum { ++ XDR_BUF_TO_SG_NENTS = 8, ++}; ++ + + static inline __be32 *xdr_encode_array(__be32 *p, const void *s, unsigned int len) + { +diff --git a/include/linux/virtio.h b/include/linux/virtio.h +index 132a474e59140a..d3f723b875a784 100644 +--- a/include/linux/virtio.h ++++ b/include/linux/virtio.h +@@ -41,13 +41,13 @@ struct virtqueue { + void *priv; + }; + +-struct vduse_iova_domain; ++struct vduse_vq_group; + + union virtio_map { + /* Device that performs DMA */ + struct device *dma_dev; +- /* VDUSE specific mapping data */ +- struct vduse_iova_domain *iova_domain; ++ /* VDUSE specific virtqueue group for doing map */ ++ struct vduse_vq_group *group; + }; + + int virtqueue_add_outbuf(struct virtqueue *vq, +diff --git a/include/linux/vtime.h b/include/linux/vtime.h +index 29dd5b91dd7d66..3fc04b849e4e30 100644 +--- a/include/linux/vtime.h ++++ b/include/linux/vtime.h +@@ -32,11 +32,17 @@ extern void vtime_account_irq(struct task_struct *tsk, unsigned int offset); + extern void vtime_account_softirq(struct task_struct *tsk); + extern void vtime_account_hardirq(struct task_struct *tsk); + extern void vtime_flush(struct task_struct *tsk); ++extern void vtime_reset(void); ++extern void vtime_dyntick_start(void); ++extern void vtime_dyntick_stop(void); + #else /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ + static inline void vtime_account_irq(struct task_struct *tsk, unsigned int offset) { } + static inline void vtime_account_softirq(struct task_struct *tsk) { } + static inline void vtime_account_hardirq(struct task_struct *tsk) { } + static inline void vtime_flush(struct task_struct *tsk) { } ++static inline void vtime_reset(void) { } ++static inline void vtime_dyntick_start(void) { } ++static inline void vtime_dyntick_stop(void) { } + #endif + + /* +diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h +index f26c323e9c9630..54a2d9620ed5b5 100644 +--- a/include/media/v4l2-async.h ++++ b/include/media/v4l2-async.h +@@ -333,8 +333,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module); + * An error is returned if the module is no longer loaded on any attempts + * to register it. + */ ++#define v4l2_async_register_subdev_sensor(sd) \ ++ __v4l2_async_register_subdev_sensor(sd, THIS_MODULE) + int __must_check +-v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd); ++__v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd, struct module *module); + + /** + * v4l2_async_unregister_subdev - unregisters a sub-device to the asynchronous +diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h +index 9b02aeba41089c..b86258b98bd212 100644 +--- a/include/media/videobuf2-core.h ++++ b/include/media/videobuf2-core.h +@@ -1106,8 +1106,8 @@ __poll_t vb2_core_poll(struct vb2_queue *q, struct file *file, + * @ppos: file handle position tracking pointer + * @nonblock: mode selector (1 means blocking calls, 0 means nonblocking) + */ +-size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, +- loff_t *ppos, int nonblock); ++ssize_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, ++ loff_t *ppos, int nonblock); + /**