diff options
author | Mike Pagano <mpagano@gentoo.org> | 2024-08-11 09:28:11 -0400 |
---|---|---|
committer | Mike Pagano <mpagano@gentoo.org> | 2024-08-11 09:28:11 -0400 |
commit | 3ac9503720269b097e58e40e291898b738067785 (patch) | |
tree | 24d39a2d191a975dcc46b38928712941cef3670f | |
parent | libbpf: workaround -Wmaybe-uninitialized false positive (diff) | |
download | linux-patches-3ac9503720269b097e58e40e291898b738067785.tar.gz linux-patches-3ac9503720269b097e58e40e291898b738067785.tar.bz2 linux-patches-3ac9503720269b097e58e40e291898b738067785.zip |
Linux patch 6.6.456.6-52
Signed-off-by: Mike Pagano <mpagano@gentoo.org>
-rw-r--r-- | 0000_README | 4 | ||||
-rw-r--r-- | 1044_linux-6.6.45.patch | 5821 |
2 files changed, 5825 insertions, 0 deletions
diff --git a/0000_README b/0000_README index a6c696ed..674bb8f3 100644 --- a/0000_README +++ b/0000_README @@ -219,6 +219,10 @@ Patch: 1043_linux-6.6.44.patch From: https://www.kernel.org Desc: Linux 6.6.44 +Patch: 1044_linux-6.6.45.patch +From: https://www.kernel.org +Desc: Linux 6.6.45 + 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/1044_linux-6.6.45.patch b/1044_linux-6.6.45.patch new file mode 100644 index 00000000..95da970d --- /dev/null +++ b/1044_linux-6.6.45.patch @@ -0,0 +1,5821 @@ +diff --git a/Makefile b/Makefile +index 2e5d92ce2774d..0bd4bee2128b4 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 6 +-SUBLEVEL = 44 ++SUBLEVEL = 45 + EXTRAVERSION = + NAME = Hurr durr I'ma ninja sloth + +diff --git a/arch/arm/kernel/perf_callchain.c b/arch/arm/kernel/perf_callchain.c +index 7147edbe56c67..1d230ac9d0eb5 100644 +--- a/arch/arm/kernel/perf_callchain.c ++++ b/arch/arm/kernel/perf_callchain.c +@@ -85,8 +85,7 @@ static bool + callchain_trace(void *data, unsigned long pc) + { + struct perf_callchain_entry_ctx *entry = data; +- perf_callchain_store(entry, pc); +- return true; ++ return perf_callchain_store(entry, pc) == 0; + } + + void +diff --git a/arch/arm64/boot/dts/qcom/ipq8074.dtsi b/arch/arm64/boot/dts/qcom/ipq8074.dtsi +index 5effd8180cc41..e5993a365870c 100644 +--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi ++++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi +@@ -641,6 +641,7 @@ dwc_0: usb@8a00000 { + interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>; + phys = <&qusb_phy_0>, <&usb0_ssphy>; + phy-names = "usb2-phy", "usb3-phy"; ++ snps,parkmode-disable-ss-quirk; + snps,is-utmi-l1-suspend; + snps,hird-threshold = /bits/ 8 <0x0>; + snps,dis_u2_susphy_quirk; +@@ -683,6 +684,7 @@ dwc_1: usb@8c00000 { + interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>; + phys = <&qusb_phy_1>, <&usb1_ssphy>; + phy-names = "usb2-phy", "usb3-phy"; ++ snps,parkmode-disable-ss-quirk; + snps,is-utmi-l1-suspend; + snps,hird-threshold = /bits/ 8 <0x0>; + snps,dis_u2_susphy_quirk; +diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi +index 9c072ce197358..7fcc15b6946ae 100644 +--- a/arch/arm64/boot/dts/qcom/msm8998.dtsi ++++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi +@@ -2159,7 +2159,8 @@ usb3_dwc3: usb@a800000 { + interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; +- phys = <&qusb2phy>, <&usb1_ssphy>; ++ snps,parkmode-disable-ss-quirk; ++ phys = <&qusb2phy>, <&usb3phy>; + phy-names = "usb2-phy", "usb3-phy"; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; +@@ -2168,33 +2169,26 @@ usb3_dwc3: usb@a800000 { + + usb3phy: phy@c010000 { + compatible = "qcom,msm8998-qmp-usb3-phy"; +- reg = <0x0c010000 0x18c>; +- status = "disabled"; +- #address-cells = <1>; +- #size-cells = <1>; +- ranges; ++ reg = <0x0c010000 0x1000>; + + clocks = <&gcc GCC_USB3_PHY_AUX_CLK>, ++ <&gcc GCC_USB3_CLKREF_CLK>, + <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, +- <&gcc GCC_USB3_CLKREF_CLK>; +- clock-names = "aux", "cfg_ahb", "ref"; ++ <&gcc GCC_USB3_PHY_PIPE_CLK>; ++ clock-names = "aux", ++ "ref", ++ "cfg_ahb", ++ "pipe"; ++ clock-output-names = "usb3_phy_pipe_clk_src"; ++ #clock-cells = <0>; ++ #phy-cells = <0>; + + resets = <&gcc GCC_USB3_PHY_BCR>, + <&gcc GCC_USB3PHY_PHY_BCR>; +- reset-names = "phy", "common"; ++ reset-names = "phy", ++ "phy_phy"; + +- usb1_ssphy: phy@c010200 { +- reg = <0xc010200 0x128>, +- <0xc010400 0x200>, +- <0xc010c00 0x20c>, +- <0xc010600 0x128>, +- <0xc010800 0x200>; +- #phy-cells = <0>; +- #clock-cells = <0>; +- clocks = <&gcc GCC_USB3_PHY_PIPE_CLK>; +- clock-names = "pipe0"; +- clock-output-names = "usb3_phy_pipe_clk_src"; +- }; ++ status = "disabled"; + }; + + qusb2phy: phy@c012000 { +diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi +index f7c528ecb224b..68b1c017a9fd5 100644 +--- a/arch/arm64/boot/dts/qcom/sc7180.dtsi ++++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi +@@ -15,6 +15,7 @@ + #include <dt-bindings/interconnect/qcom,osm-l3.h> + #include <dt-bindings/interconnect/qcom,sc7180.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> ++#include <dt-bindings/phy/phy-qcom-qmp.h> + #include <dt-bindings/phy/phy-qcom-qusb2.h> + #include <dt-bindings/power/qcom-rpmpd.h> + #include <dt-bindings/reset/qcom,sdm845-aoss.h> +@@ -2795,49 +2796,28 @@ usb_1_hsphy: phy@88e3000 { + nvmem-cells = <&qusb2p_hstx_trim>; + }; + +- usb_1_qmpphy: phy-wrapper@88e9000 { ++ usb_1_qmpphy: phy@88e8000 { + compatible = "qcom,sc7180-qmp-usb3-dp-phy"; +- reg = <0 0x088e9000 0 0x18c>, +- <0 0x088e8000 0 0x3c>, +- <0 0x088ea000 0 0x18c>; ++ reg = <0 0x088e8000 0 0x3000>; + status = "disabled"; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; + + clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>, +- <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_CLK>, +- <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>; +- clock-names = "aux", "cfg_ahb", "ref", "com_aux"; ++ <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, ++ <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, ++ <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; ++ clock-names = "aux", ++ "ref", ++ "com_aux", ++ "usb3_pipe", ++ "cfg_ahb"; + + resets = <&gcc GCC_USB3_PHY_PRIM_BCR>, + <&gcc GCC_USB3_DP_PHY_PRIM_BCR>; + reset-names = "phy", "common"; + +- usb_1_ssphy: usb3-phy@88e9200 { +- reg = <0 0x088e9200 0 0x128>, +- <0 0x088e9400 0 0x200>, +- <0 0x088e9c00 0 0x218>, +- <0 0x088e9600 0 0x128>, +- <0 0x088e9800 0 0x200>, +- <0 0x088e9a00 0 0x18>; +- #clock-cells = <0>; +- #phy-cells = <0>; +- clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; +- clock-names = "pipe0"; +- clock-output-names = "usb3_phy_pipe_clk_src"; +- }; +- +- dp_phy: dp-phy@88ea200 { +- reg = <0 0x088ea200 0 0x200>, +- <0 0x088ea400 0 0x200>, +- <0 0x088eaa00 0 0x200>, +- <0 0x088ea600 0 0x200>, +- <0 0x088ea800 0 0x200>; +- #clock-cells = <1>; +- #phy-cells = <0>; +- }; ++ #clock-cells = <1>; ++ #phy-cells = <1>; + }; + + pmu@90b6300 { +@@ -3001,7 +2981,8 @@ usb_1_dwc3: usb@a600000 { + iommus = <&apps_smmu 0x540 0>; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; +- phys = <&usb_1_hsphy>, <&usb_1_ssphy>; ++ snps,parkmode-disable-ss-quirk; ++ phys = <&usb_1_hsphy>, <&usb_1_qmpphy QMP_USB43DP_USB3_PHY>; + phy-names = "usb2-phy", "usb3-phy"; + maximum-speed = "super-speed"; + }; +@@ -3307,8 +3288,9 @@ mdss_dp: displayport-controller@ae90000 { + "ctrl_link_iface", "stream_pixel"; + assigned-clocks = <&dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>; +- assigned-clock-parents = <&dp_phy 0>, <&dp_phy 1>; +- phys = <&dp_phy>; ++ assigned-clock-parents = <&usb_1_qmpphy QMP_USB43DP_DP_LINK_CLK>, ++ <&usb_1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>; ++ phys = <&usb_1_qmpphy QMP_USB43DP_DP_PHY>; + phy-names = "dp"; + + operating-points-v2 = <&dp_opp_table>; +@@ -3365,8 +3347,8 @@ dispcc: clock-controller@af00000 { + <&gcc GCC_DISP_GPLL0_CLK_SRC>, + <&mdss_dsi0_phy 0>, + <&mdss_dsi0_phy 1>, +- <&dp_phy 0>, +- <&dp_phy 1>; ++ <&usb_1_qmpphy QMP_USB43DP_DP_LINK_CLK>, ++ <&usb_1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>; + clock-names = "bi_tcxo", + "gcc_disp_gpll0_clk_src", + "dsi0_phy_pll_out_byteclk", +diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi +index b75de7caaa7e5..149c7962f2cbb 100644 +--- a/arch/arm64/boot/dts/qcom/sc7280.dtsi ++++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi +@@ -18,6 +18,7 @@ + #include <dt-bindings/interconnect/qcom,sc7280.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/mailbox/qcom-ipcc.h> ++#include <dt-bindings/phy/phy-qcom-qmp.h> + #include <dt-bindings/power/qcom-rpmpd.h> + #include <dt-bindings/reset/qcom,sdm845-aoss.h> + #include <dt-bindings/reset/qcom,sdm845-pdc.h> +@@ -858,7 +859,7 @@ gcc: clock-controller@100000 { + <&rpmhcc RPMH_CXO_CLK_A>, <&sleep_clk>, + <0>, <&pcie1_lane>, + <0>, <0>, <0>, +- <&usb_1_ssphy>; ++ <&usb_1_qmpphy QMP_USB43DP_USB3_PIPE_CLK>; + clock-names = "bi_tcxo", "bi_tcxo_ao", "sleep_clk", + "pcie_0_pipe_clk", "pcie_1_pipe_clk", + "ufs_phy_rx_symbol_0_clk", "ufs_phy_rx_symbol_1_clk", +@@ -3351,49 +3352,26 @@ usb_2_hsphy: phy@88e4000 { + resets = <&gcc GCC_QUSB2PHY_SEC_BCR>; + }; + +- usb_1_qmpphy: phy-wrapper@88e9000 { +- compatible = "qcom,sc7280-qmp-usb3-dp-phy", +- "qcom,sm8250-qmp-usb3-dp-phy"; +- reg = <0 0x088e9000 0 0x200>, +- <0 0x088e8000 0 0x40>, +- <0 0x088ea000 0 0x200>; ++ usb_1_qmpphy: phy@88e8000 { ++ compatible = "qcom,sc7280-qmp-usb3-dp-phy"; ++ reg = <0 0x088e8000 0 0x3000>; + status = "disabled"; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; + + clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>, + <&rpmhcc RPMH_CXO_CLK>, +- <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>; +- clock-names = "aux", "ref_clk_src", "com_aux"; ++ <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, ++ <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; ++ clock-names = "aux", ++ "ref", ++ "com_aux", ++ "usb3_pipe"; + + resets = <&gcc GCC_USB3_DP_PHY_PRIM_BCR>, + <&gcc GCC_USB3_PHY_PRIM_BCR>; + reset-names = "phy", "common"; + +- usb_1_ssphy: usb3-phy@88e9200 { +- reg = <0 0x088e9200 0 0x200>, +- <0 0x088e9400 0 0x200>, +- <0 0x088e9c00 0 0x400>, +- <0 0x088e9600 0 0x200>, +- <0 0x088e9800 0 0x200>, +- <0 0x088e9a00 0 0x100>; +- #clock-cells = <0>; +- #phy-cells = <0>; +- clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; +- clock-names = "pipe0"; +- clock-output-names = "usb3_phy_pipe_clk_src"; +- }; +- +- dp_phy: dp-phy@88ea200 { +- reg = <0 0x088ea200 0 0x200>, +- <0 0x088ea400 0 0x200>, +- <0 0x088eaa00 0 0x200>, +- <0 0x088ea600 0 0x200>, +- <0 0x088ea800 0 0x200>; +- #phy-cells = <0>; +- #clock-cells = <1>; +- }; ++ #clock-cells = <1>; ++ #phy-cells = <1>; + }; + + usb_2: usb@8cf8800 { +@@ -3702,7 +3680,8 @@ usb_1_dwc3: usb@a600000 { + iommus = <&apps_smmu 0xe0 0x0>; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; +- phys = <&usb_1_hsphy>, <&usb_1_ssphy>; ++ snps,parkmode-disable-ss-quirk; ++ phys = <&usb_1_hsphy>, <&usb_1_qmpphy QMP_USB43DP_USB3_PHY>; + phy-names = "usb2-phy", "usb3-phy"; + maximum-speed = "super-speed"; + }; +@@ -3807,8 +3786,8 @@ dispcc: clock-controller@af00000 { + <&gcc GCC_DISP_GPLL0_CLK_SRC>, + <&mdss_dsi_phy 0>, + <&mdss_dsi_phy 1>, +- <&dp_phy 0>, +- <&dp_phy 1>, ++ <&usb_1_qmpphy QMP_USB43DP_DP_LINK_CLK>, ++ <&usb_1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>, + <&mdss_edp_phy 0>, + <&mdss_edp_phy 1>; + clock-names = "bi_tcxo", +@@ -4144,8 +4123,9 @@ mdss_dp: displayport-controller@ae90000 { + "stream_pixel"; + assigned-clocks = <&dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>; +- assigned-clock-parents = <&dp_phy 0>, <&dp_phy 1>; +- phys = <&dp_phy>; ++ assigned-clock-parents = <&usb_1_qmpphy QMP_USB43DP_DP_LINK_CLK>, ++ <&usb_1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>; ++ phys = <&usb_1_qmpphy QMP_USB43DP_DP_PHY>; + phy-names = "dp"; + + operating-points-v2 = <&dp_opp_table>; +diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi +index 9d9b378c07e14..dcdc8a0cd1819 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi +@@ -18,6 +18,7 @@ + #include <dt-bindings/interconnect/qcom,osm-l3.h> + #include <dt-bindings/interconnect/qcom,sdm845.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> ++#include <dt-bindings/phy/phy-qcom-qmp.h> + #include <dt-bindings/phy/phy-qcom-qusb2.h> + #include <dt-bindings/power/qcom-rpmpd.h> + #include <dt-bindings/reset/qcom,sdm845-aoss.h> +@@ -3983,80 +3984,54 @@ usb_2_hsphy: phy@88e3000 { + nvmem-cells = <&qusb2s_hstx_trim>; + }; + +- usb_1_qmpphy: phy@88e9000 { ++ usb_1_qmpphy: phy@88e8000 { + compatible = "qcom,sdm845-qmp-usb3-dp-phy"; +- reg = <0 0x088e9000 0 0x18c>, +- <0 0x088e8000 0 0x38>, +- <0 0x088ea000 0 0x40>; ++ reg = <0 0x088e8000 0 0x3000>; + status = "disabled"; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; + + clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>, +- <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_CLK>, +- <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>; +- clock-names = "aux", "cfg_ahb", "ref", "com_aux"; ++ <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, ++ <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, ++ <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; ++ clock-names = "aux", ++ "ref", ++ "com_aux", ++ "usb3_pipe", ++ "cfg_ahb"; + + resets = <&gcc GCC_USB3_PHY_PRIM_BCR>, + <&gcc GCC_USB3_DP_PHY_PRIM_BCR>; + reset-names = "phy", "common"; + +- usb_1_ssphy: usb3-phy@88e9200 { +- reg = <0 0x088e9200 0 0x128>, +- <0 0x088e9400 0 0x200>, +- <0 0x088e9c00 0 0x218>, +- <0 0x088e9600 0 0x128>, +- <0 0x088e9800 0 0x200>, +- <0 0x088e9a00 0 0x100>; +- #clock-cells = <0>; +- #phy-cells = <0>; +- clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; +- clock-names = "pipe0"; +- clock-output-names = "usb3_phy_pipe_clk_src"; +- }; +- +- dp_phy: dp-phy@88ea200 { +- reg = <0 0x088ea200 0 0x200>, +- <0 0x088ea400 0 0x200>, +- <0 0x088eaa00 0 0x200>, +- <0 0x088ea600 0 0x200>, +- <0 0x088ea800 0 0x200>; +- #clock-cells = <1>; +- #phy-cells = <0>; +- }; ++ #clock-cells = <1>; ++ #phy-cells = <1>; + }; + + usb_2_qmpphy: phy@88eb000 { + compatible = "qcom,sdm845-qmp-usb3-uni-phy"; +- reg = <0 0x088eb000 0 0x18c>; +- status = "disabled"; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; ++ reg = <0 0x088eb000 0 0x1000>; + + clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>, + <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&gcc GCC_USB3_SEC_CLKREF_CLK>, +- <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>; +- clock-names = "aux", "cfg_ahb", "ref", "com_aux"; ++ <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>, ++ <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; ++ clock-names = "aux", ++ "cfg_ahb", ++ "ref", ++ "com_aux", ++ "pipe"; ++ clock-output-names = "usb3_uni_phy_pipe_clk_src"; ++ #clock-cells = <0>; ++ #phy-cells = <0>; + +- resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>, +- <&gcc GCC_USB3_PHY_SEC_BCR>; +- reset-names = "phy", "common"; ++ resets = <&gcc GCC_USB3_PHY_SEC_BCR>, ++ <&gcc GCC_USB3PHY_PHY_SEC_BCR>; ++ reset-names = "phy", ++ "phy_phy"; + +- usb_2_ssphy: phy@88eb200 { +- reg = <0 0x088eb200 0 0x128>, +- <0 0x088eb400 0 0x1fc>, +- <0 0x088eb800 0 0x218>, +- <0 0x088eb600 0 0x70>; +- #clock-cells = <0>; +- #phy-cells = <0>; +- clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; +- clock-names = "pipe0"; +- clock-output-names = "usb3_uni_phy_pipe_clk_src"; +- }; ++ status = "disabled"; + }; + + usb_1: usb@a6f8800 { +@@ -4105,7 +4080,8 @@ usb_1_dwc3: usb@a600000 { + iommus = <&apps_smmu 0x740 0>; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; +- phys = <&usb_1_hsphy>, <&usb_1_ssphy>; ++ snps,parkmode-disable-ss-quirk; ++ phys = <&usb_1_hsphy>, <&usb_1_qmpphy QMP_USB43DP_USB3_PHY>; + phy-names = "usb2-phy", "usb3-phy"; + }; + }; +@@ -4156,7 +4132,8 @@ usb_2_dwc3: usb@a800000 { + iommus = <&apps_smmu 0x760 0>; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; +- phys = <&usb_2_hsphy>, <&usb_2_ssphy>; ++ snps,parkmode-disable-ss-quirk; ++ phys = <&usb_2_hsphy>, <&usb_2_qmpphy>; + phy-names = "usb2-phy", "usb3-phy"; + }; + }; +@@ -4573,8 +4550,9 @@ mdss_dp: displayport-controller@ae90000 { + "ctrl_link_iface", "stream_pixel"; + assigned-clocks = <&dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>; +- assigned-clock-parents = <&dp_phy 0>, <&dp_phy 1>; +- phys = <&dp_phy>; ++ assigned-clock-parents = <&usb_1_qmpphy QMP_USB43DP_DP_LINK_CLK>, ++ <&usb_1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>; ++ phys = <&usb_1_qmpphy QMP_USB43DP_DP_PHY>; + phy-names = "dp"; + + operating-points-v2 = <&dp_opp_table>; +@@ -4912,8 +4890,8 @@ dispcc: clock-controller@af00000 { + <&mdss_dsi0_phy 1>, + <&mdss_dsi1_phy 0>, + <&mdss_dsi1_phy 1>, +- <&dp_phy 0>, +- <&dp_phy 1>; ++ <&usb_1_qmpphy QMP_USB43DP_DP_LINK_CLK>, ++ <&usb_1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>; + clock-names = "bi_tcxo", + "gcc_disp_gpll0_clk_src", + "gcc_disp_gpll0_div_clk_src", +diff --git a/arch/arm64/include/asm/jump_label.h b/arch/arm64/include/asm/jump_label.h +index 6aafbb7899916..4b99159150829 100644 +--- a/arch/arm64/include/asm/jump_label.h ++++ b/arch/arm64/include/asm/jump_label.h +@@ -13,6 +13,7 @@ + #include <linux/types.h> + #include <asm/insn.h> + ++#define HAVE_JUMP_LABEL_BATCH + #define JUMP_LABEL_NOP_SIZE AARCH64_INSN_SIZE + + static __always_inline bool arch_static_branch(struct static_key * const key, +diff --git a/arch/arm64/kernel/jump_label.c b/arch/arm64/kernel/jump_label.c +index faf88ec9c48e8..f63ea915d6ad2 100644 +--- a/arch/arm64/kernel/jump_label.c ++++ b/arch/arm64/kernel/jump_label.c +@@ -7,11 +7,12 @@ + */ + #include <linux/kernel.h> + #include <linux/jump_label.h> ++#include <linux/smp.h> + #include <asm/insn.h> + #include <asm/patching.h> + +-void arch_jump_label_transform(struct jump_entry *entry, +- enum jump_label_type type) ++bool arch_jump_label_transform_queue(struct jump_entry *entry, ++ enum jump_label_type type) + { + void *addr = (void *)jump_entry_code(entry); + u32 insn; +@@ -25,4 +26,10 @@ void arch_jump_label_transform(struct jump_entry *entry, + } + + aarch64_insn_patch_text_nosync(addr, insn); ++ return true; ++} ++ ++void arch_jump_label_transform_apply(void) ++{ ++ kick_all_cpus_sync(); + } +diff --git a/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi b/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi +index c0be84a6e81fd..cc7747c5f21f3 100644 +--- a/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi ++++ b/arch/mips/boot/dts/loongson/loongson64-2k1000.dtsi +@@ -99,8 +99,8 @@ liointc1: interrupt-controller@1fe11440 { + rtc0: rtc@1fe07800 { + compatible = "loongson,ls2k1000-rtc"; + reg = <0 0x1fe07800 0 0x78>; +- interrupt-parent = <&liointc0>; +- interrupts = <60 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-parent = <&liointc1>; ++ interrupts = <8 IRQ_TYPE_LEVEL_HIGH>; + }; + + uart0: serial@1fe00000 { +@@ -108,7 +108,7 @@ uart0: serial@1fe00000 { + reg = <0 0x1fe00000 0 0x8>; + clock-frequency = <125000000>; + interrupt-parent = <&liointc0>; +- interrupts = <0 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + no-loopback-test; + }; + +@@ -117,7 +117,6 @@ pci@1a000000 { + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; +- #interrupt-cells = <2>; + + reg = <0 0x1a000000 0 0x02000000>, + <0xfe 0x00000000 0 0x20000000>; +@@ -132,8 +131,8 @@ gmac@3,0 { + "pciclass0c03"; + + reg = <0x1800 0x0 0x0 0x0 0x0>; +- interrupts = <12 IRQ_TYPE_LEVEL_LOW>, +- <13 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <12 IRQ_TYPE_LEVEL_HIGH>, ++ <13 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq", "eth_lpi"; + interrupt-parent = <&liointc0>; + phy-mode = "rgmii-id"; +@@ -156,8 +155,8 @@ gmac@3,1 { + "loongson, pci-gmac"; + + reg = <0x1900 0x0 0x0 0x0 0x0>; +- interrupts = <14 IRQ_TYPE_LEVEL_LOW>, +- <15 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <14 IRQ_TYPE_LEVEL_HIGH>, ++ <15 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq", "eth_lpi"; + interrupt-parent = <&liointc0>; + phy-mode = "rgmii-id"; +@@ -179,7 +178,7 @@ ehci@4,1 { + "pciclass0c03"; + + reg = <0x2100 0x0 0x0 0x0 0x0>; +- interrupts = <18 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <18 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + }; + +@@ -190,7 +189,7 @@ ohci@4,2 { + "pciclass0c03"; + + reg = <0x2200 0x0 0x0 0x0 0x0>; +- interrupts = <19 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + }; + +@@ -201,97 +200,121 @@ sata@8,0 { + "pciclass0106"; + + reg = <0x4000 0x0 0x0 0x0 0x0>; +- interrupts = <19 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc0>; + }; + +- pci_bridge@9,0 { ++ pcie@9,0 { + compatible = "pci0014,7a19.0", + "pci0014,7a19", + "pciclass060400", + "pciclass0604"; + + reg = <0x4800 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <0 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 0 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 0 IRQ_TYPE_LEVEL_HIGH>; ++ ranges; + external-facing; + }; + +- pci_bridge@a,0 { ++ pcie@a,0 { + compatible = "pci0014,7a09.0", + "pci0014,7a09", + "pciclass060400", + "pciclass0604"; + + reg = <0x5000 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <1 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 1 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 1 IRQ_TYPE_LEVEL_HIGH>; ++ ranges; + external-facing; + }; + +- pci_bridge@b,0 { ++ pcie@b,0 { + compatible = "pci0014,7a09.0", + "pci0014,7a09", + "pciclass060400", + "pciclass0604"; + + reg = <0x5800 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <2 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 2 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 2 IRQ_TYPE_LEVEL_HIGH>; ++ ranges; + external-facing; + }; + +- pci_bridge@c,0 { ++ pcie@c,0 { + compatible = "pci0014,7a09.0", + "pci0014,7a09", + "pciclass060400", + "pciclass0604"; + + reg = <0x6000 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <3 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 3 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 3 IRQ_TYPE_LEVEL_HIGH>; ++ ranges; + external-facing; + }; + +- pci_bridge@d,0 { ++ pcie@d,0 { + compatible = "pci0014,7a19.0", + "pci0014,7a19", + "pciclass060400", + "pciclass0604"; + + reg = <0x6800 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <4 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 4 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 4 IRQ_TYPE_LEVEL_HIGH>; ++ ranges; + external-facing; + }; + +- pci_bridge@e,0 { ++ pcie@e,0 { + compatible = "pci0014,7a09.0", + "pci0014,7a09", + "pciclass060400", + "pciclass0604"; + + reg = <0x7000 0x0 0x0 0x0 0x0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; + #interrupt-cells = <1>; +- interrupts = <5 IRQ_TYPE_LEVEL_LOW>; ++ interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&liointc1>; + interrupt-map-mask = <0 0 0 0>; +- interrupt-map = <0 0 0 0 &liointc1 5 IRQ_TYPE_LEVEL_LOW>; ++ interrupt-map = <0 0 0 0 &liointc1 5 IRQ_TYPE_LEVEL_HIGH>; ++ ranges; + external-facing; + }; + +diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c +index 5348d842c7453..e867fe465164e 100644 +--- a/arch/riscv/kernel/traps_misaligned.c ++++ b/arch/riscv/kernel/traps_misaligned.c +@@ -151,51 +151,19 @@ + #define PRECISION_S 0 + #define PRECISION_D 1 + +-#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \ +-static inline type load_##type(const type *addr) \ +-{ \ +- type val; \ +- asm (#insn " %0, %1" \ +- : "=&r" (val) : "m" (*addr)); \ +- return val; \ +-} ++static inline u8 load_u8(const u8 *addr) ++{ ++ u8 val; + +-#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type, insn) \ +-static inline void store_##type(type *addr, type val) \ +-{ \ +- asm volatile (#insn " %0, %1\n" \ +- : : "r" (val), "m" (*addr)); \ +-} ++ asm volatile("lbu %0, %1" : "=&r" (val) : "m" (*addr)); + +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu) +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u16, lhu) +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s8, lb) +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s16, lh) +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(s32, lw) +-DECLARE_UNPRIVILEGED_STORE_FUNCTION(u8, sb) +-DECLARE_UNPRIVILEGED_STORE_FUNCTION(u16, sh) +-DECLARE_UNPRIVILEGED_STORE_FUNCTION(u32, sw) +-#if defined(CONFIG_64BIT) +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu) +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld) +-DECLARE_UNPRIVILEGED_STORE_FUNCTION(u64, sd) +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld) +-#else +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw) +-DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw) +- +-static inline u64 load_u64(const u64 *addr) +-{ +- return load_u32((u32 *)addr) +- + ((u64)load_u32((u32 *)addr + 1) << 32); ++ return val; + } + +-static inline void store_u64(u64 *addr, u64 val) ++static inline void store_u8(u8 *addr, u8 val) + { +- store_u32((u32 *)addr, val); +- store_u32((u32 *)addr + 1, val >> 32); ++ asm volatile ("sb %0, %1\n" : : "r" (val), "m" (*addr)); + } +-#endif + + static inline ulong get_insn(ulong mepc) + { +diff --git a/arch/riscv/mm/fault.c b/arch/riscv/mm/fault.c +index 90d4ba36d1d06..655b2b1bb529f 100644 +--- a/arch/riscv/mm/fault.c ++++ b/arch/riscv/mm/fault.c +@@ -61,26 +61,27 @@ static inline void no_context(struct pt_regs *regs, unsigned long addr) + + static inline void mm_fault_error(struct pt_regs *regs, unsigned long addr, vm_fault_t fault) + { ++ if (!user_mode(regs)) { ++ no_context(regs, addr); ++ return; ++ } ++ + if (fault & VM_FAULT_OOM) { + /* + * We ran out of memory, call the OOM killer, and return the userspace + * (which will retry the fault, or kill us if we got oom-killed). + */ +- if (!user_mode(regs)) { +- no_context(regs, addr); +- return; +- } + pagefault_out_of_memory(); + return; + } else if (fault & (VM_FAULT_SIGBUS | VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE)) { + /* Kernel mode? Handle exceptions or die */ +- if (!user_mode(regs)) { +- no_context(regs, addr); +- return; +- } + do_trap(regs, SIGBUS, BUS_ADRERR, addr); + return; ++ } else if (fault & VM_FAULT_SIGSEGV) { ++ do_trap(regs, SIGSEGV, SEGV_MAPERR, addr); ++ return; + } ++ + BUG(); + } + +diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c +index 8adcb9419ad50..9b10e9655df8c 100644 +--- a/arch/riscv/mm/init.c ++++ b/arch/riscv/mm/init.c +@@ -217,8 +217,6 @@ static void __init setup_bootmem(void) + */ + memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start); + +- phys_ram_end = memblock_end_of_DRAM(); +- + /* + * Make sure we align the start of the memory on a PMD boundary so that + * at worst, we map the linear mapping with PMD mappings. +@@ -233,6 +231,16 @@ static void __init setup_bootmem(void) + if (IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_MMU)) + kernel_map.va_pa_offset = PAGE_OFFSET - phys_ram_base; + ++ /* ++ * The size of the linear page mapping may restrict the amount of ++ * usable RAM. ++ */ ++ if (IS_ENABLED(CONFIG_64BIT)) { ++ max_mapped_addr = __pa(PAGE_OFFSET) + KERN_VIRT_SIZE; ++ memblock_cap_memory_range(phys_ram_base, ++ max_mapped_addr - phys_ram_base); ++ } ++ + /* + * Reserve physical address space that would be mapped to virtual + * addresses greater than (void *)(-PAGE_SIZE) because: +@@ -249,6 +257,7 @@ static void __init setup_bootmem(void) + memblock_reserve(max_mapped_addr, (phys_addr_t)-max_mapped_addr); + } + ++ phys_ram_end = memblock_end_of_DRAM(); + min_low_pfn = PFN_UP(phys_ram_base); + max_low_pfn = max_pfn = PFN_DOWN(phys_ram_end); + high_memory = (void *)(__va(PFN_PHYS(max_low_pfn))); +@@ -1269,8 +1278,6 @@ static void __init create_linear_mapping_page_table(void) + if (start <= __pa(PAGE_OFFSET) && + __pa(PAGE_OFFSET) < end) + start = __pa(PAGE_OFFSET); +- if (end >= __pa(PAGE_OFFSET) + memory_limit) +- end = __pa(PAGE_OFFSET) + memory_limit; + + create_linear_mapping_range(start, end, 0); + } +diff --git a/arch/x86/include/asm/posted_intr.h b/arch/x86/include/asm/posted_intr.h +new file mode 100644 +index 0000000000000..f0324c56f7af5 +--- /dev/null ++++ b/arch/x86/include/asm/posted_intr.h +@@ -0,0 +1,88 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef _X86_POSTED_INTR_H ++#define _X86_POSTED_INTR_H ++ ++#define POSTED_INTR_ON 0 ++#define POSTED_INTR_SN 1 ++ ++#define PID_TABLE_ENTRY_VALID 1 ++ ++/* Posted-Interrupt Descriptor */ ++struct pi_desc { ++ u32 pir[8]; /* Posted interrupt requested */ ++ union { ++ struct { ++ /* bit 256 - Outstanding Notification */ ++ u16 on : 1, ++ /* bit 257 - Suppress Notification */ ++ sn : 1, ++ /* bit 271:258 - Reserved */ ++ rsvd_1 : 14; ++ /* bit 279:272 - Notification Vector */ ++ u8 nv; ++ /* bit 287:280 - Reserved */ ++ u8 rsvd_2; ++ /* bit 319:288 - Notification Destination */ ++ u32 ndst; ++ }; ++ u64 control; ++ }; ++ u32 rsvd[6]; ++} __aligned(64); ++ ++static inline bool pi_test_and_set_on(struct pi_desc *pi_desc) ++{ ++ return test_and_set_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control); ++} ++ ++static inline bool pi_test_and_clear_on(struct pi_desc *pi_desc) ++{ ++ return test_and_clear_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control); ++} ++ ++static inline bool pi_test_and_clear_sn(struct pi_desc *pi_desc) ++{ ++ return test_and_clear_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control); ++} ++ ++static inline bool pi_test_and_set_pir(int vector, struct pi_desc *pi_desc) ++{ ++ return test_and_set_bit(vector, (unsigned long *)pi_desc->pir); ++} ++ ++static inline bool pi_is_pir_empty(struct pi_desc *pi_desc) ++{ ++ return bitmap_empty((unsigned long *)pi_desc->pir, NR_VECTORS); ++} ++ ++static inline void pi_set_sn(struct pi_desc *pi_desc) ++{ ++ set_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control); ++} ++ ++static inline void pi_set_on(struct pi_desc *pi_desc) ++{ ++ set_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control); ++} ++ ++static inline void pi_clear_on(struct pi_desc *pi_desc) ++{ ++ clear_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control); ++} ++ ++static inline void pi_clear_sn(struct pi_desc *pi_desc) ++{ ++ clear_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control); ++} ++ ++static inline bool pi_test_on(struct pi_desc *pi_desc) ++{ ++ return test_bit(POSTED_INTR_ON, (unsigned long *)&pi_desc->control); ++} ++ ++static inline bool pi_test_sn(struct pi_desc *pi_desc) ++{ ++ return test_bit(POSTED_INTR_SN, (unsigned long *)&pi_desc->control); ++} ++ ++#endif /* _X86_POSTED_INTR_H */ +diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile +index 80e3fe184d17e..a99ffc3f3a3fd 100644 +--- a/arch/x86/kvm/Makefile ++++ b/arch/x86/kvm/Makefile +@@ -26,6 +26,10 @@ kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \ + vmx/hyperv.o vmx/nested.o vmx/posted_intr.o + kvm-intel-$(CONFIG_X86_SGX_KVM) += vmx/sgx.o + ++ifdef CONFIG_HYPERV ++kvm-intel-y += vmx/vmx_onhyperv.o ++endif ++ + kvm-amd-y += svm/svm.o svm/vmenter.o svm/pmu.o svm/nested.o svm/avic.o \ + svm/sev.o svm/hyperv.o + +diff --git a/arch/x86/kvm/vmx/hyperv.c b/arch/x86/kvm/vmx/hyperv.c +index 313b8bb5b8a7c..de13dc14fe1d2 100644 +--- a/arch/x86/kvm/vmx/hyperv.c ++++ b/arch/x86/kvm/vmx/hyperv.c +@@ -13,111 +13,6 @@ + + #define CC KVM_NESTED_VMENTER_CONSISTENCY_CHECK + +-/* +- * Enlightened VMCSv1 doesn't support these: +- * +- * POSTED_INTR_NV = 0x00000002, +- * GUEST_INTR_STATUS = 0x00000810, +- * APIC_ACCESS_ADDR = 0x00002014, +- * POSTED_INTR_DESC_ADDR = 0x00002016, +- * EOI_EXIT_BITMAP0 = 0x0000201c, +- * EOI_EXIT_BITMAP1 = 0x0000201e, +- * EOI_EXIT_BITMAP2 = 0x00002020, +- * EOI_EXIT_BITMAP3 = 0x00002022, +- * GUEST_PML_INDEX = 0x00000812, +- * PML_ADDRESS = 0x0000200e, +- * VM_FUNCTION_CONTROL = 0x00002018, +- * EPTP_LIST_ADDRESS = 0x00002024, +- * VMREAD_BITMAP = 0x00002026, +- * VMWRITE_BITMAP = 0x00002028, +- * +- * TSC_MULTIPLIER = 0x00002032, +- * PLE_GAP = 0x00004020, +- * PLE_WINDOW = 0x00004022, +- * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E, +- * +- * Currently unsupported in KVM: +- * GUEST_IA32_RTIT_CTL = 0x00002814, +- */ +-#define EVMCS1_SUPPORTED_PINCTRL \ +- (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \ +- PIN_BASED_EXT_INTR_MASK | \ +- PIN_BASED_NMI_EXITING | \ +- PIN_BASED_VIRTUAL_NMIS) +- +-#define EVMCS1_SUPPORTED_EXEC_CTRL \ +- (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \ +- CPU_BASED_HLT_EXITING | \ +- CPU_BASED_CR3_LOAD_EXITING | \ +- CPU_BASED_CR3_STORE_EXITING | \ +- CPU_BASED_UNCOND_IO_EXITING | \ +- CPU_BASED_MOV_DR_EXITING | \ +- CPU_BASED_USE_TSC_OFFSETTING | \ +- CPU_BASED_MWAIT_EXITING | \ +- CPU_BASED_MONITOR_EXITING | \ +- CPU_BASED_INVLPG_EXITING | \ +- CPU_BASED_RDPMC_EXITING | \ +- CPU_BASED_INTR_WINDOW_EXITING | \ +- CPU_BASED_CR8_LOAD_EXITING | \ +- CPU_BASED_CR8_STORE_EXITING | \ +- CPU_BASED_RDTSC_EXITING | \ +- CPU_BASED_TPR_SHADOW | \ +- CPU_BASED_USE_IO_BITMAPS | \ +- CPU_BASED_MONITOR_TRAP_FLAG | \ +- CPU_BASED_USE_MSR_BITMAPS | \ +- CPU_BASED_NMI_WINDOW_EXITING | \ +- CPU_BASED_PAUSE_EXITING | \ +- CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) +- +-#define EVMCS1_SUPPORTED_2NDEXEC \ +- (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \ +- SECONDARY_EXEC_WBINVD_EXITING | \ +- SECONDARY_EXEC_ENABLE_VPID | \ +- SECONDARY_EXEC_ENABLE_EPT | \ +- SECONDARY_EXEC_UNRESTRICTED_GUEST | \ +- SECONDARY_EXEC_DESC | \ +- SECONDARY_EXEC_ENABLE_RDTSCP | \ +- SECONDARY_EXEC_ENABLE_INVPCID | \ +- SECONDARY_EXEC_ENABLE_XSAVES | \ +- SECONDARY_EXEC_RDSEED_EXITING | \ +- SECONDARY_EXEC_RDRAND_EXITING | \ +- SECONDARY_EXEC_TSC_SCALING | \ +- SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \ +- SECONDARY_EXEC_PT_USE_GPA | \ +- SECONDARY_EXEC_PT_CONCEAL_VMX | \ +- SECONDARY_EXEC_BUS_LOCK_DETECTION | \ +- SECONDARY_EXEC_NOTIFY_VM_EXITING | \ +- SECONDARY_EXEC_ENCLS_EXITING) +- +-#define EVMCS1_SUPPORTED_3RDEXEC (0ULL) +- +-#define EVMCS1_SUPPORTED_VMEXIT_CTRL \ +- (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \ +- VM_EXIT_SAVE_DEBUG_CONTROLS | \ +- VM_EXIT_ACK_INTR_ON_EXIT | \ +- VM_EXIT_HOST_ADDR_SPACE_SIZE | \ +- VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \ +- VM_EXIT_SAVE_IA32_PAT | \ +- VM_EXIT_LOAD_IA32_PAT | \ +- VM_EXIT_SAVE_IA32_EFER | \ +- VM_EXIT_LOAD_IA32_EFER | \ +- VM_EXIT_CLEAR_BNDCFGS | \ +- VM_EXIT_PT_CONCEAL_PIP | \ +- VM_EXIT_CLEAR_IA32_RTIT_CTL) +- +-#define EVMCS1_SUPPORTED_VMENTRY_CTRL \ +- (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \ +- VM_ENTRY_LOAD_DEBUG_CONTROLS | \ +- VM_ENTRY_IA32E_MODE | \ +- VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \ +- VM_ENTRY_LOAD_IA32_PAT | \ +- VM_ENTRY_LOAD_IA32_EFER | \ +- VM_ENTRY_LOAD_BNDCFGS | \ +- VM_ENTRY_PT_CONCEAL_PIP | \ +- VM_ENTRY_LOAD_IA32_RTIT_CTL) +- +-#define EVMCS1_SUPPORTED_VMFUNC (0) +- + #define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x) + #define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \ + {EVMCS1_OFFSET(name), clean_field} +@@ -608,40 +503,6 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12) + return 0; + } + +-#if IS_ENABLED(CONFIG_HYPERV) +-DEFINE_STATIC_KEY_FALSE(__kvm_is_using_evmcs); +- +-/* +- * KVM on Hyper-V always uses the latest known eVMCSv1 revision, the assumption +- * is: in case a feature has corresponding fields in eVMCS described and it was +- * exposed in VMX feature MSRs, KVM is free to use it. Warn if KVM meets a +- * feature which has no corresponding eVMCS field, this likely means that KVM +- * needs to be updated. +- */ +-#define evmcs_check_vmcs_conf(field, ctrl) \ +- do { \ +- typeof(vmcs_conf->field) unsupported; \ +- \ +- unsupported = vmcs_conf->field & ~EVMCS1_SUPPORTED_ ## ctrl; \ +- if (unsupported) { \ +- pr_warn_once(#field " unsupported with eVMCS: 0x%llx\n",\ +- (u64)unsupported); \ +- vmcs_conf->field &= EVMCS1_SUPPORTED_ ## ctrl; \ +- } \ +- } \ +- while (0) +- +-void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf) +-{ +- evmcs_check_vmcs_conf(cpu_based_exec_ctrl, EXEC_CTRL); +- evmcs_check_vmcs_conf(pin_based_exec_ctrl, PINCTRL); +- evmcs_check_vmcs_conf(cpu_based_2nd_exec_ctrl, 2NDEXEC); +- evmcs_check_vmcs_conf(cpu_based_3rd_exec_ctrl, 3RDEXEC); +- evmcs_check_vmcs_conf(vmentry_ctrl, VMENTRY_CTRL); +- evmcs_check_vmcs_conf(vmexit_ctrl, VMEXIT_CTRL); +-} +-#endif +- + int nested_enable_evmcs(struct kvm_vcpu *vcpu, + uint16_t *vmcs_version) + { +diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h +index 9623fe1651c48..9401dbfaea7ce 100644 +--- a/arch/x86/kvm/vmx/hyperv.h ++++ b/arch/x86/kvm/vmx/hyperv.h +@@ -14,12 +14,113 @@ + #include "vmcs.h" + #include "vmcs12.h" + +-struct vmcs_config; +- +-#define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs)) +- + #define KVM_EVMCS_VERSION 1 + ++/* ++ * Enlightened VMCSv1 doesn't support these: ++ * ++ * POSTED_INTR_NV = 0x00000002, ++ * GUEST_INTR_STATUS = 0x00000810, ++ * APIC_ACCESS_ADDR = 0x00002014, ++ * POSTED_INTR_DESC_ADDR = 0x00002016, ++ * EOI_EXIT_BITMAP0 = 0x0000201c, ++ * EOI_EXIT_BITMAP1 = 0x0000201e, ++ * EOI_EXIT_BITMAP2 = 0x00002020, ++ * EOI_EXIT_BITMAP3 = 0x00002022, ++ * GUEST_PML_INDEX = 0x00000812, ++ * PML_ADDRESS = 0x0000200e, ++ * VM_FUNCTION_CONTROL = 0x00002018, ++ * EPTP_LIST_ADDRESS = 0x00002024, ++ * VMREAD_BITMAP = 0x00002026, ++ * VMWRITE_BITMAP = 0x00002028, ++ * ++ * TSC_MULTIPLIER = 0x00002032, ++ * PLE_GAP = 0x00004020, ++ * PLE_WINDOW = 0x00004022, ++ * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E, ++ * ++ * Currently unsupported in KVM: ++ * GUEST_IA32_RTIT_CTL = 0x00002814, ++ */ ++#define EVMCS1_SUPPORTED_PINCTRL \ ++ (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \ ++ PIN_BASED_EXT_INTR_MASK | \ ++ PIN_BASED_NMI_EXITING | \ ++ PIN_BASED_VIRTUAL_NMIS) ++ ++#define EVMCS1_SUPPORTED_EXEC_CTRL \ ++ (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \ ++ CPU_BASED_HLT_EXITING | \ ++ CPU_BASED_CR3_LOAD_EXITING | \ ++ CPU_BASED_CR3_STORE_EXITING | \ ++ CPU_BASED_UNCOND_IO_EXITING | \ ++ CPU_BASED_MOV_DR_EXITING | \ ++ CPU_BASED_USE_TSC_OFFSETTING | \ ++ CPU_BASED_MWAIT_EXITING | \ ++ CPU_BASED_MONITOR_EXITING | \ ++ CPU_BASED_INVLPG_EXITING | \ ++ CPU_BASED_RDPMC_EXITING | \ ++ CPU_BASED_INTR_WINDOW_EXITING | \ ++ CPU_BASED_CR8_LOAD_EXITING | \ ++ CPU_BASED_CR8_STORE_EXITING | \ ++ CPU_BASED_RDTSC_EXITING | \ ++ CPU_BASED_TPR_SHADOW | \ ++ CPU_BASED_USE_IO_BITMAPS | \ ++ CPU_BASED_MONITOR_TRAP_FLAG | \ ++ CPU_BASED_USE_MSR_BITMAPS | \ ++ CPU_BASED_NMI_WINDOW_EXITING | \ ++ CPU_BASED_PAUSE_EXITING | \ ++ CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) ++ ++#define EVMCS1_SUPPORTED_2NDEXEC \ ++ (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \ ++ SECONDARY_EXEC_WBINVD_EXITING | \ ++ SECONDARY_EXEC_ENABLE_VPID | \ ++ SECONDARY_EXEC_ENABLE_EPT | \ ++ SECONDARY_EXEC_UNRESTRICTED_GUEST | \ ++ SECONDARY_EXEC_DESC | \ ++ SECONDARY_EXEC_ENABLE_RDTSCP | \ ++ SECONDARY_EXEC_ENABLE_INVPCID | \ ++ SECONDARY_EXEC_ENABLE_XSAVES | \ ++ SECONDARY_EXEC_RDSEED_EXITING | \ ++ SECONDARY_EXEC_RDRAND_EXITING | \ ++ SECONDARY_EXEC_TSC_SCALING | \ ++ SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \ ++ SECONDARY_EXEC_PT_USE_GPA | \ ++ SECONDARY_EXEC_PT_CONCEAL_VMX | \ ++ SECONDARY_EXEC_BUS_LOCK_DETECTION | \ ++ SECONDARY_EXEC_NOTIFY_VM_EXITING | \ ++ SECONDARY_EXEC_ENCLS_EXITING) ++ ++#define EVMCS1_SUPPORTED_3RDEXEC (0ULL) ++ ++#define EVMCS1_SUPPORTED_VMEXIT_CTRL \ ++ (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \ ++ VM_EXIT_SAVE_DEBUG_CONTROLS | \ ++ VM_EXIT_ACK_INTR_ON_EXIT | \ ++ VM_EXIT_HOST_ADDR_SPACE_SIZE | \ ++ VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \ ++ VM_EXIT_SAVE_IA32_PAT | \ ++ VM_EXIT_LOAD_IA32_PAT | \ ++ VM_EXIT_SAVE_IA32_EFER | \ ++ VM_EXIT_LOAD_IA32_EFER | \ ++ VM_EXIT_CLEAR_BNDCFGS | \ ++ VM_EXIT_PT_CONCEAL_PIP | \ ++ VM_EXIT_CLEAR_IA32_RTIT_CTL) ++ ++#define EVMCS1_SUPPORTED_VMENTRY_CTRL \ ++ (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \ ++ VM_ENTRY_LOAD_DEBUG_CONTROLS | \ ++ VM_ENTRY_IA32E_MODE | \ ++ VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \ ++ VM_ENTRY_LOAD_IA32_PAT | \ ++ VM_ENTRY_LOAD_IA32_EFER | \ ++ VM_ENTRY_LOAD_BNDCFGS | \ ++ VM_ENTRY_PT_CONCEAL_PIP | \ ++ VM_ENTRY_LOAD_IA32_RTIT_CTL) ++ ++#define EVMCS1_SUPPORTED_VMFUNC (0) ++ + struct evmcs_field { + u16 offset; + u16 clean_field; +@@ -65,114 +166,6 @@ static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs, + return vmcs12_read_any((void *)evmcs, field, offset); + } + +-#if IS_ENABLED(CONFIG_HYPERV) +- +-DECLARE_STATIC_KEY_FALSE(__kvm_is_using_evmcs); +- +-static __always_inline bool kvm_is_using_evmcs(void) +-{ +- return static_branch_unlikely(&__kvm_is_using_evmcs); +-} +- +-static __always_inline int get_evmcs_offset(unsigned long field, +- u16 *clean_field) +-{ +- int offset = evmcs_field_offset(field, clean_field); +- +- WARN_ONCE(offset < 0, "accessing unsupported EVMCS field %lx\n", field); +- return offset; +-} +- +-static __always_inline void evmcs_write64(unsigned long field, u64 value) +-{ +- u16 clean_field; +- int offset = get_evmcs_offset(field, &clean_field); +- +- if (offset < 0) +- return; +- +- *(u64 *)((char *)current_evmcs + offset) = value; +- +- current_evmcs->hv_clean_fields &= ~clean_field; +-} +- +-static __always_inline void evmcs_write32(unsigned long field, u32 value) +-{ +- u16 clean_field; +- int offset = get_evmcs_offset(field, &clean_field); +- +- if (offset < 0) +- return; +- +- *(u32 *)((char *)current_evmcs + offset) = value; +- current_evmcs->hv_clean_fields &= ~clean_field; +-} +- +-static __always_inline void evmcs_write16(unsigned long field, u16 value) +-{ +- u16 clean_field; +- int offset = get_evmcs_offset(field, &clean_field); +- +- if (offset < 0) +- return; +- +- *(u16 *)((char *)current_evmcs + offset) = value; +- current_evmcs->hv_clean_fields &= ~clean_field; +-} +- +-static __always_inline u64 evmcs_read64(unsigned long field) +-{ +- int offset = get_evmcs_offset(field, NULL); +- +- if (offset < 0) +- return 0; +- +- return *(u64 *)((char *)current_evmcs + offset); +-} +- +-static __always_inline u32 evmcs_read32(unsigned long field) +-{ +- int offset = get_evmcs_offset(field, NULL); +- +- if (offset < 0) +- return 0; +- +- return *(u32 *)((char *)current_evmcs + offset); +-} +- +-static __always_inline u16 evmcs_read16(unsigned long field) +-{ +- int offset = get_evmcs_offset(field, NULL); +- +- if (offset < 0) +- return 0; +- +- return *(u16 *)((char *)current_evmcs + offset); +-} +- +-static inline void evmcs_load(u64 phys_addr) +-{ +- struct hv_vp_assist_page *vp_ap = +- hv_get_vp_assist_page(smp_processor_id()); +- +- if (current_evmcs->hv_enlightenments_control.nested_flush_hypercall) +- vp_ap->nested_control.features.directhypercall = 1; +- vp_ap->current_nested_vmcs = phys_addr; +- vp_ap->enlighten_vmentry = 1; +-} +- +-void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf); +-#else /* !IS_ENABLED(CONFIG_HYPERV) */ +-static __always_inline bool kvm_is_using_evmcs(void) { return false; } +-static __always_inline void evmcs_write64(unsigned long field, u64 value) {} +-static __always_inline void evmcs_write32(unsigned long field, u32 value) {} +-static __always_inline void evmcs_write16(unsigned long field, u16 value) {} +-static __always_inline u64 evmcs_read64(unsigned long field) { return 0; } +-static __always_inline u32 evmcs_read32(unsigned long field) { return 0; } +-static __always_inline u16 evmcs_read16(unsigned long field) { return 0; } +-static inline void evmcs_load(u64 phys_addr) {} +-#endif /* IS_ENABLED(CONFIG_HYPERV) */ +- + #define EVMPTR_INVALID (-1ULL) + #define EVMPTR_MAP_PENDING (-2ULL) + +diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c +index d1b4a85def0a6..0ad66b9207e85 100644 +--- a/arch/x86/kvm/vmx/nested.c ++++ b/arch/x86/kvm/vmx/nested.c +@@ -12,6 +12,7 @@ + #include "mmu.h" + #include "nested.h" + #include "pmu.h" ++#include "posted_intr.h" + #include "sgx.h" + #include "trace.h" + #include "vmx.h" +@@ -3830,8 +3831,8 @@ static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu) + if (!pi_test_and_clear_on(vmx->nested.pi_desc)) + return 0; + +- max_irr = find_last_bit((unsigned long *)vmx->nested.pi_desc->pir, 256); +- if (max_irr != 256) { ++ max_irr = pi_find_highest_vector(vmx->nested.pi_desc); ++ if (max_irr > 0) { + vapic_page = vmx->nested.virtual_apic_map.hva; + if (!vapic_page) + goto mmio_needed; +@@ -3964,8 +3965,40 @@ static bool nested_vmx_preemption_timer_pending(struct kvm_vcpu *vcpu) + + static bool vmx_has_nested_events(struct kvm_vcpu *vcpu, bool for_injection) + { +- return nested_vmx_preemption_timer_pending(vcpu) || +- to_vmx(vcpu)->nested.mtf_pending; ++ struct vcpu_vmx *vmx = to_vmx(vcpu); ++ void *vapic = vmx->nested.virtual_apic_map.hva; ++ int max_irr, vppr; ++ ++ if (nested_vmx_preemption_timer_pending(vcpu) || ++ vmx->nested.mtf_pending) ++ return true; ++ ++ /* ++ * Virtual Interrupt Delivery doesn't require manual injection. Either ++ * the interrupt is already in GUEST_RVI and will be recognized by CPU ++ * at VM-Entry, or there is a KVM_REQ_EVENT pending and KVM will move ++ * the interrupt from the PIR to RVI prior to entering the guest. ++ */ ++ if (for_injection) ++ return false; ++ ++ if (!nested_cpu_has_vid(get_vmcs12(vcpu)) || ++ __vmx_interrupt_blocked(vcpu)) ++ return false; ++ ++ if (!vapic) ++ return false; ++ ++ vppr = *((u32 *)(vapic + APIC_PROCPRI)); ++ ++ if (vmx->nested.pi_pending && vmx->nested.pi_desc && ++ pi_test_on(vmx->nested.pi_desc)) { ++ max_irr = pi_find_highest_vector(vmx->nested.pi_desc); ++ if (max_irr > 0 && (max_irr & 0xf0) > (vppr & 0xf0)) ++ return true; ++ } ++ ++ return false; + } + + /* +diff --git a/arch/x86/kvm/vmx/posted_intr.h b/arch/x86/kvm/vmx/posted_intr.h +index 26992076552ef..1715d2ab07be5 100644 +--- a/arch/x86/kvm/vmx/posted_intr.h ++++ b/arch/x86/kvm/vmx/posted_intr.h +@@ -2,97 +2,8 @@ + #ifndef __KVM_X86_VMX_POSTED_INTR_H + #define __KVM_X86_VMX_POSTED_INTR_H + +-#define POSTED_INTR_ON 0 +-#define POSTED_INTR_SN 1 +- +-#define PID_TABLE_ENTRY_VALID 1 +- +-/* Posted-Interrupt Descriptor */ +-struct pi_desc { +- u32 pir[8]; /* Posted interrupt requested */ +- union { +- struct { +- /* bit 256 - Outstanding Notification */ +- u16 on : 1, +- /* bit 257 - Suppress Notification */ +- sn : 1, +- /* bit 271:258 - Reserved */ +- rsvd_1 : 14; +- /* bit 279:272 - Notification Vector */ +- u8 nv; +- /* bit 287:280 - Reserved */ +- u8 rsvd_2; +- /* bit 319:288 - Notification Destination */ +- u32 ndst; +- }; +- u64 control; +- }; +- u32 rsvd[6]; +-} __aligned(64); +- +-static inline bool pi_test_and_set_on(struct pi_desc *pi_desc) +-{ +- return test_and_set_bit(POSTED_INTR_ON, +- (unsigned long *)&pi_desc->control); +-} +- +-static inline bool pi_test_and_clear_on(struct pi_desc *pi_desc) +-{ +- return test_and_clear_bit(POSTED_INTR_ON, +- (unsigned long *)&pi_desc->control); +-} +- +-static inline bool pi_test_and_clear_sn(struct pi_desc *pi_desc) +-{ +- return test_and_clear_bit(POSTED_INTR_SN, +- (unsigned long *)&pi_desc->control); +-} +- +-static inline bool pi_test_and_set_pir(int vector, struct pi_desc *pi_desc) +-{ +- return test_and_set_bit(vector, (unsigned long *)pi_desc->pir); +-} +- +-static inline bool pi_is_pir_empty(struct pi_desc *pi_desc) +-{ +- return bitmap_empty((unsigned long *)pi_desc->pir, NR_VECTORS); +-} +- +-static inline void pi_set_sn(struct pi_desc *pi_desc) +-{ +- set_bit(POSTED_INTR_SN, +- (unsigned long *)&pi_desc->control); +-} +- +-static inline void pi_set_on(struct pi_desc *pi_desc) +-{ +- set_bit(POSTED_INTR_ON, +- (unsigned long *)&pi_desc->control); +-} +- +-static inline void pi_clear_on(struct pi_desc *pi_desc) +-{ +- clear_bit(POSTED_INTR_ON, +- (unsigned long *)&pi_desc->control); +-} +- +-static inline void pi_clear_sn(struct pi_desc *pi_desc) +-{ +- clear_bit(POSTED_INTR_SN, +- (unsigned long *)&pi_desc->control); +-} +- +-static inline bool pi_test_on(struct pi_desc *pi_desc) +-{ +- return test_bit(POSTED_INTR_ON, +- (unsigned long *)&pi_desc->control); +-} +- +-static inline bool pi_test_sn(struct pi_desc *pi_desc) +-{ +- return test_bit(POSTED_INTR_SN, +- (unsigned long *)&pi_desc->control); +-} ++#include <linux/find.h> ++#include <asm/posted_intr.h> + + void vmx_vcpu_pi_load(struct kvm_vcpu *vcpu, int cpu); + void vmx_vcpu_pi_put(struct kvm_vcpu *vcpu); +@@ -103,4 +14,12 @@ int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq, + uint32_t guest_irq, bool set); + void vmx_pi_start_assignment(struct kvm *kvm); + ++static inline int pi_find_highest_vector(struct pi_desc *pi_desc) ++{ ++ int vec; ++ ++ vec = find_last_bit((unsigned long *)pi_desc->pir, 256); ++ return vec < 256 ? vec : -1; ++} ++ + #endif /* __KVM_X86_VMX_POSTED_INTR_H */ +diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c +index f5f652a546bf2..2e0106d9d371c 100644 +--- a/arch/x86/kvm/vmx/vmx.c ++++ b/arch/x86/kvm/vmx/vmx.c +@@ -66,6 +66,8 @@ + #include "vmx.h" + #include "x86.h" + #include "smm.h" ++#include "vmx_onhyperv.h" ++#include "posted_intr.h" + + MODULE_AUTHOR("Qumranet"); + MODULE_LICENSE("GPL"); +diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h +index 912b0c4697429..6be1627d888e5 100644 +--- a/arch/x86/kvm/vmx/vmx.h ++++ b/arch/x86/kvm/vmx/vmx.h +@@ -7,10 +7,10 @@ + #include <asm/kvm.h> + #include <asm/intel_pt.h> + #include <asm/perf_event.h> ++#include <asm/posted_intr.h> + + #include "capabilities.h" + #include "../kvm_cache_regs.h" +-#include "posted_intr.h" + #include "vmcs.h" + #include "vmx_ops.h" + #include "../cpuid.h" +diff --git a/arch/x86/kvm/vmx/vmx_onhyperv.c b/arch/x86/kvm/vmx/vmx_onhyperv.c +new file mode 100644 +index 0000000000000..b9a8b91166d02 +--- /dev/null ++++ b/arch/x86/kvm/vmx/vmx_onhyperv.c +@@ -0,0 +1,36 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include "capabilities.h" ++#include "vmx_onhyperv.h" ++ ++DEFINE_STATIC_KEY_FALSE(__kvm_is_using_evmcs); ++ ++/* ++ * KVM on Hyper-V always uses the latest known eVMCSv1 revision, the assumption ++ * is: in case a feature has corresponding fields in eVMCS described and it was ++ * exposed in VMX feature MSRs, KVM is free to use it. Warn if KVM meets a ++ * feature which has no corresponding eVMCS field, this likely means that KVM ++ * needs to be updated. ++ */ ++#define evmcs_check_vmcs_conf(field, ctrl) \ ++ do { \ ++ typeof(vmcs_conf->field) unsupported; \ ++ \ ++ unsupported = vmcs_conf->field & ~EVMCS1_SUPPORTED_ ## ctrl; \ ++ if (unsupported) { \ ++ pr_warn_once(#field " unsupported with eVMCS: 0x%llx\n",\ ++ (u64)unsupported); \ ++ vmcs_conf->field &= EVMCS1_SUPPORTED_ ## ctrl; \ ++ } \ ++ } \ ++ while (0) ++ ++void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf) ++{ ++ evmcs_check_vmcs_conf(cpu_based_exec_ctrl, EXEC_CTRL); ++ evmcs_check_vmcs_conf(pin_based_exec_ctrl, PINCTRL); ++ evmcs_check_vmcs_conf(cpu_based_2nd_exec_ctrl, 2NDEXEC); ++ evmcs_check_vmcs_conf(cpu_based_3rd_exec_ctrl, 3RDEXEC); ++ evmcs_check_vmcs_conf(vmentry_ctrl, VMENTRY_CTRL); ++ evmcs_check_vmcs_conf(vmexit_ctrl, VMEXIT_CTRL); ++} +diff --git a/arch/x86/kvm/vmx/vmx_onhyperv.h b/arch/x86/kvm/vmx/vmx_onhyperv.h +new file mode 100644 +index 0000000000000..11541d272dbd8 +--- /dev/null ++++ b/arch/x86/kvm/vmx/vmx_onhyperv.h +@@ -0,0 +1,124 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++ ++#ifndef __ARCH_X86_KVM_VMX_ONHYPERV_H__ ++#define __ARCH_X86_KVM_VMX_ONHYPERV_H__ ++ ++#include <asm/hyperv-tlfs.h> ++ ++#include <linux/jump_label.h> ++ ++#include "capabilities.h" ++#include "hyperv.h" ++#include "vmcs12.h" ++ ++#define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs)) ++ ++#if IS_ENABLED(CONFIG_HYPERV) ++ ++DECLARE_STATIC_KEY_FALSE(__kvm_is_using_evmcs); ++ ++static __always_inline bool kvm_is_using_evmcs(void) ++{ ++ return static_branch_unlikely(&__kvm_is_using_evmcs); ++} ++ ++static __always_inline int get_evmcs_offset(unsigned long field, ++ u16 *clean_field) ++{ ++ int offset = evmcs_field_offset(field, clean_field); ++ ++ WARN_ONCE(offset < 0, "accessing unsupported EVMCS field %lx\n", field); ++ return offset; ++} ++ ++static __always_inline void evmcs_write64(unsigned long field, u64 value) ++{ ++ u16 clean_field; ++ int offset = get_evmcs_offset(field, &clean_field); ++ ++ if (offset < 0) ++ return; ++ ++ *(u64 *)((char *)current_evmcs + offset) = value; ++ ++ current_evmcs->hv_clean_fields &= ~clean_field; ++} ++ ++static __always_inline void evmcs_write32(unsigned long field, u32 value) ++{ ++ u16 clean_field; ++ int offset = get_evmcs_offset(field, &clean_field); ++ ++ if (offset < 0) ++ return; ++ ++ *(u32 *)((char *)current_evmcs + offset) = value; ++ current_evmcs->hv_clean_fields &= ~clean_field; ++} ++ ++static __always_inline void evmcs_write16(unsigned long field, u16 value) ++{ ++ u16 clean_field; ++ int offset = get_evmcs_offset(field, &clean_field); ++ ++ if (offset < 0) ++ return; ++ ++ *(u16 *)((char *)current_evmcs + offset) = value; ++ current_evmcs->hv_clean_fields &= ~clean_field; ++} ++ ++static __always_inline u64 evmcs_read64(unsigned long field) ++{ ++ int offset = get_evmcs_offset(field, NULL); ++ ++ if (offset < 0) ++ return 0; ++ ++ return *(u64 *)((char *)current_evmcs + offset); ++} ++ ++static __always_inline u32 evmcs_read32(unsigned long field) ++{ ++ int offset = get_evmcs_offset(field, NULL); ++ ++ if (offset < 0) ++ return 0; ++ ++ return *(u32 *)((char *)current_evmcs + offset); ++} ++ ++static __always_inline u16 evmcs_read16(unsigned long field) ++{ ++ int offset = get_evmcs_offset(field, NULL); ++ ++ if (offset < 0) ++ return 0; ++ ++ return *(u16 *)((char *)current_evmcs + offset); ++} ++ ++static inline void evmcs_load(u64 phys_addr) ++{ ++ struct hv_vp_assist_page *vp_ap = ++ hv_get_vp_assist_page(smp_processor_id()); ++ ++ if (current_evmcs->hv_enlightenments_control.nested_flush_hypercall) ++ vp_ap->nested_control.features.directhypercall = 1; ++ vp_ap->current_nested_vmcs = phys_addr; ++ vp_ap->enlighten_vmentry = 1; ++} ++ ++void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf); ++#else /* !IS_ENABLED(CONFIG_HYPERV) */ ++static __always_inline bool kvm_is_using_evmcs(void) { return false; } ++static __always_inline void evmcs_write64(unsigned long field, u64 value) {} ++static __always_inline void evmcs_write32(unsigned long field, u32 value) {} ++static __always_inline void evmcs_write16(unsigned long field, u16 value) {} ++static __always_inline u64 evmcs_read64(unsigned long field) { return 0; } ++static __always_inline u32 evmcs_read32(unsigned long field) { return 0; } ++static __always_inline u16 evmcs_read16(unsigned long field) { return 0; } ++static inline void evmcs_load(u64 phys_addr) {} ++#endif /* IS_ENABLED(CONFIG_HYPERV) */ ++ ++#endif /* __ARCH_X86_KVM_VMX_ONHYPERV_H__ */ +diff --git a/arch/x86/kvm/vmx/vmx_ops.h b/arch/x86/kvm/vmx/vmx_ops.h +index 6a0c6e81f7f3e..8060e5fc6dbd8 100644 +--- a/arch/x86/kvm/vmx/vmx_ops.h ++++ b/arch/x86/kvm/vmx/vmx_ops.h +@@ -6,7 +6,7 @@ + + #include <asm/vmx.h> + +-#include "hyperv.h" ++#include "vmx_onhyperv.h" + #include "vmcs.h" + #include "../x86.h" + +diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c +index 3da3c266a66f3..a936219aebb81 100644 +--- a/drivers/bluetooth/btintel.c ++++ b/drivers/bluetooth/btintel.c +@@ -2845,6 +2845,9 @@ static int btintel_setup_combined(struct hci_dev *hdev) + btintel_set_dsm_reset_method(hdev, &ver_tlv); + + err = btintel_bootloader_setup_tlv(hdev, &ver_tlv); ++ if (err) ++ goto exit_error; ++ + btintel_register_devcoredump_support(hdev); + break; + default: +diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c +index 84d7033e5efe8..ef51dfb39baa9 100644 +--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c ++++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c +@@ -40,10 +40,14 @@ struct qcom_cpufreq_match_data { + const char **genpd_names; + }; + ++struct qcom_cpufreq_drv_cpu { ++ int opp_token; ++}; ++ + struct qcom_cpufreq_drv { +- int *opp_tokens; + u32 versions; + const struct qcom_cpufreq_match_data *data; ++ struct qcom_cpufreq_drv_cpu cpus[]; + }; + + static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev; +@@ -243,42 +247,39 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) + return -ENOENT; + } + +- drv = kzalloc(sizeof(*drv), GFP_KERNEL); +- if (!drv) ++ drv = devm_kzalloc(&pdev->dev, struct_size(drv, cpus, num_possible_cpus()), ++ GFP_KERNEL); ++ if (!drv) { ++ of_node_put(np); + return -ENOMEM; ++ } + + match = pdev->dev.platform_data; + drv->data = match->data; + if (!drv->data) { +- ret = -ENODEV; +- goto free_drv; ++ of_node_put(np); ++ return -ENODEV; + } + + if (drv->data->get_version) { + speedbin_nvmem = of_nvmem_cell_get(np, NULL); + if (IS_ERR(speedbin_nvmem)) { +- ret = dev_err_probe(cpu_dev, PTR_ERR(speedbin_nvmem), +- "Could not get nvmem cell\n"); +- goto free_drv; ++ of_node_put(np); ++ return dev_err_probe(cpu_dev, PTR_ERR(speedbin_nvmem), ++ "Could not get nvmem cell\n"); + } + + ret = drv->data->get_version(cpu_dev, + speedbin_nvmem, &pvs_name, drv); + if (ret) { ++ of_node_put(np); + nvmem_cell_put(speedbin_nvmem); +- goto free_drv; ++ return ret; + } + nvmem_cell_put(speedbin_nvmem); + } + of_node_put(np); + +- drv->opp_tokens = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tokens), +- GFP_KERNEL); +- if (!drv->opp_tokens) { +- ret = -ENOMEM; +- goto free_drv; +- } +- + for_each_possible_cpu(cpu) { + struct dev_pm_opp_config config = { + .supported_hw = NULL, +@@ -304,9 +305,9 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) + } + + if (config.supported_hw || config.genpd_names) { +- drv->opp_tokens[cpu] = dev_pm_opp_set_config(cpu_dev, &config); +- if (drv->opp_tokens[cpu] < 0) { +- ret = drv->opp_tokens[cpu]; ++ drv->cpus[cpu].opp_token = dev_pm_opp_set_config(cpu_dev, &config); ++ if (drv->cpus[cpu].opp_token < 0) { ++ ret = drv->cpus[cpu].opp_token; + dev_err(cpu_dev, "Failed to set OPP config\n"); + goto free_opp; + } +@@ -325,11 +326,7 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) + + free_opp: + for_each_possible_cpu(cpu) +- dev_pm_opp_clear_config(drv->opp_tokens[cpu]); +- kfree(drv->opp_tokens); +-free_drv: +- kfree(drv); +- ++ dev_pm_opp_clear_config(drv->cpus[cpu].opp_token); + return ret; + } + +@@ -341,10 +338,7 @@ static void qcom_cpufreq_remove(struct platform_device *pdev) + platform_device_unregister(cpufreq_dt_pdev); + + for_each_possible_cpu(cpu) +- dev_pm_opp_clear_config(drv->opp_tokens[cpu]); +- +- kfree(drv->opp_tokens); +- kfree(drv); ++ dev_pm_opp_clear_config(drv->cpus[cpu].opp_token); + } + + static struct platform_driver qcom_cpufreq_driver = { +diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c +index 793f1a7ad5e34..53fdfd32a7e77 100644 +--- a/drivers/dma/fsl-edma-common.c ++++ b/drivers/dma/fsl-edma-common.c +@@ -3,6 +3,7 @@ + // Copyright (c) 2013-2014 Freescale Semiconductor, Inc + // Copyright (c) 2017 Sysam, Angelo Dureghello <angelo@sysam.it> + ++#include <linux/clk.h> + #include <linux/dmapool.h> + #include <linux/module.h> + #include <linux/slab.h> +@@ -74,18 +75,10 @@ static void fsl_edma3_enable_request(struct fsl_edma_chan *fsl_chan) + + flags = fsl_edma_drvflags(fsl_chan); + val = edma_readl_chreg(fsl_chan, ch_sbr); +- /* Remote/local swapped wrongly on iMX8 QM Audio edma */ +- if (flags & FSL_EDMA_DRV_QUIRK_SWAPPED) { +- if (!fsl_chan->is_rxchan) +- val |= EDMA_V3_CH_SBR_RD; +- else +- val |= EDMA_V3_CH_SBR_WR; +- } else { +- if (fsl_chan->is_rxchan) +- val |= EDMA_V3_CH_SBR_RD; +- else +- val |= EDMA_V3_CH_SBR_WR; +- } ++ if (fsl_chan->is_rxchan) ++ val |= EDMA_V3_CH_SBR_RD; ++ else ++ val |= EDMA_V3_CH_SBR_WR; + + if (fsl_chan->is_remote) + val &= ~(EDMA_V3_CH_SBR_RD | EDMA_V3_CH_SBR_WR); +@@ -97,8 +90,8 @@ static void fsl_edma3_enable_request(struct fsl_edma_chan *fsl_chan) + * ch_mux: With the exception of 0, attempts to write a value + * already in use will be forced to 0. + */ +- if (!edma_readl_chreg(fsl_chan, ch_mux)) +- edma_writel_chreg(fsl_chan, fsl_chan->srcid, ch_mux); ++ if (!edma_readl(fsl_chan->edma, fsl_chan->mux_addr)) ++ edma_writel(fsl_chan->edma, fsl_chan->srcid, fsl_chan->mux_addr); + } + + val = edma_readl_chreg(fsl_chan, ch_csr); +@@ -134,7 +127,7 @@ static void fsl_edma3_disable_request(struct fsl_edma_chan *fsl_chan) + flags = fsl_edma_drvflags(fsl_chan); + + if (flags & FSL_EDMA_DRV_HAS_CHMUX) +- edma_writel_chreg(fsl_chan, 0, ch_mux); ++ edma_writel(fsl_chan->edma, 0, fsl_chan->mux_addr); + + val &= ~EDMA_V3_CH_CSR_ERQ; + edma_writel_chreg(fsl_chan, val, ch_csr); +@@ -754,6 +747,8 @@ struct dma_async_tx_descriptor *fsl_edma_prep_memcpy(struct dma_chan *chan, + fsl_desc->iscyclic = false; + + fsl_chan->is_sw = true; ++ if (fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_MEM_REMOTE) ++ fsl_chan->is_remote = true; + + /* To match with copy_align and max_seg_size so 1 tcd is enough */ + fsl_edma_fill_tcd(fsl_chan, fsl_desc->tcd[0].vtcd, dma_src, dma_dst, +@@ -802,6 +797,9 @@ int fsl_edma_alloc_chan_resources(struct dma_chan *chan) + { + struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); + ++ if (fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_HAS_CHCLK) ++ clk_prepare_enable(fsl_chan->clk); ++ + fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev, + sizeof(struct fsl_edma_hw_tcd), + 32, 0); +@@ -829,6 +827,9 @@ void fsl_edma_free_chan_resources(struct dma_chan *chan) + fsl_chan->tcd_pool = NULL; + fsl_chan->is_sw = false; + fsl_chan->srcid = 0; ++ fsl_chan->is_remote = false; ++ if (fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_HAS_CHCLK) ++ clk_disable_unprepare(fsl_chan->clk); + } + + void fsl_edma_cleanup_vchan(struct dma_device *dmadev) +diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h +index 92fe53faa53b1..6028389de408b 100644 +--- a/drivers/dma/fsl-edma-common.h ++++ b/drivers/dma/fsl-edma-common.h +@@ -146,6 +146,7 @@ struct fsl_edma_chan { + enum dma_data_direction dma_dir; + char chan_name[32]; + struct fsl_edma_hw_tcd __iomem *tcd; ++ void __iomem *mux_addr; + u32 real_count; + struct work_struct issue_worker; + struct platform_device *pdev; +@@ -177,8 +178,7 @@ struct fsl_edma_desc { + #define FSL_EDMA_DRV_HAS_PD BIT(5) + #define FSL_EDMA_DRV_HAS_CHCLK BIT(6) + #define FSL_EDMA_DRV_HAS_CHMUX BIT(7) +-/* imx8 QM audio edma remote local swapped */ +-#define FSL_EDMA_DRV_QUIRK_SWAPPED BIT(8) ++#define FSL_EDMA_DRV_MEM_REMOTE BIT(8) + /* control and status register is in tcd address space, edma3 reg layout */ + #define FSL_EDMA_DRV_SPLIT_REG BIT(9) + #define FSL_EDMA_DRV_BUS_8BYTE BIT(10) +@@ -207,6 +207,8 @@ struct fsl_edma_drvdata { + u32 chreg_off; + u32 chreg_space_sz; + u32 flags; ++ u32 mux_off; /* channel mux register offset */ ++ u32 mux_skip; /* how much skip for each channel */ + int (*setup_irq)(struct platform_device *pdev, + struct fsl_edma_engine *fsl_edma); + }; +diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c +index 42a338cbe6143..8a0ae90548997 100644 +--- a/drivers/dma/fsl-edma-main.c ++++ b/drivers/dma/fsl-edma-main.c +@@ -340,16 +340,19 @@ static struct fsl_edma_drvdata imx7ulp_data = { + }; + + static struct fsl_edma_drvdata imx8qm_data = { +- .flags = FSL_EDMA_DRV_HAS_PD | FSL_EDMA_DRV_EDMA3, ++ .flags = FSL_EDMA_DRV_HAS_PD | FSL_EDMA_DRV_EDMA3 | FSL_EDMA_DRV_MEM_REMOTE, + .chreg_space_sz = 0x10000, + .chreg_off = 0x10000, + .setup_irq = fsl_edma3_irq_init, + }; + +-static struct fsl_edma_drvdata imx8qm_audio_data = { +- .flags = FSL_EDMA_DRV_QUIRK_SWAPPED | FSL_EDMA_DRV_HAS_PD | FSL_EDMA_DRV_EDMA3, ++static struct fsl_edma_drvdata imx8ulp_data = { ++ .flags = FSL_EDMA_DRV_HAS_CHMUX | FSL_EDMA_DRV_HAS_CHCLK | FSL_EDMA_DRV_HAS_DMACLK | ++ FSL_EDMA_DRV_EDMA3, + .chreg_space_sz = 0x10000, + .chreg_off = 0x10000, ++ .mux_off = 0x10000 + offsetof(struct fsl_edma3_ch_reg, ch_mux), ++ .mux_skip = 0x10000, + .setup_irq = fsl_edma3_irq_init, + }; + +@@ -364,6 +367,8 @@ static struct fsl_edma_drvdata imx93_data4 = { + .flags = FSL_EDMA_DRV_HAS_CHMUX | FSL_EDMA_DRV_HAS_DMACLK | FSL_EDMA_DRV_EDMA4, + .chreg_space_sz = 0x8000, + .chreg_off = 0x10000, ++ .mux_off = 0x10000 + offsetof(struct fsl_edma3_ch_reg, ch_mux), ++ .mux_skip = 0x8000, + .setup_irq = fsl_edma3_irq_init, + }; + +@@ -372,7 +377,7 @@ static const struct of_device_id fsl_edma_dt_ids[] = { + { .compatible = "fsl,ls1028a-edma", .data = &ls1028a_data}, + { .compatible = "fsl,imx7ulp-edma", .data = &imx7ulp_data}, + { .compatible = "fsl,imx8qm-edma", .data = &imx8qm_data}, +- { .compatible = "fsl,imx8qm-adma", .data = &imx8qm_audio_data}, ++ { .compatible = "fsl,imx8ulp-edma", .data = &imx8ulp_data}, + { .compatible = "fsl,imx93-edma3", .data = &imx93_data3}, + { .compatible = "fsl,imx93-edma4", .data = &imx93_data4}, + { /* sentinel */ } +@@ -427,6 +432,7 @@ static int fsl_edma_probe(struct platform_device *pdev) + struct fsl_edma_engine *fsl_edma; + const struct fsl_edma_drvdata *drvdata = NULL; + u32 chan_mask[2] = {0, 0}; ++ char clk_name[36]; + struct edma_regs *regs; + int chans; + int ret, i; +@@ -540,12 +546,23 @@ static int fsl_edma_probe(struct platform_device *pdev) + offsetof(struct fsl_edma3_ch_reg, tcd) : 0; + fsl_chan->tcd = fsl_edma->membase + + i * drvdata->chreg_space_sz + drvdata->chreg_off + len; ++ fsl_chan->mux_addr = fsl_edma->membase + drvdata->mux_off + i * drvdata->mux_skip; + ++ if (drvdata->flags & FSL_EDMA_DRV_HAS_CHCLK) { ++ snprintf(clk_name, sizeof(clk_name), "ch%02d", i); ++ fsl_chan->clk = devm_clk_get_enabled(&pdev->dev, ++ (const char *)clk_name); ++ ++ if (IS_ERR(fsl_chan->clk)) ++ return PTR_ERR(fsl_chan->clk); ++ } + fsl_chan->pdev = pdev; + vchan_init(&fsl_chan->vchan, &fsl_edma->dma_dev); + + edma_write_tcdreg(fsl_chan, 0, csr); + fsl_edma_chan_mux(fsl_chan, 0, false); ++ if (fsl_chan->edma->drvdata->flags & FSL_EDMA_DRV_HAS_CHCLK) ++ clk_disable_unprepare(fsl_chan->clk); + } + + ret = fsl_edma->drvdata->setup_irq(pdev, fsl_edma); +diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig +index b59e3041fd627..f0e9f250669e2 100644 +--- a/drivers/firmware/Kconfig ++++ b/drivers/firmware/Kconfig +@@ -229,6 +229,7 @@ config QCOM_SCM_DOWNLOAD_MODE_DEFAULT + config SYSFB + bool + select BOOT_VESA_SUPPORT ++ select SCREEN_INFO + + config SYSFB_SIMPLEFB + bool "Mark VGA/VBE/EFI FB as generic system framebuffer" +diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c +index 3c197db42c9d9..defd7a36cb08a 100644 +--- a/drivers/firmware/sysfb.c ++++ b/drivers/firmware/sysfb.c +@@ -77,6 +77,8 @@ static __init int sysfb_init(void) + bool compatible; + int ret = 0; + ++ screen_info_apply_fixups(); ++ + mutex_lock(&disable_lock); + if (disabled) + goto unlock_mutex; +diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +index d0255ea98348d..247e7d675e2b9 100644 +--- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c ++++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +@@ -1556,7 +1556,7 @@ static void skl_wrpll_params_populate(struct skl_wrpll_params *params, + } + + static int +-skl_ddi_calculate_wrpll(int clock /* in Hz */, ++skl_ddi_calculate_wrpll(int clock, + int ref_clock, + struct skl_wrpll_params *wrpll_params) + { +@@ -1581,7 +1581,7 @@ skl_ddi_calculate_wrpll(int clock /* in Hz */, + }; + unsigned int dco, d, i; + unsigned int p0, p1, p2; +- u64 afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */ ++ u64 afe_clock = (u64)clock * 1000 * 5; /* AFE Clock is 5x Pixel clock, in Hz */ + + for (d = 0; d < ARRAY_SIZE(dividers); d++) { + for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) { +@@ -1713,7 +1713,7 @@ static int skl_ddi_hdmi_pll_dividers(struct intel_crtc_state *crtc_state) + + ctrl1 |= DPLL_CTRL1_HDMI_MODE(0); + +- ret = skl_ddi_calculate_wrpll(crtc_state->port_clock * 1000, ++ ret = skl_ddi_calculate_wrpll(crtc_state->port_clock, + i915->display.dpll.ref_clks.nssc, &wrpll_params); + if (ret) + return ret; +diff --git a/drivers/gpu/drm/i915/display/intel_hdcp_regs.h b/drivers/gpu/drm/i915/display/intel_hdcp_regs.h +index 8023c85c7fa0e..74059384892af 100644 +--- a/drivers/gpu/drm/i915/display/intel_hdcp_regs.h ++++ b/drivers/gpu/drm/i915/display/intel_hdcp_regs.h +@@ -249,7 +249,7 @@ + #define HDCP2_STREAM_STATUS(dev_priv, trans, port) \ + (GRAPHICS_VER(dev_priv) >= 12 ? \ + TRANS_HDCP2_STREAM_STATUS(trans) : \ +- PIPE_HDCP2_STREAM_STATUS(pipe)) ++ PIPE_HDCP2_STREAM_STATUS(port)) + + #define _PORTA_HDCP2_AUTH_STREAM 0x66F00 + #define _PORTB_HDCP2_AUTH_STREAM 0x66F04 +diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c +index 3f90403d86cb4..0808b54d3c518 100644 +--- a/drivers/gpu/drm/i915/i915_perf.c ++++ b/drivers/gpu/drm/i915/i915_perf.c +@@ -2781,26 +2781,6 @@ oa_configure_all_contexts(struct i915_perf_stream *stream, + return 0; + } + +-static int +-gen12_configure_all_contexts(struct i915_perf_stream *stream, +- const struct i915_oa_config *oa_config, +- struct i915_active *active) +-{ +- struct flex regs[] = { +- { +- GEN8_R_PWR_CLK_STATE(RENDER_RING_BASE), +- CTX_R_PWR_CLK_STATE, +- }, +- }; +- +- if (stream->engine->class != RENDER_CLASS) +- return 0; +- +- return oa_configure_all_contexts(stream, +- regs, ARRAY_SIZE(regs), +- active); +-} +- + static int + lrc_configure_all_contexts(struct i915_perf_stream *stream, + const struct i915_oa_config *oa_config, +@@ -2907,7 +2887,6 @@ gen12_enable_metric_set(struct i915_perf_stream *stream, + { + struct drm_i915_private *i915 = stream->perf->i915; + struct intel_uncore *uncore = stream->uncore; +- struct i915_oa_config *oa_config = stream->oa_config; + bool periodic = stream->periodic; + u32 period_exponent = stream->period_exponent; + u32 sqcnt1; +@@ -2951,15 +2930,6 @@ gen12_enable_metric_set(struct i915_perf_stream *stream, + + intel_uncore_rmw(uncore, GEN12_SQCNT1, 0, sqcnt1); + +- /* +- * Update all contexts prior writing the mux configurations as we need +- * to make sure all slices/subslices are ON before writing to NOA +- * registers. +- */ +- ret = gen12_configure_all_contexts(stream, oa_config, active); +- if (ret) +- return ret; +- + /* + * For Gen12, performance counters are context + * saved/restored. Only enable it for the context that +@@ -3014,9 +2984,6 @@ static void gen12_disable_metric_set(struct i915_perf_stream *stream) + _MASKED_BIT_DISABLE(GEN12_DISABLE_DOP_GATING)); + } + +- /* Reset all contexts' slices/subslices configurations. */ +- gen12_configure_all_contexts(stream, NULL, NULL); +- + /* disable the context save/restore or OAR counters */ + if (stream->ctx) + gen12_configure_oar_context(stream, NULL); +diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c +index 1b2ff0c40fc1c..6c599a9f49ee4 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_prime.c ++++ b/drivers/gpu/drm/nouveau/nouveau_prime.c +@@ -64,7 +64,8 @@ struct drm_gem_object *nouveau_gem_prime_import_sg_table(struct drm_device *dev, + * to the caller, instead of a normal nouveau_bo ttm reference. */ + ret = drm_gem_object_init(dev, &nvbo->bo.base, size); + if (ret) { +- nouveau_bo_ref(NULL, &nvbo); ++ drm_gem_object_release(&nvbo->bo.base); ++ kfree(nvbo); + obj = ERR_PTR(-ENOMEM); + goto unlock; + } +diff --git a/drivers/gpu/drm/virtio/virtgpu_submit.c b/drivers/gpu/drm/virtio/virtgpu_submit.c +index 5c514946bbad9..d530c058f53e2 100644 +--- a/drivers/gpu/drm/virtio/virtgpu_submit.c ++++ b/drivers/gpu/drm/virtio/virtgpu_submit.c +@@ -48,7 +48,7 @@ struct virtio_gpu_submit { + static int virtio_gpu_do_fence_wait(struct virtio_gpu_submit *submit, + struct dma_fence *in_fence) + { +- u32 context = submit->fence_ctx + submit->ring_idx; ++ u64 context = submit->fence_ctx + submit->ring_idx; + + if (dma_fence_match_context(in_fence, context)) + return 0; +diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +index 5efc6a766f64e..588d50ababf60 100644 +--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c ++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +@@ -32,7 +32,6 @@ + #define VMW_FENCE_WRAP (1 << 31) + + struct vmw_fence_manager { +- int num_fence_objects; + struct vmw_private *dev_priv; + spinlock_t lock; + struct list_head fence_list; +@@ -124,13 +123,13 @@ static void vmw_fence_obj_destroy(struct dma_fence *f) + { + struct vmw_fence_obj *fence = + container_of(f, struct vmw_fence_obj, base); +- + struct vmw_fence_manager *fman = fman_from_fence(fence); + +- spin_lock(&fman->lock); +- list_del_init(&fence->head); +- --fman->num_fence_objects; +- spin_unlock(&fman->lock); ++ if (!list_empty(&fence->head)) { ++ spin_lock(&fman->lock); ++ list_del_init(&fence->head); ++ spin_unlock(&fman->lock); ++ } + fence->destroy(fence); + } + +@@ -257,7 +256,6 @@ static const struct dma_fence_ops vmw_fence_ops = { + .release = vmw_fence_obj_destroy, + }; + +- + /* + * Execute signal actions on fences recently signaled. + * This is done from a workqueue so we don't have to execute +@@ -355,7 +353,6 @@ static int vmw_fence_obj_init(struct vmw_fence_manager *fman, + goto out_unlock; + } + list_add_tail(&fence->head, &fman->fence_list); +- ++fman->num_fence_objects; + + out_unlock: + spin_unlock(&fman->lock); +@@ -403,7 +400,7 @@ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman, + u32 passed_seqno) + { + u32 goal_seqno; +- struct vmw_fence_obj *fence; ++ struct vmw_fence_obj *fence, *next_fence; + + if (likely(!fman->seqno_valid)) + return false; +@@ -413,7 +410,7 @@ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman, + return false; + + fman->seqno_valid = false; +- list_for_each_entry(fence, &fman->fence_list, head) { ++ list_for_each_entry_safe(fence, next_fence, &fman->fence_list, head) { + if (!list_empty(&fence->seq_passed_actions)) { + fman->seqno_valid = true; + vmw_fence_goal_write(fman->dev_priv, +diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +index c45b4724e4141..e20f64b67b266 100644 +--- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c ++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +@@ -92,7 +92,7 @@ static int vmw_overlay_send_put(struct vmw_private *dev_priv, + { + struct vmw_escape_video_flush *flush; + size_t fifo_size; +- bool have_so = (dev_priv->active_display_unit == vmw_du_screen_object); ++ bool have_so = (dev_priv->active_display_unit != vmw_du_legacy); + int i, num_items; + SVGAGuestPtr ptr; + +diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +index 4ccab07faff08..cb03c589ab226 100644 +--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c ++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +@@ -868,6 +868,32 @@ vmw_stdu_connector_mode_valid(struct drm_connector *connector, + return MODE_OK; + } + ++/* ++ * Trigger a modeset if the X,Y position of the Screen Target changes. ++ * This is needed when multi-mon is cycled. The original Screen Target will have ++ * the same mode but its relative X,Y position in the topology will change. ++ */ ++static int vmw_stdu_connector_atomic_check(struct drm_connector *conn, ++ struct drm_atomic_state *state) ++{ ++ struct drm_connector_state *conn_state; ++ struct vmw_screen_target_display_unit *du; ++ struct drm_crtc_state *new_crtc_state; ++ ++ conn_state = drm_atomic_get_connector_state(state, conn); ++ du = vmw_connector_to_stdu(conn); ++ ++ if (!conn_state->crtc) ++ return 0; ++ ++ new_crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); ++ if (du->base.gui_x != du->base.set_gui_x || ++ du->base.gui_y != du->base.set_gui_y) ++ new_crtc_state->mode_changed = true; ++ ++ return 0; ++} ++ + static const struct drm_connector_funcs vmw_stdu_connector_funcs = { + .dpms = vmw_du_connector_dpms, + .detect = vmw_du_connector_detect, +@@ -882,7 +908,8 @@ static const struct drm_connector_funcs vmw_stdu_connector_funcs = { + static const struct + drm_connector_helper_funcs vmw_stdu_connector_helper_funcs = { + .get_modes = vmw_connector_get_modes, +- .mode_valid = vmw_stdu_connector_mode_valid ++ .mode_valid = vmw_stdu_connector_mode_valid, ++ .atomic_check = vmw_stdu_connector_atomic_check, + }; + + +diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c +index bdb578e0899f5..4b59687ff5d82 100644 +--- a/drivers/hid/amd-sfh-hid/amd_sfh_client.c ++++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c +@@ -288,12 +288,22 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) + mp2_ops->start(privdata, info); + cl_data->sensor_sts[i] = amd_sfh_wait_for_response + (privdata, cl_data->sensor_idx[i], SENSOR_ENABLED); ++ ++ if (cl_data->sensor_sts[i] == SENSOR_ENABLED) ++ cl_data->is_any_sensor_enabled = true; ++ } ++ ++ if (!cl_data->is_any_sensor_enabled || ++ (mp2_ops->discovery_status && mp2_ops->discovery_status(privdata) == 0)) { ++ dev_warn(dev, "Failed to discover, sensors not enabled is %d\n", ++ cl_data->is_any_sensor_enabled); ++ rc = -EOPNOTSUPP; ++ goto cleanup; + } + + for (i = 0; i < cl_data->num_hid_devices; i++) { + cl_data->cur_hid_dev = i; + if (cl_data->sensor_sts[i] == SENSOR_ENABLED) { +- cl_data->is_any_sensor_enabled = true; + rc = amdtp_hid_probe(i, cl_data); + if (rc) + goto cleanup; +@@ -305,12 +315,6 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) + cl_data->sensor_sts[i]); + } + +- if (!cl_data->is_any_sensor_enabled || +- (mp2_ops->discovery_status && mp2_ops->discovery_status(privdata) == 0)) { +- dev_warn(dev, "Failed to discover, sensors not enabled is %d\n", cl_data->is_any_sensor_enabled); +- rc = -EOPNOTSUPP; +- goto cleanup; +- } + schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); + return 0; + +diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c +index 002cbaa16bd16..d2fe14ce423e2 100644 +--- a/drivers/hid/wacom_wac.c ++++ b/drivers/hid/wacom_wac.c +@@ -714,13 +714,12 @@ static int wacom_intuos_get_tool_type(int tool_id) + case 0x8e2: /* IntuosHT2 pen */ + case 0x022: + case 0x200: /* Pro Pen 3 */ +- case 0x04200: /* Pro Pen 3 */ + case 0x10842: /* MobileStudio Pro Pro Pen slim */ + case 0x14802: /* Intuos4/5 13HD/24HD Classic Pen */ + case 0x16802: /* Cintiq 13HD Pro Pen */ + case 0x18802: /* DTH2242 Pen */ + case 0x10802: /* Intuos4/5 13HD/24HD General Pen */ +- case 0x80842: /* Intuos Pro and Cintiq Pro 3D Pen */ ++ case 0x8842: /* Intuos Pro and Cintiq Pro 3D Pen */ + tool_type = BTN_TOOL_PEN; + break; + +diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c +index 4f5829b726a75..72fd2fe8f6fe8 100644 +--- a/drivers/leds/led-triggers.c ++++ b/drivers/leds/led-triggers.c +@@ -194,11 +194,24 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig) + spin_unlock(&trig->leddev_list_lock); + led_cdev->trigger = trig; + ++ /* ++ * Some activate() calls use led_trigger_event() to initialize ++ * the brightness of the LED for which the trigger is being set. ++ * Ensure the led_cdev is visible on trig->led_cdevs for this. ++ */ ++ synchronize_rcu(); ++ ++ /* ++ * If "set brightness to 0" is pending in workqueue, ++ * we don't want that to be reordered after ->activate() ++ */ ++ flush_work(&led_cdev->set_brightness_work); ++ ++ ret = 0; + if (trig->activate) + ret = trig->activate(led_cdev); + else +- ret = 0; +- ++ led_set_brightness(led_cdev, trig->brightness); + if (ret) + goto err_activate; + +@@ -269,19 +282,6 @@ void led_trigger_set_default(struct led_classdev *led_cdev) + } + EXPORT_SYMBOL_GPL(led_trigger_set_default); + +-void led_trigger_rename_static(const char *name, struct led_trigger *trig) +-{ +- /* new name must be on a temporary string to prevent races */ +- BUG_ON(name == trig->name); +- +- down_write(&triggers_list_lock); +- /* this assumes that trig->name was originaly allocated to +- * non constant storage */ +- strcpy((char *)trig->name, name); +- up_write(&triggers_list_lock); +-} +-EXPORT_SYMBOL_GPL(led_trigger_rename_static); +- + /* LED Trigger Interface */ + + int led_trigger_register(struct led_trigger *trig) +@@ -386,6 +386,8 @@ void led_trigger_event(struct led_trigger *trig, + if (!trig) + return; + ++ trig->brightness = brightness; ++ + rcu_read_lock(); + list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list) + led_set_brightness(led_cdev, brightness); +diff --git a/drivers/leds/trigger/ledtrig-timer.c b/drivers/leds/trigger/ledtrig-timer.c +index b4688d1d9d2b2..1d213c999d40a 100644 +--- a/drivers/leds/trigger/ledtrig-timer.c ++++ b/drivers/leds/trigger/ledtrig-timer.c +@@ -110,11 +110,6 @@ static int timer_trig_activate(struct led_classdev *led_cdev) + led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER; + } + +- /* +- * If "set brightness to 0" is pending in workqueue, we don't +- * want that to be reordered after blink_set() +- */ +- flush_work(&led_cdev->set_brightness_work); + led_blink_set(led_cdev, &led_cdev->blink_delay_on, + &led_cdev->blink_delay_off); + +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c +index 24c914015973e..49b1fa9651161 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.c ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c +@@ -456,7 +456,7 @@ void ice_free_rx_ring(struct ice_rx_ring *rx_ring) + if (rx_ring->vsi->type == ICE_VSI_PF) + if (xdp_rxq_info_is_reg(&rx_ring->xdp_rxq)) + xdp_rxq_info_unreg(&rx_ring->xdp_rxq); +- rx_ring->xdp_prog = NULL; ++ WRITE_ONCE(rx_ring->xdp_prog, NULL); + if (rx_ring->xsk_pool) { + kfree(rx_ring->xdp_buf); + rx_ring->xdp_buf = NULL; +diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c +index f53566cb6bfbd..67511153081ae 100644 +--- a/drivers/net/ethernet/intel/ice/ice_xsk.c ++++ b/drivers/net/ethernet/intel/ice/ice_xsk.c +@@ -52,10 +52,8 @@ static void ice_qp_reset_stats(struct ice_vsi *vsi, u16 q_idx) + static void ice_qp_clean_rings(struct ice_vsi *vsi, u16 q_idx) + { + ice_clean_tx_ring(vsi->tx_rings[q_idx]); +- if (ice_is_xdp_ena_vsi(vsi)) { +- synchronize_rcu(); ++ if (ice_is_xdp_ena_vsi(vsi)) + ice_clean_tx_ring(vsi->xdp_rings[q_idx]); +- } + ice_clean_rx_ring(vsi->rx_rings[q_idx]); + } + +@@ -180,11 +178,12 @@ static int ice_qp_dis(struct ice_vsi *vsi, u16 q_idx) + usleep_range(1000, 2000); + } + ++ synchronize_net(); ++ netif_tx_stop_queue(netdev_get_tx_queue(vsi->netdev, q_idx)); ++ + ice_qvec_dis_irq(vsi, rx_ring, q_vector); + ice_qvec_toggle_napi(vsi, q_vector, false); + +- netif_tx_stop_queue(netdev_get_tx_queue(vsi->netdev, q_idx)); +- + ice_fill_txq_meta(vsi, tx_ring, &txq_meta); + err = ice_vsi_stop_tx_ring(vsi, ICE_NO_RESET, 0, tx_ring, &txq_meta); + if (err) +@@ -199,10 +198,8 @@ static int ice_qp_dis(struct ice_vsi *vsi, u16 q_idx) + if (err) + return err; + } +- err = ice_vsi_ctrl_one_rx_ring(vsi, false, q_idx, true); +- if (err) +- return err; + ++ ice_vsi_ctrl_one_rx_ring(vsi, false, q_idx, false); + ice_qp_clean_rings(vsi, q_idx); + ice_qp_reset_stats(vsi, q_idx); + +@@ -1068,6 +1065,10 @@ bool ice_xmit_zc(struct ice_tx_ring *xdp_ring) + + ice_clean_xdp_irq_zc(xdp_ring); + ++ if (!netif_carrier_ok(xdp_ring->vsi->netdev) || ++ !netif_running(xdp_ring->vsi->netdev)) ++ return true; ++ + budget = ICE_DESC_UNUSED(xdp_ring); + budget = min_t(u16, budget, ICE_RING_QUARTER(xdp_ring)); + +@@ -1111,7 +1112,7 @@ ice_xsk_wakeup(struct net_device *netdev, u32 queue_id, + struct ice_vsi *vsi = np->vsi; + struct ice_tx_ring *ring; + +- if (test_bit(ICE_VSI_DOWN, vsi->state)) ++ if (test_bit(ICE_VSI_DOWN, vsi->state) || !netif_carrier_ok(netdev)) + return -ENETDOWN; + + if (!ice_is_xdp_ena_vsi(vsi)) +diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c +index e83700ad7e622..d80bbcdeb93ed 100644 +--- a/drivers/net/ethernet/intel/igc/igc_main.c ++++ b/drivers/net/ethernet/intel/igc/igc_main.c +@@ -6208,21 +6208,6 @@ static int igc_save_qbv_schedule(struct igc_adapter *adapter, + size_t n; + int i; + +- switch (qopt->cmd) { +- case TAPRIO_CMD_REPLACE: +- break; +- case TAPRIO_CMD_DESTROY: +- return igc_tsn_clear_schedule(adapter); +- case TAPRIO_CMD_STATS: +- igc_taprio_stats(adapter->netdev, &qopt->stats); +- return 0; +- case TAPRIO_CMD_QUEUE_STATS: +- igc_taprio_queue_stats(adapter->netdev, &qopt->queue_stats); +- return 0; +- default: +- return -EOPNOTSUPP; +- } +- + if (qopt->base_time < 0) + return -ERANGE; + +@@ -6331,7 +6316,23 @@ static int igc_tsn_enable_qbv_scheduling(struct igc_adapter *adapter, + if (hw->mac.type != igc_i225) + return -EOPNOTSUPP; + +- err = igc_save_qbv_schedule(adapter, qopt); ++ switch (qopt->cmd) { ++ case TAPRIO_CMD_REPLACE: ++ err = igc_save_qbv_schedule(adapter, qopt); ++ break; ++ case TAPRIO_CMD_DESTROY: ++ err = igc_tsn_clear_schedule(adapter); ++ break; ++ case TAPRIO_CMD_STATS: ++ igc_taprio_stats(adapter->netdev, &qopt->stats); ++ return 0; ++ case TAPRIO_CMD_QUEUE_STATS: ++ igc_taprio_queue_stats(adapter->netdev, &qopt->queue_stats); ++ return 0; ++ default: ++ return -EOPNOTSUPP; ++ } ++ + if (err) + return err; + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +index 05f4aa11b95c3..34051c9abd97d 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -953,13 +953,13 @@ static void mvpp2_bm_pool_update_fc(struct mvpp2_port *port, + static void mvpp2_bm_pool_update_priv_fc(struct mvpp2 *priv, bool en) + { + struct mvpp2_port *port; +- int i; ++ int i, j; + + for (i = 0; i < priv->port_count; i++) { + port = priv->port_list[i]; + if (port->priv->percpu_pools) { +- for (i = 0; i < port->nrxqs; i++) +- mvpp2_bm_pool_update_fc(port, &port->priv->bm_pools[i], ++ for (j = 0; j < port->nrxqs; j++) ++ mvpp2_bm_pool_update_fc(port, &port->priv->bm_pools[j], + port->tx_fc & en); + } else { + mvpp2_bm_pool_update_fc(port, port->pool_long, port->tx_fc & en); +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c +index fadfa8b50bebe..8c4e3ecef5901 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c +@@ -920,6 +920,7 @@ mlx5_tc_ct_entry_replace_rule(struct mlx5_tc_ct_priv *ct_priv, + mlx5_tc_ct_entry_destroy_mod_hdr(ct_priv, zone_rule->attr, mh); + mlx5_put_label_mapping(ct_priv, attr->ct_attr.ct_labels_id); + err_mod_hdr: ++ *attr = *old_attr; + kfree(old_attr); + err_attr: + kvfree(spec); +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c +index ce29e31721208..de83567aae791 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c +@@ -50,9 +50,10 @@ u32 mlx5_ipsec_device_caps(struct mlx5_core_dev *mdev) + MLX5_CAP_FLOWTABLE_NIC_RX(mdev, decap)) + caps |= MLX5_IPSEC_CAP_PACKET_OFFLOAD; + +- if ((MLX5_CAP_FLOWTABLE_NIC_TX(mdev, ignore_flow_level) && +- MLX5_CAP_FLOWTABLE_NIC_RX(mdev, ignore_flow_level)) || +- MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, ignore_flow_level)) ++ if (IS_ENABLED(CONFIG_MLX5_CLS_ACT) && ++ ((MLX5_CAP_FLOWTABLE_NIC_TX(mdev, ignore_flow_level) && ++ MLX5_CAP_FLOWTABLE_NIC_RX(mdev, ignore_flow_level)) || ++ MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, ignore_flow_level))) + caps |= MLX5_IPSEC_CAP_PRIO; + + if (MLX5_CAP_FLOWTABLE_NIC_TX(mdev, +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +index 38263d5c98b34..50db127e6371b 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +@@ -1223,7 +1223,12 @@ int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv, + if (!an_changes && link_modes == eproto.admin) + goto out; + +- mlx5_port_set_eth_ptys(mdev, an_disable, link_modes, ext); ++ err = mlx5_port_set_eth_ptys(mdev, an_disable, link_modes, ext); ++ if (err) { ++ netdev_err(priv->netdev, "%s: failed to set ptys reg: %d\n", __func__, err); ++ goto out; ++ } ++ + mlx5_toggle_port_link(mdev); + + out: +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +index 3a9cdf79403ae..6b17346aa4cef 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +@@ -206,6 +206,7 @@ int mlx5_fw_reset_set_live_patch(struct mlx5_core_dev *dev) + static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev, bool unloaded) + { + struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset; ++ struct devlink *devlink = priv_to_devlink(dev); + + /* if this is the driver that initiated the fw reset, devlink completed the reload */ + if (test_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags)) { +@@ -217,9 +218,11 @@ static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev, bool unload + mlx5_core_err(dev, "reset reload flow aborted, PCI reads still not working\n"); + else + mlx5_load_one(dev, true); +- devlink_remote_reload_actions_performed(priv_to_devlink(dev), 0, ++ devl_lock(devlink); ++ devlink_remote_reload_actions_performed(devlink, 0, + BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) | + BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE)); ++ devl_unlock(devlink); + } + } + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c b/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c +index 612e666ec2635..e2230c8f18152 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/irq_affinity.c +@@ -48,6 +48,7 @@ static struct mlx5_irq * + irq_pool_request_irq(struct mlx5_irq_pool *pool, struct irq_affinity_desc *af_desc) + { + struct irq_affinity_desc auto_desc = {}; ++ struct mlx5_irq *irq; + u32 irq_index; + int err; + +@@ -64,9 +65,12 @@ irq_pool_request_irq(struct mlx5_irq_pool *pool, struct irq_affinity_desc *af_de + else + cpu_get(pool, cpumask_first(&af_desc->mask)); + } +- return mlx5_irq_alloc(pool, irq_index, +- cpumask_empty(&auto_desc.mask) ? af_desc : &auto_desc, +- NULL); ++ irq = mlx5_irq_alloc(pool, irq_index, ++ cpumask_empty(&auto_desc.mask) ? af_desc : &auto_desc, ++ NULL); ++ if (IS_ERR(irq)) ++ xa_erase(&pool->irqs, irq_index); ++ return irq; + } + + /* Looking for the IRQ with the smallest refcount that fits req_mask. +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +index dfc2ba6f780a2..18cf756bad8cc 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +@@ -1512,7 +1512,7 @@ u8 mlx5_lag_get_slave_port(struct mlx5_core_dev *dev, + goto unlock; + + for (i = 0; i < ldev->ports; i++) { +- if (ldev->pf[MLX5_LAG_P1].netdev == slave) { ++ if (ldev->pf[i].netdev == slave) { + port = i; + break; + } +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c +index 2237b3d01e0e5..11f11248feb8b 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c +@@ -2130,7 +2130,6 @@ static int mlx5_try_fast_unload(struct mlx5_core_dev *dev) + /* Panic tear down fw command will stop the PCI bus communication + * with the HCA, so the health poll is no longer needed. + */ +- mlx5_drain_health_wq(dev); + mlx5_stop_health_poll(dev, false); + + ret = mlx5_cmd_fast_teardown_hca(dev); +@@ -2165,6 +2164,7 @@ static void shutdown(struct pci_dev *pdev) + + mlx5_core_info(dev, "Shutdown was called\n"); + set_bit(MLX5_BREAK_FW_WAIT, &dev->intf_state); ++ mlx5_drain_health_wq(dev); + err = mlx5_try_fast_unload(dev); + if (err) + mlx5_unload_one(dev, false); +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c +index 30218f37d5285..2028acbe85ca2 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c +@@ -90,6 +90,7 @@ static void mlx5_sf_dev_shutdown(struct auxiliary_device *adev) + struct mlx5_core_dev *mdev = sf_dev->mdev; + + set_bit(MLX5_BREAK_FW_WAIT, &mdev->intf_state); ++ mlx5_drain_health_wq(mdev); + mlx5_unload_one(mdev, false); + } + +diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c +index d759f3373b175..8a732edac15a0 100644 +--- a/drivers/net/ethernet/realtek/r8169_main.c ++++ b/drivers/net/ethernet/realtek/r8169_main.c +@@ -4256,7 +4256,8 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, + if (unlikely(!rtl_tx_slots_avail(tp))) { + if (net_ratelimit()) + netdev_err(dev, "BUG! Tx Ring full when queue awake!\n"); +- goto err_stop_0; ++ netif_stop_queue(dev); ++ return NETDEV_TX_BUSY; + } + + opts[1] = rtl8169_tx_vlan_tag(skb); +@@ -4312,11 +4313,6 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, + dev_kfree_skb_any(skb); + dev->stats.tx_dropped++; + return NETDEV_TX_OK; +- +-err_stop_0: +- netif_stop_queue(dev); +- dev->stats.tx_dropped++; +- return NETDEV_TX_BUSY; + } + + static unsigned int rtl_last_frag_len(struct sk_buff *skb) +diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +index 3297aff969c80..11e08cb8d3c3e 100644 +--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c ++++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +@@ -1826,9 +1826,9 @@ static void axienet_dma_err_handler(struct work_struct *work) + ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN)); + axienet_set_mac_address(ndev, NULL); + axienet_set_multicast_list(ndev); +- axienet_setoptions(ndev, lp->options); + napi_enable(&lp->napi_rx); + napi_enable(&lp->napi_tx); ++ axienet_setoptions(ndev, lp->options); + } + + /** +diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c +index 029c82f88ee38..9a0432145645f 100644 +--- a/drivers/net/phy/micrel.c ++++ b/drivers/net/phy/micrel.c +@@ -1293,6 +1293,8 @@ static int ksz9131_config_init(struct phy_device *phydev) + const struct device *dev_walker; + int ret; + ++ phydev->mdix_ctrl = ETH_TP_MDI_AUTO; ++ + dev_walker = &phydev->mdio.dev; + do { + of_node = dev_walker->of_node; +@@ -1342,28 +1344,30 @@ static int ksz9131_config_init(struct phy_device *phydev) + #define MII_KSZ9131_AUTO_MDIX 0x1C + #define MII_KSZ9131_AUTO_MDI_SET BIT(7) + #define MII_KSZ9131_AUTO_MDIX_SWAP_OFF BIT(6) ++#define MII_KSZ9131_DIG_AXAN_STS 0x14 ++#define MII_KSZ9131_DIG_AXAN_STS_LINK_DET BIT(14) ++#define MII_KSZ9131_DIG_AXAN_STS_A_SELECT BIT(12) + + static int ksz9131_mdix_update(struct phy_device *phydev) + { + int ret; + +- ret = phy_read(phydev, MII_KSZ9131_AUTO_MDIX); +- if (ret < 0) +- return ret; +- +- if (ret & MII_KSZ9131_AUTO_MDIX_SWAP_OFF) { +- if (ret & MII_KSZ9131_AUTO_MDI_SET) +- phydev->mdix_ctrl = ETH_TP_MDI; +- else +- phydev->mdix_ctrl = ETH_TP_MDI_X; ++ if (phydev->mdix_ctrl != ETH_TP_MDI_AUTO) { ++ phydev->mdix = phydev->mdix_ctrl; + } else { +- phydev->mdix_ctrl = ETH_TP_MDI_AUTO; +- } ++ ret = phy_read(phydev, MII_KSZ9131_DIG_AXAN_STS); ++ if (ret < 0) ++ return ret; + +- if (ret & MII_KSZ9131_AUTO_MDI_SET) +- phydev->mdix = ETH_TP_MDI; +- else +- phydev->mdix = ETH_TP_MDI_X; ++ if (ret & MII_KSZ9131_DIG_AXAN_STS_LINK_DET) { ++ if (ret & MII_KSZ9131_DIG_AXAN_STS_A_SELECT) ++ phydev->mdix = ETH_TP_MDI; ++ else ++ phydev->mdix = ETH_TP_MDI_X; ++ } else { ++ phydev->mdix = ETH_TP_MDI_INVALID; ++ } ++ } + + return 0; + } +diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c +index 337899c69738e..2604d9663a5b2 100644 +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -1083,6 +1083,13 @@ static struct phy_driver realtek_drvs[] = { + .handle_interrupt = genphy_handle_interrupt_no_ack, + .suspend = genphy_suspend, + .resume = genphy_resume, ++ }, { ++ PHY_ID_MATCH_EXACT(0x001cc960), ++ .name = "RTL8366S Gigabit Ethernet", ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_mmd = genphy_read_mmd_unsupported, ++ .write_mmd = genphy_write_mmd_unsupported, + }, + }; + +diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c +index 0a662e42ed965..cb7d2f798fb43 100644 +--- a/drivers/net/usb/sr9700.c ++++ b/drivers/net/usb/sr9700.c +@@ -179,6 +179,7 @@ static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc) + struct usbnet *dev = netdev_priv(netdev); + __le16 res; + int rc = 0; ++ int err; + + if (phy_id) { + netdev_dbg(netdev, "Only internal phy supported\n"); +@@ -189,11 +190,17 @@ static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc) + if (loc == MII_BMSR) { + u8 value; + +- sr_read_reg(dev, SR_NSR, &value); ++ err = sr_read_reg(dev, SR_NSR, &value); ++ if (err < 0) ++ return err; ++ + if (value & NSR_LINKST) + rc = 1; + } +- sr_share_read_word(dev, 1, loc, &res); ++ err = sr_share_read_word(dev, 1, loc, &res); ++ if (err < 0) ++ return err; ++ + if (rc == 1) + res = le16_to_cpu(res) | BMSR_LSTATUS; + else +diff --git a/drivers/pci/search.c b/drivers/pci/search.c +index b4c138a6ec025..53840634fbfc2 100644 +--- a/drivers/pci/search.c ++++ b/drivers/pci/search.c +@@ -363,6 +363,37 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from) + } + EXPORT_SYMBOL(pci_get_class); + ++/** ++ * pci_get_base_class - searching for a PCI device by matching against the base class code only ++ * @class: search for a PCI device with this base class code ++ * @from: Previous PCI device found in search, or %NULL for new search. ++ * ++ * Iterates through the list of known PCI devices. If a PCI device is found ++ * with a matching base class code, the reference count to the device is ++ * incremented. See pci_match_one_device() to figure out how does this works. ++ * A new search is initiated by passing %NULL as the @from argument. ++ * Otherwise if @from is not %NULL, searches continue from next device on the ++ * global list. The reference count for @from is always decremented if it is ++ * not %NULL. ++ * ++ * Returns: ++ * A pointer to a matched PCI device, %NULL Otherwise. ++ */ ++struct pci_dev *pci_get_base_class(unsigned int class, struct pci_dev *from) ++{ ++ struct pci_device_id id = { ++ .vendor = PCI_ANY_ID, ++ .device = PCI_ANY_ID, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .class_mask = 0xFF0000, ++ .class = class << 16, ++ }; ++ ++ return pci_get_dev_by_id(&id, from); ++} ++EXPORT_SYMBOL(pci_get_base_class); ++ + /** + * pci_dev_present - Returns 1 if device matching the device list is present, 0 if not. + * @ids: A pointer to a null terminated list of struct pci_device_id structures +diff --git a/drivers/perf/fsl_imx9_ddr_perf.c b/drivers/perf/fsl_imx9_ddr_perf.c +index 5cf770a1bc312..4f6eade522024 100644 +--- a/drivers/perf/fsl_imx9_ddr_perf.c ++++ b/drivers/perf/fsl_imx9_ddr_perf.c +@@ -476,12 +476,12 @@ static int ddr_perf_event_add(struct perf_event *event, int flags) + hwc->idx = counter; + hwc->state |= PERF_HES_STOPPED; + +- if (flags & PERF_EF_START) +- ddr_perf_event_start(event, flags); +- + /* read trans, write trans, read beat */ + ddr_perf_monitor_config(pmu, cfg, cfg1, cfg2); + ++ if (flags & PERF_EF_START) ++ ddr_perf_event_start(event, flags); ++ + return 0; + } + +diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c +index ae16ecb15f2d9..901da688ea3f8 100644 +--- a/drivers/perf/riscv_pmu_sbi.c ++++ b/drivers/perf/riscv_pmu_sbi.c +@@ -355,7 +355,7 @@ static int pmu_sbi_ctr_get_idx(struct perf_event *event) + * but not in the user access mode as we want to use the other counters + * that support sampling/filtering. + */ +- if (hwc->flags & PERF_EVENT_FLAG_LEGACY) { ++ if ((hwc->flags & PERF_EVENT_FLAG_LEGACY) && (event->attr.type == PERF_TYPE_HARDWARE)) { + if (event->attr.config == PERF_COUNT_HW_CPU_CYCLES) { + cflags |= SBI_PMU_CFG_FLAG_SKIP_MATCH; + cmask = 1; +diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c +index 475a6dd72db6b..809fabef3b44a 100644 +--- a/drivers/platform/chrome/cros_ec_proto.c ++++ b/drivers/platform/chrome/cros_ec_proto.c +@@ -805,9 +805,11 @@ int cros_ec_get_next_event(struct cros_ec_device *ec_dev, + if (ret == -ENOPROTOOPT) { + dev_dbg(ec_dev->dev, + "GET_NEXT_EVENT returned invalid version error.\n"); ++ mutex_lock(&ec_dev->lock); + ret = cros_ec_get_host_command_version_mask(ec_dev, + EC_CMD_GET_NEXT_EVENT, + &ver_mask); ++ mutex_unlock(&ec_dev->lock); + if (ret < 0 || ver_mask == 0) + /* + * Do not change the MKBP supported version if we can't +diff --git a/drivers/thermal/broadcom/bcm2835_thermal.c b/drivers/thermal/broadcom/bcm2835_thermal.c +index 3acc9288b3105..3b1030fc4fbfe 100644 +--- a/drivers/thermal/broadcom/bcm2835_thermal.c ++++ b/drivers/thermal/broadcom/bcm2835_thermal.c +@@ -185,7 +185,7 @@ static int bcm2835_thermal_probe(struct platform_device *pdev) + return err; + } + +- data->clk = devm_clk_get(&pdev->dev, NULL); ++ data->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(data->clk)) { + err = PTR_ERR(data->clk); + if (err != -EPROBE_DEFER) +@@ -193,10 +193,6 @@ static int bcm2835_thermal_probe(struct platform_device *pdev) + return err; + } + +- err = clk_prepare_enable(data->clk); +- if (err) +- return err; +- + rate = clk_get_rate(data->clk); + if ((rate < 1920000) || (rate > 5000000)) + dev_warn(&pdev->dev, +@@ -211,7 +207,7 @@ static int bcm2835_thermal_probe(struct platform_device *pdev) + dev_err(&pdev->dev, + "Failed to register the thermal device: %d\n", + err); +- goto err_clk; ++ return err; + } + + /* +@@ -236,7 +232,7 @@ static int bcm2835_thermal_probe(struct platform_device *pdev) + dev_err(&pdev->dev, + "Not able to read trip_temp: %d\n", + err); +- goto err_tz; ++ return err; + } + + /* set bandgap reference voltage and enable voltage regulator */ +@@ -269,32 +265,23 @@ static int bcm2835_thermal_probe(struct platform_device *pdev) + */ + err = thermal_add_hwmon_sysfs(tz); + if (err) +- goto err_tz; ++ return err; + + bcm2835_thermal_debugfs(pdev); + + return 0; +-err_tz: +- devm_thermal_of_zone_unregister(&pdev->dev, tz); +-err_clk: +- clk_disable_unprepare(data->clk); +- +- return err; + } + +-static int bcm2835_thermal_remove(struct platform_device *pdev) ++static void bcm2835_thermal_remove(struct platform_device *pdev) + { + struct bcm2835_thermal_data *data = platform_get_drvdata(pdev); + + debugfs_remove_recursive(data->debugfsdir); +- clk_disable_unprepare(data->clk); +- +- return 0; + } + + static struct platform_driver bcm2835_thermal_driver = { + .probe = bcm2835_thermal_probe, +- .remove = bcm2835_thermal_remove, ++ .remove_new = bcm2835_thermal_remove, + .driver = { + .name = "bcm2835_thermal", + .of_match_table = bcm2835_thermal_of_match_table, +diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig +index b694d7669d320..1eb755a94940a 100644 +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -11,6 +11,10 @@ config APERTURE_HELPERS + Support tracking and hand-over of aperture ownership. Required + by graphics drivers for firmware-provided framebuffers. + ++config SCREEN_INFO ++ bool ++ default n ++ + config STI_CORE + bool + depends on PARISC +diff --git a/drivers/video/Makefile b/drivers/video/Makefile +index 6bbc039508995..6bbf87c1b579e 100644 +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -1,12 +1,16 @@ + # SPDX-License-Identifier: GPL-2.0 + + obj-$(CONFIG_APERTURE_HELPERS) += aperture.o ++obj-$(CONFIG_SCREEN_INFO) += screen_info.o + obj-$(CONFIG_STI_CORE) += sticore.o + obj-$(CONFIG_VGASTATE) += vgastate.o + obj-$(CONFIG_VIDEO_CMDLINE) += cmdline.o + obj-$(CONFIG_VIDEO_NOMODESET) += nomodeset.o + obj-$(CONFIG_HDMI) += hdmi.o + ++screen_info-y := screen_info_generic.o ++screen_info-$(CONFIG_PCI) += screen_info_pci.o ++ + obj-$(CONFIG_VT) += console/ + obj-$(CONFIG_FB_STI) += console/ + obj-$(CONFIG_LOGO) += logo/ +diff --git a/drivers/video/fbdev/vesafb.c b/drivers/video/fbdev/vesafb.c +index c0edceea0a793..a21581b40256c 100644 +--- a/drivers/video/fbdev/vesafb.c ++++ b/drivers/video/fbdev/vesafb.c +@@ -243,6 +243,7 @@ static int vesafb_setup(char *options) + + static int vesafb_probe(struct platform_device *dev) + { ++ struct screen_info *si = &screen_info; + struct fb_info *info; + struct vesafb_par *par; + int i, err; +@@ -255,17 +256,17 @@ static int vesafb_probe(struct platform_device *dev) + fb_get_options("vesafb", &option); + vesafb_setup(option); + +- if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) ++ if (si->orig_video_isVGA != VIDEO_TYPE_VLFB) + return -ENODEV; + +- vga_compat = (screen_info.capabilities & 2) ? 0 : 1; +- vesafb_fix.smem_start = screen_info.lfb_base; +- vesafb_defined.bits_per_pixel = screen_info.lfb_depth; ++ vga_compat = !__screen_info_vbe_mode_nonvga(si); ++ vesafb_fix.smem_start = si->lfb_base; ++ vesafb_defined.bits_per_pixel = si->lfb_depth; + if (15 == vesafb_defined.bits_per_pixel) + vesafb_defined.bits_per_pixel = 16; +- vesafb_defined.xres = screen_info.lfb_width; +- vesafb_defined.yres = screen_info.lfb_height; +- vesafb_fix.line_length = screen_info.lfb_linelength; ++ vesafb_defined.xres = si->lfb_width; ++ vesafb_defined.yres = si->lfb_height; ++ vesafb_fix.line_length = si->lfb_linelength; + vesafb_fix.visual = (vesafb_defined.bits_per_pixel == 8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + +@@ -277,7 +278,7 @@ static int vesafb_probe(struct platform_device *dev) + /* size_total -- all video memory we have. Used for mtrr + * entries, resource allocation and bounds + * checking. */ +- size_total = screen_info.lfb_size * 65536; ++ size_total = si->lfb_size * 65536; + if (vram_total) + size_total = vram_total * 1024 * 1024; + if (size_total < size_vmode) +@@ -297,7 +298,7 @@ static int vesafb_probe(struct platform_device *dev) + vesafb_fix.smem_len = size_remap; + + #ifndef __i386__ +- screen_info.vesapm_seg = 0; ++ si->vesapm_seg = 0; + #endif + + if (!request_mem_region(vesafb_fix.smem_start, size_total, "vesafb")) { +@@ -317,23 +318,26 @@ static int vesafb_probe(struct platform_device *dev) + par = info->par; + info->pseudo_palette = par->pseudo_palette; + +- par->base = screen_info.lfb_base; ++ par->base = si->lfb_base; + par->size = size_total; + + printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n", +- vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, vesafb_fix.line_length, screen_info.pages); ++ vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, ++ vesafb_fix.line_length, si->pages); + +- if (screen_info.vesapm_seg) { ++ if (si->vesapm_seg) { + printk(KERN_INFO "vesafb: protected mode interface info at %04x:%04x\n", +- screen_info.vesapm_seg,screen_info.vesapm_off); ++ si->vesapm_seg, si->vesapm_off); + } + +- if (screen_info.vesapm_seg < 0xc000) ++ if (si->vesapm_seg < 0xc000) + ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */ + + if (ypan || pmi_setpal) { ++ unsigned long pmi_phys; + unsigned short *pmi_base; +- pmi_base = (unsigned short*)phys_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off); ++ pmi_phys = ((unsigned long)si->vesapm_seg << 4) + si->vesapm_off; ++ pmi_base = (unsigned short *)phys_to_virt(pmi_phys); + pmi_start = (void*)((char*)pmi_base + pmi_base[1]); + pmi_pal = (void*)((char*)pmi_base + pmi_base[2]); + printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal); +@@ -377,14 +381,14 @@ static int vesafb_probe(struct platform_device *dev) + vesafb_defined.left_margin = (vesafb_defined.xres / 8) & 0xf8; + vesafb_defined.hsync_len = (vesafb_defined.xres / 8) & 0xf8; + +- vesafb_defined.red.offset = screen_info.red_pos; +- vesafb_defined.red.length = screen_info.red_size; +- vesafb_defined.green.offset = screen_info.green_pos; +- vesafb_defined.green.length = screen_info.green_size; +- vesafb_defined.blue.offset = screen_info.blue_pos; +- vesafb_defined.blue.length = screen_info.blue_size; +- vesafb_defined.transp.offset = screen_info.rsvd_pos; +- vesafb_defined.transp.length = screen_info.rsvd_size; ++ vesafb_defined.red.offset = si->red_pos; ++ vesafb_defined.red.length = si->red_size; ++ vesafb_defined.green.offset = si->green_pos; ++ vesafb_defined.green.length = si->green_size; ++ vesafb_defined.blue.offset = si->blue_pos; ++ vesafb_defined.blue.length = si->blue_size; ++ vesafb_defined.transp.offset = si->rsvd_pos; ++ vesafb_defined.transp.length = si->rsvd_size; + + if (vesafb_defined.bits_per_pixel <= 8) { + depth = vesafb_defined.green.length; +@@ -399,14 +403,14 @@ static int vesafb_probe(struct platform_device *dev) + (vesafb_defined.bits_per_pixel > 8) ? + "Truecolor" : (vga_compat || pmi_setpal) ? + "Pseudocolor" : "Static Pseudocolor", +- screen_info.rsvd_size, +- screen_info.red_size, +- screen_info.green_size, +- screen_info.blue_size, +- screen_info.rsvd_pos, +- screen_info.red_pos, +- screen_info.green_pos, +- screen_info.blue_pos); ++ si->rsvd_size, ++ si->red_size, ++ si->green_size, ++ si->blue_size, ++ si->rsvd_pos, ++ si->red_pos, ++ si->green_pos, ++ si->blue_pos); + + vesafb_fix.ypanstep = ypan ? 1 : 0; + vesafb_fix.ywrapstep = (ypan>1) ? 1 : 0; +diff --git a/drivers/video/screen_info_generic.c b/drivers/video/screen_info_generic.c +new file mode 100644 +index 0000000000000..64117c6367abb +--- /dev/null ++++ b/drivers/video/screen_info_generic.c +@@ -0,0 +1,146 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include <linux/export.h> ++#include <linux/ioport.h> ++#include <linux/screen_info.h> ++#include <linux/string.h> ++ ++static void resource_init_named(struct resource *r, ++ resource_size_t start, resource_size_t size, ++ const char *name, unsigned int flags) ++{ ++ memset(r, 0, sizeof(*r)); ++ ++ r->start = start; ++ r->end = start + size - 1; ++ r->name = name; ++ r->flags = flags; ++} ++ ++static void resource_init_io_named(struct resource *r, ++ resource_size_t start, resource_size_t size, ++ const char *name) ++{ ++ resource_init_named(r, start, size, name, IORESOURCE_IO); ++} ++ ++static void resource_init_mem_named(struct resource *r, ++ resource_size_t start, resource_size_t size, ++ const char *name) ++{ ++ resource_init_named(r, start, size, name, IORESOURCE_MEM); ++} ++ ++static inline bool __screen_info_has_ega_gfx(unsigned int mode) ++{ ++ switch (mode) { ++ case 0x0d: /* 320x200-4 */ ++ case 0x0e: /* 640x200-4 */ ++ case 0x0f: /* 640x350-1 */ ++ case 0x10: /* 640x350-4 */ ++ return true; ++ default: ++ return false; ++ } ++} ++ ++static inline bool __screen_info_has_vga_gfx(unsigned int mode) ++{ ++ switch (mode) { ++ case 0x10: /* 640x480-1 */ ++ case 0x12: /* 640x480-4 */ ++ case 0x13: /* 320-200-8 */ ++ case 0x6a: /* 800x600-4 (VESA) */ ++ return true; ++ default: ++ return __screen_info_has_ega_gfx(mode); ++ } ++} ++ ++/** ++ * screen_info_resources() - Get resources from screen_info structure ++ * @si: the screen_info ++ * @r: pointer to an array of resource structures ++ * @num: number of elements in @r: ++ * ++ * Returns: ++ * The number of resources stored in @r on success, or a negative errno code otherwise. ++ * ++ * A call to screen_info_resources() returns the resources consumed by the ++ * screen_info's device or framebuffer. The result is stored in the caller-supplied ++ * array @r with up to @num elements. The function returns the number of ++ * initialized elements. ++ */ ++ssize_t screen_info_resources(const struct screen_info *si, struct resource *r, size_t num) ++{ ++ struct resource *pos = r; ++ unsigned int type = screen_info_video_type(si); ++ u64 base, size; ++ ++ switch (type) { ++ case VIDEO_TYPE_MDA: ++ if (num > 0) ++ resource_init_io_named(pos++, 0x3b0, 12, "mda"); ++ if (num > 1) ++ resource_init_io_named(pos++, 0x3bf, 0x01, "mda"); ++ if (num > 2) ++ resource_init_mem_named(pos++, 0xb0000, 0x2000, "mda"); ++ break; ++ case VIDEO_TYPE_CGA: ++ if (num > 0) ++ resource_init_io_named(pos++, 0x3d4, 0x02, "cga"); ++ if (num > 1) ++ resource_init_mem_named(pos++, 0xb8000, 0x2000, "cga"); ++ break; ++ case VIDEO_TYPE_EGAM: ++ if (num > 0) ++ resource_init_io_named(pos++, 0x3bf, 0x10, "ega"); ++ if (num > 1) ++ resource_init_mem_named(pos++, 0xb0000, 0x8000, "ega"); ++ break; ++ case VIDEO_TYPE_EGAC: ++ if (num > 0) ++ resource_init_io_named(pos++, 0x3c0, 0x20, "ega"); ++ if (num > 1) { ++ if (__screen_info_has_ega_gfx(si->orig_video_mode)) ++ resource_init_mem_named(pos++, 0xa0000, 0x10000, "ega"); ++ else ++ resource_init_mem_named(pos++, 0xb8000, 0x8000, "ega"); ++ } ++ break; ++ case VIDEO_TYPE_VGAC: ++ if (num > 0) ++ resource_init_io_named(pos++, 0x3c0, 0x20, "vga+"); ++ if (num > 1) { ++ if (__screen_info_has_vga_gfx(si->orig_video_mode)) ++ resource_init_mem_named(pos++, 0xa0000, 0x10000, "vga+"); ++ else ++ resource_init_mem_named(pos++, 0xb8000, 0x8000, "vga+"); ++ } ++ break; ++ case VIDEO_TYPE_VLFB: ++ case VIDEO_TYPE_EFI: ++ base = __screen_info_lfb_base(si); ++ if (!base) ++ break; ++ size = __screen_info_lfb_size(si, type); ++ if (!size) ++ break; ++ if (num > 0) ++ resource_init_mem_named(pos++, base, size, "lfb"); ++ break; ++ case VIDEO_TYPE_PICA_S3: ++ case VIDEO_TYPE_MIPS_G364: ++ case VIDEO_TYPE_SGI: ++ case VIDEO_TYPE_TGAC: ++ case VIDEO_TYPE_SUN: ++ case VIDEO_TYPE_SUNPCI: ++ case VIDEO_TYPE_PMAC: ++ default: ++ /* not supported */ ++ return -EINVAL; ++ } ++ ++ return pos - r; ++} ++EXPORT_SYMBOL(screen_info_resources); +diff --git a/drivers/video/screen_info_pci.c b/drivers/video/screen_info_pci.c +new file mode 100644 +index 0000000000000..6c58335171410 +--- /dev/null ++++ b/drivers/video/screen_info_pci.c +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include <linux/pci.h> ++#include <linux/printk.h> ++#include <linux/screen_info.h> ++#include <linux/string.h> ++ ++static struct pci_dev *screen_info_lfb_pdev; ++static size_t screen_info_lfb_bar; ++static resource_size_t screen_info_lfb_offset; ++static struct resource screen_info_lfb_res = DEFINE_RES_MEM(0, 0); ++ ++static bool __screen_info_relocation_is_valid(const struct screen_info *si, struct resource *pr) ++{ ++ u64 size = __screen_info_lfb_size(si, screen_info_video_type(si)); ++ ++ if (screen_info_lfb_offset > resource_size(pr)) ++ return false; ++ if (size > resource_size(pr)) ++ return false; ++ if (resource_size(pr) - size < screen_info_lfb_offset) ++ return false; ++ ++ return true; ++} ++ ++void screen_info_apply_fixups(void) ++{ ++ struct screen_info *si = &screen_info; ++ ++ if (screen_info_lfb_pdev) { ++ struct resource *pr = &screen_info_lfb_pdev->resource[screen_info_lfb_bar]; ++ ++ if (pr->start != screen_info_lfb_res.start) { ++ if (__screen_info_relocation_is_valid(si, pr)) { ++ /* ++ * Only update base if we have an actual ++ * relocation to a valid I/O range. ++ */ ++ __screen_info_set_lfb_base(si, pr->start + screen_info_lfb_offset); ++ pr_info("Relocating firmware framebuffer to offset %pa[d] within %pr\n", ++ &screen_info_lfb_offset, pr); ++ } else { ++ pr_warn("Invalid relocating, disabling firmware framebuffer\n"); ++ } ++ } ++ } ++} ++ ++static void screen_info_fixup_lfb(struct pci_dev *pdev) ++{ ++ unsigned int type; ++ struct resource res[SCREEN_INFO_MAX_RESOURCES]; ++ size_t i, numres; ++ int ret; ++ const struct screen_info *si = &screen_info; ++ ++ if (screen_info_lfb_pdev) ++ return; // already found ++ ++ type = screen_info_video_type(si); ++ if (type != VIDEO_TYPE_EFI) ++ return; // only applies to EFI ++ ++ ret = screen_info_resources(si, res, ARRAY_SIZE(res)); ++ if (ret < 0) ++ return; ++ numres = ret; ++ ++ for (i = 0; i < numres; ++i) { ++ struct resource *r = &res[i]; ++ const struct resource *pr; ++ ++ if (!(r->flags & IORESOURCE_MEM)) ++ continue; ++ pr = pci_find_resource(pdev, r); ++ if (!pr) ++ continue; ++ ++ /* ++ * We've found a PCI device with the framebuffer ++ * resource. Store away the parameters to track ++ * relocation of the framebuffer aperture. ++ */ ++ screen_info_lfb_pdev = pdev; ++ screen_info_lfb_bar = pr - pdev->resource; ++ screen_info_lfb_offset = r->start - pr->start; ++ memcpy(&screen_info_lfb_res, r, sizeof(screen_info_lfb_res)); ++ } ++} ++DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY, 16, ++ screen_info_fixup_lfb); ++ ++static struct pci_dev *__screen_info_pci_dev(struct resource *res) ++{ ++ struct pci_dev *pdev = NULL; ++ const struct resource *r = NULL; ++ ++ if (!(res->flags & IORESOURCE_MEM)) ++ return NULL; ++ ++ while (!r && (pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) { ++ r = pci_find_resource(pdev, res); ++ } ++ ++ return pdev; ++} ++ ++/** ++ * screen_info_pci_dev() - Return PCI parent device that contains screen_info's framebuffer ++ * @si: the screen_info ++ * ++ * Returns: ++ * The screen_info's parent device or NULL on success, or a pointer-encoded ++ * errno value otherwise. The value NULL is not an error. It signals that no ++ * PCI device has been found. ++ */ ++struct pci_dev *screen_info_pci_dev(const struct screen_info *si) ++{ ++ struct resource res[SCREEN_INFO_MAX_RESOURCES]; ++ ssize_t i, numres; ++ ++ numres = screen_info_resources(si, res, ARRAY_SIZE(res)); ++ if (numres < 0) ++ return ERR_PTR(numres); ++ ++ for (i = 0; i < numres; ++i) { ++ struct pci_dev *pdev = __screen_info_pci_dev(&res[i]); ++ ++ if (pdev) ++ return pdev; ++ } ++ ++ return NULL; ++} ++EXPORT_SYMBOL(screen_info_pci_dev); +diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c +index dd065349fae3a..4e999e1c14075 100644 +--- a/fs/btrfs/block-group.c ++++ b/fs/btrfs/block-group.c +@@ -1214,8 +1214,8 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, + block_group->space_info->total_bytes -= block_group->length; + block_group->space_info->bytes_readonly -= + (block_group->length - block_group->zone_unusable); +- block_group->space_info->bytes_zone_unusable -= +- block_group->zone_unusable; ++ btrfs_space_info_update_bytes_zone_unusable(fs_info, block_group->space_info, ++ -block_group->zone_unusable); + block_group->space_info->disk_total -= block_group->length * factor; + + spin_unlock(&block_group->space_info->lock); +@@ -1399,7 +1399,8 @@ static int inc_block_group_ro(struct btrfs_block_group *cache, int force) + if (btrfs_is_zoned(cache->fs_info)) { + /* Migrate zone_unusable bytes to readonly */ + sinfo->bytes_readonly += cache->zone_unusable; +- sinfo->bytes_zone_unusable -= cache->zone_unusable; ++ btrfs_space_info_update_bytes_zone_unusable(cache->fs_info, sinfo, ++ -cache->zone_unusable); + cache->zone_unusable = 0; + } + cache->ro++; +@@ -3023,9 +3024,11 @@ void btrfs_dec_block_group_ro(struct btrfs_block_group *cache) + if (btrfs_is_zoned(cache->fs_info)) { + /* Migrate zone_unusable bytes back */ + cache->zone_unusable = +- (cache->alloc_offset - cache->used) + ++ (cache->alloc_offset - cache->used - cache->pinned - ++ cache->reserved) + + (cache->length - cache->zone_capacity); +- sinfo->bytes_zone_unusable += cache->zone_unusable; ++ btrfs_space_info_update_bytes_zone_unusable(cache->fs_info, sinfo, ++ cache->zone_unusable); + sinfo->bytes_readonly -= cache->zone_unusable; + } + num_bytes = cache->length - cache->reserved - +diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c +index b89b558b15926..c6ecfd05e1db9 100644 +--- a/fs/btrfs/extent-tree.c ++++ b/fs/btrfs/extent-tree.c +@@ -2749,7 +2749,8 @@ static int unpin_extent_range(struct btrfs_fs_info *fs_info, + readonly = true; + } else if (btrfs_is_zoned(fs_info)) { + /* Need reset before reusing in a zoned block group */ +- space_info->bytes_zone_unusable += len; ++ btrfs_space_info_update_bytes_zone_unusable(fs_info, space_info, ++ len); + readonly = true; + } + spin_unlock(&cache->lock); +diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c +index dcfc0425115e9..f59e599766662 100644 +--- a/fs/btrfs/free-space-cache.c ++++ b/fs/btrfs/free-space-cache.c +@@ -2721,8 +2721,10 @@ static int __btrfs_add_free_space_zoned(struct btrfs_block_group *block_group, + * If the block group is read-only, we should account freed space into + * bytes_readonly. + */ +- if (!block_group->ro) ++ if (!block_group->ro) { + block_group->zone_unusable += to_unusable; ++ WARN_ON(block_group->zone_unusable > block_group->length); ++ } + spin_unlock(&ctl->tree_lock); + if (!used) { + spin_lock(&block_group->lock); +diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c +index 3f7a9605e2d3a..581bdd709ee0d 100644 +--- a/fs/btrfs/space-info.c ++++ b/fs/btrfs/space-info.c +@@ -312,7 +312,7 @@ void btrfs_add_bg_to_space_info(struct btrfs_fs_info *info, + found->bytes_used += block_group->used; + found->disk_used += block_group->used * factor; + found->bytes_readonly += block_group->bytes_super; +- found->bytes_zone_unusable += block_group->zone_unusable; ++ btrfs_space_info_update_bytes_zone_unusable(info, found, block_group->zone_unusable); + if (block_group->length > 0) + found->full = 0; + btrfs_try_granting_tickets(info, found); +@@ -524,8 +524,7 @@ void btrfs_dump_space_info(struct btrfs_fs_info *fs_info, + + spin_lock(&cache->lock); + avail = cache->length - cache->used - cache->pinned - +- cache->reserved - cache->delalloc_bytes - +- cache->bytes_super - cache->zone_unusable; ++ cache->reserved - cache->bytes_super - cache->zone_unusable; + btrfs_info(fs_info, + "block group %llu has %llu bytes, %llu used %llu pinned %llu reserved %llu delalloc %llu super %llu zone_unusable (%llu bytes available) %s", + cache->start, cache->length, cache->used, cache->pinned, +diff --git a/fs/btrfs/space-info.h b/fs/btrfs/space-info.h +index 0bb9d14e60a82..08a3bd10addcf 100644 +--- a/fs/btrfs/space-info.h ++++ b/fs/btrfs/space-info.h +@@ -197,6 +197,7 @@ btrfs_space_info_update_##name(struct btrfs_fs_info *fs_info, \ + + DECLARE_SPACE_INFO_UPDATE(bytes_may_use, "space_info"); + DECLARE_SPACE_INFO_UPDATE(bytes_pinned, "pinned"); ++DECLARE_SPACE_INFO_UPDATE(bytes_zone_unusable, "zone_unusable"); + + int btrfs_init_space_info(struct btrfs_fs_info *fs_info); + void btrfs_add_bg_to_space_info(struct btrfs_fs_info *info, +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index d5eb8d44c6c81..cef119a2476bb 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -453,6 +453,35 @@ static void ext4_map_blocks_es_recheck(handle_t *handle, + } + #endif /* ES_AGGRESSIVE_TEST */ + ++static int ext4_map_query_blocks(handle_t *handle, struct inode *inode, ++ struct ext4_map_blocks *map) ++{ ++ unsigned int status; ++ int retval; ++ ++ if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) ++ retval = ext4_ext_map_blocks(handle, inode, map, 0); ++ else ++ retval = ext4_ind_map_blocks(handle, inode, map, 0); ++ ++ if (retval <= 0) ++ return retval; ++ ++ if (unlikely(retval != map->m_len)) { ++ ext4_warning(inode->i_sb, ++ "ES len assertion failed for inode " ++ "%lu: retval %d != map->m_len %d", ++ inode->i_ino, retval, map->m_len); ++ WARN_ON(1); ++ } ++ ++ status = map->m_flags & EXT4_MAP_UNWRITTEN ? ++ EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; ++ ext4_es_insert_extent(inode, map->m_lblk, map->m_len, ++ map->m_pblk, status); ++ return retval; ++} ++ + /* + * The ext4_map_blocks() function tries to look up the requested blocks, + * and returns if the blocks are already mapped. +@@ -1705,12 +1734,10 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, + + /* Lookup extent status tree firstly */ + if (ext4_es_lookup_extent(inode, iblock, NULL, &es)) { +- if (ext4_es_is_hole(&es)) { +- retval = 0; +- down_read(&EXT4_I(inode)->i_data_sem); ++ if (ext4_es_is_hole(&es)) + goto add_delayed; +- } + ++found: + /* + * Delayed extent could be allocated by fallocate. + * So we need to check it. +@@ -1747,49 +1774,42 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, + down_read(&EXT4_I(inode)->i_data_sem); + if (ext4_has_inline_data(inode)) + retval = 0; +- else if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) +- retval = ext4_ext_map_blocks(NULL, inode, map, 0); + else +- retval = ext4_ind_map_blocks(NULL, inode, map, 0); ++ retval = ext4_map_query_blocks(NULL, inode, map); ++ up_read(&EXT4_I(inode)->i_data_sem); ++ if (retval) ++ return retval; + + add_delayed: +- if (retval == 0) { +- int ret; +- +- /* +- * XXX: __block_prepare_write() unmaps passed block, +- * is it OK? +- */ +- +- ret = ext4_insert_delayed_block(inode, map->m_lblk); +- if (ret != 0) { +- retval = ret; +- goto out_unlock; ++ down_write(&EXT4_I(inode)->i_data_sem); ++ /* ++ * Page fault path (ext4_page_mkwrite does not take i_rwsem) ++ * and fallocate path (no folio lock) can race. Make sure we ++ * lookup the extent status tree here again while i_data_sem ++ * is held in write mode, before inserting a new da entry in ++ * the extent status tree. ++ */ ++ if (ext4_es_lookup_extent(inode, iblock, NULL, &es)) { ++ if (!ext4_es_is_hole(&es)) { ++ up_write(&EXT4_I(inode)->i_data_sem); ++ goto found; + } +- +- map_bh(bh, inode->i_sb, invalid_block); +- set_buffer_new(bh); +- set_buffer_delay(bh); +- } else if (retval > 0) { +- unsigned int status; +- +- if (unlikely(retval != map->m_len)) { +- ext4_warning(inode->i_sb, +- "ES len assertion failed for inode " +- "%lu: retval %d != map->m_len %d", +- inode->i_ino, retval, map->m_len); +- WARN_ON(1); ++ } else if (!ext4_has_inline_data(inode)) { ++ retval = ext4_map_query_blocks(NULL, inode, map); ++ if (retval) { ++ up_write(&EXT4_I(inode)->i_data_sem); ++ return retval; + } +- +- status = map->m_flags & EXT4_MAP_UNWRITTEN ? +- EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; +- ext4_es_insert_extent(inode, map->m_lblk, map->m_len, +- map->m_pblk, status); + } + +-out_unlock: +- up_read((&EXT4_I(inode)->i_data_sem)); ++ retval = ext4_insert_delayed_block(inode, map->m_lblk); ++ up_write(&EXT4_I(inode)->i_data_sem); ++ if (retval) ++ return retval; + ++ map_bh(bh, inode->i_sb, invalid_block); ++ set_buffer_new(bh); ++ set_buffer_delay(bh); + return retval; + } + +diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c +index 22080606b8769..804958c6de34c 100644 +--- a/fs/f2fs/segment.c ++++ b/fs/f2fs/segment.c +@@ -3350,7 +3350,9 @@ static int __get_segment_type_6(struct f2fs_io_info *fio) + if (page_private_gcing(fio->page)) { + if (fio->sbi->am.atgc_enabled && + (fio->io_type == FS_DATA_IO) && +- (fio->sbi->gc_mode != GC_URGENT_HIGH)) ++ (fio->sbi->gc_mode != GC_URGENT_HIGH) && ++ __is_valid_data_blkaddr(fio->old_blkaddr) && ++ !is_inode_flag_set(inode, FI_OPU_WRITE)) + return CURSEG_ALL_DATA_ATGC; + else + return CURSEG_COLD_DATA; +diff --git a/fs/file.c b/fs/file.c +index a815f6eddc511..b64a84137c00f 100644 +--- a/fs/file.c ++++ b/fs/file.c +@@ -1124,6 +1124,7 @@ __releases(&files->file_lock) + * tables and this condition does not arise without those. + */ + fdt = files_fdtable(files); ++ fd = array_index_nospec(fd, fdt->max_fds); + tofree = fdt->fd[fd]; + if (!tofree && fd_is_open(fd, fdt)) + goto Ebusy; +diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c +index 5b5cdc747cef3..071a71eb1a2d4 100644 +--- a/fs/proc/proc_sysctl.c ++++ b/fs/proc/proc_sysctl.c +@@ -480,12 +480,10 @@ static struct inode *proc_sys_make_inode(struct super_block *sb, + make_empty_dir_inode(inode); + } + ++ inode->i_uid = GLOBAL_ROOT_UID; ++ inode->i_gid = GLOBAL_ROOT_GID; + if (root->set_ownership) +- root->set_ownership(head, table, &inode->i_uid, &inode->i_gid); +- else { +- inode->i_uid = GLOBAL_ROOT_UID; +- inode->i_gid = GLOBAL_ROOT_GID; +- } ++ root->set_ownership(head, &inode->i_uid, &inode->i_gid); + + return inode; + } +diff --git a/include/linux/leds.h b/include/linux/leds.h +index aa16dc2a8230f..d3056bc6f0a1a 100644 +--- a/include/linux/leds.h ++++ b/include/linux/leds.h +@@ -474,6 +474,9 @@ struct led_trigger { + int (*activate)(struct led_classdev *led_cdev); + void (*deactivate)(struct led_classdev *led_cdev); + ++ /* Brightness set by led_trigger_event */ ++ enum led_brightness brightness; ++ + /* LED-private triggers have this set */ + struct led_hw_trigger_type *trigger_type; + +@@ -527,22 +530,11 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev) + return led_cdev->trigger_data; + } + +-/** +- * led_trigger_rename_static - rename a trigger +- * @name: the new trigger name +- * @trig: the LED trigger to rename +- * +- * Change a LED trigger name by copying the string passed in +- * name into current trigger name, which MUST be large +- * enough for the new string. +- * +- * Note that name must NOT point to the same string used +- * during LED registration, as that could lead to races. +- * +- * This is meant to be used on triggers with statically +- * allocated name. +- */ +-void led_trigger_rename_static(const char *name, struct led_trigger *trig); ++static inline enum led_brightness ++led_trigger_get_brightness(const struct led_trigger *trigger) ++{ ++ return trigger ? trigger->brightness : LED_OFF; ++} + + #define module_led_trigger(__led_trigger) \ + module_driver(__led_trigger, led_trigger_register, \ +@@ -580,6 +572,12 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev) + return NULL; + } + ++static inline enum led_brightness ++led_trigger_get_brightness(const struct led_trigger *trigger) ++{ ++ return LED_OFF; ++} ++ + #endif /* CONFIG_LEDS_TRIGGERS */ + + /* Trigger specific enum */ +diff --git a/include/linux/pci.h b/include/linux/pci.h +index f141300116219..7b18a4b3efb0e 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -1182,6 +1182,8 @@ struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn); + struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus, + unsigned int devfn); + struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from); ++struct pci_dev *pci_get_base_class(unsigned int class, struct pci_dev *from); ++ + int pci_dev_present(const struct pci_device_id *ids); + + int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn, +@@ -1958,6 +1960,9 @@ static inline struct pci_dev *pci_get_class(unsigned int class, + struct pci_dev *from) + { return NULL; } + ++static inline struct pci_dev *pci_get_base_class(unsigned int class, ++ struct pci_dev *from) ++{ return NULL; } + + static inline int pci_dev_present(const struct pci_device_id *ids) + { return 0; } +diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h +index eab7081392d50..6a4a3cec4638b 100644 +--- a/include/linux/screen_info.h ++++ b/include/linux/screen_info.h +@@ -4,6 +4,142 @@ + + #include <uapi/linux/screen_info.h> + ++#include <linux/bits.h> ++ ++/** ++ * SCREEN_INFO_MAX_RESOURCES - maximum number of resources per screen_info ++ */ ++#define SCREEN_INFO_MAX_RESOURCES 3 ++ ++struct pci_dev; ++struct resource; ++ ++static inline bool __screen_info_has_lfb(unsigned int type) ++{ ++ return (type == VIDEO_TYPE_VLFB) || (type == VIDEO_TYPE_EFI); ++} ++ ++static inline u64 __screen_info_lfb_base(const struct screen_info *si) ++{ ++ u64 lfb_base = si->lfb_base; ++ ++ if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE) ++ lfb_base |= (u64)si->ext_lfb_base << 32; ++ ++ return lfb_base; ++} ++ ++static inline void __screen_info_set_lfb_base(struct screen_info *si, u64 lfb_base) ++{ ++ si->lfb_base = lfb_base & GENMASK_ULL(31, 0); ++ si->ext_lfb_base = (lfb_base & GENMASK_ULL(63, 32)) >> 32; ++ ++ if (si->ext_lfb_base) ++ si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE; ++ else ++ si->capabilities &= ~VIDEO_CAPABILITY_64BIT_BASE; ++} ++ ++static inline u64 __screen_info_lfb_size(const struct screen_info *si, unsigned int type) ++{ ++ u64 lfb_size = si->lfb_size; ++ ++ if (type == VIDEO_TYPE_VLFB) ++ lfb_size <<= 16; ++ return lfb_size; ++} ++ ++static inline bool __screen_info_vbe_mode_nonvga(const struct screen_info *si) ++{ ++ /* ++ * VESA modes typically run on VGA hardware. Set bit 5 signals that this ++ * is not the case. Drivers can then not make use of VGA resources. See ++ * Sec 4.4 of the VBE 2.0 spec. ++ */ ++ return si->vesa_attributes & BIT(5); ++} ++ ++static inline unsigned int __screen_info_video_type(unsigned int type) ++{ ++ switch (type) { ++ case VIDEO_TYPE_MDA: ++ case VIDEO_TYPE_CGA: ++ case VIDEO_TYPE_EGAM: ++ case VIDEO_TYPE_EGAC: ++ case VIDEO_TYPE_VGAC: ++ case VIDEO_TYPE_VLFB: ++ case VIDEO_TYPE_PICA_S3: ++ case VIDEO_TYPE_MIPS_G364: ++ case VIDEO_TYPE_SGI: ++ case VIDEO_TYPE_TGAC: ++ case VIDEO_TYPE_SUN: ++ case VIDEO_TYPE_SUNPCI: ++ case VIDEO_TYPE_PMAC: ++ case VIDEO_TYPE_EFI: ++ return type; ++ default: ++ return 0; ++ } ++} ++ ++/** ++ * screen_info_video_type() - Decodes the video type from struct screen_info ++ * @si: an instance of struct screen_info ++ * ++ * Returns: ++ * A VIDEO_TYPE_ constant representing si's type of video display, or 0 otherwise. ++ */ ++static inline unsigned int screen_info_video_type(const struct screen_info *si) ++{ ++ unsigned int type; ++ ++ // check if display output is on ++ if (!si->orig_video_isVGA) ++ return 0; ++ ++ // check for a known VIDEO_TYPE_ constant ++ type = __screen_info_video_type(si->orig_video_isVGA); ++ if (type) ++ return si->orig_video_isVGA; ++ ++ // check if text mode has been initialized ++ if (!si->orig_video_lines || !si->orig_video_cols) ++ return 0; ++ ++ // 80x25 text, mono ++ if (si->orig_video_mode == 0x07) { ++ if ((si->orig_video_ega_bx & 0xff) != 0x10) ++ return VIDEO_TYPE_EGAM; ++ else ++ return VIDEO_TYPE_MDA; ++ } ++ ++ // EGA/VGA, 16 colors ++ if ((si->orig_video_ega_bx & 0xff) != 0x10) { ++ if (si->orig_video_isVGA) ++ return VIDEO_TYPE_VGAC; ++ else ++ return VIDEO_TYPE_EGAC; ++ } ++ ++ // the rest... ++ return VIDEO_TYPE_CGA; ++} ++ ++ssize_t screen_info_resources(const struct screen_info *si, struct resource *r, size_t num); ++ ++#if defined(CONFIG_PCI) ++void screen_info_apply_fixups(void); ++struct pci_dev *screen_info_pci_dev(const struct screen_info *si); ++#else ++static inline void screen_info_apply_fixups(void) ++{ } ++static inline struct pci_dev *screen_info_pci_dev(const struct screen_info *si) ++{ ++ return NULL; ++} ++#endif ++ + extern struct screen_info screen_info; + + #endif /* _SCREEN_INFO_H */ +diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h +index 61b40ea81f4d3..698a71422a14b 100644 +--- a/include/linux/sysctl.h ++++ b/include/linux/sysctl.h +@@ -205,7 +205,6 @@ struct ctl_table_root { + struct ctl_table_set default_set; + struct ctl_table_set *(*lookup)(struct ctl_table_root *root); + void (*set_ownership)(struct ctl_table_header *head, +- struct ctl_table *table, + kuid_t *uid, kgid_t *gid); + int (*permissions)(struct ctl_table_header *head, struct ctl_table *table); + }; +diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h +index b2db2c2f1c577..3c4d5ef6d4463 100644 +--- a/include/trace/events/btrfs.h ++++ b/include/trace/events/btrfs.h +@@ -2430,6 +2430,14 @@ DEFINE_EVENT(btrfs__space_info_update, update_bytes_pinned, + TP_ARGS(fs_info, sinfo, old, diff) + ); + ++DEFINE_EVENT(btrfs__space_info_update, update_bytes_zone_unusable, ++ ++ TP_PROTO(const struct btrfs_fs_info *fs_info, ++ const struct btrfs_space_info *sinfo, u64 old, s64 diff), ++ ++ TP_ARGS(fs_info, sinfo, old, diff) ++); ++ + DECLARE_EVENT_CLASS(btrfs_raid56_bio, + + TP_PROTO(const struct btrfs_raid_bio *rbio, +diff --git a/include/trace/events/mptcp.h b/include/trace/events/mptcp.h +index 563e48617374d..54e8fb5a229cd 100644 +--- a/include/trace/events/mptcp.h ++++ b/include/trace/events/mptcp.h +@@ -34,7 +34,7 @@ TRACE_EVENT(mptcp_subflow_get_send, + struct sock *ssk; + + __entry->active = mptcp_subflow_active(subflow); +- __entry->backup = subflow->backup; ++ __entry->backup = subflow->backup || subflow->request_bkup; + + if (subflow->tcp_sock && sk_fullsock(subflow->tcp_sock)) + __entry->free = sk_stream_memory_free(subflow->tcp_sock); +diff --git a/init/Kconfig b/init/Kconfig +index e403a29256357..e173364abd6c0 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1898,6 +1898,7 @@ config RUST + depends on !MODVERSIONS + depends on !GCC_PLUGINS + depends on !RANDSTRUCT ++ depends on !SHADOW_CALL_STACK + depends on !DEBUG_INFO_BTF || PAHOLE_HAS_LANG_EXCLUDE + help + Enables Rust support in the kernel. +diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c +index 8c62e443f78b3..b2f39a86f4734 100644 +--- a/ipc/ipc_sysctl.c ++++ b/ipc/ipc_sysctl.c +@@ -14,6 +14,7 @@ + #include <linux/ipc_namespace.h> + #include <linux/msg.h> + #include <linux/slab.h> ++#include <linux/cred.h> + #include "util.h" + + static int proc_ipc_dointvec_minmax_orphans(struct ctl_table *table, int write, +@@ -190,25 +191,56 @@ static int set_is_seen(struct ctl_table_set *set) + return ¤t->nsproxy->ipc_ns->ipc_set == set; + } + ++static void ipc_set_ownership(struct ctl_table_header *head, ++ kuid_t *uid, kgid_t *gid) ++{ ++ struct ipc_namespace *ns = ++ container_of(head->set, struct ipc_namespace, ipc_set); ++ ++ kuid_t ns_root_uid = make_kuid(ns->user_ns, 0); ++ kgid_t ns_root_gid = make_kgid(ns->user_ns, 0); ++ ++ *uid = uid_valid(ns_root_uid) ? ns_root_uid : GLOBAL_ROOT_UID; ++ *gid = gid_valid(ns_root_gid) ? ns_root_gid : GLOBAL_ROOT_GID; ++} ++ + static int ipc_permissions(struct ctl_table_header *head, struct ctl_table *table) + { + int mode = table->mode; + + #ifdef CONFIG_CHECKPOINT_RESTORE +- struct ipc_namespace *ns = current->nsproxy->ipc_ns; ++ struct ipc_namespace *ns = ++ container_of(head->set, struct ipc_namespace, ipc_set); + + if (((table->data == &ns->ids[IPC_SEM_IDS].next_id) || + (table->data == &ns->ids[IPC_MSG_IDS].next_id) || + (table->data == &ns->ids[IPC_SHM_IDS].next_id)) && + checkpoint_restore_ns_capable(ns->user_ns)) + mode = 0666; ++ else + #endif +- return mode; ++ { ++ kuid_t ns_root_uid; ++ kgid_t ns_root_gid; ++ ++ ipc_set_ownership(head, &ns_root_uid, &ns_root_gid); ++ ++ if (uid_eq(current_euid(), ns_root_uid)) ++ mode >>= 6; ++ ++ else if (in_egroup_p(ns_root_gid)) ++ mode >>= 3; ++ } ++ ++ mode &= 7; ++ ++ return (mode << 6) | (mode << 3) | mode; + } + + static struct ctl_table_root set_root = { + .lookup = set_lookup, + .permissions = ipc_permissions, ++ .set_ownership = ipc_set_ownership, + }; + + bool setup_ipc_sysctls(struct ipc_namespace *ns) +diff --git a/ipc/mq_sysctl.c b/ipc/mq_sysctl.c +index ebb5ed81c151a..6bb1c5397c69b 100644 +--- a/ipc/mq_sysctl.c ++++ b/ipc/mq_sysctl.c +@@ -12,6 +12,7 @@ + #include <linux/stat.h> + #include <linux/capability.h> + #include <linux/slab.h> ++#include <linux/cred.h> + + static int msg_max_limit_min = MIN_MSGMAX; + static int msg_max_limit_max = HARD_MSGMAX; +@@ -76,8 +77,42 @@ static int set_is_seen(struct ctl_table_set *set) + return ¤t->nsproxy->ipc_ns->mq_set == set; + } + ++static void mq_set_ownership(struct ctl_table_header *head, ++ kuid_t *uid, kgid_t *gid) ++{ ++ struct ipc_namespace *ns = ++ container_of(head->set, struct ipc_namespace, mq_set); ++ ++ kuid_t ns_root_uid = make_kuid(ns->user_ns, 0); ++ kgid_t ns_root_gid = make_kgid(ns->user_ns, 0); ++ ++ *uid = uid_valid(ns_root_uid) ? ns_root_uid : GLOBAL_ROOT_UID; ++ *gid = gid_valid(ns_root_gid) ? ns_root_gid : GLOBAL_ROOT_GID; ++} ++ ++static int mq_permissions(struct ctl_table_header *head, struct ctl_table *table) ++{ ++ int mode = table->mode; ++ kuid_t ns_root_uid; ++ kgid_t ns_root_gid; ++ ++ mq_set_ownership(head, &ns_root_uid, &ns_root_gid); ++ ++ if (uid_eq(current_euid(), ns_root_uid)) ++ mode >>= 6; ++ ++ else if (in_egroup_p(ns_root_gid)) ++ mode >>= 3; ++ ++ mode &= 7; ++ ++ return (mode << 6) | (mode << 3) | mode; ++} ++ + static struct ctl_table_root set_root = { + .lookup = set_lookup, ++ .permissions = mq_permissions, ++ .set_ownership = mq_set_ownership, + }; + + bool setup_mq_sysctls(struct ipc_namespace *ns) +diff --git a/mm/Kconfig b/mm/Kconfig +index 264a2df5ecf5b..ece4f2847e2b4 100644 +--- a/mm/Kconfig ++++ b/mm/Kconfig +@@ -704,6 +704,17 @@ config HUGETLB_PAGE_SIZE_VARIABLE + config CONTIG_ALLOC + def_bool (MEMORY_ISOLATION && COMPACTION) || CMA + ++config PCP_BATCH_SCALE_MAX ++ int "Maximum scale factor of PCP (Per-CPU pageset) batch allocate/free" ++ default 5 ++ range 0 6 ++ help ++ In page allocator, PCP (Per-CPU pageset) is refilled and drained in ++ batches. The batch number is scaled automatically to improve page ++ allocation/free throughput. But too large scale factor may hurt ++ latency. This option sets the upper limit of scale factor to limit ++ the maximum latency. ++ + config PHYS_ADDR_T_64BIT + def_bool 64BIT + +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index e99d3223f0fc2..39bdbfb5313fb 100644 +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -2185,14 +2185,21 @@ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp) + */ + static void drain_pages_zone(unsigned int cpu, struct zone *zone) + { +- struct per_cpu_pages *pcp; ++ struct per_cpu_pages *pcp = per_cpu_ptr(zone->per_cpu_pageset, cpu); ++ int count; + +- pcp = per_cpu_ptr(zone->per_cpu_pageset, cpu); +- if (pcp->count) { ++ do { + spin_lock(&pcp->lock); +- free_pcppages_bulk(zone, pcp->count, pcp, 0); ++ count = pcp->count; ++ if (count) { ++ int to_drain = min(count, ++ pcp->batch << CONFIG_PCP_BATCH_SCALE_MAX); ++ ++ free_pcppages_bulk(zone, to_drain, pcp, 0); ++ count -= to_drain; ++ } + spin_unlock(&pcp->lock); +- } ++ } while (count); + } + + /* +@@ -2343,7 +2350,7 @@ static int nr_pcp_free(struct per_cpu_pages *pcp, int high, bool free_high) + * freeing of pages without any allocation. + */ + batch <<= pcp->free_factor; +- if (batch < max_nr_free) ++ if (batch < max_nr_free && pcp->free_factor < CONFIG_PCP_BATCH_SCALE_MAX) + pcp->free_factor++; + batch = clamp(batch, min_nr_free, max_nr_free); + +diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c +index b3f5714dab342..6dab0c99c82c7 100644 +--- a/net/bluetooth/hci_sync.c ++++ b/net/bluetooth/hci_sync.c +@@ -2862,6 +2862,27 @@ static int hci_passive_scan_sync(struct hci_dev *hdev) + */ + filter_policy = hci_update_accept_list_sync(hdev); + ++ /* If suspended and filter_policy set to 0x00 (no acceptlist) then ++ * passive scanning cannot be started since that would require the host ++ * to be woken up to process the reports. ++ */ ++ if (hdev->suspended && !filter_policy) { ++ /* Check if accept list is empty then there is no need to scan ++ * while suspended. ++ */ ++ if (list_empty(&hdev->le_accept_list)) ++ return 0; ++ ++ /* If there are devices is the accept_list that means some ++ * devices could not be programmed which in non-suspended case ++ * means filter_policy needs to be set to 0x00 so the host needs ++ * to filter, but since this is treating suspended case we ++ * can ignore device needing host to filter to allow devices in ++ * the acceptlist to be able to wakeup the system. ++ */ ++ filter_policy = 0x01; ++ } ++ + /* When the controller is using random resolvable addresses and + * with that having LE privacy enabled, then controllers with + * Extended Scanner Filter Policies support can now enable support +diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c +index 7ea66de1442cc..8573dad6d8171 100644 +--- a/net/core/rtnetlink.c ++++ b/net/core/rtnetlink.c +@@ -3263,7 +3263,7 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, + if (ifm->ifi_index > 0) + dev = __dev_get_by_index(tgt_net, ifm->ifi_index); + else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) +- dev = rtnl_dev_get(net, tb); ++ dev = rtnl_dev_get(tgt_net, tb); + else if (tb[IFLA_GROUP]) + err = rtnl_group_dellink(tgt_net, nla_get_u32(tb[IFLA_GROUP])); + else +diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c +index 56f6ecc43451e..12ca666d6e2c1 100644 +--- a/net/ipv4/netfilter/iptable_nat.c ++++ b/net/ipv4/netfilter/iptable_nat.c +@@ -145,25 +145,27 @@ static struct pernet_operations iptable_nat_net_ops = { + + static int __init iptable_nat_init(void) + { +- int ret = xt_register_template(&nf_nat_ipv4_table, +- iptable_nat_table_init); ++ int ret; + ++ /* net->gen->ptr[iptable_nat_net_id] must be allocated ++ * before calling iptable_nat_table_init(). ++ */ ++ ret = register_pernet_subsys(&iptable_nat_net_ops); + if (ret < 0) + return ret; + +- ret = register_pernet_subsys(&iptable_nat_net_ops); +- if (ret < 0) { +- xt_unregister_template(&nf_nat_ipv4_table); +- return ret; +- } ++ ret = xt_register_template(&nf_nat_ipv4_table, ++ iptable_nat_table_init); ++ if (ret < 0) ++ unregister_pernet_subsys(&iptable_nat_net_ops); + + return ret; + } + + static void __exit iptable_nat_exit(void) + { +- unregister_pernet_subsys(&iptable_nat_net_ops); + xt_unregister_template(&nf_nat_ipv4_table); ++ unregister_pernet_subsys(&iptable_nat_net_ops); + } + + module_init(iptable_nat_init); +diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c +index 3b4dafefb4b03..e143562077958 100644 +--- a/net/ipv4/syncookies.c ++++ b/net/ipv4/syncookies.c +@@ -424,7 +424,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) + } + + /* Try to redo what tcp_v4_send_synack did. */ +- req->rsk_window_clamp = tp->window_clamp ? :dst_metric(&rt->dst, RTAX_WINDOW); ++ req->rsk_window_clamp = READ_ONCE(tp->window_clamp) ? : ++ dst_metric(&rt->dst, RTAX_WINDOW); + /* limit the window selection if the user enforce a smaller rx buffer */ + full_space = tcp_full_space(sk); + if (sk->sk_userlocks & SOCK_RCVBUF_LOCK && +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 91c3d8264059d..1e3202f2b7a87 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -1723,7 +1723,7 @@ int tcp_set_rcvlowat(struct sock *sk, int val) + space = tcp_space_from_win(sk, val); + if (space > sk->sk_rcvbuf) { + WRITE_ONCE(sk->sk_rcvbuf, space); +- tcp_sk(sk)->window_clamp = val; ++ WRITE_ONCE(tcp_sk(sk)->window_clamp, val); + } + return 0; + } +@@ -3386,7 +3386,7 @@ int tcp_set_window_clamp(struct sock *sk, int val) + if (!val) { + if (sk->sk_state != TCP_CLOSE) + return -EINVAL; +- tp->window_clamp = 0; ++ WRITE_ONCE(tp->window_clamp, 0); + } else { + u32 new_rcv_ssthresh, old_window_clamp = tp->window_clamp; + u32 new_window_clamp = val < SOCK_MIN_RCVBUF / 2 ? +@@ -3395,7 +3395,7 @@ int tcp_set_window_clamp(struct sock *sk, int val) + if (new_window_clamp == old_window_clamp) + return 0; + +- tp->window_clamp = new_window_clamp; ++ WRITE_ONCE(tp->window_clamp, new_window_clamp); + if (new_window_clamp < old_window_clamp) { + /* need to apply the reserved mem provisioning only + * when shrinking the window clamp +@@ -4020,7 +4020,7 @@ int do_tcp_getsockopt(struct sock *sk, int level, + TCP_RTO_MAX / HZ); + break; + case TCP_WINDOW_CLAMP: +- val = tp->window_clamp; ++ val = READ_ONCE(tp->window_clamp); + break; + case TCP_INFO: { + struct tcp_info info; +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +index c2e4dac42453b..d0364cff65c9f 100644 +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -570,19 +570,20 @@ static void tcp_init_buffer_space(struct sock *sk) + maxwin = tcp_full_space(sk); + + if (tp->window_clamp >= maxwin) { +- tp->window_clamp = maxwin; ++ WRITE_ONCE(tp->window_clamp, maxwin); + + if (tcp_app_win && maxwin > 4 * tp->advmss) +- tp->window_clamp = max(maxwin - +- (maxwin >> tcp_app_win), +- 4 * tp->advmss); ++ WRITE_ONCE(tp->window_clamp, ++ max(maxwin - (maxwin >> tcp_app_win), ++ 4 * tp->advmss)); + } + + /* Force reservation of one segment. */ + if (tcp_app_win && + tp->window_clamp > 2 * tp->advmss && + tp->window_clamp + tp->advmss > maxwin) +- tp->window_clamp = max(2 * tp->advmss, maxwin - tp->advmss); ++ WRITE_ONCE(tp->window_clamp, ++ max(2 * tp->advmss, maxwin - tp->advmss)); + + tp->rcv_ssthresh = min(tp->rcv_ssthresh, tp->window_clamp); + tp->snd_cwnd_stamp = tcp_jiffies32; +@@ -747,8 +748,7 @@ void tcp_rcv_space_adjust(struct sock *sk) + * <prev RTT . ><current RTT .. ><next RTT .... > + */ + +- if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_moderate_rcvbuf) && +- !(sk->sk_userlocks & SOCK_RCVBUF_LOCK)) { ++ if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_moderate_rcvbuf)) { + u64 rcvwin, grow; + int rcvbuf; + +@@ -764,11 +764,22 @@ void tcp_rcv_space_adjust(struct sock *sk) + + rcvbuf = min_t(u64, tcp_space_from_win(sk, rcvwin), + READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2])); +- if (rcvbuf > sk->sk_rcvbuf) { +- WRITE_ONCE(sk->sk_rcvbuf, rcvbuf); ++ if (!(sk->sk_userlocks & SOCK_RCVBUF_LOCK)) { ++ if (rcvbuf > sk->sk_rcvbuf) { ++ WRITE_ONCE(sk->sk_rcvbuf, rcvbuf); + +- /* Make the window clamp follow along. */ +- tp->window_clamp = tcp_win_from_space(sk, rcvbuf); ++ /* Make the window clamp follow along. */ ++ WRITE_ONCE(tp->window_clamp, ++ tcp_win_from_space(sk, rcvbuf)); ++ } ++ } else { ++ /* Make the window clamp follow along while being bounded ++ * by SO_RCVBUF. ++ */ ++ int clamp = tcp_win_from_space(sk, min(rcvbuf, sk->sk_rcvbuf)); ++ ++ if (clamp > tp->window_clamp) ++ WRITE_ONCE(tp->window_clamp, clamp); + } + } + tp->rcvq_space.space = copied; +@@ -6347,7 +6358,8 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, + + if (!tp->rx_opt.wscale_ok) { + tp->rx_opt.snd_wscale = tp->rx_opt.rcv_wscale = 0; +- tp->window_clamp = min(tp->window_clamp, 65535U); ++ WRITE_ONCE(tp->window_clamp, ++ min(tp->window_clamp, 65535U)); + } + + if (tp->rx_opt.saw_tstamp) { +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 5631041ae12cb..15c49d559db53 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -203,16 +203,17 @@ static inline void tcp_event_ack_sent(struct sock *sk, u32 rcv_nxt) + * This MUST be enforced by all callers. + */ + void tcp_select_initial_window(const struct sock *sk, int __space, __u32 mss, +- __u32 *rcv_wnd, __u32 *window_clamp, ++ __u32 *rcv_wnd, __u32 *__window_clamp, + int wscale_ok, __u8 *rcv_wscale, + __u32 init_rcv_wnd) + { + unsigned int space = (__space < 0 ? 0 : __space); ++ u32 window_clamp = READ_ONCE(*__window_clamp); + + /* If no clamp set the clamp to the max possible scaled window */ +- if (*window_clamp == 0) +- (*window_clamp) = (U16_MAX << TCP_MAX_WSCALE); +- space = min(*window_clamp, space); ++ if (window_clamp == 0) ++ window_clamp = (U16_MAX << TCP_MAX_WSCALE); ++ space = min(window_clamp, space); + + /* Quantize space offering to a multiple of mss if possible. */ + if (space > mss) +@@ -239,12 +240,13 @@ void tcp_select_initial_window(const struct sock *sk, int __space, __u32 mss, + /* Set window scaling on max possible window */ + space = max_t(u32, space, READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2])); + space = max_t(u32, space, READ_ONCE(sysctl_rmem_max)); +- space = min_t(u32, space, *window_clamp); ++ space = min_t(u32, space, window_clamp); + *rcv_wscale = clamp_t(int, ilog2(space) - 15, + 0, TCP_MAX_WSCALE); + } + /* Set the clamp no higher than max representable value */ +- (*window_clamp) = min_t(__u32, U16_MAX << (*rcv_wscale), *window_clamp); ++ WRITE_ONCE(*__window_clamp, ++ min_t(__u32, U16_MAX << (*rcv_wscale), window_clamp)); + } + EXPORT_SYMBOL(tcp_select_initial_window); + +@@ -3787,7 +3789,7 @@ static void tcp_connect_init(struct sock *sk) + tcp_ca_dst_init(sk, dst); + + if (!tp->window_clamp) +- tp->window_clamp = dst_metric(dst, RTAX_WINDOW); ++ WRITE_ONCE(tp->window_clamp, dst_metric(dst, RTAX_WINDOW)); + tp->advmss = tcp_mss_clamp(tp, dst_metric_advmss(dst)); + + tcp_initialize_rcv_mss(sk); +@@ -3795,7 +3797,7 @@ static void tcp_connect_init(struct sock *sk) + /* limit the window selection if the user enforce a smaller rx buffer */ + if (sk->sk_userlocks & SOCK_RCVBUF_LOCK && + (tp->window_clamp > tcp_full_space(sk) || tp->window_clamp == 0)) +- tp->window_clamp = tcp_full_space(sk); ++ WRITE_ONCE(tp->window_clamp, tcp_full_space(sk)); + + rcv_wnd = tcp_rwnd_init_bpf(sk); + if (rcv_wnd == 0) +diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c +index 68debc78189c2..2062ab94721e3 100644 +--- a/net/ipv6/ndisc.c ++++ b/net/ipv6/ndisc.c +@@ -227,6 +227,7 @@ struct ndisc_options *ndisc_parse_options(const struct net_device *dev, + return NULL; + memset(ndopts, 0, sizeof(*ndopts)); + while (opt_len) { ++ bool unknown = false; + int l; + if (opt_len < sizeof(struct nd_opt_hdr)) + return NULL; +@@ -262,22 +263,23 @@ struct ndisc_options *ndisc_parse_options(const struct net_device *dev, + break; + #endif + default: +- if (ndisc_is_useropt(dev, nd_opt)) { +- ndopts->nd_useropts_end = nd_opt; +- if (!ndopts->nd_useropts) +- ndopts->nd_useropts = nd_opt; +- } else { +- /* +- * Unknown options must be silently ignored, +- * to accommodate future extension to the +- * protocol. +- */ +- ND_PRINTK(2, notice, +- "%s: ignored unsupported option; type=%d, len=%d\n", +- __func__, +- nd_opt->nd_opt_type, +- nd_opt->nd_opt_len); +- } ++ unknown = true; ++ } ++ if (ndisc_is_useropt(dev, nd_opt)) { ++ ndopts->nd_useropts_end = nd_opt; ++ if (!ndopts->nd_useropts) ++ ndopts->nd_useropts = nd_opt; ++ } else if (unknown) { ++ /* ++ * Unknown options must be silently ignored, ++ * to accommodate future extension to the ++ * protocol. ++ */ ++ ND_PRINTK(2, notice, ++ "%s: ignored unsupported option; type=%d, len=%d\n", ++ __func__, ++ nd_opt->nd_opt_type, ++ nd_opt->nd_opt_len); + } + next_opt: + opt_len -= l; +diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c +index bf3cb3a13600c..52d597b16b658 100644 +--- a/net/ipv6/netfilter/ip6table_nat.c ++++ b/net/ipv6/netfilter/ip6table_nat.c +@@ -147,23 +147,27 @@ static struct pernet_operations ip6table_nat_net_ops = { + + static int __init ip6table_nat_init(void) + { +- int ret = xt_register_template(&nf_nat_ipv6_table, +- ip6table_nat_table_init); ++ int ret; + ++ /* net->gen->ptr[ip6table_nat_net_id] must be allocated ++ * before calling ip6t_nat_register_lookups(). ++ */ ++ ret = register_pernet_subsys(&ip6table_nat_net_ops); + if (ret < 0) + return ret; + +- ret = register_pernet_subsys(&ip6table_nat_net_ops); ++ ret = xt_register_template(&nf_nat_ipv6_table, ++ ip6table_nat_table_init); + if (ret) +- xt_unregister_template(&nf_nat_ipv6_table); ++ unregister_pernet_subsys(&ip6table_nat_net_ops); + + return ret; + } + + static void __exit ip6table_nat_exit(void) + { +- unregister_pernet_subsys(&ip6table_nat_net_ops); + xt_unregister_template(&nf_nat_ipv6_table); ++ unregister_pernet_subsys(&ip6table_nat_net_ops); + } + + module_init(ip6table_nat_init); +diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c +index 8698b49dfc8de..593ead8a45d79 100644 +--- a/net/ipv6/syncookies.c ++++ b/net/ipv6/syncookies.c +@@ -243,7 +243,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) + goto out_free; + } + +- req->rsk_window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW); ++ req->rsk_window_clamp = READ_ONCE(tp->window_clamp) ? :dst_metric(dst, RTAX_WINDOW); + /* limit the window selection if the user enforce a smaller rx buffer */ + full_space = tcp_full_space(sk); + if (sk->sk_userlocks & SOCK_RCVBUF_LOCK && +diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c +index 498a0c35b7bb2..815b1df0b2d19 100644 +--- a/net/iucv/af_iucv.c ++++ b/net/iucv/af_iucv.c +@@ -335,8 +335,8 @@ static void iucv_sever_path(struct sock *sk, int with_user_data) + struct iucv_sock *iucv = iucv_sk(sk); + struct iucv_path *path = iucv->path; + +- if (iucv->path) { +- iucv->path = NULL; ++ /* Whoever resets the path pointer, must sever and free it. */ ++ if (xchg(&iucv->path, NULL)) { + if (with_user_data) { + low_nmcpy(user_data, iucv->src_name); + high_nmcpy(user_data, iucv->dst_name); +diff --git a/net/mptcp/mib.c b/net/mptcp/mib.c +index c30405e768337..7884217f33eb2 100644 +--- a/net/mptcp/mib.c ++++ b/net/mptcp/mib.c +@@ -19,7 +19,9 @@ static const struct snmp_mib mptcp_snmp_list[] = { + SNMP_MIB_ITEM("MPTCPRetrans", MPTCP_MIB_RETRANSSEGS), + SNMP_MIB_ITEM("MPJoinNoTokenFound", MPTCP_MIB_JOINNOTOKEN), + SNMP_MIB_ITEM("MPJoinSynRx", MPTCP_MIB_JOINSYNRX), ++ SNMP_MIB_ITEM("MPJoinSynBackupRx", MPTCP_MIB_JOINSYNBACKUPRX), + SNMP_MIB_ITEM("MPJoinSynAckRx", MPTCP_MIB_JOINSYNACKRX), ++ SNMP_MIB_ITEM("MPJoinSynAckBackupRx", MPTCP_MIB_JOINSYNACKBACKUPRX), + SNMP_MIB_ITEM("MPJoinSynAckHMacFailure", MPTCP_MIB_JOINSYNACKMAC), + SNMP_MIB_ITEM("MPJoinAckRx", MPTCP_MIB_JOINACKRX), + SNMP_MIB_ITEM("MPJoinAckHMacFailure", MPTCP_MIB_JOINACKMAC), +diff --git a/net/mptcp/mib.h b/net/mptcp/mib.h +index dd7fd1f246b5f..443604462ace8 100644 +--- a/net/mptcp/mib.h ++++ b/net/mptcp/mib.h +@@ -12,7 +12,9 @@ enum linux_mptcp_mib_field { + MPTCP_MIB_RETRANSSEGS, /* Segments retransmitted at the MPTCP-level */ + MPTCP_MIB_JOINNOTOKEN, /* Received MP_JOIN but the token was not found */ + MPTCP_MIB_JOINSYNRX, /* Received a SYN + MP_JOIN */ ++ MPTCP_MIB_JOINSYNBACKUPRX, /* Received a SYN + MP_JOIN + backup flag */ + MPTCP_MIB_JOINSYNACKRX, /* Received a SYN/ACK + MP_JOIN */ ++ MPTCP_MIB_JOINSYNACKBACKUPRX, /* Received a SYN/ACK + MP_JOIN + backup flag */ + MPTCP_MIB_JOINSYNACKMAC, /* HMAC was wrong on SYN/ACK + MP_JOIN */ + MPTCP_MIB_JOINACKRX, /* Received an ACK + MP_JOIN */ + MPTCP_MIB_JOINACKMAC, /* HMAC was wrong on ACK + MP_JOIN */ +diff --git a/net/mptcp/options.c b/net/mptcp/options.c +index 63fc0758c22d4..85aafa94cc8ab 100644 +--- a/net/mptcp/options.c ++++ b/net/mptcp/options.c +@@ -909,7 +909,7 @@ bool mptcp_synack_options(const struct request_sock *req, unsigned int *size, + return true; + } else if (subflow_req->mp_join) { + opts->suboptions = OPTION_MPTCP_MPJ_SYNACK; +- opts->backup = subflow_req->backup; ++ opts->backup = subflow_req->request_bkup; + opts->join_id = subflow_req->local_id; + opts->thmac = subflow_req->thmac; + opts->nonce = subflow_req->local_nonce; +diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c +index f58bf77d76b81..db621933b2035 100644 +--- a/net/mptcp/pm_netlink.c ++++ b/net/mptcp/pm_netlink.c +@@ -476,7 +476,6 @@ static void __mptcp_pm_send_ack(struct mptcp_sock *msk, struct mptcp_subflow_con + slow = lock_sock_fast(ssk); + if (prio) { + subflow->send_mp_prio = 1; +- subflow->backup = backup; + subflow->request_bkup = backup; + } + +@@ -1432,6 +1431,7 @@ static bool mptcp_pm_remove_anno_addr(struct mptcp_sock *msk, + ret = remove_anno_list_by_saddr(msk, addr); + if (ret || force) { + spin_lock_bh(&msk->pm.lock); ++ msk->pm.add_addr_signaled -= ret; + mptcp_pm_remove_addr(msk, &list); + spin_unlock_bh(&msk->pm.lock); + } +@@ -1565,16 +1565,25 @@ void mptcp_pm_remove_addrs(struct mptcp_sock *msk, struct list_head *rm_list) + { + struct mptcp_rm_list alist = { .nr = 0 }; + struct mptcp_pm_addr_entry *entry; ++ int anno_nr = 0; + + list_for_each_entry(entry, rm_list, list) { +- if ((remove_anno_list_by_saddr(msk, &entry->addr) || +- lookup_subflow_by_saddr(&msk->conn_list, &entry->addr)) && +- alist.nr < MPTCP_RM_IDS_MAX) +- alist.ids[alist.nr++] = entry->addr.id; ++ if (alist.nr >= MPTCP_RM_IDS_MAX) ++ break; ++ ++ /* only delete if either announced or matching a subflow */ ++ if (remove_anno_list_by_saddr(msk, &entry->addr)) ++ anno_nr++; ++ else if (!lookup_subflow_by_saddr(&msk->conn_list, ++ &entry->addr)) ++ continue; ++ ++ alist.ids[alist.nr++] = entry->addr.id; + } + + if (alist.nr) { + spin_lock_bh(&msk->pm.lock); ++ msk->pm.add_addr_signaled -= anno_nr; + mptcp_pm_remove_addr(msk, &alist); + spin_unlock_bh(&msk->pm.lock); + } +@@ -1587,17 +1596,18 @@ void mptcp_pm_remove_addrs_and_subflows(struct mptcp_sock *msk, + struct mptcp_pm_addr_entry *entry; + + list_for_each_entry(entry, rm_list, list) { +- if (lookup_subflow_by_saddr(&msk->conn_list, &entry->addr) && +- slist.nr < MPTCP_RM_IDS_MAX) ++ if (slist.nr < MPTCP_RM_IDS_MAX && ++ lookup_subflow_by_saddr(&msk->conn_list, &entry->addr)) + slist.ids[slist.nr++] = entry->addr.id; + +- if (remove_anno_list_by_saddr(msk, &entry->addr) && +- alist.nr < MPTCP_RM_IDS_MAX) ++ if (alist.nr < MPTCP_RM_IDS_MAX && ++ remove_anno_list_by_saddr(msk, &entry->addr)) + alist.ids[alist.nr++] = entry->addr.id; + } + + if (alist.nr) { + spin_lock_bh(&msk->pm.lock); ++ msk->pm.add_addr_signaled -= alist.nr; + mptcp_pm_remove_addr(msk, &alist); + spin_unlock_bh(&msk->pm.lock); + } +diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c +index fbf2b26760731..c1d652a3f7a9b 100644 +--- a/net/mptcp/protocol.c ++++ b/net/mptcp/protocol.c +@@ -352,8 +352,10 @@ static bool __mptcp_move_skb(struct mptcp_sock *msk, struct sock *ssk, + skb_orphan(skb); + + /* try to fetch required memory from subflow */ +- if (!mptcp_rmem_schedule(sk, ssk, skb->truesize)) ++ if (!mptcp_rmem_schedule(sk, ssk, skb->truesize)) { ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RCVPRUNED); + goto drop; ++ } + + has_rxtstamp = TCP_SKB_CB(skb)->has_rxtstamp; + +@@ -842,16 +844,13 @@ void mptcp_data_ready(struct sock *sk, struct sock *ssk) + sk_rbuf = ssk_rbuf; + + /* over limit? can't append more skbs to msk, Also, no need to wake-up*/ +- if (__mptcp_rmem(sk) > sk_rbuf) { +- MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RCVPRUNED); ++ if (__mptcp_rmem(sk) > sk_rbuf) + return; +- } + + /* Wake-up the reader only for in-sequence data */ + mptcp_data_lock(sk); +- if (move_skbs_to_msk(msk, ssk)) ++ if (move_skbs_to_msk(msk, ssk) && mptcp_epollin_ready(sk)) + sk->sk_data_ready(sk); +- + mptcp_data_unlock(sk); + } + +@@ -1418,13 +1417,15 @@ struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk) + } + + mptcp_for_each_subflow(msk, subflow) { ++ bool backup = subflow->backup || subflow->request_bkup; ++ + trace_mptcp_subflow_get_send(subflow); + ssk = mptcp_subflow_tcp_sock(subflow); + if (!mptcp_subflow_active(subflow)) + continue; + + tout = max(tout, mptcp_timeout_from_subflow(subflow)); +- nr_active += !subflow->backup; ++ nr_active += !backup; + pace = subflow->avg_pacing_rate; + if (unlikely(!pace)) { + /* init pacing rate from socket */ +@@ -1435,9 +1436,9 @@ struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk) + } + + linger_time = div_u64((u64)READ_ONCE(ssk->sk_wmem_queued) << 32, pace); +- if (linger_time < send_info[subflow->backup].linger_time) { +- send_info[subflow->backup].ssk = ssk; +- send_info[subflow->backup].linger_time = linger_time; ++ if (linger_time < send_info[backup].linger_time) { ++ send_info[backup].ssk = ssk; ++ send_info[backup].linger_time = linger_time; + } + } + __mptcp_set_timeout(sk, tout); +@@ -1918,6 +1919,7 @@ static int __mptcp_recvmsg_mskq(struct mptcp_sock *msk, + if (!(flags & MSG_PEEK)) { + MPTCP_SKB_CB(skb)->offset += count; + MPTCP_SKB_CB(skb)->map_seq += count; ++ msk->bytes_consumed += count; + } + break; + } +@@ -1928,6 +1930,7 @@ static int __mptcp_recvmsg_mskq(struct mptcp_sock *msk, + WRITE_ONCE(msk->rmem_released, msk->rmem_released + skb->truesize); + __skb_unlink(skb, &msk->receive_queue); + __kfree_skb(skb); ++ msk->bytes_consumed += count; + } + + if (copied >= len) +@@ -2023,7 +2026,7 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied) + ssk = mptcp_subflow_tcp_sock(subflow); + slow = lock_sock_fast(ssk); + WRITE_ONCE(ssk->sk_rcvbuf, rcvbuf); +- tcp_sk(ssk)->window_clamp = window_clamp; ++ WRITE_ONCE(tcp_sk(ssk)->window_clamp, window_clamp); + tcp_cleanup_rbuf(ssk, 1); + unlock_sock_fast(ssk, slow); + } +@@ -2752,6 +2755,7 @@ static void __mptcp_init_sock(struct sock *sk) + msk->rmem_fwd_alloc = 0; + WRITE_ONCE(msk->rmem_released, 0); + msk->timer_ival = TCP_RTO_MIN; ++ msk->scaling_ratio = TCP_DEFAULT_SCALING_RATIO; + + WRITE_ONCE(msk->first, NULL); + inet_csk(sk)->icsk_sync_mss = mptcp_sync_mss; +@@ -2984,16 +2988,9 @@ void __mptcp_unaccepted_force_close(struct sock *sk) + __mptcp_destroy_sock(sk); + } + +-static __poll_t mptcp_check_readable(struct mptcp_sock *msk) ++static __poll_t mptcp_check_readable(struct sock *sk) + { +- /* Concurrent splices from sk_receive_queue into receive_queue will +- * always show at least one non-empty queue when checked in this order. +- */ +- if (skb_queue_empty_lockless(&((struct sock *)msk)->sk_receive_queue) && +- skb_queue_empty_lockless(&msk->receive_queue)) +- return 0; +- +- return EPOLLIN | EPOLLRDNORM; ++ return mptcp_epollin_ready(sk) ? EPOLLIN | EPOLLRDNORM : 0; + } + + static void mptcp_check_listen_stop(struct sock *sk) +@@ -3031,7 +3028,7 @@ bool __mptcp_close(struct sock *sk, long timeout) + goto cleanup; + } + +- if (mptcp_check_readable(msk) || timeout < 0) { ++ if (mptcp_data_avail(msk) || timeout < 0) { + /* If the msk has read data, or the caller explicitly ask it, + * do the MPTCP equivalent of TCP reset, aka MPTCP fastclose + */ +@@ -3157,6 +3154,7 @@ static int mptcp_disconnect(struct sock *sk, int flags) + msk->snd_data_fin_enable = false; + msk->rcv_fastclose = false; + msk->use_64bit_ack = false; ++ msk->bytes_consumed = 0; + WRITE_ONCE(msk->csum_enabled, mptcp_is_checksum_enabled(sock_net(sk))); + mptcp_pm_data_reset(msk); + mptcp_ca_reset(sk); +@@ -3983,7 +3981,7 @@ static __poll_t mptcp_poll(struct file *file, struct socket *sock, + mask |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP; + + if (state != TCP_SYN_SENT && state != TCP_SYN_RECV) { +- mask |= mptcp_check_readable(msk); ++ mask |= mptcp_check_readable(sk); + if (shutdown & SEND_SHUTDOWN) + mask |= EPOLLOUT | EPOLLWRNORM; + else +@@ -4021,6 +4019,7 @@ static const struct proto_ops mptcp_stream_ops = { + .sendmsg = inet_sendmsg, + .recvmsg = inet_recvmsg, + .mmap = sock_no_mmap, ++ .set_rcvlowat = mptcp_set_rcvlowat, + }; + + static struct inet_protosw mptcp_protosw = { +@@ -4122,6 +4121,7 @@ static const struct proto_ops mptcp_v6_stream_ops = { + #ifdef CONFIG_COMPAT + .compat_ioctl = inet6_compat_ioctl, + #endif ++ .set_rcvlowat = mptcp_set_rcvlowat, + }; + + static struct proto mptcp_v6_prot; +diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h +index 93ba48f4ae386..c28ac5dfd0b58 100644 +--- a/net/mptcp/protocol.h ++++ b/net/mptcp/protocol.h +@@ -268,6 +268,7 @@ struct mptcp_sock { + atomic64_t rcv_wnd_sent; + u64 rcv_data_fin_seq; + u64 bytes_retrans; ++ u64 bytes_consumed; + int rmem_fwd_alloc; + int snd_burst; + int old_wspace; +@@ -418,6 +419,7 @@ struct mptcp_subflow_request_sock { + u16 mp_capable : 1, + mp_join : 1, + backup : 1, ++ request_bkup : 1, + csum_reqd : 1, + allow_join_id0 : 1; + u8 local_id; +@@ -674,6 +676,24 @@ struct sock *mptcp_subflow_get_retrans(struct mptcp_sock *msk); + int mptcp_sched_get_send(struct mptcp_sock *msk); + int mptcp_sched_get_retrans(struct mptcp_sock *msk); + ++static inline u64 mptcp_data_avail(const struct mptcp_sock *msk) ++{ ++ return READ_ONCE(msk->bytes_received) - READ_ONCE(msk->bytes_consumed); ++} ++ ++static inline bool mptcp_epollin_ready(const struct sock *sk) ++{ ++ /* mptcp doesn't have to deal with small skbs in the receive queue, ++ * at it can always coalesce them ++ */ ++ return (mptcp_data_avail(mptcp_sk(sk)) >= sk->sk_rcvlowat) || ++ (mem_cgroup_sockets_enabled && sk->sk_memcg && ++ mem_cgroup_under_socket_pressure(sk->sk_memcg)) || ++ READ_ONCE(tcp_memory_pressure); ++} ++ ++int mptcp_set_rcvlowat(struct sock *sk, int val); ++ + static inline bool __tcp_can_send(const struct sock *ssk) + { + /* only send if our side has not closed yet */ +@@ -748,6 +768,7 @@ static inline bool mptcp_is_fully_established(struct sock *sk) + return inet_sk_state_load(sk) == TCP_ESTABLISHED && + READ_ONCE(mptcp_sk(sk)->fully_established); + } ++ + void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk); + void mptcp_data_ready(struct sock *sk, struct sock *ssk); + bool mptcp_finish_join(struct sock *sk); +diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c +index cc04b5e29dd35..bdfeecea814f3 100644 +--- a/net/mptcp/sockopt.c ++++ b/net/mptcp/sockopt.c +@@ -1521,9 +1521,55 @@ void mptcp_sockopt_sync_locked(struct mptcp_sock *msk, struct sock *ssk) + + msk_owned_by_me(msk); + ++ ssk->sk_rcvlowat = 0; ++ + if (READ_ONCE(subflow->setsockopt_seq) != msk->setsockopt_seq) { + sync_socket_options(msk, ssk); + + subflow->setsockopt_seq = msk->setsockopt_seq; + } + } ++ ++/* unfortunately this is different enough from the tcp version so ++ * that we can't factor it out ++ */ ++int mptcp_set_rcvlowat(struct sock *sk, int val) ++{ ++ struct mptcp_subflow_context *subflow; ++ int space, cap; ++ ++ /* bpf can land here with a wrong sk type */ ++ if (sk->sk_protocol == IPPROTO_TCP) ++ return -EINVAL; ++ ++ if (sk->sk_userlocks & SOCK_RCVBUF_LOCK) ++ cap = sk->sk_rcvbuf >> 1; ++ else ++ cap = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2]) >> 1; ++ val = min(val, cap); ++ WRITE_ONCE(sk->sk_rcvlowat, val ? : 1); ++ ++ /* Check if we need to signal EPOLLIN right now */ ++ if (mptcp_epollin_ready(sk)) ++ sk->sk_data_ready(sk); ++ ++ if (sk->sk_userlocks & SOCK_RCVBUF_LOCK) ++ return 0; ++ ++ space = __tcp_space_from_win(mptcp_sk(sk)->scaling_ratio, val); ++ if (space <= sk->sk_rcvbuf) ++ return 0; ++ ++ /* propagate the rcvbuf changes to all the subflows */ ++ WRITE_ONCE(sk->sk_rcvbuf, space); ++ mptcp_for_each_subflow(mptcp_sk(sk), subflow) { ++ struct sock *ssk = mptcp_subflow_tcp_sock(subflow); ++ bool slow; ++ ++ slow = lock_sock_fast(ssk); ++ WRITE_ONCE(ssk->sk_rcvbuf, space); ++ WRITE_ONCE(tcp_sk(ssk)->window_clamp, val); ++ unlock_sock_fast(ssk, slow); ++ } ++ return 0; ++} +diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c +index 23ee96c6abcbf..bc1efc1787720 100644 +--- a/net/mptcp/subflow.c ++++ b/net/mptcp/subflow.c +@@ -166,6 +166,9 @@ static int subflow_check_req(struct request_sock *req, + return 0; + } else if (opt_mp_join) { + SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINSYNRX); ++ ++ if (mp_opt.backup) ++ SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINSYNBACKUPRX); + } + + if (opt_mp_capable && listener->request_mptcp) { +@@ -558,6 +561,9 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb) + subflow->mp_join = 1; + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINSYNACKRX); + ++ if (subflow->backup) ++ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINSYNACKBACKUPRX); ++ + if (subflow_use_different_dport(msk, sk)) { + pr_debug("synack inet_dport=%d %d", + ntohs(inet_sk(sk)->inet_dport), +@@ -1192,14 +1198,22 @@ static void mptcp_subflow_discard_data(struct sock *ssk, struct sk_buff *skb, + { + struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk); + bool fin = TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN; +- u32 incr; ++ struct tcp_sock *tp = tcp_sk(ssk); ++ u32 offset, incr, avail_len; ++ ++ offset = tp->copied_seq - TCP_SKB_CB(skb)->seq; ++ if (WARN_ON_ONCE(offset > skb->len)) ++ goto out; + +- incr = limit >= skb->len ? skb->len + fin : limit; ++ avail_len = skb->len - offset; ++ incr = limit >= avail_len ? avail_len + fin : limit; + +- pr_debug("discarding=%d len=%d seq=%d", incr, skb->len, +- subflow->map_subflow_seq); ++ pr_debug("discarding=%d len=%d offset=%d seq=%d", incr, skb->len, ++ offset, subflow->map_subflow_seq); + MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_DUPDATA); + tcp_sk(ssk)->copied_seq += incr; ++ ++out: + if (!before(tcp_sk(ssk)->copied_seq, TCP_SKB_CB(skb)->end_seq)) + sk_eat_skb(ssk, skb); + if (mptcp_subflow_get_map_offset(subflow) >= subflow->map_data_len) +@@ -1432,10 +1446,18 @@ static void subflow_data_ready(struct sock *sk) + WARN_ON_ONCE(!__mptcp_check_fallback(msk) && !subflow->mp_capable && + !subflow->mp_join && !(state & TCPF_CLOSE)); + +- if (mptcp_subflow_data_available(sk)) ++ if (mptcp_subflow_data_available(sk)) { + mptcp_data_ready(parent, sk); +- else if (unlikely(sk->sk_err)) ++ ++ /* subflow-level lowat test are not relevant. ++ * respect the msk-level threshold eventually mandating an immediate ack ++ */ ++ if (mptcp_data_avail(msk) < parent->sk_rcvlowat && ++ (tcp_sk(sk)->rcv_nxt - tcp_sk(sk)->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss) ++ inet_csk(sk)->icsk_ack.pending |= ICSK_ACK_NOW; ++ } else if (unlikely(sk->sk_err)) { + subflow_error_report(sk); ++ } + } + + static void subflow_write_space(struct sock *ssk) +@@ -1968,6 +1990,7 @@ static void subflow_ulp_clone(const struct request_sock *req, + new_ctx->fully_established = 1; + new_ctx->remote_key_valid = 1; + new_ctx->backup = subflow_req->backup; ++ new_ctx->request_bkup = subflow_req->request_bkup; + WRITE_ONCE(new_ctx->remote_id, subflow_req->remote_id); + new_ctx->token = subflow_req->token; + new_ctx->thmac = subflow_req->thmac; +diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c +index 3ac19516ed803..50d24e240e8fb 100644 +--- a/net/sched/act_ct.c ++++ b/net/sched/act_ct.c +@@ -44,6 +44,8 @@ static DEFINE_MUTEX(zones_mutex); + struct zones_ht_key { + struct net *net; + u16 zone; ++ /* Note : pad[] must be the last field. */ ++ u8 pad[]; + }; + + struct tcf_ct_flow_table { +@@ -60,7 +62,7 @@ struct tcf_ct_flow_table { + static const struct rhashtable_params zones_params = { + .head_offset = offsetof(struct tcf_ct_flow_table, node), + .key_offset = offsetof(struct tcf_ct_flow_table, key), +- .key_len = sizeof_field(struct tcf_ct_flow_table, key), ++ .key_len = offsetof(struct zones_ht_key, pad), + .automatic_shrinking = true, + }; + +diff --git a/net/sysctl_net.c b/net/sysctl_net.c +index 051ed5f6fc937..a0a7a79991f9f 100644 +--- a/net/sysctl_net.c ++++ b/net/sysctl_net.c +@@ -54,7 +54,6 @@ static int net_ctl_permissions(struct ctl_table_header *head, + } + + static void net_ctl_set_ownership(struct ctl_table_header *head, +- struct ctl_table *table, + kuid_t *uid, kgid_t *gid) + { + struct net *net = container_of(head->set, struct net, sysctls); +diff --git a/net/wireless/sme.c b/net/wireless/sme.c +index 9bba233b5a6ec..72d78dbc55ffd 100644 +--- a/net/wireless/sme.c ++++ b/net/wireless/sme.c +@@ -1057,6 +1057,7 @@ void cfg80211_connect_done(struct net_device *dev, + cfg80211_hold_bss( + bss_from_pub(params->links[link].bss)); + ev->cr.links[link].bss = params->links[link].bss; ++ ev->cr.links[link].status = params->links[link].status; + + if (params->links[link].addr) { + ev->cr.links[link].addr = next; +diff --git a/sound/core/seq/seq_ump_convert.c b/sound/core/seq/seq_ump_convert.c +index e90b27a135e6f..d9dacfbe4a9ae 100644 +--- a/sound/core/seq/seq_ump_convert.c ++++ b/sound/core/seq/seq_ump_convert.c +@@ -1192,44 +1192,53 @@ static int cvt_sysex_to_ump(struct snd_seq_client *dest, + { + struct snd_seq_ump_event ev_cvt; + unsigned char status; +- u8 buf[6], *xbuf; ++ u8 buf[8], *xbuf; + int offset = 0; + int len, err; ++ bool finished = false; + + if (!snd_seq_ev_is_variable(event)) + return 0; + + setup_ump_event(&ev_cvt, event); +- for (;;) { ++ while (!finished) { + len = snd_seq_expand_var_event_at(event, sizeof(buf), buf, offset); + if (len <= 0) + break; +- if (WARN_ON(len > 6)) ++ if (WARN_ON(len > sizeof(buf))) + break; +- offset += len; ++ + xbuf = buf; ++ status = UMP_SYSEX_STATUS_CONTINUE; ++ /* truncate the sysex start-marker */ + if (*xbuf == UMP_MIDI1_MSG_SYSEX_START) { + status = UMP_SYSEX_STATUS_START; +- xbuf++; + len--; +- if (len > 0 && xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) { ++ offset++; ++ xbuf++; ++ } ++ ++ /* if the last of this packet or the 1st byte of the next packet ++ * is the end-marker, finish the transfer with this packet ++ */ ++ if (len > 0 && len < 8 && ++ xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) { ++ if (status == UMP_SYSEX_STATUS_START) + status = UMP_SYSEX_STATUS_SINGLE; +- len--; +- } +- } else { +- if (xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) { ++ else + status = UMP_SYSEX_STATUS_END; +- len--; +- } else { +- status = UMP_SYSEX_STATUS_CONTINUE; +- } ++ len--; ++ finished = true; + } ++ ++ len = min(len, 6); + fill_sysex7_ump(dest_port, ev_cvt.ump, status, xbuf, len); + err = __snd_seq_deliver_single_event(dest, dest_port, + (struct snd_seq_event *)&ev_cvt, + atomic, hop); + if (err < 0) + return err; ++ offset += len; + } + return 0; + } +diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c +index c9f153f85ae6b..5f0f8d9c08d1e 100644 +--- a/sound/firewire/amdtp-stream.c ++++ b/sound/firewire/amdtp-stream.c +@@ -77,6 +77,8 @@ + // overrun. Actual device can skip more, then this module stops the packet streaming. + #define IR_JUMBO_PAYLOAD_MAX_SKIP_CYCLES 5 + ++static void pcm_period_work(struct work_struct *work); ++ + /** + * amdtp_stream_init - initialize an AMDTP stream structure + * @s: the AMDTP stream to initialize +@@ -105,6 +107,7 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, + s->flags = flags; + s->context = ERR_PTR(-1); + mutex_init(&s->mutex); ++ INIT_WORK(&s->period_work, pcm_period_work); + s->packet_index = 0; + + init_waitqueue_head(&s->ready_wait); +@@ -347,6 +350,7 @@ EXPORT_SYMBOL(amdtp_stream_get_max_payload); + */ + void amdtp_stream_pcm_prepare(struct amdtp_stream *s) + { ++ cancel_work_sync(&s->period_work); + s->pcm_buffer_pointer = 0; + s->pcm_period_pointer = 0; + } +@@ -611,19 +615,21 @@ static void update_pcm_pointers(struct amdtp_stream *s, + // The program in user process should periodically check the status of intermediate + // buffer associated to PCM substream to process PCM frames in the buffer, instead + // of receiving notification of period elapsed by poll wait. +- if (!pcm->runtime->no_period_wakeup) { +- if (in_softirq()) { +- // In software IRQ context for 1394 OHCI. +- snd_pcm_period_elapsed(pcm); +- } else { +- // In process context of ALSA PCM application under acquired lock of +- // PCM substream. +- snd_pcm_period_elapsed_under_stream_lock(pcm); +- } +- } ++ if (!pcm->runtime->no_period_wakeup) ++ queue_work(system_highpri_wq, &s->period_work); + } + } + ++static void pcm_period_work(struct work_struct *work) ++{ ++ struct amdtp_stream *s = container_of(work, struct amdtp_stream, ++ period_work); ++ struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); ++ ++ if (pcm) ++ snd_pcm_period_elapsed(pcm); ++} ++ + static int queue_packet(struct amdtp_stream *s, struct fw_iso_packet *params, + bool sched_irq) + { +@@ -1852,11 +1858,14 @@ unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d, + { + struct amdtp_stream *irq_target = d->irq_target; + +- // Process isochronous packets queued till recent isochronous cycle to handle PCM frames. + if (irq_target && amdtp_stream_running(irq_target)) { +- // In software IRQ context, the call causes dead-lock to disable the tasklet +- // synchronously. +- if (!in_softirq()) ++ // use wq to prevent AB/BA deadlock competition for ++ // substream lock: ++ // fw_iso_context_flush_completions() acquires ++ // lock by ohci_flush_iso_completions(), ++ // amdtp-stream process_rx_packets() attempts to ++ // acquire same lock by snd_pcm_elapsed() ++ if (current_work() != &s->period_work) + fw_iso_context_flush_completions(irq_target->context); + } + +@@ -1912,6 +1921,7 @@ static void amdtp_stream_stop(struct amdtp_stream *s) + return; + } + ++ cancel_work_sync(&s->period_work); + fw_iso_context_stop(s->context); + fw_iso_context_destroy(s->context); + s->context = ERR_PTR(-1); +diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h +index a1ed2e80f91a7..775db3fc4959f 100644 +--- a/sound/firewire/amdtp-stream.h ++++ b/sound/firewire/amdtp-stream.h +@@ -191,6 +191,7 @@ struct amdtp_stream { + + /* For a PCM substream processing. */ + struct snd_pcm_substream *pcm; ++ struct work_struct period_work; + snd_pcm_uframes_t pcm_buffer_pointer; + unsigned int pcm_period_pointer; + unsigned int pcm_frame_multiplier; +diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h +index 8556031bcd68e..f31cb31d46362 100644 +--- a/sound/pci/hda/hda_controller.h ++++ b/sound/pci/hda/hda_controller.h +@@ -28,7 +28,7 @@ + #else + #define AZX_DCAPS_I915_COMPONENT 0 /* NOP */ + #endif +-/* 14 unused */ ++#define AZX_DCAPS_AMD_ALLOC_FIX (1 << 14) /* AMD allocation workaround */ + #define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */ + #define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */ + #define AZX_DCAPS_AMD_WORKAROUND (1 << 17) /* AMD-specific workaround */ +diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c +index a6a9d353fe635..d5c9f113e477a 100644 +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -40,6 +40,7 @@ + + #ifdef CONFIG_X86 + /* for snoop control */ ++#include <linux/dma-map-ops.h> + #include <asm/set_memory.h> + #include <asm/cpufeature.h> + #endif +@@ -301,7 +302,7 @@ enum { + + /* quirks for ATI HDMI with snoop off */ + #define AZX_DCAPS_PRESET_ATI_HDMI_NS \ +- (AZX_DCAPS_PRESET_ATI_HDMI | AZX_DCAPS_SNOOP_OFF) ++ (AZX_DCAPS_PRESET_ATI_HDMI | AZX_DCAPS_AMD_ALLOC_FIX) + + /* quirks for AMD SB */ + #define AZX_DCAPS_PRESET_AMD_SB \ +@@ -1715,6 +1716,13 @@ static void azx_check_snoop_available(struct azx *chip) + if (chip->driver_caps & AZX_DCAPS_SNOOP_OFF) + snoop = false; + ++#ifdef CONFIG_X86 ++ /* check the presence of DMA ops (i.e. IOMMU), disable snoop conditionally */ ++ if ((chip->driver_caps & AZX_DCAPS_AMD_ALLOC_FIX) && ++ !get_dma_ops(chip->card->dev)) ++ snoop = false; ++#endif ++ + chip->snoop = snoop; + if (!snoop) { + dev_info(chip->card->dev, "Force to non-snoop mode\n"); +diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c +index e8209178d87bb..af921364195e4 100644 +--- a/sound/pci/hda/patch_conexant.c ++++ b/sound/pci/hda/patch_conexant.c +@@ -21,12 +21,6 @@ + #include "hda_jack.h" + #include "hda_generic.h" + +-enum { +- CX_HEADSET_NOPRESENT = 0, +- CX_HEADSET_PARTPRESENT, +- CX_HEADSET_ALLPRESENT, +-}; +- + struct conexant_spec { + struct hda_gen_spec gen; + +@@ -48,7 +42,6 @@ struct conexant_spec { + unsigned int gpio_led; + unsigned int gpio_mute_led_mask; + unsigned int gpio_mic_led_mask; +- unsigned int headset_present_flag; + bool is_cx8070_sn6140; + }; + +@@ -250,48 +243,19 @@ static void cx_process_headset_plugin(struct hda_codec *codec) + } + } + +-static void cx_update_headset_mic_vref(struct hda_codec *codec, unsigned int res) ++static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_callback *event) + { +- unsigned int phone_present, mic_persent, phone_tag, mic_tag; +- struct conexant_spec *spec = codec->spec; ++ unsigned int mic_present; + + /* In cx8070 and sn6140, the node 16 can only be config to headphone or disabled, + * the node 19 can only be config to microphone or disabled. + * Check hp&mic tag to process headset pulgin&plugout. + */ +- phone_tag = snd_hda_codec_read(codec, 0x16, 0, AC_VERB_GET_UNSOLICITED_RESPONSE, 0x0); +- mic_tag = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_UNSOLICITED_RESPONSE, 0x0); +- if ((phone_tag & (res >> AC_UNSOL_RES_TAG_SHIFT)) || +- (mic_tag & (res >> AC_UNSOL_RES_TAG_SHIFT))) { +- phone_present = snd_hda_codec_read(codec, 0x16, 0, AC_VERB_GET_PIN_SENSE, 0x0); +- if (!(phone_present & AC_PINSENSE_PRESENCE)) {/* headphone plugout */ +- spec->headset_present_flag = CX_HEADSET_NOPRESENT; +- snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20); +- return; +- } +- if (spec->headset_present_flag == CX_HEADSET_NOPRESENT) { +- spec->headset_present_flag = CX_HEADSET_PARTPRESENT; +- } else if (spec->headset_present_flag == CX_HEADSET_PARTPRESENT) { +- mic_persent = snd_hda_codec_read(codec, 0x19, 0, +- AC_VERB_GET_PIN_SENSE, 0x0); +- /* headset is present */ +- if ((phone_present & AC_PINSENSE_PRESENCE) && +- (mic_persent & AC_PINSENSE_PRESENCE)) { +- cx_process_headset_plugin(codec); +- spec->headset_present_flag = CX_HEADSET_ALLPRESENT; +- } +- } +- } +-} +- +-static void cx_jack_unsol_event(struct hda_codec *codec, unsigned int res) +-{ +- struct conexant_spec *spec = codec->spec; +- +- if (spec->is_cx8070_sn6140) +- cx_update_headset_mic_vref(codec, res); +- +- snd_hda_jack_unsol_event(codec, res); ++ mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0); ++ if (!(mic_present & AC_PINSENSE_PRESENCE)) /* mic plugout */ ++ snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20); ++ else ++ cx_process_headset_plugin(codec); + } + + #ifdef CONFIG_PM +@@ -307,7 +271,7 @@ static const struct hda_codec_ops cx_auto_patch_ops = { + .build_pcms = snd_hda_gen_build_pcms, + .init = cx_auto_init, + .free = cx_auto_free, +- .unsol_event = cx_jack_unsol_event, ++ .unsol_event = snd_hda_jack_unsol_event, + #ifdef CONFIG_PM + .suspend = cx_auto_suspend, + .check_power_status = snd_hda_gen_check_power_status, +@@ -1167,7 +1131,7 @@ static int patch_conexant_auto(struct hda_codec *codec) + case 0x14f11f86: + case 0x14f11f87: + spec->is_cx8070_sn6140 = true; +- spec->headset_present_flag = CX_HEADSET_NOPRESENT; ++ snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref); + break; + } + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index f3aca1c38b77d..0b33a00771450 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -9639,6 +9639,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS), + SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x0840, "Acer Aspire E1", ALC269VB_FIXUP_ASPIRE_E1_COEF), ++ SND_PCI_QUIRK(0x1025, 0x100c, "Acer Aspire E5-574G", ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x1025, 0x101c, "Acer Veriton N2510G", ALC269_FIXUP_LIFEBOOK), + SND_PCI_QUIRK(0x1025, 0x102b, "Acer Aspire C24-860", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1025, 0x1065, "Acer Aspire C20-820", ALC269VC_FIXUP_ACER_HEADSET_MIC), +diff --git a/sound/usb/stream.c b/sound/usb/stream.c +index d5409f3879455..e14c725acebf2 100644 +--- a/sound/usb/stream.c ++++ b/sound/usb/stream.c +@@ -244,8 +244,8 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits, + SNDRV_CHMAP_FR, /* right front */ + SNDRV_CHMAP_FC, /* center front */ + SNDRV_CHMAP_LFE, /* LFE */ +- SNDRV_CHMAP_SL, /* left surround */ +- SNDRV_CHMAP_SR, /* right surround */ ++ SNDRV_CHMAP_RL, /* left surround */ ++ SNDRV_CHMAP_RR, /* right surround */ + SNDRV_CHMAP_FLC, /* left of center */ + SNDRV_CHMAP_FRC, /* right of center */ + SNDRV_CHMAP_RC, /* surround */ +diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c +index aee937d14fbbf..09e6b4e1401c9 100644 +--- a/tools/perf/util/callchain.c ++++ b/tools/perf/util/callchain.c +@@ -1126,7 +1126,7 @@ int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *samp + int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node, + bool hide_unresolved) + { +- struct machine *machine = maps__machine(node->ms.maps); ++ struct machine *machine = node->ms.maps ? maps__machine(node->ms.maps) : NULL; + + maps__put(al->maps); + al->maps = maps__get(node->ms.maps); +diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/testing/selftests/net/mptcp/mptcp_connect.c +index d2043ec3bf6d6..4209b95690394 100644 +--- a/tools/testing/selftests/net/mptcp/mptcp_connect.c ++++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c +@@ -1115,11 +1115,11 @@ int main_loop_s(int listensock) + return 1; + } + +- if (--cfg_repeat > 0) { +- if (cfg_input) +- close(fd); ++ if (cfg_input) ++ close(fd); ++ ++ if (--cfg_repeat > 0) + goto again; +- } + + return 0; + } +diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh +index 231a95a8de9ee..a2dae2a3a93e0 100755 +--- a/tools/testing/selftests/net/mptcp/mptcp_join.sh ++++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh +@@ -1778,6 +1778,8 @@ chk_prio_nr() + { + local mp_prio_nr_tx=$1 + local mp_prio_nr_rx=$2 ++ local mpj_syn=$3 ++ local mpj_syn_ack=$4 + local count + + print_check "ptx" +@@ -1799,6 +1801,26 @@ chk_prio_nr() + else + print_ok + fi ++ ++ print_check "syn backup" ++ count=$(mptcp_lib_get_counter ${ns1} "MPTcpExtMPJoinSynBackupRx") ++ if [ -z "$count" ]; then ++ print_skip ++ elif [ "$count" != "$mpj_syn" ]; then ++ fail_test "got $count JOIN[s] syn with Backup expected $mpj_syn" ++ else ++ print_ok ++ fi ++ ++ print_check "synack backup" ++ count=$(mptcp_lib_get_counter ${ns2} "MPTcpExtMPJoinSynAckBackupRx") ++ if [ -z "$count" ]; then ++ print_skip ++ elif [ "$count" != "$mpj_syn_ack" ]; then ++ fail_test "got $count JOIN[s] synack with Backup expected $mpj_syn_ack" ++ else ++ print_ok ++ fi + } + + chk_subflow_nr() +@@ -2751,11 +2773,24 @@ backup_tests() + sflags=nobackup speed=slow \ + run_tests $ns1 $ns2 10.0.1.1 + chk_join_nr 1 1 1 +- chk_prio_nr 0 1 ++ chk_prio_nr 0 1 1 0 + fi + + # single address, backup + if reset "single address, backup" && ++ continue_if mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then ++ pm_nl_set_limits $ns1 0 1 ++ pm_nl_add_endpoint $ns1 10.0.2.1 flags signal,backup ++ pm_nl_set_limits $ns2 1 1 ++ sflags=nobackup speed=slow \ ++ run_tests $ns1 $ns2 10.0.1.1 ++ chk_join_nr 1 1 1 ++ chk_add_nr 1 1 ++ chk_prio_nr 1 0 0 1 ++ fi ++ ++ # single address, switch to backup ++ if reset "single address, switch to backup" && + continue_if mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then + pm_nl_set_limits $ns1 0 1 + pm_nl_add_endpoint $ns1 10.0.2.1 flags signal +@@ -2764,20 +2799,20 @@ backup_tests() + run_tests $ns1 $ns2 10.0.1.1 + chk_join_nr 1 1 1 + chk_add_nr 1 1 +- chk_prio_nr 1 1 ++ chk_prio_nr 1 1 0 0 + fi + + # single address with port, backup + if reset "single address with port, backup" && + continue_if mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then + pm_nl_set_limits $ns1 0 1 +- pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100 ++ pm_nl_add_endpoint $ns1 10.0.2.1 flags signal,backup port 10100 + pm_nl_set_limits $ns2 1 1 +- sflags=backup speed=slow \ ++ sflags=nobackup speed=slow \ + run_tests $ns1 $ns2 10.0.1.1 + chk_join_nr 1 1 1 + chk_add_nr 1 1 +- chk_prio_nr 1 1 ++ chk_prio_nr 1 0 0 1 + fi + + if reset "mpc backup" && +@@ -2786,17 +2821,26 @@ backup_tests() + speed=slow \ + run_tests $ns1 $ns2 10.0.1.1 + chk_join_nr 0 0 0 +- chk_prio_nr 0 1 ++ chk_prio_nr 0 1 0 0 + fi + + if reset "mpc backup both sides" && + continue_if mptcp_lib_kallsyms_doesnt_have "T mptcp_subflow_send_ack$"; then +- pm_nl_add_endpoint $ns1 10.0.1.1 flags subflow,backup ++ pm_nl_set_limits $ns1 0 2 ++ pm_nl_set_limits $ns2 1 2 ++ pm_nl_add_endpoint $ns1 10.0.1.1 flags signal,backup + pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow,backup ++ ++ # 10.0.2.2 (non-backup) -> 10.0.1.1 (backup) ++ pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow ++ # 10.0.1.2 (backup) -> 10.0.2.1 (non-backup) ++ pm_nl_add_endpoint $ns1 10.0.2.1 flags signal ++ ip -net "$ns2" route add 10.0.2.1 via 10.0.1.1 dev ns2eth1 # force this path ++ + speed=slow \ + run_tests $ns1 $ns2 10.0.1.1 +- chk_join_nr 0 0 0 +- chk_prio_nr 1 1 ++ chk_join_nr 2 2 2 ++ chk_prio_nr 1 1 1 1 + fi + + if reset "mpc switch to backup" && +@@ -2805,7 +2849,7 @@ backup_tests() + sflags=backup speed=slow \ + run_tests $ns1 $ns2 10.0.1.1 + chk_join_nr 0 0 0 +- chk_prio_nr 0 1 ++ chk_prio_nr 0 1 0 0 + fi + + if reset "mpc switch to backup both sides" && +@@ -2815,7 +2859,7 @@ backup_tests() + sflags=backup speed=slow \ + run_tests $ns1 $ns2 10.0.1.1 + chk_join_nr 0 0 0 +- chk_prio_nr 1 1 ++ chk_prio_nr 1 1 0 0 + fi + } + +@@ -3215,7 +3259,7 @@ fullmesh_tests() + addr_nr_ns2=1 sflags=backup,fullmesh speed=slow \ + run_tests $ns1 $ns2 10.0.1.1 + chk_join_nr 2 2 2 +- chk_prio_nr 0 1 ++ chk_prio_nr 0 1 1 0 + chk_rm_nr 0 1 + fi + +@@ -3228,7 +3272,7 @@ fullmesh_tests() + sflags=nobackup,nofullmesh speed=slow \ + run_tests $ns1 $ns2 10.0.1.1 + chk_join_nr 2 2 2 +- chk_prio_nr 0 1 ++ chk_prio_nr 0 1 1 0 + chk_rm_nr 0 1 + fi + } +@@ -3407,7 +3451,7 @@ userspace_tests() + sflags=backup speed=slow \ + run_tests $ns1 $ns2 10.0.1.1 + chk_join_nr 1 1 0 +- chk_prio_nr 0 0 ++ chk_prio_nr 0 0 0 0 + fi + + # userspace pm type prevents rm_addr |