summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pagano <mpagano@gentoo.org>2022-07-12 11:58:51 -0400
committerMike Pagano <mpagano@gentoo.org>2022-07-12 11:58:51 -0400
commit4824c4b5ea3aecde6921c31db83c00a5ce263107 (patch)
tree9009dc45e6ae8244ce1c4235e9b069e9fd971939
parentLinux patch 5.15.53 (diff)
downloadlinux-patches-4824c4b5ea3aecde6921c31db83c00a5ce263107.tar.gz
linux-patches-4824c4b5ea3aecde6921c31db83c00a5ce263107.tar.bz2
linux-patches-4824c4b5ea3aecde6921c31db83c00a5ce263107.zip
Linux patch 5.15.545.15-58
Signed-off-by: Mike Pagano <mpagano@gentoo.org>
-rw-r--r--0000_README4
-rw-r--r--1053_linux-5.15.54.patch13095
2 files changed, 13099 insertions, 0 deletions
diff --git a/0000_README b/0000_README
index 4a6d5005..faf4691f 100644
--- a/0000_README
+++ b/0000_README
@@ -255,6 +255,10 @@ Patch: 1052_linux-5.15.53.patch
From: http://www.kernel.org
Desc: Linux 5.15.53
+Patch: 1053_linux-5.15.54.patch
+From: http://www.kernel.org
+Desc: Linux 5.15.54
+
Patch: 1500_XATTR_USER_PREFIX.patch
From: https://bugs.gentoo.org/show_bug.cgi?id=470644
Desc: Support for namespace user.pax.* on tmpfs.
diff --git a/1053_linux-5.15.54.patch b/1053_linux-5.15.54.patch
new file mode 100644
index 00000000..587df41d
--- /dev/null
+++ b/1053_linux-5.15.54.patch
@@ -0,0 +1,13095 @@
+diff --git a/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml b/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml
+index b6e1ebfaf3666..bb3cbc30d9121 100644
+--- a/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml
++++ b/Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml
+@@ -64,7 +64,7 @@ if:
+ then:
+ properties:
+ clocks:
+- maxItems: 2
++ minItems: 2
+
+ required:
+ - clock-names
+diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml
+index cc3fe5ed7421e..1b0062e3c1a4b 100644
+--- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml
++++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml
+@@ -34,6 +34,8 @@ properties:
+ - qcom,rpm-ipq6018
+ - qcom,rpm-msm8226
+ - qcom,rpm-msm8916
++ - qcom,rpm-msm8936
++ - qcom,rpm-msm8953
+ - qcom,rpm-msm8974
+ - qcom,rpm-msm8976
+ - qcom,rpm-msm8996
+@@ -57,6 +59,7 @@ if:
+ - qcom,rpm-apq8084
+ - qcom,rpm-msm8916
+ - qcom,rpm-msm8974
++ - qcom,rpm-msm8953
+ then:
+ required:
+ - qcom,smd-channels
+diff --git a/MAINTAINERS b/MAINTAINERS
+index a60d7e0466afa..edc32575828b5 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -7952,9 +7952,10 @@ F: drivers/media/usb/go7007/
+
+ GOODIX TOUCHSCREEN
+ M: Bastien Nocera <hadess@hadess.net>
++M: Hans de Goede <hdegoede@redhat.com>
+ L: linux-input@vger.kernel.org
+ S: Maintained
+-F: drivers/input/touchscreen/goodix.c
++F: drivers/input/touchscreen/goodix*
+
+ GOOGLE ETHERNET DRIVERS
+ M: Jeroen de Borst <jeroendb@google.com>
+diff --git a/Makefile b/Makefile
+index c7750d260a551..f8dc156aa3021 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ VERSION = 5
+ PATCHLEVEL = 15
+-SUBLEVEL = 53
++SUBLEVEL = 54
+ EXTRAVERSION =
+ NAME = Trick or Treat
+
+@@ -1011,6 +1011,21 @@ ifdef CONFIG_CC_IS_GCC
+ KBUILD_CFLAGS += -Wno-maybe-uninitialized
+ endif
+
++ifdef CONFIG_CC_IS_GCC
++# The allocators already balk at large sizes, so silence the compiler
++# warnings for bounds checks involving those possible values. While
++# -Wno-alloc-size-larger-than would normally be used here, earlier versions
++# of gcc (<9.1) weirdly don't handle the option correctly when _other_
++# warnings are produced (?!). Using -Walloc-size-larger-than=SIZE_MAX
++# doesn't work (as it is documented to), silently resolving to "0" prior to
++# version 9.1 (and producing an error more recently). Numeric values larger
++# than PTRDIFF_MAX also don't work prior to version 9.1, which are silently
++# ignored, continuing to default to PTRDIFF_MAX. So, left with no other
++# choice, we must perform a versioned check to disable this warning.
++# https://lore.kernel.org/lkml/20210824115859.187f272f@canb.auug.org.au
++KBUILD_CFLAGS += $(call cc-ifversion, -ge, 0901, -Wno-alloc-size-larger-than)
++endif
++
+ # disable invalid "can't wrap" optimizations for signed / pointers
+ KBUILD_CFLAGS += -fno-strict-overflow
+
+diff --git a/arch/arm/boot/dts/at91-sam9x60ek.dts b/arch/arm/boot/dts/at91-sam9x60ek.dts
+index b1068cca42287..fd8dc1183b3e8 100644
+--- a/arch/arm/boot/dts/at91-sam9x60ek.dts
++++ b/arch/arm/boot/dts/at91-sam9x60ek.dts
+@@ -233,10 +233,9 @@
+ status = "okay";
+
+ eeprom@53 {
+- compatible = "atmel,24c32";
++ compatible = "atmel,24c02";
+ reg = <0x53>;
+ pagesize = <16>;
+- size = <128>;
+ status = "okay";
+ };
+ };
+diff --git a/arch/arm/boot/dts/at91-sama5d2_icp.dts b/arch/arm/boot/dts/at91-sama5d2_icp.dts
+index e06b58724ca83..fd1a288f686bc 100644
+--- a/arch/arm/boot/dts/at91-sama5d2_icp.dts
++++ b/arch/arm/boot/dts/at91-sama5d2_icp.dts
+@@ -323,21 +323,21 @@
+ status = "okay";
+
+ eeprom@50 {
+- compatible = "atmel,24c32";
++ compatible = "atmel,24c02";
+ reg = <0x50>;
+ pagesize = <16>;
+ status = "okay";
+ };
+
+ eeprom@52 {
+- compatible = "atmel,24c32";
++ compatible = "atmel,24c02";
+ reg = <0x52>;
+ pagesize = <16>;
+ status = "disabled";
+ };
+
+ eeprom@53 {
+- compatible = "atmel,24c32";
++ compatible = "atmel,24c02";
+ reg = <0x53>;
+ pagesize = <16>;
+ status = "disabled";
+diff --git a/arch/arm/boot/dts/stm32mp151.dtsi b/arch/arm/boot/dts/stm32mp151.dtsi
+index 6992a4b0ba79b..a9b65b3bfda58 100644
+--- a/arch/arm/boot/dts/stm32mp151.dtsi
++++ b/arch/arm/boot/dts/stm32mp151.dtsi
+@@ -1452,7 +1452,7 @@
+ usbh_ohci: usb@5800c000 {
+ compatible = "generic-ohci";
+ reg = <0x5800c000 0x1000>;
+- clocks = <&rcc USBH>;
++ clocks = <&usbphyc>, <&rcc USBH>;
+ resets = <&rcc USBH_R>;
+ interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+@@ -1461,7 +1461,7 @@
+ usbh_ehci: usb@5800d000 {
+ compatible = "generic-ehci";
+ reg = <0x5800d000 0x1000>;
+- clocks = <&rcc USBH>;
++ clocks = <&usbphyc>, <&rcc USBH>;
+ resets = <&rcc USBH_R>;
+ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+ companion = <&usbh_ohci>;
+diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig
+index ca32446b187f5..f53086ddc48b0 100644
+--- a/arch/arm/configs/mxs_defconfig
++++ b/arch/arm/configs/mxs_defconfig
+@@ -93,6 +93,7 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y
+ CONFIG_DRM=y
+ CONFIG_DRM_PANEL_SEIKO_43WVF1G=y
+ CONFIG_DRM_MXSFB=y
++CONFIG_FB=y
+ CONFIG_FB_MODE_HELPERS=y
+ CONFIG_LCD_CLASS_DEVICE=y
+ CONFIG_BACKLIGHT_CLASS_DEVICE=y
+diff --git a/arch/arm/include/asm/arch_gicv3.h b/arch/arm/include/asm/arch_gicv3.h
+index 413abfb42989e..f82a819eb0dbb 100644
+--- a/arch/arm/include/asm/arch_gicv3.h
++++ b/arch/arm/include/asm/arch_gicv3.h
+@@ -48,6 +48,7 @@ static inline u32 read_ ## a64(void) \
+ return read_sysreg(a32); \
+ } \
+
++CPUIF_MAP(ICC_EOIR1, ICC_EOIR1_EL1)
+ CPUIF_MAP(ICC_PMR, ICC_PMR_EL1)
+ CPUIF_MAP(ICC_AP0R0, ICC_AP0R0_EL1)
+ CPUIF_MAP(ICC_AP0R1, ICC_AP0R1_EL1)
+@@ -63,12 +64,6 @@ CPUIF_MAP(ICC_AP1R3, ICC_AP1R3_EL1)
+
+ /* Low-level accessors */
+
+-static inline void gic_write_eoir(u32 irq)
+-{
+- write_sysreg(irq, ICC_EOIR1);
+- isb();
+-}
+-
+ static inline void gic_write_dir(u32 val)
+ {
+ write_sysreg(val, ICC_DIR);
+diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
+index 8711d6824c1fa..ed1050404ef0a 100644
+--- a/arch/arm/mach-at91/pm.c
++++ b/arch/arm/mach-at91/pm.c
+@@ -146,7 +146,7 @@ static const struct wakeup_source_info ws_info[] = {
+
+ static const struct of_device_id sama5d2_ws_ids[] = {
+ { .compatible = "atmel,sama5d2-gem", .data = &ws_info[0] },
+- { .compatible = "atmel,at91rm9200-rtc", .data = &ws_info[1] },
++ { .compatible = "atmel,sama5d2-rtc", .data = &ws_info[1] },
+ { .compatible = "atmel,sama5d3-udc", .data = &ws_info[2] },
+ { .compatible = "atmel,at91rm9200-ohci", .data = &ws_info[2] },
+ { .compatible = "usb-ohci", .data = &ws_info[2] },
+@@ -157,24 +157,24 @@ static const struct of_device_id sama5d2_ws_ids[] = {
+ };
+
+ static const struct of_device_id sam9x60_ws_ids[] = {
+- { .compatible = "atmel,at91sam9x5-rtc", .data = &ws_info[1] },
++ { .compatible = "microchip,sam9x60-rtc", .data = &ws_info[1] },
+ { .compatible = "atmel,at91rm9200-ohci", .data = &ws_info[2] },
+ { .compatible = "usb-ohci", .data = &ws_info[2] },
+ { .compatible = "atmel,at91sam9g45-ehci", .data = &ws_info[2] },
+ { .compatible = "usb-ehci", .data = &ws_info[2] },
+- { .compatible = "atmel,at91sam9260-rtt", .data = &ws_info[4] },
++ { .compatible = "microchip,sam9x60-rtt", .data = &ws_info[4] },
+ { .compatible = "cdns,sam9x60-macb", .data = &ws_info[5] },
+ { /* sentinel */ }
+ };
+
+ static const struct of_device_id sama7g5_ws_ids[] = {
+- { .compatible = "atmel,at91sam9x5-rtc", .data = &ws_info[1] },
++ { .compatible = "microchip,sama7g5-rtc", .data = &ws_info[1] },
+ { .compatible = "microchip,sama7g5-ohci", .data = &ws_info[2] },
+ { .compatible = "usb-ohci", .data = &ws_info[2] },
+ { .compatible = "atmel,at91sam9g45-ehci", .data = &ws_info[2] },
+ { .compatible = "usb-ehci", .data = &ws_info[2] },
+ { .compatible = "microchip,sama7g5-sdhci", .data = &ws_info[3] },
+- { .compatible = "atmel,at91sam9260-rtt", .data = &ws_info[4] },
++ { .compatible = "microchip,sama7g5-rtt", .data = &ws_info[4] },
+ { /* sentinel */ }
+ };
+
+diff --git a/arch/arm/mach-meson/platsmp.c b/arch/arm/mach-meson/platsmp.c
+index 4b8ad728bb42a..32ac60b89fdcc 100644
+--- a/arch/arm/mach-meson/platsmp.c
++++ b/arch/arm/mach-meson/platsmp.c
+@@ -71,6 +71,7 @@ static void __init meson_smp_prepare_cpus(const char *scu_compatible,
+ }
+
+ sram_base = of_iomap(node, 0);
++ of_node_put(node);
+ if (!sram_base) {
+ pr_err("Couldn't map SRAM registers\n");
+ return;
+@@ -91,6 +92,7 @@ static void __init meson_smp_prepare_cpus(const char *scu_compatible,
+ }
+
+ scu_base = of_iomap(node, 0);
++ of_node_put(node);
+ if (!scu_base) {
+ pr_err("Couldn't map SCU registers\n");
+ return;
+diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
+index 7b99fad6e4d6e..5c9fb39dd99e5 100644
+--- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
+@@ -285,21 +285,21 @@
+ &iomuxc {
+ pinctrl_eqos: eqosgrp {
+ fsl,pins = <
+- MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC 0x3
+- MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO 0x3
+- MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0 0x91
+- MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1 0x91
+- MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2 0x91
+- MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3 0x91
+- MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK 0x91
+- MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x91
+- MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0 0x1f
+- MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1 0x1f
+- MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2 0x1f
+- MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3 0x1f
+- MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x1f
+- MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK 0x1f
+- MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22 0x19
++ MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC 0x2
++ MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO 0x2
++ MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0 0x90
++ MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1 0x90
++ MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2 0x90
++ MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3 0x90
++ MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK 0x90
++ MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x90
++ MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0 0x16
++ MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1 0x16
++ MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2 0x16
++ MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3 0x16
++ MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x16
++ MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK 0x16
++ MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22 0x10
+ >;
+ };
+
+@@ -351,21 +351,21 @@
+
+ pinctrl_gpio_led: gpioledgrp {
+ fsl,pins = <
+- MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16 0x19
++ MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16 0x140
+ >;
+ };
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+- MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL 0x400001c3
+- MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA 0x400001c3
++ MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL 0x400001c2
++ MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA 0x400001c2
+ >;
+ };
+
+ pinctrl_i2c3: i2c3grp {
+ fsl,pins = <
+- MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL 0x400001c3
+- MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA 0x400001c3
++ MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL 0x400001c2
++ MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA 0x400001c2
+ >;
+ };
+
+@@ -377,20 +377,20 @@
+
+ pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+ fsl,pins = <
+- MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19 0x41
++ MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19 0x40
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+- MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX 0x49
+- MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX 0x49
++ MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX 0x140
++ MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX 0x140
+ >;
+ };
+
+ pinctrl_usb1_vbus: usb1grp {
+ fsl,pins = <
+- MX8MP_IOMUXC_GPIO1_IO14__USB2_OTG_PWR 0x19
++ MX8MP_IOMUXC_GPIO1_IO14__USB2_OTG_PWR 0x10
+ >;
+ };
+
+@@ -402,7 +402,7 @@
+ MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d0
+ MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d0
+ MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d0
+- MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
++ MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
+ >;
+ };
+
+@@ -414,7 +414,7 @@
+ MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d4
+ MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d4
+ MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d4
+- MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
++ MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
+ >;
+ };
+
+@@ -426,7 +426,7 @@
+ MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d6
+ MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d6
+ MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d6
+- MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
++ MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
+ >;
+ };
+
+diff --git a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
+index 984a6b9ded8d7..6aa720bafe289 100644
+--- a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
++++ b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
+@@ -116,48 +116,48 @@
+ &iomuxc {
+ pinctrl_eqos: eqosgrp {
+ fsl,pins = <
+- MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC 0x3
+- MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO 0x3
+- MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0 0x91
+- MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1 0x91
+- MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2 0x91
+- MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3 0x91
+- MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK 0x91
+- MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x91
+- MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0 0x1f
+- MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1 0x1f
+- MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2 0x1f
+- MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3 0x1f
+- MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x1f
+- MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK 0x1f
++ MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC 0x2
++ MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO 0x2
++ MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0 0x90
++ MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1 0x90
++ MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2 0x90
++ MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3 0x90
++ MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK 0x90
++ MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x90
++ MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0 0x16
++ MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1 0x16
++ MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2 0x16
++ MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3 0x16
++ MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x16
++ MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK 0x16
+ MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20 0x10
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+- MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL 0x400001c3
+- MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA 0x400001c3
++ MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL 0x400001c2
++ MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA 0x400001c2
+ >;
+ };
+
+ pinctrl_i2c2_gpio: i2c2gpiogrp {
+ fsl,pins = <
+- MX8MP_IOMUXC_I2C2_SCL__GPIO5_IO16 0x1e3
+- MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17 0x1e3
++ MX8MP_IOMUXC_I2C2_SCL__GPIO5_IO16 0x1e2
++ MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17 0x1e2
+ >;
+ };
+
+ pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+ fsl,pins = <
+- MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19 0x41
++ MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19 0x40
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+- MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 0x49
+- MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX 0x49
++ MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 0x40
++ MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX 0x40
+ >;
+ };
+
+@@ -175,7 +175,7 @@
+ MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d0
+ MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d0
+ MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d0
+- MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
++ MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
+ >;
+ };
+
+@@ -187,7 +187,7 @@
+ MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d4
+ MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d4
+ MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d4
+- MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
++ MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
+ >;
+ };
+
+@@ -199,7 +199,7 @@
+ MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d6
+ MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d6
+ MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d6
+- MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
++ MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
+ >;
+ };
+ };
+diff --git a/arch/arm64/boot/dts/qcom/msm8992-bullhead-rev-101.dts b/arch/arm64/boot/dts/qcom/msm8992-bullhead-rev-101.dts
+index 1ccca83292ac9..c7d191dc6d4ba 100644
+--- a/arch/arm64/boot/dts/qcom/msm8992-bullhead-rev-101.dts
++++ b/arch/arm64/boot/dts/qcom/msm8992-bullhead-rev-101.dts
+@@ -74,7 +74,7 @@
+ vdd_l17_29-supply = <&vph_pwr>;
+ vdd_l20_21-supply = <&vph_pwr>;
+ vdd_l25-supply = <&pm8994_s5>;
+- vdd_lvs1_2 = <&pm8994_s4>;
++ vdd_lvs1_2-supply = <&pm8994_s4>;
+
+ /* S1, S2, S6 and S12 are managed by RPMPD */
+
+diff --git a/arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts b/arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts
+index 357d55496e750..a3d6340a0c55b 100644
+--- a/arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts
++++ b/arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts
+@@ -142,7 +142,7 @@
+ vdd_l17_29-supply = <&vph_pwr>;
+ vdd_l20_21-supply = <&vph_pwr>;
+ vdd_l25-supply = <&pm8994_s5>;
+- vdd_lvs1_2 = <&pm8994_s4>;
++ vdd_lvs1_2-supply = <&pm8994_s4>;
+
+ /* S1, S2, S6 and S12 are managed by RPMPD */
+
+diff --git a/arch/arm64/boot/dts/qcom/msm8994.dtsi b/arch/arm64/boot/dts/qcom/msm8994.dtsi
+index 3c27671c8b5c3..a8dc8163ee82d 100644
+--- a/arch/arm64/boot/dts/qcom/msm8994.dtsi
++++ b/arch/arm64/boot/dts/qcom/msm8994.dtsi
+@@ -93,7 +93,7 @@
+ CPU6: cpu@102 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57";
+- reg = <0x0 0x101>;
++ reg = <0x0 0x102>;
+ enable-method = "psci";
+ next-level-cache = <&L2_1>;
+ };
+@@ -101,7 +101,7 @@
+ CPU7: cpu@103 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57";
+- reg = <0x0 0x101>;
++ reg = <0x0 0x103>;
+ enable-method = "psci";
+ next-level-cache = <&L2_1>;
+ };
+diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
+index d20eacfc10176..ea7a272d267a7 100644
+--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
++++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
+@@ -4147,7 +4147,7 @@
+
+ power-domains = <&dispcc MDSS_GDSC>;
+
+- clocks = <&gcc GCC_DISP_AHB_CLK>,
++ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&dispcc DISP_CC_MDSS_MDP_CLK>;
+ clock-names = "iface", "core";
+
+diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h
+index 4ad22c3135dbb..5a0f792492af0 100644
+--- a/arch/arm64/include/asm/arch_gicv3.h
++++ b/arch/arm64/include/asm/arch_gicv3.h
+@@ -26,12 +26,6 @@
+ * sets the GP register's most significant bits to 0 with an explicit cast.
+ */
+
+-static inline void gic_write_eoir(u32 irq)
+-{
+- write_sysreg_s(irq, SYS_ICC_EOIR1_EL1);
+- isb();
+-}
+-
+ static __always_inline void gic_write_dir(u32 irq)
+ {
+ write_sysreg_s(irq, SYS_ICC_DIR_EL1);
+diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
+index 95439bbe5df8f..4895b4d7e150f 100644
+--- a/arch/arm64/net/bpf_jit_comp.c
++++ b/arch/arm64/net/bpf_jit_comp.c
+@@ -788,7 +788,10 @@ emit_cond_jmp:
+ u64 imm64;
+
+ imm64 = (u64)insn1.imm << 32 | (u32)imm;
+- emit_a64_mov_i64(dst, imm64, ctx);
++ if (bpf_pseudo_func(insn))
++ emit_addr_mov_i64(dst, imm64, ctx);
++ else
++ emit_a64_mov_i64(dst, imm64, ctx);
+
+ return 1;
+ }
+diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S
+index 1d83966f5ef64..e8f10a5996593 100644
+--- a/arch/powerpc/boot/crt0.S
++++ b/arch/powerpc/boot/crt0.S
+@@ -226,16 +226,19 @@ p_base: mflr r10 /* r10 now points to runtime addr of p_base */
+ #ifdef __powerpc64__
+
+ #define PROM_FRAME_SIZE 512
+-#define SAVE_GPR(n, base) std n,8*(n)(base)
+-#define REST_GPR(n, base) ld n,8*(n)(base)
+-#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+-#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+-#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+-#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+-#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base)
+-#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+-#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+-#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base)
++
++.macro OP_REGS op, width, start, end, base, offset
++ .Lreg=\start
++ .rept (\end - \start + 1)
++ \op .Lreg,\offset+\width*.Lreg(\base)
++ .Lreg=.Lreg+1
++ .endr
++.endm
++
++#define SAVE_GPRS(start, end, base) OP_REGS std, 8, start, end, base, 0
++#define REST_GPRS(start, end, base) OP_REGS ld, 8, start, end, base, 0
++#define SAVE_GPR(n, base) SAVE_GPRS(n, n, base)
++#define REST_GPR(n, base) REST_GPRS(n, n, base)
+
+ /* prom handles the jump into and return from firmware. The prom args pointer
+ is loaded in r3. */
+@@ -246,9 +249,7 @@ prom:
+ stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */
+
+ SAVE_GPR(2, r1)
+- SAVE_GPR(13, r1)
+- SAVE_8GPRS(14, r1)
+- SAVE_10GPRS(22, r1)
++ SAVE_GPRS(13, 31, r1)
+ mfcr r10
+ std r10,8*32(r1)
+ mfmsr r10
+@@ -283,9 +284,7 @@ prom:
+
+ /* Restore other registers */
+ REST_GPR(2, r1)
+- REST_GPR(13, r1)
+- REST_8GPRS(14, r1)
+- REST_10GPRS(22, r1)
++ REST_GPRS(13, 31, r1)
+ ld r10,8*32(r1)
+ mtcr r10
+
+diff --git a/arch/powerpc/crypto/md5-asm.S b/arch/powerpc/crypto/md5-asm.S
+index 948d100a29343..fa6bc440cf4ac 100644
+--- a/arch/powerpc/crypto/md5-asm.S
++++ b/arch/powerpc/crypto/md5-asm.S
+@@ -38,15 +38,11 @@
+
+ #define INITIALIZE \
+ PPC_STLU r1,-INT_FRAME_SIZE(r1); \
+- SAVE_8GPRS(14, r1); /* push registers onto stack */ \
+- SAVE_4GPRS(22, r1); \
+- SAVE_GPR(26, r1)
++ SAVE_GPRS(14, 26, r1) /* push registers onto stack */
+
+ #define FINALIZE \
+- REST_8GPRS(14, r1); /* pop registers from stack */ \
+- REST_4GPRS(22, r1); \
+- REST_GPR(26, r1); \
+- addi r1,r1,INT_FRAME_SIZE;
++ REST_GPRS(14, 26, r1); /* pop registers from stack */ \
++ addi r1,r1,INT_FRAME_SIZE
+
+ #ifdef __BIG_ENDIAN__
+ #define LOAD_DATA(reg, off) \
+diff --git a/arch/powerpc/crypto/sha1-powerpc-asm.S b/arch/powerpc/crypto/sha1-powerpc-asm.S
+index 23e248beff716..f0d5ed557ab14 100644
+--- a/arch/powerpc/crypto/sha1-powerpc-asm.S
++++ b/arch/powerpc/crypto/sha1-powerpc-asm.S
+@@ -125,8 +125,7 @@
+
+ _GLOBAL(powerpc_sha_transform)
+ PPC_STLU r1,-INT_FRAME_SIZE(r1)
+- SAVE_8GPRS(14, r1)
+- SAVE_10GPRS(22, r1)
++ SAVE_GPRS(14, 31, r1)
+
+ /* Load up A - E */
+ lwz RA(0),0(r3) /* A */
+@@ -184,7 +183,6 @@ _GLOBAL(powerpc_sha_transform)
+ stw RD(0),12(r3)
+ stw RE(0),16(r3)
+
+- REST_8GPRS(14, r1)
+- REST_10GPRS(22, r1)
++ REST_GPRS(14, 31, r1)
+ addi r1,r1,INT_FRAME_SIZE
+ blr
+diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
+index 1c538a9a11e09..f21e6bde17a1e 100644
+--- a/arch/powerpc/include/asm/ppc_asm.h
++++ b/arch/powerpc/include/asm/ppc_asm.h
+@@ -16,30 +16,41 @@
+
+ #define SZL (BITS_PER_LONG/8)
+
++/*
++ * This expands to a sequence of operations with reg incrementing from
++ * start to end inclusive, of this form:
++ *
++ * op reg, (offset + (width * reg))(base)
++ *
++ * Note that offset is not the offset of the first operation unless start
++ * is zero (or width is zero).
++ */
++.macro OP_REGS op, width, start, end, base, offset
++ .Lreg=\start
++ .rept (\end - \start + 1)
++ \op .Lreg, \offset + \width * .Lreg(\base)
++ .Lreg=.Lreg+1
++ .endr
++.endm
++
+ /*
+ * Macros for storing registers into and loading registers from
+ * exception frames.
+ */
+ #ifdef __powerpc64__
+-#define SAVE_GPR(n, base) std n,GPR0+8*(n)(base)
+-#define REST_GPR(n, base) ld n,GPR0+8*(n)(base)
+-#define SAVE_NVGPRS(base) SAVE_8GPRS(14, base); SAVE_10GPRS(22, base)
+-#define REST_NVGPRS(base) REST_8GPRS(14, base); REST_10GPRS(22, base)
++#define SAVE_GPRS(start, end, base) OP_REGS std, 8, start, end, base, GPR0
++#define REST_GPRS(start, end, base) OP_REGS ld, 8, start, end, base, GPR0
++#define SAVE_NVGPRS(base) SAVE_GPRS(14, 31, base)
++#define REST_NVGPRS(base) REST_GPRS(14, 31, base)
+ #else
+-#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base)
+-#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base)
+-#define SAVE_NVGPRS(base) stmw 13, GPR0+4*13(base)
+-#define REST_NVGPRS(base) lmw 13, GPR0+4*13(base)
++#define SAVE_GPRS(start, end, base) OP_REGS stw, 4, start, end, base, GPR0
++#define REST_GPRS(start, end, base) OP_REGS lwz, 4, start, end, base, GPR0
++#define SAVE_NVGPRS(base) SAVE_GPRS(13, 31, base)
++#define REST_NVGPRS(base) REST_GPRS(13, 31, base)
+ #endif
+
+-#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+-#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+-#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+-#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+-#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base)
+-#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+-#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+-#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base)
++#define SAVE_GPR(n, base) SAVE_GPRS(n, n, base)
++#define REST_GPR(n, base) REST_GPRS(n, n, base)
+
+ #define SAVE_FPR(n, base) stfd n,8*TS_FPRWIDTH*(n)(base)
+ #define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base)
+diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
+index 61fdd53cdd9af..c62dd98159653 100644
+--- a/arch/powerpc/kernel/entry_32.S
++++ b/arch/powerpc/kernel/entry_32.S
+@@ -90,8 +90,7 @@ transfer_to_syscall:
+ stw r12,8(r1)
+ stw r2,_TRAP(r1)
+ SAVE_GPR(0, r1)
+- SAVE_4GPRS(3, r1)
+- SAVE_2GPRS(7, r1)
++ SAVE_GPRS(3, 8, r1)
+ addi r2,r10,-THREAD
+ SAVE_NVGPRS(r1)
+
+@@ -139,7 +138,7 @@ syscall_exit_finish:
+ mtxer r5
+ lwz r0,GPR0(r1)
+ lwz r3,GPR3(r1)
+- REST_8GPRS(4,r1)
++ REST_GPRS(4, 11, r1)
+ lwz r12,GPR12(r1)
+ b 1b
+
+@@ -232,9 +231,9 @@ fast_exception_return:
+ beq 3f /* if not, we've got problems */
+ #endif
+
+-2: REST_4GPRS(3, r11)
++2: REST_GPRS(3, 6, r11)
+ lwz r10,_CCR(r11)
+- REST_2GPRS(1, r11)
++ REST_GPRS(1, 2, r11)
+ mtcr r10
+ lwz r10,_LINK(r11)
+ mtlr r10
+@@ -298,16 +297,14 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
+ * the reliable stack unwinder later on. Clear it.
+ */
+ stw r0,8(r1)
+- REST_4GPRS(7, r1)
+- REST_2GPRS(11, r1)
++ REST_GPRS(7, 12, r1)
+
+ mtcr r3
+ mtlr r4
+ mtctr r5
+ mtspr SPRN_XER,r6
+
+- REST_4GPRS(2, r1)
+- REST_GPR(6, r1)
++ REST_GPRS(2, 6, r1)
+ REST_GPR(0, r1)
+ REST_GPR(1, r1)
+ rfi
+@@ -341,8 +338,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
+ lwz r6,_CCR(r1)
+ li r0,0
+
+- REST_4GPRS(7, r1)
+- REST_2GPRS(11, r1)
++ REST_GPRS(7, 12, r1)
+
+ mtlr r3
+ mtctr r4
+@@ -354,7 +350,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
+ */
+ stw r0,8(r1)
+
+- REST_4GPRS(2, r1)
++ REST_GPRS(2, 5, r1)
+
+ bne- cr1,1f /* emulate stack store */
+ mtcr r6
+@@ -430,8 +426,7 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return)
+ bne interrupt_return; \
+ lwz r0,GPR0(r1); \
+ lwz r2,GPR2(r1); \
+- REST_4GPRS(3, r1); \
+- REST_2GPRS(7, r1); \
++ REST_GPRS(3, 8, r1); \
+ lwz r10,_XER(r1); \
+ lwz r11,_CTR(r1); \
+ mtspr SPRN_XER,r10; \
+diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
+index 711c66b76df1a..67dc4e3179a02 100644
+--- a/arch/powerpc/kernel/exceptions-64e.S
++++ b/arch/powerpc/kernel/exceptions-64e.S
+@@ -198,8 +198,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV)
+
+ stdcx. r0,0,r1 /* to clear the reservation */
+
+- REST_4GPRS(2, r1)
+- REST_4GPRS(6, r1)
++ REST_GPRS(2, 9, r1)
+
+ ld r10,_CTR(r1)
+ ld r11,_XER(r1)
+@@ -375,9 +374,7 @@ ret_from_mc_except:
+ exc_##n##_common: \
+ std r0,GPR0(r1); /* save r0 in stackframe */ \
+ std r2,GPR2(r1); /* save r2 in stackframe */ \
+- SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \
+- SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \
+- std r9,GPR9(r1); /* save r9 in stackframe */ \
++ SAVE_GPRS(3, 9, r1); /* save r3 - r9 in stackframe */ \
+ std r10,_NIP(r1); /* save SRR0 to stackframe */ \
+ std r11,_MSR(r1); /* save SRR1 to stackframe */ \
+ beq 2f; /* if from kernel mode */ \
+@@ -1061,9 +1058,7 @@ bad_stack_book3e:
+ std r11,_ESR(r1)
+ std r0,GPR0(r1); /* save r0 in stackframe */ \
+ std r2,GPR2(r1); /* save r2 in stackframe */ \
+- SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \
+- SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \
+- std r9,GPR9(r1); /* save r9 in stackframe */ \
++ SAVE_GPRS(3, 9, r1); /* save r3 - r9 in stackframe */ \
+ ld r3,PACA_EXGEN+EX_R10(r13);/* get back r10 */ \
+ ld r4,PACA_EXGEN+EX_R11(r13);/* get back r11 */ \
+ mfspr r5,SPRN_SPRG_GEN_SCRATCH;/* get back r13 XXX can be wrong */ \
+@@ -1077,8 +1072,7 @@ bad_stack_book3e:
+ std r10,_LINK(r1)
+ std r11,_CTR(r1)
+ std r12,_XER(r1)
+- SAVE_10GPRS(14,r1)
+- SAVE_8GPRS(24,r1)
++ SAVE_GPRS(14, 31, r1)
+ lhz r12,PACA_TRAP_SAVE(r13)
+ std r12,_TRAP(r1)
+ addi r11,r1,INT_FRAME_SIZE
+diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
+index eaf1f72131a18..277eccf0f0868 100644
+--- a/arch/powerpc/kernel/exceptions-64s.S
++++ b/arch/powerpc/kernel/exceptions-64s.S
+@@ -574,8 +574,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
+ ld r10,IAREA+EX_CTR(r13)
+ std r10,_CTR(r1)
+ std r2,GPR2(r1) /* save r2 in stackframe */
+- SAVE_4GPRS(3, r1) /* save r3 - r6 in stackframe */
+- SAVE_2GPRS(7, r1) /* save r7, r8 in stackframe */
++ SAVE_GPRS(3, 8, r1) /* save r3 - r8 in stackframe */
+ mflr r9 /* Get LR, later save to stack */
+ ld r2,PACATOC(r13) /* get kernel TOC into r2 */
+ std r9,_LINK(r1)
+@@ -693,8 +692,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
+ mtlr r9
+ ld r9,_CCR(r1)
+ mtcr r9
+- REST_8GPRS(2, r1)
+- REST_4GPRS(10, r1)
++ REST_GPRS(2, 13, r1)
+ REST_GPR(0, r1)
+ /* restore original r1. */
+ ld r1,GPR1(r1)
+diff --git a/arch/powerpc/kernel/head_32.h b/arch/powerpc/kernel/head_32.h
+index 349c4a820231b..261c79bdbe53f 100644
+--- a/arch/powerpc/kernel/head_32.h
++++ b/arch/powerpc/kernel/head_32.h
+@@ -115,8 +115,7 @@ _ASM_NOKPROBE_SYMBOL(\name\()_virt)
+ stw r10,8(r1)
+ li r10, \trapno
+ stw r10,_TRAP(r1)
+- SAVE_4GPRS(3, r1)
+- SAVE_2GPRS(7, r1)
++ SAVE_GPRS(3, 8, r1)
+ SAVE_NVGPRS(r1)
+ stw r2,GPR2(r1)
+ stw r12,_NIP(r1)
+diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h
+index ef8d1b1c234e7..bb6d5d0fc4ac8 100644
+--- a/arch/powerpc/kernel/head_booke.h
++++ b/arch/powerpc/kernel/head_booke.h
+@@ -87,8 +87,7 @@ END_BTB_FLUSH_SECTION
+ stw r10, 8(r1)
+ li r10, \trapno
+ stw r10,_TRAP(r1)
+- SAVE_4GPRS(3, r1)
+- SAVE_2GPRS(7, r1)
++ SAVE_GPRS(3, 8, r1)
+ SAVE_NVGPRS(r1)
+ stw r2,GPR2(r1)
+ stw r12,_NIP(r1)
+diff --git a/arch/powerpc/kernel/interrupt_64.S b/arch/powerpc/kernel/interrupt_64.S
+index 4c6d1a8dcefed..ff8c8c03f41ac 100644
+--- a/arch/powerpc/kernel/interrupt_64.S
++++ b/arch/powerpc/kernel/interrupt_64.S
+@@ -166,10 +166,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
+ * The value of AMR only matters while we're in the kernel.
+ */
+ mtcr r2
+- ld r2,GPR2(r1)
+- ld r3,GPR3(r1)
+- ld r13,GPR13(r1)
+- ld r1,GPR1(r1)
++ REST_GPRS(2, 3, r1)
++ REST_GPR(13, r1)
++ REST_GPR(1, r1)
+ RFSCV_TO_USER
+ b . /* prevent speculative execution */
+
+@@ -187,9 +186,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
+ mtctr r3
+ mtlr r4
+ mtspr SPRN_XER,r5
+- REST_10GPRS(2, r1)
+- REST_2GPRS(12, r1)
+- ld r1,GPR1(r1)
++ REST_GPRS(2, 13, r1)
++ REST_GPR(1, r1)
+ RFI_TO_USER
+ .Lsyscall_vectored_\name\()_rst_end:
+
+@@ -378,10 +376,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
+ * The value of AMR only matters while we're in the kernel.
+ */
+ mtcr r2
+- ld r2,GPR2(r1)
+- ld r3,GPR3(r1)
+- ld r13,GPR13(r1)
+- ld r1,GPR1(r1)
++ REST_GPRS(2, 3, r1)
++ REST_GPR(13, r1)
++ REST_GPR(1, r1)
+ RFI_TO_USER
+ b . /* prevent speculative execution */
+
+@@ -392,8 +389,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
+ mtctr r3
+ mtspr SPRN_XER,r4
+ ld r0,GPR0(r1)
+- REST_8GPRS(4, r1)
+- ld r12,GPR12(r1)
++ REST_GPRS(4, 12, r1)
+ b .Lsyscall_restore_regs_cont
+ .Lsyscall_rst_end:
+
+@@ -522,17 +518,14 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
+ ld r6,_XER(r1)
+ li r0,0
+
+- REST_4GPRS(7, r1)
+- REST_2GPRS(11, r1)
+- REST_GPR(13, r1)
++ REST_GPRS(7, 13, r1)
+
+ mtcr r3
+ mtlr r4
+ mtctr r5
+ mtspr SPRN_XER,r6
+
+- REST_4GPRS(2, r1)
+- REST_GPR(6, r1)
++ REST_GPRS(2, 6, r1)
+ REST_GPR(0, r1)
+ REST_GPR(1, r1)
+ .ifc \srr,srr
+@@ -629,8 +622,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
+ ld r6,_CCR(r1)
+ li r0,0
+
+- REST_4GPRS(7, r1)
+- REST_2GPRS(11, r1)
++ REST_GPRS(7, 12, r1)
+
+ mtlr r3
+ mtctr r4
+@@ -642,7 +634,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
+ */
+ std r0,STACK_FRAME_OVERHEAD-16(r1)
+
+- REST_4GPRS(2, r1)
++ REST_GPRS(2, 5, r1)
+
+ bne- cr1,1f /* emulate stack store */
+ mtcr r6
+diff --git a/arch/powerpc/kernel/optprobes_head.S b/arch/powerpc/kernel/optprobes_head.S
+index 19ea3312403ca..5c7f0b4b784b2 100644
+--- a/arch/powerpc/kernel/optprobes_head.S
++++ b/arch/powerpc/kernel/optprobes_head.S
+@@ -10,8 +10,8 @@
+ #include <asm/asm-offsets.h>
+
+ #ifdef CONFIG_PPC64
+-#define SAVE_30GPRS(base) SAVE_10GPRS(2,base); SAVE_10GPRS(12,base); SAVE_10GPRS(22,base)
+-#define REST_30GPRS(base) REST_10GPRS(2,base); REST_10GPRS(12,base); REST_10GPRS(22,base)
++#define SAVE_30GPRS(base) SAVE_GPRS(2, 31, base)
++#define REST_30GPRS(base) REST_GPRS(2, 31, base)
+ #define TEMPLATE_FOR_IMM_LOAD_INSNS nop; nop; nop; nop; nop
+ #else
+ #define SAVE_30GPRS(base) stmw r2, GPR2(base)
+diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S
+index 2b91f233b05d5..5a0f023a26e90 100644
+--- a/arch/powerpc/kernel/tm.S
++++ b/arch/powerpc/kernel/tm.S
+@@ -226,11 +226,8 @@ _GLOBAL(tm_reclaim)
+
+ /* Sync the userland GPRs 2-12, 14-31 to thread->regs: */
+ SAVE_GPR(0, r7) /* user r0 */
+- SAVE_GPR(2, r7) /* user r2 */
+- SAVE_4GPRS(3, r7) /* user r3-r6 */
+- SAVE_GPR(8, r7) /* user r8 */
+- SAVE_GPR(9, r7) /* user r9 */
+- SAVE_GPR(10, r7) /* user r10 */
++ SAVE_GPRS(2, 6, r7) /* user r2-r6 */
++ SAVE_GPRS(8, 10, r7) /* user r8-r10 */
+ ld r3, GPR1(r1) /* user r1 */
+ ld r4, GPR7(r1) /* user r7 */
+ ld r5, GPR11(r1) /* user r11 */
+@@ -445,12 +442,9 @@ restore_gprs:
+ ld r6, THREAD_TM_PPR(r3)
+
+ REST_GPR(0, r7) /* GPR0 */
+- REST_2GPRS(2, r7) /* GPR2-3 */
+- REST_GPR(4, r7) /* GPR4 */
+- REST_4GPRS(8, r7) /* GPR8-11 */
+- REST_2GPRS(12, r7) /* GPR12-13 */
+-
+- REST_NVGPRS(r7) /* GPR14-31 */
++ REST_GPRS(2, 4, r7) /* GPR2-4 */
++ REST_GPRS(8, 12, r7) /* GPR8-12 */
++ REST_GPRS(14, 31, r7) /* GPR14-31 */
+
+ /* Load up PPR and DSCR here so we don't run with user values for long */
+ mtspr SPRN_DSCR, r5
+@@ -486,18 +480,24 @@ restore_gprs:
+ REST_GPR(6, r7)
+
+ /*
+- * Store r1 and r5 on the stack so that we can access them after we
+- * clear MSR RI.
++ * Store user r1 and r5 and r13 on the stack (in the unused save
++ * areas / compiler reserved areas), so that we can access them after
++ * we clear MSR RI.
+ */
+
+ REST_GPR(5, r7)
+ std r5, -8(r1)
+- ld r5, GPR1(r7)
++ ld r5, GPR13(r7)
+ std r5, -16(r1)
++ ld r5, GPR1(r7)
++ std r5, -24(r1)
+
+ REST_GPR(7, r7)
+
+- /* Clear MSR RI since we are about to use SCRATCH0. EE is already off */
++ /* Stash the stack pointer away for use after recheckpoint */
++ std r1, PACAR1(r13)
++
++ /* Clear MSR RI since we are about to clobber r13. EE is already off */
+ li r5, 0
+ mtmsrd r5, 1
+
+@@ -508,9 +508,9 @@ restore_gprs:
+ * until we turn MSR RI back on.
+ */
+
+- SET_SCRATCH0(r1)
+ ld r5, -8(r1)
+- ld r1, -16(r1)
++ ld r13, -16(r1)
++ ld r1, -24(r1)
+
+ /* Commit register state as checkpointed state: */
+ TRECHKPT
+@@ -526,9 +526,9 @@ restore_gprs:
+ */
+
+ GET_PACA(r13)
+- GET_SCRATCH0(r1)
++ ld r1, PACAR1(r13)
+
+- /* R1 is restored, so we are recoverable again. EE is still off */
++ /* R13, R1 is restored, so we are recoverable again. EE is still off */
+ li r4, MSR_RI
+ mtmsrd r4, 1
+
+diff --git a/arch/powerpc/kernel/trace/ftrace_64_mprofile.S b/arch/powerpc/kernel/trace/ftrace_64_mprofile.S
+index f9fd5f743eba3..d636fc755f608 100644
+--- a/arch/powerpc/kernel/trace/ftrace_64_mprofile.S
++++ b/arch/powerpc/kernel/trace/ftrace_64_mprofile.S
+@@ -41,15 +41,14 @@ _GLOBAL(ftrace_regs_caller)
+
+ /* Save all gprs to pt_regs */
+ SAVE_GPR(0, r1)
+- SAVE_10GPRS(2, r1)
++ SAVE_GPRS(2, 11, r1)
+
+ /* Ok to continue? */
+ lbz r3, PACA_FTRACE_ENABLED(r13)
+ cmpdi r3, 0
+ beq ftrace_no_trace
+
+- SAVE_10GPRS(12, r1)
+- SAVE_10GPRS(22, r1)
++ SAVE_GPRS(12, 31, r1)
+
+ /* Save previous stack pointer (r1) */
+ addi r8, r1, SWITCH_FRAME_SIZE
+@@ -108,10 +107,8 @@ ftrace_regs_call:
+ #endif
+
+ /* Restore gprs */
+- REST_GPR(0,r1)
+- REST_10GPRS(2,r1)
+- REST_10GPRS(12,r1)
+- REST_10GPRS(22,r1)
++ REST_GPR(0, r1)
++ REST_GPRS(2, 31, r1)
+
+ /* Restore possibly modified LR */
+ ld r0, _LINK(r1)
+@@ -157,7 +154,7 @@ _GLOBAL(ftrace_caller)
+ stdu r1, -SWITCH_FRAME_SIZE(r1)
+
+ /* Save all gprs to pt_regs */
+- SAVE_8GPRS(3, r1)
++ SAVE_GPRS(3, 10, r1)
+
+ lbz r3, PACA_FTRACE_ENABLED(r13)
+ cmpdi r3, 0
+@@ -194,7 +191,7 @@ ftrace_call:
+ mtctr r3
+
+ /* Restore gprs */
+- REST_8GPRS(3,r1)
++ REST_GPRS(3, 10, r1)
+
+ /* Restore callee's TOC */
+ ld r2, 24(r1)
+diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+index 32a4b4d412b92..81fc1e0ebe9a8 100644
+--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
++++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+@@ -2711,8 +2711,7 @@ kvmppc_bad_host_intr:
+ std r0, GPR0(r1)
+ std r9, GPR1(r1)
+ std r2, GPR2(r1)
+- SAVE_4GPRS(3, r1)
+- SAVE_2GPRS(7, r1)
++ SAVE_GPRS(3, 8, r1)
+ srdi r0, r12, 32
+ clrldi r12, r12, 32
+ std r0, _CCR(r1)
+@@ -2735,7 +2734,7 @@ kvmppc_bad_host_intr:
+ ld r9, HSTATE_SCRATCH2(r13)
+ ld r12, HSTATE_SCRATCH0(r13)
+ GET_SCRATCH0(r0)
+- SAVE_4GPRS(9, r1)
++ SAVE_GPRS(9, 12, r1)
+ std r0, GPR13(r1)
+ SAVE_NVGPRS(r1)
+ ld r5, HSTATE_CFAR(r13)
+diff --git a/arch/powerpc/kvm/book3s_hv_uvmem.c b/arch/powerpc/kvm/book3s_hv_uvmem.c
+index 3fbe710ff8390..3d4ee75b0fb76 100644
+--- a/arch/powerpc/kvm/book3s_hv_uvmem.c
++++ b/arch/powerpc/kvm/book3s_hv_uvmem.c
+@@ -251,7 +251,7 @@ int kvmppc_uvmem_slot_init(struct kvm *kvm, const struct kvm_memory_slot *slot)
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+- p->pfns = vzalloc(array_size(slot->npages, sizeof(*p->pfns)));
++ p->pfns = vcalloc(slot->npages, sizeof(*p->pfns));
+ if (!p->pfns) {
+ kfree(p);
+ return -ENOMEM;
+diff --git a/arch/powerpc/lib/test_emulate_step_exec_instr.S b/arch/powerpc/lib/test_emulate_step_exec_instr.S
+index 9ef941d958d80..5473f9d03df3a 100644
+--- a/arch/powerpc/lib/test_emulate_step_exec_instr.S
++++ b/arch/powerpc/lib/test_emulate_step_exec_instr.S
+@@ -37,7 +37,7 @@ _GLOBAL(exec_instr)
+ * The stack pointer (GPR1) and the thread pointer (GPR13) are not
+ * saved as these should not be modified anyway.
+ */
+- SAVE_2GPRS(2, r1)
++ SAVE_GPRS(2, 3, r1)
+ SAVE_NVGPRS(r1)
+
+ /*
+@@ -75,8 +75,7 @@ _GLOBAL(exec_instr)
+
+ /* Load GPRs from pt_regs */
+ REST_GPR(0, r31)
+- REST_10GPRS(2, r31)
+- REST_GPR(12, r31)
++ REST_GPRS(2, 12, r31)
+ REST_NVGPRS(r31)
+
+ /* Placeholder for the test instruction */
+@@ -99,8 +98,7 @@ _GLOBAL(exec_instr)
+ subi r3, r3, GPR0
+ SAVE_GPR(0, r3)
+ SAVE_GPR(2, r3)
+- SAVE_8GPRS(4, r3)
+- SAVE_GPR(12, r3)
++ SAVE_GPRS(4, 12, r3)
+ SAVE_NVGPRS(r3)
+
+ /* Save resulting LR to pt_regs */
+diff --git a/arch/powerpc/platforms/powernv/rng.c b/arch/powerpc/platforms/powernv/rng.c
+index 2b5a1a41234cc..236bd2ba51b98 100644
+--- a/arch/powerpc/platforms/powernv/rng.c
++++ b/arch/powerpc/platforms/powernv/rng.c
+@@ -176,12 +176,8 @@ static int __init pnv_get_random_long_early(unsigned long *v)
+ NULL) != pnv_get_random_long_early)
+ return 0;
+
+- for_each_compatible_node(dn, NULL, "ibm,power-rng") {
+- if (rng_create(dn))
+- continue;
+- /* Create devices for hwrng driver */
+- of_platform_device_create(dn, NULL, NULL);
+- }
++ for_each_compatible_node(dn, NULL, "ibm,power-rng")
++ rng_create(dn);
+
+ if (!ppc_md.get_random_seed)
+ return 0;
+@@ -205,10 +201,18 @@ void __init pnv_rng_init(void)
+
+ static int __init pnv_rng_late_init(void)
+ {
++ struct device_node *dn;
+ unsigned long v;
++
+ /* In case it wasn't called during init for some other reason. */
+ if (ppc_md.get_random_seed == pnv_get_random_long_early)
+ pnv_get_random_long_early(&v);
++
++ if (ppc_md.get_random_seed == powernv_get_random_long) {
++ for_each_compatible_node(dn, NULL, "ibm,power-rng")
++ of_platform_device_create(dn, NULL, NULL);
++ }
++
+ return 0;
+ }
+ machine_subsys_initcall(powernv, pnv_rng_late_init);
+diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
+index 4ebc80315f013..f2a2f9c9ed49c 100644
+--- a/arch/riscv/configs/defconfig
++++ b/arch/riscv/configs/defconfig
+@@ -72,9 +72,11 @@ CONFIG_GPIOLIB=y
+ CONFIG_GPIO_SIFIVE=y
+ # CONFIG_PTP_1588_CLOCK is not set
+ CONFIG_POWER_RESET=y
+-CONFIG_DRM=y
+-CONFIG_DRM_RADEON=y
+-CONFIG_DRM_VIRTIO_GPU=y
++CONFIG_DRM=m
++CONFIG_DRM_RADEON=m
++CONFIG_DRM_NOUVEAU=m
++CONFIG_DRM_VIRTIO_GPU=m
++CONFIG_FB=y
+ CONFIG_FRAMEBUFFER_CONSOLE=y
+ CONFIG_USB=y
+ CONFIG_USB_XHCI_HCD=y
+diff --git a/arch/riscv/configs/rv32_defconfig b/arch/riscv/configs/rv32_defconfig
+index 434ef5b645998..cdd113e7a2912 100644
+--- a/arch/riscv/configs/rv32_defconfig
++++ b/arch/riscv/configs/rv32_defconfig
+@@ -71,6 +71,7 @@ CONFIG_POWER_RESET=y
+ CONFIG_DRM=y
+ CONFIG_DRM_RADEON=y
+ CONFIG_DRM_VIRTIO_GPU=y
++CONFIG_FB=y
+ CONFIG_FRAMEBUFFER_CONSOLE=y
+ CONFIG_USB=y
+ CONFIG_USB_XHCI_HCD=y
+diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
+index 7f130ac3b9f9a..c58a7c77989b0 100644
+--- a/arch/riscv/mm/init.c
++++ b/arch/riscv/mm/init.c
+@@ -265,6 +265,7 @@ pgd_t early_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE);
+ static pmd_t __maybe_unused early_dtb_pmd[PTRS_PER_PMD] __initdata __aligned(PAGE_SIZE);
+
+ #ifdef CONFIG_XIP_KERNEL
++#define riscv_pfn_base (*(unsigned long *)XIP_FIXUP(&riscv_pfn_base))
+ #define trampoline_pg_dir ((pgd_t *)XIP_FIXUP(trampoline_pg_dir))
+ #define fixmap_pte ((pte_t *)XIP_FIXUP(fixmap_pte))
+ #define early_pg_dir ((pgd_t *)XIP_FIXUP(early_pg_dir))
+diff --git a/arch/s390/boot/compressed/decompressor.h b/arch/s390/boot/compressed/decompressor.h
+index a59f75c5b0490..f75cc31a77dd9 100644
+--- a/arch/s390/boot/compressed/decompressor.h
++++ b/arch/s390/boot/compressed/decompressor.h
+@@ -24,6 +24,7 @@ struct vmlinux_info {
+ unsigned long dynsym_start;
+ unsigned long rela_dyn_start;
+ unsigned long rela_dyn_end;
++ unsigned long amode31_size;
+ };
+
+ /* Symbols defined by linker scripts */
+diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c
+index b13352dd1e1cf..1aa11a8f57dd8 100644
+--- a/arch/s390/boot/startup.c
++++ b/arch/s390/boot/startup.c
+@@ -15,6 +15,7 @@
+ #include "uv.h"
+
+ unsigned long __bootdata_preserved(__kaslr_offset);
++unsigned long __bootdata(__amode31_base);
+ unsigned long __bootdata_preserved(VMALLOC_START);
+ unsigned long __bootdata_preserved(VMALLOC_END);
+ struct page *__bootdata_preserved(vmemmap);
+@@ -233,6 +234,12 @@ static void offset_vmlinux_info(unsigned long offset)
+ vmlinux.dynsym_start += offset;
+ }
+
++static unsigned long reserve_amode31(unsigned long safe_addr)
++{
++ __amode31_base = PAGE_ALIGN(safe_addr);
++ return safe_addr + vmlinux.amode31_size;
++}
++
+ void startup_kernel(void)
+ {
+ unsigned long random_lma;
+@@ -247,6 +254,7 @@ void startup_kernel(void)
+ setup_lpp();
+ store_ipl_parmblock();
+ safe_addr = mem_safe_offset();
++ safe_addr = reserve_amode31(safe_addr);
+ safe_addr = read_ipl_report(safe_addr);
+ uv_query_info();
+ rescue_initrd(safe_addr);
+diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
+index 7f2696e8d511e..6083090be1f46 100644
+--- a/arch/s390/kernel/entry.h
++++ b/arch/s390/kernel/entry.h
+@@ -70,5 +70,6 @@ extern struct exception_table_entry _stop_amode31_ex_table[];
+ #define __amode31_data __section(".amode31.data")
+ #define __amode31_ref __section(".amode31.refs")
+ extern long _start_amode31_refs[], _end_amode31_refs[];
++extern unsigned long __amode31_base;
+
+ #endif /* _ENTRY_H */
+diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
+index 8ede12c4ba6b5..36c1f31dfd66f 100644
+--- a/arch/s390/kernel/setup.c
++++ b/arch/s390/kernel/setup.c
+@@ -95,10 +95,10 @@ EXPORT_SYMBOL(console_irq);
+ * relocated above 2 GB, because it has to use 31 bit addresses.
+ * Such code and data is part of the .amode31 section.
+ */
+-unsigned long __amode31_ref __samode31 = __pa(&_samode31);
+-unsigned long __amode31_ref __eamode31 = __pa(&_eamode31);
+-unsigned long __amode31_ref __stext_amode31 = __pa(&_stext_amode31);
+-unsigned long __amode31_ref __etext_amode31 = __pa(&_etext_amode31);
++unsigned long __amode31_ref __samode31 = (unsigned long)&_samode31;
++unsigned long __amode31_ref __eamode31 = (unsigned long)&_eamode31;
++unsigned long __amode31_ref __stext_amode31 = (unsigned long)&_stext_amode31;
++unsigned long __amode31_ref __etext_amode31 = (unsigned long)&_etext_amode31;
+ struct exception_table_entry __amode31_ref *__start_amode31_ex_table = _start_amode31_ex_table;
+ struct exception_table_entry __amode31_ref *__stop_amode31_ex_table = _stop_amode31_ex_table;
+
+@@ -149,6 +149,7 @@ struct mem_detect_info __bootdata(mem_detect);
+ struct initrd_data __bootdata(initrd_data);
+
+ unsigned long __bootdata_preserved(__kaslr_offset);
++unsigned long __bootdata(__amode31_base);
+ unsigned int __bootdata_preserved(zlib_dfltcc_support);
+ EXPORT_SYMBOL(zlib_dfltcc_support);
+ u64 __bootdata_preserved(stfle_fac_list[16]);
+@@ -796,12 +797,12 @@ static void __init check_initrd(void)
+ */
+ static void __init reserve_kernel(void)
+ {
+- unsigned long start_pfn = PFN_UP(__pa(_end));
+-
+ memblock_reserve(0, STARTUP_NORMAL_OFFSET);
+- memblock_reserve((unsigned long)sclp_early_sccb, EXT_SCCB_READ_SCP);
+- memblock_reserve((unsigned long)_stext, PFN_PHYS(start_pfn)
+- - (unsigned long)_stext);
++ memblock_reserve(OLDMEM_BASE, sizeof(unsigned long));
++ memblock_reserve(OLDMEM_SIZE, sizeof(unsigned long));
++ memblock_reserve(__amode31_base, __eamode31 - __samode31);
++ memblock_reserve(__pa(sclp_early_sccb), EXT_SCCB_READ_SCP);
++ memblock_reserve(__pa(_stext), _end - _stext);
+ }
+
+ static void __init setup_memory(void)
+@@ -820,20 +821,14 @@ static void __init setup_memory(void)
+
+ static void __init relocate_amode31_section(void)
+ {
+- unsigned long amode31_addr, amode31_size;
+- long amode31_offset;
++ unsigned long amode31_size = __eamode31 - __samode31;
++ long amode31_offset = __amode31_base - __samode31;
+ long *ptr;
+
+- /* Allocate a new AMODE31 capable memory region */
+- amode31_size = __eamode31 - __samode31;
+ pr_info("Relocating AMODE31 section of size 0x%08lx\n", amode31_size);
+- amode31_addr = (unsigned long)memblock_alloc_low(amode31_size, PAGE_SIZE);
+- if (!amode31_addr)
+- panic("Failed to allocate memory for AMODE31 section\n");
+- amode31_offset = amode31_addr - __samode31;
+
+ /* Move original AMODE31 section to the new one */
+- memmove((void *)amode31_addr, (void *)__samode31, amode31_size);
++ memmove((void *)__amode31_base, (void *)__samode31, amode31_size);
+ /* Zero out the old AMODE31 section to catch invalid accesses within it */
+ memset((void *)__samode31, 0, amode31_size);
+
+diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
+index 63bdb9e1bfc13..42c43521878ff 100644
+--- a/arch/s390/kernel/vmlinux.lds.S
++++ b/arch/s390/kernel/vmlinux.lds.S
+@@ -212,6 +212,7 @@ SECTIONS
+ QUAD(__dynsym_start) /* dynsym_start */
+ QUAD(__rela_dyn_start) /* rela_dyn_start */
+ QUAD(__rela_dyn_end) /* rela_dyn_end */
++ QUAD(_eamode31 - _samode31) /* amode31_size */
+ } :NONE
+
+ /* Debugging sections. */
+diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
+index 402597f9d0505..b456aa196c04f 100644
+--- a/arch/s390/kvm/kvm-s390.c
++++ b/arch/s390/kvm/kvm-s390.c
+@@ -3913,14 +3913,12 @@ retry:
+ return 0;
+ }
+
+-void kvm_s390_set_tod_clock(struct kvm *kvm,
+- const struct kvm_s390_vm_tod_clock *gtod)
++static void __kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod)
+ {
+ struct kvm_vcpu *vcpu;
+ union tod_clock clk;
+ int i;
+
+- mutex_lock(&kvm->lock);
+ preempt_disable();
+
+ store_tod_clock_ext(&clk);
+@@ -3941,7 +3939,22 @@ void kvm_s390_set_tod_clock(struct kvm *kvm,
+
+ kvm_s390_vcpu_unblock_all(kvm);
+ preempt_enable();
++}
++
++void kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod)
++{
++ mutex_lock(&kvm->lock);
++ __kvm_s390_set_tod_clock(kvm, gtod);
++ mutex_unlock(&kvm->lock);
++}
++
++int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod)
++{
++ if (!mutex_trylock(&kvm->lock))
++ return 0;
++ __kvm_s390_set_tod_clock(kvm, gtod);
+ mutex_unlock(&kvm->lock);
++ return 1;
+ }
+
+ /**
+diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
+index 1539dd981104f..f8803bf0ff170 100644
+--- a/arch/s390/kvm/kvm-s390.h
++++ b/arch/s390/kvm/kvm-s390.h
+@@ -326,8 +326,8 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
+ int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
+
+ /* implemented in kvm-s390.c */
+-void kvm_s390_set_tod_clock(struct kvm *kvm,
+- const struct kvm_s390_vm_tod_clock *gtod);
++void kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod);
++int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod);
+ long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable);
+ int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr);
+ int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr);
+diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
+index 417154b314a64..6a765fe22eafc 100644
+--- a/arch/s390/kvm/priv.c
++++ b/arch/s390/kvm/priv.c
+@@ -102,7 +102,20 @@ static int handle_set_clock(struct kvm_vcpu *vcpu)
+ return kvm_s390_inject_prog_cond(vcpu, rc);
+
+ VCPU_EVENT(vcpu, 3, "SCK: setting guest TOD to 0x%llx", gtod.tod);
+- kvm_s390_set_tod_clock(vcpu->kvm, &gtod);
++ /*
++ * To set the TOD clock the kvm lock must be taken, but the vcpu lock
++ * is already held in handle_set_clock. The usual lock order is the
++ * opposite. As SCK is deprecated and should not be used in several
++ * cases, for example when the multiple epoch facility or TOD clock
++ * steering facility is installed (see Principles of Operation), a
++ * slow path can be used. If the lock can not be taken via try_lock,
++ * the instruction will be retried via -EAGAIN at a later point in
++ * time.
++ */
++ if (!kvm_s390_try_set_tod_clock(vcpu->kvm, &gtod)) {
++ kvm_s390_retry_instr(vcpu);
++ return -EAGAIN;
++ }
+
+ kvm_s390_set_psw_cc(vcpu, 0);
+ return 0;
+diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c
+index e23e74e2f928d..848cfb013f58c 100644
+--- a/arch/x86/kernel/cpu/mce/core.c
++++ b/arch/x86/kernel/cpu/mce/core.c
+@@ -1297,10 +1297,12 @@ static void kill_me_maybe(struct callback_head *cb)
+
+ /*
+ * -EHWPOISON from memory_failure() means that it already sent SIGBUS
+- * to the current process with the proper error info, so no need to
+- * send SIGBUS here again.
++ * to the current process with the proper error info,
++ * -EOPNOTSUPP means hwpoison_filter() filtered the error event,
++ *
++ * In both cases, no further processing is required.
+ */
+- if (ret == -EHWPOISON)
++ if (ret == -EHWPOISON || ret == -EOPNOTSUPP)
+ return;
+
+ if (p->mce_vaddr != (void __user *)-1l) {
+diff --git a/arch/x86/kvm/mmu/page_track.c b/arch/x86/kvm/mmu/page_track.c
+index 21427e84a82ef..630ae70bb6bd3 100644
+--- a/arch/x86/kvm/mmu/page_track.c
++++ b/arch/x86/kvm/mmu/page_track.c
+@@ -36,8 +36,8 @@ int kvm_page_track_create_memslot(struct kvm_memory_slot *slot,
+
+ for (i = 0; i < KVM_PAGE_TRACK_MAX; i++) {
+ slot->arch.gfn_track[i] =
+- kvcalloc(npages, sizeof(*slot->arch.gfn_track[i]),
+- GFP_KERNEL_ACCOUNT);
++ __vcalloc(npages, sizeof(*slot->arch.gfn_track[i]),
++ GFP_KERNEL_ACCOUNT);
+ if (!slot->arch.gfn_track[i])
+ goto track_free;
+ }
+diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c
+index 853780eb033b4..6c2bb60ccd88b 100644
+--- a/arch/x86/kvm/mmu/tdp_mmu.c
++++ b/arch/x86/kvm/mmu/tdp_mmu.c
+@@ -1098,13 +1098,8 @@ int kvm_tdp_mmu_map(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code,
+ bool kvm_tdp_mmu_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range,
+ bool flush)
+ {
+- struct kvm_mmu_page *root;
+-
+- for_each_tdp_mmu_root(kvm, root, range->slot->as_id)
+- flush = zap_gfn_range(kvm, root, range->start, range->end,
+- range->may_block, flush, false);
+-
+- return flush;
++ return __kvm_tdp_mmu_zap_gfn_range(kvm, range->slot->as_id, range->start,
++ range->end, range->may_block, flush);
+ }
+
+ typedef bool (*tdp_handler_t)(struct kvm *kvm, struct tdp_iter *iter,
+diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
+index 39aaa21e28f78..8974884ef2ad5 100644
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -11552,7 +11552,7 @@ static int memslot_rmap_alloc(struct kvm_memory_slot *slot,
+ if (slot->arch.rmap[i])
+ continue;
+
+- slot->arch.rmap[i] = kvcalloc(lpages, sz, GFP_KERNEL_ACCOUNT);
++ slot->arch.rmap[i] = __vcalloc(lpages, sz, GFP_KERNEL_ACCOUNT);
+ if (!slot->arch.rmap[i]) {
+ memslot_rmap_free(slot);
+ return -ENOMEM;
+@@ -11633,7 +11633,7 @@ static int kvm_alloc_memslot_metadata(struct kvm *kvm,
+
+ lpages = __kvm_mmu_slot_lpages(slot, npages, level);
+
+- linfo = kvcalloc(lpages, sizeof(*linfo), GFP_KERNEL_ACCOUNT);
++ linfo = __vcalloc(lpages, sizeof(*linfo), GFP_KERNEL_ACCOUNT);
+ if (!linfo)
+ goto out_free;
+
+diff --git a/block/bio.c b/block/bio.c
+index 8381c6690dd6c..b8a8bfba714f4 100644
+--- a/block/bio.c
++++ b/block/bio.c
+@@ -910,7 +910,7 @@ EXPORT_SYMBOL(bio_add_pc_page);
+ int bio_add_zone_append_page(struct bio *bio, struct page *page,
+ unsigned int len, unsigned int offset)
+ {
+- struct request_queue *q = bio->bi_bdev->bd_disk->queue;
++ struct request_queue *q = bdev_get_queue(bio->bi_bdev);
+ bool same_page = false;
+
+ if (WARN_ON_ONCE(bio_op(bio) != REQ_OP_ZONE_APPEND))
+@@ -1054,7 +1054,7 @@ static int bio_iov_bvec_set(struct bio *bio, struct iov_iter *iter)
+
+ static int bio_iov_bvec_set_append(struct bio *bio, struct iov_iter *iter)
+ {
+- struct request_queue *q = bio->bi_bdev->bd_disk->queue;
++ struct request_queue *q = bdev_get_queue(bio->bi_bdev);
+ struct iov_iter i = *iter;
+
+ iov_iter_truncate(&i, queue_max_zone_append_sectors(q) << 9);
+@@ -1132,7 +1132,7 @@ static int __bio_iov_append_get_pages(struct bio *bio, struct iov_iter *iter)
+ {
+ unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt;
+ unsigned short entries_left = bio->bi_max_vecs - bio->bi_vcnt;
+- struct request_queue *q = bio->bi_bdev->bd_disk->queue;
++ struct request_queue *q = bdev_get_queue(bio->bi_bdev);
+ unsigned int max_append_sectors = queue_max_zone_append_sectors(q);
+ struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt;
+ struct page **pages = (struct page **)bv;
+@@ -1470,11 +1470,10 @@ again:
+ if (!bio_integrity_endio(bio))
+ return;
+
+- if (bio->bi_bdev && bio_flagged(bio, BIO_TRACKED))
+- rq_qos_done_bio(bio->bi_bdev->bd_disk->queue, bio);
++ rq_qos_done_bio(bio);
+
+ if (bio->bi_bdev && bio_flagged(bio, BIO_TRACE_COMPLETION)) {
+- trace_block_bio_complete(bio->bi_bdev->bd_disk->queue, bio);
++ trace_block_bio_complete(bdev_get_queue(bio->bi_bdev), bio);
+ bio_clear_flag(bio, BIO_TRACE_COMPLETION);
+ }
+
+diff --git a/block/blk-iolatency.c b/block/blk-iolatency.c
+index ce3847499d85b..d85f30a85ee75 100644
+--- a/block/blk-iolatency.c
++++ b/block/blk-iolatency.c
+@@ -601,7 +601,7 @@ static void blkcg_iolatency_done_bio(struct rq_qos *rqos, struct bio *bio)
+ int inflight = 0;
+
+ blkg = bio->bi_blkg;
+- if (!blkg || !bio_flagged(bio, BIO_TRACKED))
++ if (!blkg || !bio_flagged(bio, BIO_QOS_THROTTLED))
+ return;
+
+ iolat = blkg_to_lat(bio->bi_blkg);
+diff --git a/block/blk-rq-qos.h b/block/blk-rq-qos.h
+index f000f83e0621c..68267007da1c6 100644
+--- a/block/blk-rq-qos.h
++++ b/block/blk-rq-qos.h
+@@ -177,21 +177,22 @@ static inline void rq_qos_requeue(struct request_queue *q, struct request *rq)
+ __rq_qos_requeue(q->rq_qos, rq);
+ }
+
+-static inline void rq_qos_done_bio(struct request_queue *q, struct bio *bio)
++static inline void rq_qos_done_bio(struct bio *bio)
+ {
+- if (q->rq_qos)
+- __rq_qos_done_bio(q->rq_qos, bio);
++ if (bio->bi_bdev && (bio_flagged(bio, BIO_QOS_THROTTLED) ||
++ bio_flagged(bio, BIO_QOS_MERGED))) {
++ struct request_queue *q = bdev_get_queue(bio->bi_bdev);
++ if (q->rq_qos)
++ __rq_qos_done_bio(q->rq_qos, bio);
++ }
+ }
+
+ static inline void rq_qos_throttle(struct request_queue *q, struct bio *bio)
+ {
+- /*
+- * BIO_TRACKED lets controllers know that a bio went through the
+- * normal rq_qos path.
+- */
+- bio_set_flag(bio, BIO_TRACKED);
+- if (q->rq_qos)
++ if (q->rq_qos) {
++ bio_set_flag(bio, BIO_QOS_THROTTLED);
+ __rq_qos_throttle(q->rq_qos, bio);
++ }
+ }
+
+ static inline void rq_qos_track(struct request_queue *q, struct request *rq,
+@@ -204,8 +205,10 @@ static inline void rq_qos_track(struct request_queue *q, struct request *rq,
+ static inline void rq_qos_merge(struct request_queue *q, struct request *rq,
+ struct bio *bio)
+ {
+- if (q->rq_qos)
++ if (q->rq_qos) {
++ bio_set_flag(bio, BIO_QOS_MERGED);
+ __rq_qos_merge(q->rq_qos, rq, bio);
++ }
+ }
+
+ static inline void rq_qos_queue_depth_changed(struct request_queue *q)
+diff --git a/drivers/base/core.c b/drivers/base/core.c
+index 8e73a34e10055..10e027e926926 100644
+--- a/drivers/base/core.c
++++ b/drivers/base/core.c
+@@ -485,7 +485,8 @@ static void device_link_release_fn(struct work_struct *work)
+ /* Ensure that all references to the link object have been dropped. */
+ device_link_synchronize_removal();
+
+- pm_runtime_release_supplier(link, true);
++ pm_runtime_release_supplier(link);
++ pm_request_idle(link->supplier);
+
+ put_device(link->consumer);
+ put_device(link->supplier);
+diff --git a/drivers/base/memory.c b/drivers/base/memory.c
+index c0d501a3a7140..c778d1df74557 100644
+--- a/drivers/base/memory.c
++++ b/drivers/base/memory.c
+@@ -555,6 +555,8 @@ static ssize_t hard_offline_page_store(struct device *dev,
+ return -EINVAL;
+ pfn >>= PAGE_SHIFT;
+ ret = memory_failure(pfn, 0);
++ if (ret == -EOPNOTSUPP)
++ ret = 0;
+ return ret ? ret : count;
+ }
+
+diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
+index 44ae3909e64bb..3179c9265471b 100644
+--- a/drivers/base/power/runtime.c
++++ b/drivers/base/power/runtime.c
+@@ -308,13 +308,10 @@ static int rpm_get_suppliers(struct device *dev)
+ /**
+ * pm_runtime_release_supplier - Drop references to device link's supplier.
+ * @link: Target device link.
+- * @check_idle: Whether or not to check if the supplier device is idle.
+ *
+- * Drop all runtime PM references associated with @link to its supplier device
+- * and if @check_idle is set, check if that device is idle (and so it can be
+- * suspended).
++ * Drop all runtime PM references associated with @link to its supplier device.
+ */
+-void pm_runtime_release_supplier(struct device_link *link, bool check_idle)
++void pm_runtime_release_supplier(struct device_link *link)
+ {
+ struct device *supplier = link->supplier;
+
+@@ -327,9 +324,6 @@ void pm_runtime_release_supplier(struct device_link *link, bool check_idle)
+ while (refcount_dec_not_one(&link->rpm_active) &&
+ atomic_read(&supplier->power.usage_count) > 0)
+ pm_runtime_put_noidle(supplier);
+-
+- if (check_idle)
+- pm_request_idle(supplier);
+ }
+
+ static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend)
+@@ -337,8 +331,11 @@ static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend)
+ struct device_link *link;
+
+ list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
+- device_links_read_lock_held())
+- pm_runtime_release_supplier(link, try_to_suspend);
++ device_links_read_lock_held()) {
++ pm_runtime_release_supplier(link);
++ if (try_to_suspend)
++ pm_request_idle(link->supplier);
++ }
+ }
+
+ static void rpm_put_suppliers(struct device *dev)
+@@ -1791,7 +1788,8 @@ void pm_runtime_drop_link(struct device_link *link)
+ return;
+
+ pm_runtime_drop_link_count(link->consumer);
+- pm_runtime_release_supplier(link, true);
++ pm_runtime_release_supplier(link);
++ pm_request_idle(link->supplier);
+ }
+
+ static bool pm_runtime_need_not_resume(struct device *dev)
+diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
+index f93cb989241cc..28ed157b1203b 100644
+--- a/drivers/block/Kconfig
++++ b/drivers/block/Kconfig
+@@ -410,6 +410,7 @@ config XEN_BLKDEV_BACKEND
+ config VIRTIO_BLK
+ tristate "Virtio block driver"
+ depends on VIRTIO
++ select SG_POOL
+ help
+ This is the virtual block driver for virtio. It can be used with
+ QEMU based VMMs (like KVM or Xen). Say Y or M.
+diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
+index 8ba2fe356f01a..d59af26d77032 100644
+--- a/drivers/block/drbd/drbd_main.c
++++ b/drivers/block/drbd/drbd_main.c
+@@ -2795,10 +2795,12 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
+
+ if (init_submitter(device)) {
+ err = ERR_NOMEM;
+- goto out_idr_remove_vol;
++ goto out_idr_remove_from_resource;
+ }
+
+- add_disk(disk);
++ err = add_disk(disk);
++ if (err)
++ goto out_idr_remove_from_resource;
+
+ /* inherit the connection state */
+ device->state.conn = first_connection(resource)->cstate;
+@@ -2812,8 +2814,6 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
+ drbd_debugfs_device_add(device);
+ return NO_ERROR;
+
+-out_idr_remove_vol:
+- idr_remove(&connection->peer_devices, vnr);
+ out_idr_remove_from_resource:
+ for_each_connection(connection, resource) {
+ peer_device = idr_remove(&connection->peer_devices, vnr);
+diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
+index c05138a284755..d2ba849bb8d19 100644
+--- a/drivers/block/virtio_blk.c
++++ b/drivers/block/virtio_blk.c
+@@ -24,6 +24,12 @@
+ /* The maximum number of sg elements that fit into a virtqueue */
+ #define VIRTIO_BLK_MAX_SG_ELEMS 32768
+
++#ifdef CONFIG_ARCH_NO_SG_CHAIN
++#define VIRTIO_BLK_INLINE_SG_CNT 0
++#else
++#define VIRTIO_BLK_INLINE_SG_CNT 2
++#endif
++
+ static int major;
+ static DEFINE_IDA(vd_index_ida);
+
+@@ -77,6 +83,7 @@ struct virtio_blk {
+ struct virtblk_req {
+ struct virtio_blk_outhdr out_hdr;
+ u8 status;
++ struct sg_table sg_table;
+ struct scatterlist sg[];
+ };
+
+@@ -162,12 +169,92 @@ static int virtblk_setup_discard_write_zeroes(struct request *req, bool unmap)
+ return 0;
+ }
+
+-static inline void virtblk_request_done(struct request *req)
++static void virtblk_unmap_data(struct request *req, struct virtblk_req *vbr)
+ {
+- struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
++ if (blk_rq_nr_phys_segments(req))
++ sg_free_table_chained(&vbr->sg_table,
++ VIRTIO_BLK_INLINE_SG_CNT);
++}
++
++static int virtblk_map_data(struct blk_mq_hw_ctx *hctx, struct request *req,
++ struct virtblk_req *vbr)
++{
++ int err;
++
++ if (!blk_rq_nr_phys_segments(req))
++ return 0;
++
++ vbr->sg_table.sgl = vbr->sg;
++ err = sg_alloc_table_chained(&vbr->sg_table,
++ blk_rq_nr_phys_segments(req),
++ vbr->sg_table.sgl,
++ VIRTIO_BLK_INLINE_SG_CNT);
++ if (unlikely(err))
++ return -ENOMEM;
+
++ return blk_rq_map_sg(hctx->queue, req, vbr->sg_table.sgl);
++}
++
++static void virtblk_cleanup_cmd(struct request *req)
++{
+ if (req->rq_flags & RQF_SPECIAL_PAYLOAD)
+ kfree(bvec_virt(&req->special_vec));
++}
++
++static int virtblk_setup_cmd(struct virtio_device *vdev, struct request *req,
++ struct virtblk_req *vbr)
++{
++ bool unmap = false;
++ u32 type;
++
++ vbr->out_hdr.sector = 0;
++
++ switch (req_op(req)) {
++ case REQ_OP_READ:
++ type = VIRTIO_BLK_T_IN;
++ vbr->out_hdr.sector = cpu_to_virtio64(vdev,
++ blk_rq_pos(req));
++ break;
++ case REQ_OP_WRITE:
++ type = VIRTIO_BLK_T_OUT;
++ vbr->out_hdr.sector = cpu_to_virtio64(vdev,
++ blk_rq_pos(req));
++ break;
++ case REQ_OP_FLUSH:
++ type = VIRTIO_BLK_T_FLUSH;
++ break;
++ case REQ_OP_DISCARD:
++ type = VIRTIO_BLK_T_DISCARD;
++ break;
++ case REQ_OP_WRITE_ZEROES:
++ type = VIRTIO_BLK_T_WRITE_ZEROES;
++ unmap = !(req->cmd_flags & REQ_NOUNMAP);
++ break;
++ case REQ_OP_DRV_IN:
++ type = VIRTIO_BLK_T_GET_ID;
++ break;
++ default:
++ WARN_ON_ONCE(1);
++ return BLK_STS_IOERR;
++ }
++
++ vbr->out_hdr.type = cpu_to_virtio32(vdev, type);
++ vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req));
++
++ if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES) {
++ if (virtblk_setup_discard_write_zeroes(req, unmap))
++ return BLK_STS_RESOURCE;
++ }
++
++ return 0;
++}
++
++static inline void virtblk_request_done(struct request *req)
++{
++ struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
++
++ virtblk_unmap_data(req, vbr);
++ virtblk_cleanup_cmd(req);
+ blk_mq_end_request(req, virtblk_result(vbr));
+ }
+
+@@ -221,61 +308,27 @@ static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx,
+ struct request *req = bd->rq;
+ struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
+ unsigned long flags;
+- unsigned int num;
++ int num;
+ int qid = hctx->queue_num;
+ int err;
+ bool notify = false;
+- bool unmap = false;
+- u32 type;
+
+ BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems);
+
+- switch (req_op(req)) {
+- case REQ_OP_READ:
+- case REQ_OP_WRITE:
+- type = 0;
+- break;
+- case REQ_OP_FLUSH:
+- type = VIRTIO_BLK_T_FLUSH;
+- break;
+- case REQ_OP_DISCARD:
+- type = VIRTIO_BLK_T_DISCARD;
+- break;
+- case REQ_OP_WRITE_ZEROES:
+- type = VIRTIO_BLK_T_WRITE_ZEROES;
+- unmap = !(req->cmd_flags & REQ_NOUNMAP);
+- break;
+- case REQ_OP_DRV_IN:
+- type = VIRTIO_BLK_T_GET_ID;
+- break;
+- default:
+- WARN_ON_ONCE(1);
+- return BLK_STS_IOERR;
+- }
+-
+- vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, type);
+- vbr->out_hdr.sector = type ?
+- 0 : cpu_to_virtio64(vblk->vdev, blk_rq_pos(req));
+- vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(req));
++ err = virtblk_setup_cmd(vblk->vdev, req, vbr);
++ if (unlikely(err))
++ return err;
+
+ blk_mq_start_request(req);
+
+- if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES) {
+- err = virtblk_setup_discard_write_zeroes(req, unmap);
+- if (err)
+- return BLK_STS_RESOURCE;
+- }
+-
+- num = blk_rq_map_sg(hctx->queue, req, vbr->sg);
+- if (num) {
+- if (rq_data_dir(req) == WRITE)
+- vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_OUT);
+- else
+- vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_IN);
++ num = virtblk_map_data(hctx, req, vbr);
++ if (unlikely(num < 0)) {
++ virtblk_cleanup_cmd(req);
++ return BLK_STS_RESOURCE;
+ }
+
+ spin_lock_irqsave(&vblk->vqs[qid].lock, flags);
+- err = virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num);
++ err = virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg_table.sgl, num);
+ if (err) {
+ virtqueue_kick(vblk->vqs[qid].vq);
+ /* Don't stop the queue if -ENOMEM: we may have failed to
+@@ -284,6 +337,8 @@ static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx,
+ if (err == -ENOSPC)
+ blk_mq_stop_hw_queue(hctx);
+ spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags);
++ virtblk_unmap_data(req, vbr);
++ virtblk_cleanup_cmd(req);
+ switch (err) {
+ case -ENOSPC:
+ return BLK_STS_DEV_RESOURCE;
+@@ -660,16 +715,6 @@ static const struct attribute_group *virtblk_attr_groups[] = {
+ NULL,
+ };
+
+-static int virtblk_init_request(struct blk_mq_tag_set *set, struct request *rq,
+- unsigned int hctx_idx, unsigned int numa_node)
+-{
+- struct virtio_blk *vblk = set->driver_data;
+- struct virtblk_req *vbr = blk_mq_rq_to_pdu(rq);
+-
+- sg_init_table(vbr->sg, vblk->sg_elems);
+- return 0;
+-}
+-
+ static int virtblk_map_queues(struct blk_mq_tag_set *set)
+ {
+ struct virtio_blk *vblk = set->driver_data;
+@@ -682,7 +727,6 @@ static const struct blk_mq_ops virtio_mq_ops = {
+ .queue_rq = virtio_queue_rq,
+ .commit_rqs = virtio_commit_rqs,
+ .complete = virtblk_request_done,
+- .init_request = virtblk_init_request,
+ .map_queues = virtblk_map_queues,
+ };
+
+@@ -762,7 +806,7 @@ static int virtblk_probe(struct virtio_device *vdev)
+ vblk->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
+ vblk->tag_set.cmd_size =
+ sizeof(struct virtblk_req) +
+- sizeof(struct scatterlist) * sg_elems;
++ sizeof(struct scatterlist) * VIRTIO_BLK_INLINE_SG_CNT;
+ vblk->tag_set.driver_data = vblk;
+ vblk->tag_set.nr_hw_queues = vblk->num_vqs;
+
+diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
+index ff1f5dfbb6dbf..d66e4df171d20 100644
+--- a/drivers/bluetooth/btmtksdio.c
++++ b/drivers/bluetooth/btmtksdio.c
+@@ -331,6 +331,7 @@ static int btmtksdio_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
+ {
+ struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
+ struct hci_event_hdr *hdr = (void *)skb->data;
++ u8 evt = hdr->evt;
+ int err;
+
+ /* Fix up the vendor event id with 0xff for vendor specific instead
+@@ -355,7 +356,7 @@ static int btmtksdio_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
+ if (err < 0)
+ goto err_free_skb;
+
+- if (hdr->evt == HCI_EV_VENDOR) {
++ if (evt == HCI_EV_VENDOR) {
+ if (test_and_clear_bit(BTMTKSDIO_TX_WAIT_VND_EVT,
+ &bdev->tx_state)) {
+ /* Barrier to sync with other CPUs */
+diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c
+index 4183945fc2c41..d8787aaa176ba 100644
+--- a/drivers/bus/mhi/core/init.c
++++ b/drivers/bus/mhi/core/init.c
+@@ -77,11 +77,14 @@ static const char * const mhi_pm_state_str[] = {
+ [MHI_PM_STATE_LD_ERR_FATAL_DETECT] = "Linkdown or Error Fatal Detect",
+ };
+
+-const char *to_mhi_pm_state_str(enum mhi_pm_state state)
++const char *to_mhi_pm_state_str(u32 state)
+ {
+- int index = find_last_bit((unsigned long *)&state, 32);
++ int index;
+
+- if (index >= ARRAY_SIZE(mhi_pm_state_str))
++ if (state)
++ index = __fls(state);
++
++ if (!state || index >= ARRAY_SIZE(mhi_pm_state_str))
+ return "Invalid State";
+
+ return mhi_pm_state_str[index];
+diff --git a/drivers/bus/mhi/core/internal.h b/drivers/bus/mhi/core/internal.h
+index c02c4d48b744c..71f181402be98 100644
+--- a/drivers/bus/mhi/core/internal.h
++++ b/drivers/bus/mhi/core/internal.h
+@@ -622,7 +622,7 @@ void mhi_free_bhie_table(struct mhi_controller *mhi_cntrl,
+ enum mhi_pm_state __must_check mhi_tryset_pm_state(
+ struct mhi_controller *mhi_cntrl,
+ enum mhi_pm_state state);
+-const char *to_mhi_pm_state_str(enum mhi_pm_state state);
++const char *to_mhi_pm_state_str(u32 state);
+ int mhi_queue_state_transition(struct mhi_controller *mhi_cntrl,
+ enum dev_st_transition state);
+ void mhi_pm_st_worker(struct work_struct *work);
+diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c
+index 1490446985e2e..61609eddf7d04 100644
+--- a/drivers/clk/renesas/r9a07g044-cpg.c
++++ b/drivers/clk/renesas/r9a07g044-cpg.c
+@@ -61,8 +61,8 @@ static const struct cpg_core_clk r9a07g044_core_clks[] __initconst = {
+ DEF_FIXED(".osc", R9A07G044_OSCCLK, CLK_EXTAL, 1, 1),
+ DEF_FIXED(".osc_div1000", CLK_OSC_DIV1000, CLK_EXTAL, 1, 1000),
+ DEF_SAMPLL(".pll1", CLK_PLL1, CLK_EXTAL, PLL146_CONF(0)),
+- DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 133, 2),
+- DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 133, 2),
++ DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 200, 3),
++ DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 200, 3),
+
+ DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 1, 2),
+ DEF_FIXED(".pll2_div16", CLK_PLL2_DIV16, CLK_PLL2, 1, 16),
+diff --git a/drivers/cxl/core/bus.c b/drivers/cxl/core/bus.c
+index 267d8042bec22..0987a6423ee06 100644
+--- a/drivers/cxl/core/bus.c
++++ b/drivers/cxl/core/bus.c
+@@ -182,6 +182,7 @@ static void cxl_decoder_release(struct device *dev)
+
+ ida_free(&port->decoder_ida, cxld->id);
+ kfree(cxld);
++ put_device(&port->dev);
+ }
+
+ static const struct device_type cxl_decoder_switch_type = {
+@@ -481,6 +482,9 @@ cxl_decoder_alloc(struct cxl_port *port, int nr_targets, resource_size_t base,
+ if (rc < 0)
+ goto err;
+
++ /* need parent to stick around to release the id */
++ get_device(&port->dev);
++
+ *cxld = (struct cxl_decoder) {
+ .id = rc,
+ .range = {
+diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
+index f9217e300eea9..968c3df2810e6 100644
+--- a/drivers/dma-buf/dma-buf.c
++++ b/drivers/dma-buf/dma-buf.c
+@@ -67,12 +67,9 @@ static void dma_buf_release(struct dentry *dentry)
+ BUG_ON(dmabuf->vmapping_counter);
+
+ /*
+- * Any fences that a dma-buf poll can wait on should be signaled
+- * before releasing dma-buf. This is the responsibility of each
+- * driver that uses the reservation objects.
+- *
+- * If you hit this BUG() it means someone dropped their ref to the
+- * dma-buf while still having pending operation to the buffer.
++ * If you hit this BUG() it could mean:
++ * * There's a file reference imbalance in dma_buf_poll / dma_buf_poll_cb or somewhere else
++ * * dmabuf->cb_in/out.active are non-0 despite no pending fence callback
+ */
+ BUG_ON(dmabuf->cb_in.active || dmabuf->cb_out.active);
+
+@@ -200,6 +197,7 @@ static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence)
+ static void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
+ {
+ struct dma_buf_poll_cb_t *dcb = (struct dma_buf_poll_cb_t *)cb;
++ struct dma_buf *dmabuf = container_of(dcb->poll, struct dma_buf, poll);
+ unsigned long flags;
+
+ spin_lock_irqsave(&dcb->poll->lock, flags);
+@@ -207,6 +205,8 @@ static void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
+ dcb->active = 0;
+ spin_unlock_irqrestore(&dcb->poll->lock, flags);
+ dma_fence_put(fence);
++ /* Paired with get_file in dma_buf_poll */
++ fput(dmabuf->file);
+ }
+
+ static bool dma_buf_poll_shared(struct dma_resv *resv,
+@@ -282,8 +282,12 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
+ spin_unlock_irq(&dmabuf->poll.lock);
+
+ if (events & EPOLLOUT) {
++ /* Paired with fput in dma_buf_poll_cb */
++ get_file(dmabuf->file);
++
+ if (!dma_buf_poll_shared(resv, dcb) &&
+ !dma_buf_poll_excl(resv, dcb))
++
+ /* No callback queued, wake up any other waiters */
+ dma_buf_poll_cb(NULL, &dcb->cb);
+ else
+@@ -303,6 +307,9 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
+ spin_unlock_irq(&dmabuf->poll.lock);
+
+ if (events & EPOLLIN) {
++ /* Paired with fput in dma_buf_poll_cb */
++ get_file(dmabuf->file);
++
+ if (!dma_buf_poll_excl(resv, dcb))
+ /* No callback queued, wake up any other waiters */
+ dma_buf_poll_cb(NULL, &dcb->cb);
+diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
+index 177a537971a1b..c5638afe94368 100644
+--- a/drivers/dma/at_xdmac.c
++++ b/drivers/dma/at_xdmac.c
+@@ -1898,6 +1898,11 @@ static int at_xdmac_alloc_chan_resources(struct dma_chan *chan)
+ for (i = 0; i < init_nr_desc_per_channel; i++) {
+ desc = at_xdmac_alloc_desc(chan, GFP_KERNEL);
+ if (!desc) {
++ if (i == 0) {
++ dev_warn(chan2dev(chan),
++ "can't allocate any descriptors\n");
++ return -EIO;
++ }
+ dev_warn(chan2dev(chan),
+ "only %d descriptors have been allocated\n", i);
+ break;
+diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
+index e622245c93804..11d3f2aede711 100644
+--- a/drivers/dma/idxd/device.c
++++ b/drivers/dma/idxd/device.c
+@@ -720,10 +720,7 @@ static void idxd_device_wqs_clear_state(struct idxd_device *idxd)
+ for (i = 0; i < idxd->max_wqs; i++) {
+ struct idxd_wq *wq = idxd->wqs[i];
+
+- if (wq->state == IDXD_WQ_ENABLED) {
+- idxd_wq_disable_cleanup(wq);
+- wq->state = IDXD_WQ_DISABLED;
+- }
++ idxd_wq_disable_cleanup(wq);
+ idxd_wq_device_reset_cleanup(wq);
+ }
+ }
+diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
+index 2300d965a3f44..5215a5e39f3c3 100644
+--- a/drivers/dma/imx-sdma.c
++++ b/drivers/dma/imx-sdma.c
+@@ -2264,7 +2264,7 @@ MODULE_DESCRIPTION("i.MX SDMA driver");
+ #if IS_ENABLED(CONFIG_SOC_IMX6Q)
+ MODULE_FIRMWARE("imx/sdma/sdma-imx6q.bin");
+ #endif
+-#if IS_ENABLED(CONFIG_SOC_IMX7D)
++#if IS_ENABLED(CONFIG_SOC_IMX7D) || IS_ENABLED(CONFIG_SOC_IMX8M)
+ MODULE_FIRMWARE("imx/sdma/sdma-imx7d.bin");
+ #endif
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/dma/lgm/lgm-dma.c b/drivers/dma/lgm/lgm-dma.c
+index efe8bd3a0e2aa..9b9184f964be3 100644
+--- a/drivers/dma/lgm/lgm-dma.c
++++ b/drivers/dma/lgm/lgm-dma.c
+@@ -1593,11 +1593,12 @@ static int intel_ldma_probe(struct platform_device *pdev)
+ d->core_clk = devm_clk_get_optional(dev, NULL);
+ if (IS_ERR(d->core_clk))
+ return PTR_ERR(d->core_clk);
+- clk_prepare_enable(d->core_clk);
+
+ d->rst = devm_reset_control_get_optional(dev, NULL);
+ if (IS_ERR(d->rst))
+ return PTR_ERR(d->rst);
++
++ clk_prepare_enable(d->core_clk);
+ reset_control_deassert(d->rst);
+
+ ret = devm_add_action_or_reset(dev, ldma_clk_disable, d);
+diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
+index 110de8a600588..4ef68ddff75bc 100644
+--- a/drivers/dma/pl330.c
++++ b/drivers/dma/pl330.c
+@@ -2589,7 +2589,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
+
+ /* If the DMAC pool is empty, alloc new */
+ if (!desc) {
+- DEFINE_SPINLOCK(lock);
++ static DEFINE_SPINLOCK(lock);
+ LIST_HEAD(pool);
+
+ if (!add_desc(&pool, &lock, GFP_ATOMIC, 1))
+diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
+index c8a77b428b528..ca8c862c9747e 100644
+--- a/drivers/dma/qcom/bam_dma.c
++++ b/drivers/dma/qcom/bam_dma.c
+@@ -515,14 +515,6 @@ static int bam_alloc_chan(struct dma_chan *chan)
+ return 0;
+ }
+
+-static int bam_pm_runtime_get_sync(struct device *dev)
+-{
+- if (pm_runtime_enabled(dev))
+- return pm_runtime_get_sync(dev);
+-
+- return 0;
+-}
+-
+ /**
+ * bam_free_chan - Frees dma resources associated with specific channel
+ * @chan: specified channel
+@@ -538,7 +530,7 @@ static void bam_free_chan(struct dma_chan *chan)
+ unsigned long flags;
+ int ret;
+
+- ret = bam_pm_runtime_get_sync(bdev->dev);
++ ret = pm_runtime_get_sync(bdev->dev);
+ if (ret < 0)
+ return;
+
+@@ -734,7 +726,7 @@ static int bam_pause(struct dma_chan *chan)
+ unsigned long flag;
+ int ret;
+
+- ret = bam_pm_runtime_get_sync(bdev->dev);
++ ret = pm_runtime_get_sync(bdev->dev);
+ if (ret < 0)
+ return ret;
+
+@@ -760,7 +752,7 @@ static int bam_resume(struct dma_chan *chan)
+ unsigned long flag;
+ int ret;
+
+- ret = bam_pm_runtime_get_sync(bdev->dev);
++ ret = pm_runtime_get_sync(bdev->dev);
+ if (ret < 0)
+ return ret;
+
+@@ -869,7 +861,7 @@ static irqreturn_t bam_dma_irq(int irq, void *data)
+ if (srcs & P_IRQ)
+ tasklet_schedule(&bdev->task);
+
+- ret = bam_pm_runtime_get_sync(bdev->dev);
++ ret = pm_runtime_get_sync(bdev->dev);
+ if (ret < 0)
+ return IRQ_NONE;
+
+@@ -987,7 +979,7 @@ static void bam_start_dma(struct bam_chan *bchan)
+ if (!vd)
+ return;
+
+- ret = bam_pm_runtime_get_sync(bdev->dev);
++ ret = pm_runtime_get_sync(bdev->dev);
+ if (ret < 0)
+ return;
+
+@@ -1350,11 +1342,6 @@ static int bam_dma_probe(struct platform_device *pdev)
+ if (ret)
+ goto err_unregister_dma;
+
+- if (!bdev->bamclk) {
+- pm_runtime_disable(&pdev->dev);
+- return 0;
+- }
+-
+ pm_runtime_irq_safe(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, BAM_DMA_AUTOSUSPEND_DELAY);
+ pm_runtime_use_autosuspend(&pdev->dev);
+@@ -1438,10 +1425,8 @@ static int __maybe_unused bam_dma_suspend(struct device *dev)
+ {
+ struct bam_device *bdev = dev_get_drvdata(dev);
+
+- if (bdev->bamclk) {
+- pm_runtime_force_suspend(dev);
+- clk_unprepare(bdev->bamclk);
+- }
++ pm_runtime_force_suspend(dev);
++ clk_unprepare(bdev->bamclk);
+
+ return 0;
+ }
+@@ -1451,13 +1436,11 @@ static int __maybe_unused bam_dma_resume(struct device *dev)
+ struct bam_device *bdev = dev_get_drvdata(dev);
+ int ret;
+
+- if (bdev->bamclk) {
+- ret = clk_prepare(bdev->bamclk);
+- if (ret)
+- return ret;
++ ret = clk_prepare(bdev->bamclk);
++ if (ret)
++ return ret;
+
+- pm_runtime_force_resume(dev);
+- }
++ pm_runtime_force_resume(dev);
+
+ return 0;
+ }
+diff --git a/drivers/dma/ti/dma-crossbar.c b/drivers/dma/ti/dma-crossbar.c
+index 71d24fc07c003..f744ddbbbad7f 100644
+--- a/drivers/dma/ti/dma-crossbar.c
++++ b/drivers/dma/ti/dma-crossbar.c
+@@ -245,6 +245,7 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
+ if (dma_spec->args[0] >= xbar->xbar_requests) {
+ dev_err(&pdev->dev, "Invalid XBAR request number: %d\n",
+ dma_spec->args[0]);
++ put_device(&pdev->dev);
+ return ERR_PTR(-EINVAL);
+ }
+
+@@ -252,12 +253,14 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
+ dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
+ if (!dma_spec->np) {
+ dev_err(&pdev->dev, "Can't get DMA master\n");
++ put_device(&pdev->dev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
+ if (!map) {
+ of_node_put(dma_spec->np);
++ put_device(&pdev->dev);
+ return ERR_PTR(-ENOMEM);
+ }
+
+@@ -268,6 +271,8 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
+ mutex_unlock(&xbar->mutex);
+ dev_err(&pdev->dev, "Run out of free DMA requests\n");
+ kfree(map);
++ of_node_put(dma_spec->np);
++ put_device(&pdev->dev);
+ return ERR_PTR(-ENOMEM);
+ }
+ set_bit(map->xbar_out, xbar->dma_inuse);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+index 2eebefd26fa82..5f95d03fd46a0 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+@@ -1285,6 +1285,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
+ void amdgpu_device_pci_config_reset(struct amdgpu_device *adev);
+ int amdgpu_device_pci_reset(struct amdgpu_device *adev);
+ bool amdgpu_device_need_post(struct amdgpu_device *adev);
++bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev);
+
+ void amdgpu_cs_report_moved_bytes(struct amdgpu_device *adev, u64 num_bytes,
+ u64 num_vis_bytes);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+index a926b5ebbfdf5..d1af709cc7dca 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+@@ -1309,6 +1309,31 @@ bool amdgpu_device_need_post(struct amdgpu_device *adev)
+ return true;
+ }
+
++/**
++ * amdgpu_device_should_use_aspm - check if the device should program ASPM
++ *
++ * @adev: amdgpu_device pointer
++ *
++ * Confirm whether the module parameter and pcie bridge agree that ASPM should
++ * be set for this device.
++ *
++ * Returns true if it should be used or false if not.
++ */
++bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev)
++{
++ switch (amdgpu_aspm) {
++ case -1:
++ break;
++ case 0:
++ return false;
++ case 1:
++ return true;
++ default:
++ return false;
++ }
++ return pcie_aspm_enabled(adev->pdev);
++}
++
+ /* if we get transitioned to only one device, take VGA back */
+ /**
+ * amdgpu_device_vga_set_decode - enable/disable vga decode
+diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c
+index f10ce740a29cc..de6d10390ab2f 100644
+--- a/drivers/gpu/drm/amd/amdgpu/cik.c
++++ b/drivers/gpu/drm/amd/amdgpu/cik.c
+@@ -1719,7 +1719,7 @@ static void cik_program_aspm(struct amdgpu_device *adev)
+ bool disable_l0s = false, disable_l1 = false, disable_plloff_in_l1 = false;
+ bool disable_clkreq = false;
+
+- if (amdgpu_aspm == 0)
++ if (!amdgpu_device_should_use_aspm(adev))
+ return;
+
+ if (pci_is_root_bus(adev->pdev->bus))
+diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c
+index 9cbed9a8f1c04..6e277236b44fb 100644
+--- a/drivers/gpu/drm/amd/amdgpu/nv.c
++++ b/drivers/gpu/drm/amd/amdgpu/nv.c
+@@ -584,7 +584,7 @@ static void nv_pcie_gen3_enable(struct amdgpu_device *adev)
+
+ static void nv_program_aspm(struct amdgpu_device *adev)
+ {
+- if (!amdgpu_aspm)
++ if (!amdgpu_device_should_use_aspm(adev))
+ return;
+
+ if (!(adev->flags & AMD_IS_APU) &&
+diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c
+index e6d2f74a79765..7f99e130acd06 100644
+--- a/drivers/gpu/drm/amd/amdgpu/si.c
++++ b/drivers/gpu/drm/amd/amdgpu/si.c
+@@ -2453,7 +2453,7 @@ static void si_program_aspm(struct amdgpu_device *adev)
+ bool disable_l0s = false, disable_l1 = false, disable_plloff_in_l1 = false;
+ bool disable_clkreq = false;
+
+- if (amdgpu_aspm == 0)
++ if (!amdgpu_device_should_use_aspm(adev))
+ return;
+
+ if (adev->flags & AMD_IS_APU)
+diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c
+index 6439d5c3d8d8b..bdb47ae96ce6a 100644
+--- a/drivers/gpu/drm/amd/amdgpu/soc15.c
++++ b/drivers/gpu/drm/amd/amdgpu/soc15.c
+@@ -689,7 +689,7 @@ static void soc15_pcie_gen3_enable(struct amdgpu_device *adev)
+
+ static void soc15_program_aspm(struct amdgpu_device *adev)
+ {
+- if (!amdgpu_aspm)
++ if (!amdgpu_device_should_use_aspm(adev))
+ return;
+
+ if (!(adev->flags & AMD_IS_APU) &&
+diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
+index 6e56bef4fdf81..1310617f030f7 100644
+--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
+@@ -1511,7 +1511,7 @@ static int vcn_v3_0_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx)
+ struct dpg_pause_state state = {.fw_based = VCN_DPG_STATE__UNPAUSE};
+ uint32_t tmp;
+
+- vcn_v3_0_pause_dpg_mode(adev, 0, &state);
++ vcn_v3_0_pause_dpg_mode(adev, inst_idx, &state);
+
+ /* Wait for power status to be 1 */
+ SOC15_WAIT_ON_RREG(VCN, inst_idx, mmUVD_POWER_STATUS, 1,
+diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c
+index 6645ebbd2696c..45f0188c42739 100644
+--- a/drivers/gpu/drm/amd/amdgpu/vi.c
++++ b/drivers/gpu/drm/amd/amdgpu/vi.c
+@@ -81,6 +81,10 @@
+ #include "mxgpu_vi.h"
+ #include "amdgpu_dm.h"
+
++#if IS_ENABLED(CONFIG_X86)
++#include <asm/intel-family.h>
++#endif
++
+ #define ixPCIE_LC_L1_PM_SUBSTATE 0x100100C6
+ #define PCIE_LC_L1_PM_SUBSTATE__LC_L1_SUBSTATES_OVERRIDE_EN_MASK 0x00000001L
+ #define PCIE_LC_L1_PM_SUBSTATE__LC_PCI_PM_L1_2_OVERRIDE_MASK 0x00000002L
+@@ -1134,13 +1138,24 @@ static void vi_enable_aspm(struct amdgpu_device *adev)
+ WREG32_PCIE(ixPCIE_LC_CNTL, data);
+ }
+
++static bool aspm_support_quirk_check(void)
++{
++#if IS_ENABLED(CONFIG_X86)
++ struct cpuinfo_x86 *c = &cpu_data(0);
++
++ return !(c->x86 == 6 && c->x86_model == INTEL_FAM6_ALDERLAKE);
++#else
++ return true;
++#endif
++}
++
+ static void vi_program_aspm(struct amdgpu_device *adev)
+ {
+ u32 data, data1, orig;
+ bool bL1SS = false;
+ bool bClkReqSupport = true;
+
+- if (!amdgpu_aspm)
++ if (!amdgpu_device_should_use_aspm(adev) || !aspm_support_quirk_check())
+ return;
+
+ if (adev->flags & AMD_IS_APU ||
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
+index 0294d0cc47595..735c92a5aa36a 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
+@@ -1856,7 +1856,7 @@ static struct pipe_ctx *dcn30_find_split_pipe(
+ return pipe;
+ }
+
+-static noinline bool dcn30_internal_validate_bw(
++noinline bool dcn30_internal_validate_bw(
+ struct dc *dc,
+ struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h
+index b754b89beadfb..b92e4cc0232f2 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h
++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h
+@@ -55,6 +55,13 @@ unsigned int dcn30_calc_max_scaled_time(
+
+ bool dcn30_validate_bandwidth(struct dc *dc, struct dc_state *context,
+ bool fast_validate);
++bool dcn30_internal_validate_bw(
++ struct dc *dc,
++ struct dc_state *context,
++ display_e2e_pipe_params_st *pipes,
++ int *pipe_cnt_out,
++ int *vlevel_out,
++ bool fast_validate);
+ void dcn30_calculate_wm_and_dlg(
+ struct dc *dc, struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
+index b60ab3cc0f119..e224c52132581 100644
+--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
+@@ -1664,6 +1664,15 @@ static void dcn31_calculate_wm_and_dlg_fp(
+ if (context->bw_ctx.dml.soc.min_dcfclk > dcfclk)
+ dcfclk = context->bw_ctx.dml.soc.min_dcfclk;
+
++ /* We don't recalculate clocks for 0 pipe configs, which can block
++ * S0i3 as high clocks will block low power states
++ * Override any clocks that can block S0i3 to min here
++ */
++ if (pipe_cnt == 0) {
++ context->bw_ctx.bw.dcn.clk.dcfclk_khz = dcfclk; // always should be vlevel 0
++ return;
++ }
++
+ pipes[0].clks_cfg.voltage = vlevel;
+ pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
+ pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz;
+@@ -1789,6 +1798,60 @@ static void dcn31_calculate_wm_and_dlg(
+ DC_FP_END();
+ }
+
++bool dcn31_validate_bandwidth(struct dc *dc,
++ struct dc_state *context,
++ bool fast_validate)
++{
++ bool out = false;
++
++ BW_VAL_TRACE_SETUP();
++
++ int vlevel = 0;
++ int pipe_cnt = 0;
++ display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_KERNEL);
++ DC_LOGGER_INIT(dc->ctx->logger);
++
++ BW_VAL_TRACE_COUNT();
++
++ DC_FP_START();
++ out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate);
++ DC_FP_END();
++
++ // Disable fast_validate to set min dcfclk in alculate_wm_and_dlg
++ if (pipe_cnt == 0)
++ fast_validate = false;
++
++ if (!out)
++ goto validate_fail;
++
++ BW_VAL_TRACE_END_VOLTAGE_LEVEL();
++
++ if (fast_validate) {
++ BW_VAL_TRACE_SKIP(fast);
++ goto validate_out;
++ }
++
++ dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel);
++
++ BW_VAL_TRACE_END_WATERMARKS();
++
++ goto validate_out;
++
++validate_fail:
++ DC_LOG_WARNING("Mode Validation Warning: %s failed alidation.\n",
++ dml_get_status_message(context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states]));
++
++ BW_VAL_TRACE_SKIP(fail);
++ out = false;
++
++validate_out:
++ kfree(pipes);
++
++ BW_VAL_TRACE_FINISH();
++
++ return out;
++}
++
+ static struct dc_cap_funcs cap_funcs = {
+ .get_dcc_compression_cap = dcn20_get_dcc_compression_cap
+ };
+@@ -1871,7 +1934,7 @@ static struct resource_funcs dcn31_res_pool_funcs = {
+ .link_encs_assign = link_enc_cfg_link_encs_assign,
+ .link_enc_unassign = link_enc_cfg_link_enc_unassign,
+ .panel_cntl_create = dcn31_panel_cntl_create,
+- .validate_bandwidth = dcn30_validate_bandwidth,
++ .validate_bandwidth = dcn31_validate_bandwidth,
+ .calculate_wm_and_dlg = dcn31_calculate_wm_and_dlg,
+ .update_soc_for_wm_a = dcn31_update_soc_for_wm_a,
+ .populate_dml_pipes = dcn31_populate_dml_pipes_from_context,
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+index 574a9d7f7a5e7..918d5c7c2328b 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
++++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
+@@ -338,7 +338,7 @@ sienna_cichlid_get_allowed_feature_mask(struct smu_context *smu,
+ if (smu->dc_controlled_by_gpio)
+ *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ACDC_BIT);
+
+- if (amdgpu_aspm)
++ if (amdgpu_device_should_use_aspm(adev))
+ *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_LCLK_BIT);
+
+ return 0;
+diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
+index ee0c0b712522f..ba2e037a82e4e 100644
+--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
++++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
+@@ -442,6 +442,13 @@ set_proto_ctx_engines_bond(struct i915_user_extension __user *base, void *data)
+ u16 idx, num_bonds;
+ int err, n;
+
++ if (GRAPHICS_VER(i915) >= 12 && !IS_TIGERLAKE(i915) &&
++ !IS_ROCKETLAKE(i915) && !IS_ALDERLAKE_S(i915)) {
++ drm_dbg(&i915->drm,
++ "Bonding on gen12+ aside from TGL, RKL, and ADL_S not supported\n");
++ return -ENODEV;
++ }
++
+ if (get_user(idx, &ext->virtual_index))
+ return -EFAULT;
+
+diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
+index 6fb9afb65034b..5f48d5ea5c158 100644
+--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
++++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
+@@ -224,6 +224,12 @@ void __i915_gem_free_object(struct drm_i915_gem_object *obj)
+ GEM_BUG_ON(vma->obj != obj);
+ spin_unlock(&obj->vma.lock);
+
++ /* Verify that the vma is unbound under the vm mutex. */
++ mutex_lock(&vma->vm->mutex);
++ atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
++ __i915_vma_unbind(vma);
++ mutex_unlock(&vma->vm->mutex);
++
+ __i915_vma_put(vma);
+
+ spin_lock(&obj->vma.lock);
+diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h
+index e54351a170e2c..a63631ea0ec47 100644
+--- a/drivers/gpu/drm/i915/gt/intel_context_types.h
++++ b/drivers/gpu/drm/i915/gt/intel_context_types.h
+@@ -152,6 +152,14 @@ struct intel_context {
+ /** sseu: Control eu/slice partitioning */
+ struct intel_sseu sseu;
+
++ /**
++ * pinned_contexts_link: List link for the engine's pinned contexts.
++ * This is only used if this is a perma-pinned kernel context and
++ * the list is assumed to only be manipulated during driver load
++ * or unload time so no mutex protection currently.
++ */
++ struct list_head pinned_contexts_link;
++
+ u8 wa_bb_page; /* if set, page num reserved for context workarounds */
+
+ struct {
+diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+index 0d9105a31d84e..eb99441e0ada0 100644
+--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c
++++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+@@ -320,6 +320,7 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id)
+
+ BUILD_BUG_ON(BITS_PER_TYPE(engine->mask) < I915_NUM_ENGINES);
+
++ INIT_LIST_HEAD(&engine->pinned_contexts_list);
+ engine->id = id;
+ engine->legacy_idx = INVALID_ENGINE;
+ engine->mask = BIT(id);
+@@ -875,6 +876,8 @@ intel_engine_create_pinned_context(struct intel_engine_cs *engine,
+ return ERR_PTR(err);
+ }
+
++ list_add_tail(&ce->pinned_contexts_link, &engine->pinned_contexts_list);
++
+ /*
+ * Give our perma-pinned kernel timelines a separate lockdep class,
+ * so that we can use them from within the normal user timelines
+@@ -897,6 +900,7 @@ void intel_engine_destroy_pinned_context(struct intel_context *ce)
+ list_del(&ce->timeline->engine_link);
+ mutex_unlock(&hwsp->vm->mutex);
+
++ list_del(&ce->pinned_contexts_link);
+ intel_context_unpin(ce);
+ intel_context_put(ce);
+ }
+diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i915/gt/intel_engine_pm.c
+index 1f07ac4e0672a..dacd627737359 100644
+--- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c
++++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c
+@@ -298,6 +298,29 @@ void intel_engine_init__pm(struct intel_engine_cs *engine)
+ intel_engine_init_heartbeat(engine);
+ }
+
++/**
++ * intel_engine_reset_pinned_contexts - Reset the pinned contexts of
++ * an engine.
++ * @engine: The engine whose pinned contexts we want to reset.
++ *
++ * Typically the pinned context LMEM images lose or get their content
++ * corrupted on suspend. This function resets their images.
++ */
++void intel_engine_reset_pinned_contexts(struct intel_engine_cs *engine)
++{
++ struct intel_context *ce;
++
++ list_for_each_entry(ce, &engine->pinned_contexts_list,
++ pinned_contexts_link) {
++ /* kernel context gets reset at __engine_unpark() */
++ if (ce == engine->kernel_context)
++ continue;
++
++ dbg_poison_ce(ce);
++ ce->ops->reset(ce);
++ }
++}
++
+ #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+ #include "selftest_engine_pm.c"
+ #endif
+diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.h b/drivers/gpu/drm/i915/gt/intel_engine_pm.h
+index 70ea46d6cfb00..8520c595f5e18 100644
+--- a/drivers/gpu/drm/i915/gt/intel_engine_pm.h
++++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.h
+@@ -69,4 +69,6 @@ intel_engine_create_kernel_request(struct intel_engine_cs *engine)
+
+ void intel_engine_init__pm(struct intel_engine_cs *engine);
+
++void intel_engine_reset_pinned_contexts(struct intel_engine_cs *engine);
++
+ #endif /* INTEL_ENGINE_PM_H */
+diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h
+index ed91bcff20eb5..adc44c9fac6de 100644
+--- a/drivers/gpu/drm/i915/gt/intel_engine_types.h
++++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h
+@@ -304,6 +304,13 @@ struct intel_engine_cs {
+
+ struct intel_context *kernel_context; /* pinned */
+
++ /**
++ * pinned_contexts_list: List of pinned contexts. This list is only
++ * assumed to be manipulated during driver load- or unload time and
++ * does therefore not have any additional protection.
++ */
++ struct list_head pinned_contexts_list;
++
+ intel_engine_mask_t saturated; /* submitting semaphores too late? */
+
+ struct {
+diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+index cafb0608ffb46..416f5e0657f07 100644
+--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
++++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+@@ -2787,6 +2787,8 @@ static void execlists_sanitize(struct intel_engine_cs *engine)
+
+ /* And scrub the dirty cachelines for the HWSP */
+ clflush_cache_range(engine->status_page.addr, PAGE_SIZE);
++
++ intel_engine_reset_pinned_contexts(engine);
+ }
+
+ static void enable_error_interrupt(struct intel_engine_cs *engine)
+diff --git a/drivers/gpu/drm/i915/gt/intel_ring_submission.c b/drivers/gpu/drm/i915/gt/intel_ring_submission.c
+index 2958e2fae3800..02e18e70c78ea 100644
+--- a/drivers/gpu/drm/i915/gt/intel_ring_submission.c
++++ b/drivers/gpu/drm/i915/gt/intel_ring_submission.c
+@@ -17,6 +17,7 @@
+ #include "intel_ring.h"
+ #include "shmem_utils.h"
+ #include "intel_engine_heartbeat.h"
++#include "intel_engine_pm.h"
+
+ /* Rough estimate of the typical request size, performing a flush,
+ * set-context and then emitting the batch.
+@@ -291,7 +292,9 @@ static void xcs_sanitize(struct intel_engine_cs *engine)
+ sanitize_hwsp(engine);
+
+ /* And scrub the dirty cachelines for the HWSP */
+- clflush_cache_range(engine->status_page.addr, PAGE_SIZE);
++ drm_clflush_virt_range(engine->status_page.addr, PAGE_SIZE);
++
++ intel_engine_reset_pinned_contexts(engine);
+ }
+
+ static void reset_prepare(struct intel_engine_cs *engine)
+diff --git a/drivers/gpu/drm/i915/gt/mock_engine.c b/drivers/gpu/drm/i915/gt/mock_engine.c
+index 2c1af030310c0..8b89215afe46b 100644
+--- a/drivers/gpu/drm/i915/gt/mock_engine.c
++++ b/drivers/gpu/drm/i915/gt/mock_engine.c
+@@ -376,6 +376,8 @@ int mock_engine_init(struct intel_engine_cs *engine)
+ {
+ struct intel_context *ce;
+
++ INIT_LIST_HEAD(&engine->pinned_contexts_list);
++
+ engine->sched_engine = i915_sched_engine_create(ENGINE_MOCK);
+ if (!engine->sched_engine)
+ return -ENOMEM;
+diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
+index 93c9de8f43e8e..6e09a1cca37b4 100644
+--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
++++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
+@@ -2347,6 +2347,8 @@ static void guc_sanitize(struct intel_engine_cs *engine)
+
+ /* And scrub the dirty cachelines for the HWSP */
+ clflush_cache_range(engine->status_page.addr, PAGE_SIZE);
++
++ intel_engine_reset_pinned_contexts(engine);
+ }
+
+ static void setup_hwsp(struct intel_engine_cs *engine)
+@@ -2422,9 +2424,13 @@ static inline void guc_init_lrc_mapping(struct intel_guc *guc)
+ * and even it did this code would be run again.
+ */
+
+- for_each_engine(engine, gt, id)
+- if (engine->kernel_context)
+- guc_kernel_context_pin(guc, engine->kernel_context);
++ for_each_engine(engine, gt, id) {
++ struct intel_context *ce;
++
++ list_for_each_entry(ce, &engine->pinned_contexts_list,
++ pinned_contexts_link)
++ guc_kernel_context_pin(guc, ce);
++ }
+ }
+
+ static void guc_release(struct intel_engine_cs *engine)
+diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+index 86c3068894b11..974462831133b 100644
+--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
++++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+@@ -76,9 +76,11 @@ void mtk_ovl_layer_off(struct device *dev, unsigned int idx,
+ void mtk_ovl_start(struct device *dev);
+ void mtk_ovl_stop(struct device *dev);
+ unsigned int mtk_ovl_supported_rotations(struct device *dev);
+-void mtk_ovl_enable_vblank(struct device *dev,
+- void (*vblank_cb)(void *),
+- void *vblank_cb_data);
++void mtk_ovl_register_vblank_cb(struct device *dev,
++ void (*vblank_cb)(void *),
++ void *vblank_cb_data);
++void mtk_ovl_unregister_vblank_cb(struct device *dev);
++void mtk_ovl_enable_vblank(struct device *dev);
+ void mtk_ovl_disable_vblank(struct device *dev);
+
+ void mtk_rdma_bypass_shadow(struct device *dev);
+@@ -93,9 +95,11 @@ void mtk_rdma_layer_config(struct device *dev, unsigned int idx,
+ struct cmdq_pkt *cmdq_pkt);
+ void mtk_rdma_start(struct device *dev);
+ void mtk_rdma_stop(struct device *dev);
+-void mtk_rdma_enable_vblank(struct device *dev,
+- void (*vblank_cb)(void *),
+- void *vblank_cb_data);
++void mtk_rdma_register_vblank_cb(struct device *dev,
++ void (*vblank_cb)(void *),
++ void *vblank_cb_data);
++void mtk_rdma_unregister_vblank_cb(struct device *dev);
++void mtk_rdma_enable_vblank(struct device *dev);
+ void mtk_rdma_disable_vblank(struct device *dev);
+
+ #endif
+diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+index 5326989d52061..411cf0f216611 100644
+--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
++++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+@@ -96,14 +96,28 @@ static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id)
+ return IRQ_HANDLED;
+ }
+
+-void mtk_ovl_enable_vblank(struct device *dev,
+- void (*vblank_cb)(void *),
+- void *vblank_cb_data)
++void mtk_ovl_register_vblank_cb(struct device *dev,
++ void (*vblank_cb)(void *),
++ void *vblank_cb_data)
+ {
+ struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+
+ ovl->vblank_cb = vblank_cb;
+ ovl->vblank_cb_data = vblank_cb_data;
++}
++
++void mtk_ovl_unregister_vblank_cb(struct device *dev)
++{
++ struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
++
++ ovl->vblank_cb = NULL;
++ ovl->vblank_cb_data = NULL;
++}
++
++void mtk_ovl_enable_vblank(struct device *dev)
++{
++ struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
++
+ writel(0x0, ovl->regs + DISP_REG_OVL_INTSTA);
+ writel_relaxed(OVL_FME_CPL_INT, ovl->regs + DISP_REG_OVL_INTEN);
+ }
+@@ -112,8 +126,6 @@ void mtk_ovl_disable_vblank(struct device *dev)
+ {
+ struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+
+- ovl->vblank_cb = NULL;
+- ovl->vblank_cb_data = NULL;
+ writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_INTEN);
+ }
+
+diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
+index 75d7f45579e26..a6a6cb5f75af7 100644
+--- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
++++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
+@@ -94,24 +94,32 @@ static void rdma_update_bits(struct device *dev, unsigned int reg,
+ writel(tmp, rdma->regs + reg);
+ }
+
+-void mtk_rdma_enable_vblank(struct device *dev,
+- void (*vblank_cb)(void *),
+- void *vblank_cb_data)
++void mtk_rdma_register_vblank_cb(struct device *dev,
++ void (*vblank_cb)(void *),
++ void *vblank_cb_data)
+ {
+ struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
+
+ rdma->vblank_cb = vblank_cb;
+ rdma->vblank_cb_data = vblank_cb_data;
+- rdma_update_bits(dev, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT,
+- RDMA_FRAME_END_INT);
+ }
+
+-void mtk_rdma_disable_vblank(struct device *dev)
++void mtk_rdma_unregister_vblank_cb(struct device *dev)
+ {
+ struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
+
+ rdma->vblank_cb = NULL;
+ rdma->vblank_cb_data = NULL;
++}
++
++void mtk_rdma_enable_vblank(struct device *dev)
++{
++ rdma_update_bits(dev, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT,
++ RDMA_FRAME_END_INT);
++}
++
++void mtk_rdma_disable_vblank(struct device *dev)
++{
+ rdma_update_bits(dev, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, 0);
+ }
+
+diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+index a4e80e4996748..34bb6c713a908 100644
+--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
++++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+@@ -4,6 +4,8 @@
+ */
+
+ #include <linux/clk.h>
++#include <linux/dma-mapping.h>
++#include <linux/mailbox_controller.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/soc/mediatek/mtk-cmdq.h>
+ #include <linux/soc/mediatek/mtk-mmsys.h>
+@@ -50,8 +52,10 @@ struct mtk_drm_crtc {
+ bool pending_async_planes;
+
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+- struct cmdq_client *cmdq_client;
++ struct cmdq_client cmdq_client;
++ struct cmdq_pkt cmdq_handle;
+ u32 cmdq_event;
++ u32 cmdq_vblank_cnt;
+ #endif
+
+ struct device *mmsys_dev;
+@@ -104,11 +108,63 @@ static void mtk_drm_finish_page_flip(struct mtk_drm_crtc *mtk_crtc)
+ }
+ }
+
++#if IS_REACHABLE(CONFIG_MTK_CMDQ)
++static int mtk_drm_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt,
++ size_t size)
++{
++ struct device *dev;
++ dma_addr_t dma_addr;
++
++ pkt->va_base = kzalloc(size, GFP_KERNEL);
++ if (!pkt->va_base) {
++ kfree(pkt);
++ return -ENOMEM;
++ }
++ pkt->buf_size = size;
++ pkt->cl = (void *)client;
++
++ dev = client->chan->mbox->dev;
++ dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size,
++ DMA_TO_DEVICE);
++ if (dma_mapping_error(dev, dma_addr)) {
++ dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size);
++ kfree(pkt->va_base);
++ kfree(pkt);
++ return -ENOMEM;
++ }
++
++ pkt->pa_base = dma_addr;
++
++ return 0;
++}
++
++static void mtk_drm_cmdq_pkt_destroy(struct cmdq_pkt *pkt)
++{
++ struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
++
++ dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size,
++ DMA_TO_DEVICE);
++ kfree(pkt->va_base);
++ kfree(pkt);
++}
++#endif
++
+ static void mtk_drm_crtc_destroy(struct drm_crtc *crtc)
+ {
+ struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
++ int i;
+
+ mtk_mutex_put(mtk_crtc->mutex);
++#if IS_REACHABLE(CONFIG_MTK_CMDQ)
++ mtk_drm_cmdq_pkt_destroy(&mtk_crtc->cmdq_handle);
++#endif
++
++ for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
++ struct mtk_ddp_comp *comp;
++
++ comp = mtk_crtc->ddp_comp[i];
++ mtk_ddp_comp_unregister_vblank_cb(comp);
++ }
+
+ drm_crtc_cleanup(crtc);
+ }
+@@ -222,9 +278,12 @@ struct mtk_ddp_comp *mtk_drm_ddp_comp_for_plane(struct drm_crtc *crtc,
+ }
+
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+-static void ddp_cmdq_cb(struct cmdq_cb_data data)
++static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
+ {
+- cmdq_pkt_destroy(data.data);
++ struct cmdq_client *cmdq_cl = container_of(cl, struct cmdq_client, client);
++ struct mtk_drm_crtc *mtk_crtc = container_of(cmdq_cl, struct mtk_drm_crtc, cmdq_client);
++
++ mtk_crtc->cmdq_vblank_cnt = 0;
+ }
+ #endif
+
+@@ -430,7 +489,7 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc,
+ bool needs_vblank)
+ {
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+- struct cmdq_pkt *cmdq_handle;
++ struct cmdq_pkt *cmdq_handle = &mtk_crtc->cmdq_handle;
+ #endif
+ struct drm_crtc *crtc = &mtk_crtc->base;
+ struct mtk_drm_private *priv = crtc->dev->dev_private;
+@@ -468,14 +527,28 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc,
+ mtk_mutex_release(mtk_crtc->mutex);
+ }
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+- if (mtk_crtc->cmdq_client) {
+- mbox_flush(mtk_crtc->cmdq_client->chan, 2000);
+- cmdq_handle = cmdq_pkt_create(mtk_crtc->cmdq_client, PAGE_SIZE);
++ if (mtk_crtc->cmdq_client.chan) {
++ mbox_flush(mtk_crtc->cmdq_client.chan, 2000);
++ cmdq_handle->cmd_buf_size = 0;
+ cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event);
+ cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false);
+ mtk_crtc_ddp_config(crtc, cmdq_handle);
+ cmdq_pkt_finalize(cmdq_handle);
+- cmdq_pkt_flush_async(cmdq_handle, ddp_cmdq_cb, cmdq_handle);
++ dma_sync_single_for_device(mtk_crtc->cmdq_client.chan->mbox->dev,
++ cmdq_handle->pa_base,
++ cmdq_handle->cmd_buf_size,
++ DMA_TO_DEVICE);
++ /*
++ * CMDQ command should execute in next 3 vblank.
++ * One vblank interrupt before send message (occasionally)
++ * and one vblank interrupt after cmdq done,
++ * so it's timeout after 3 vblank interrupt.
++ * If it fail to execute in next 3 vblank, timeout happen.
++ */
++ mtk_crtc->cmdq_vblank_cnt = 3;
++
++ mbox_send_message(mtk_crtc->cmdq_client.chan, cmdq_handle);
++ mbox_client_txdone(mtk_crtc->cmdq_client.chan, 0);
+ }
+ #endif
+ mtk_crtc->config_updating = false;
+@@ -489,12 +562,15 @@ static void mtk_crtc_ddp_irq(void *data)
+ struct mtk_drm_private *priv = crtc->dev->dev_private;
+
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+- if (!priv->data->shadow_register && !mtk_crtc->cmdq_client)
++ if (!priv->data->shadow_register && !mtk_crtc->cmdq_client.chan)
++ mtk_crtc_ddp_config(crtc, NULL);
++ else if (mtk_crtc->cmdq_vblank_cnt > 0 && --mtk_crtc->cmdq_vblank_cnt == 0)
++ DRM_ERROR("mtk_crtc %d CMDQ execute command timeout!\n",
++ drm_crtc_index(&mtk_crtc->base));
+ #else
+ if (!priv->data->shadow_register)
+-#endif
+ mtk_crtc_ddp_config(crtc, NULL);
+-
++#endif
+ mtk_drm_finish_page_flip(mtk_crtc);
+ }
+
+@@ -503,7 +579,7 @@ static int mtk_drm_crtc_enable_vblank(struct drm_crtc *crtc)
+ struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+ struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
+
+- mtk_ddp_comp_enable_vblank(comp, mtk_crtc_ddp_irq, &mtk_crtc->base);
++ mtk_ddp_comp_enable_vblank(comp);
+
+ return 0;
+ }
+@@ -803,6 +879,9 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
+ if (comp->funcs->ctm_set)
+ has_ctm = true;
+ }
++
++ mtk_ddp_comp_register_vblank_cb(comp, mtk_crtc_ddp_irq,
++ &mtk_crtc->base);
+ }
+
+ for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
+@@ -829,16 +908,20 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
+ mutex_init(&mtk_crtc->hw_lock);
+
+ #if IS_REACHABLE(CONFIG_MTK_CMDQ)
+- mtk_crtc->cmdq_client =
+- cmdq_mbox_create(mtk_crtc->mmsys_dev,
+- drm_crtc_index(&mtk_crtc->base));
+- if (IS_ERR(mtk_crtc->cmdq_client)) {
++ mtk_crtc->cmdq_client.client.dev = mtk_crtc->mmsys_dev;
++ mtk_crtc->cmdq_client.client.tx_block = false;
++ mtk_crtc->cmdq_client.client.knows_txdone = true;
++ mtk_crtc->cmdq_client.client.rx_callback = ddp_cmdq_cb;
++ mtk_crtc->cmdq_client.chan =
++ mbox_request_channel(&mtk_crtc->cmdq_client.client,
++ drm_crtc_index(&mtk_crtc->base));
++ if (IS_ERR(mtk_crtc->cmdq_client.chan)) {
+ dev_dbg(dev, "mtk_crtc %d failed to create mailbox client, writing register by CPU now\n",
+ drm_crtc_index(&mtk_crtc->base));
+- mtk_crtc->cmdq_client = NULL;
++ mtk_crtc->cmdq_client.chan = NULL;
+ }
+
+- if (mtk_crtc->cmdq_client) {
++ if (mtk_crtc->cmdq_client.chan) {
+ ret = of_property_read_u32_index(priv->mutex_node,
+ "mediatek,gce-events",
+ drm_crtc_index(&mtk_crtc->base),
+@@ -846,8 +929,18 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
+ if (ret) {
+ dev_dbg(dev, "mtk_crtc %d failed to get mediatek,gce-events property\n",
+ drm_crtc_index(&mtk_crtc->base));
+- cmdq_mbox_destroy(mtk_crtc->cmdq_client);
+- mtk_crtc->cmdq_client = NULL;
++ mbox_free_channel(mtk_crtc->cmdq_client.chan);
++ mtk_crtc->cmdq_client.chan = NULL;
++ } else {
++ ret = mtk_drm_cmdq_pkt_create(&mtk_crtc->cmdq_client,
++ &mtk_crtc->cmdq_handle,
++ PAGE_SIZE);
++ if (ret) {
++ dev_dbg(dev, "mtk_crtc %d failed to create cmdq packet\n",
++ drm_crtc_index(&mtk_crtc->base));
++ mbox_free_channel(mtk_crtc->cmdq_client.chan);
++ mtk_crtc->cmdq_client.chan = NULL;
++ }
+ }
+ }
+ #endif
+diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+index 99cbf44463e40..22d23668b4840 100644
+--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
++++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
+@@ -276,6 +276,8 @@ static const struct mtk_ddp_comp_funcs ddp_ovl = {
+ .config = mtk_ovl_config,
+ .start = mtk_ovl_start,
+ .stop = mtk_ovl_stop,
++ .register_vblank_cb = mtk_ovl_register_vblank_cb,
++ .unregister_vblank_cb = mtk_ovl_unregister_vblank_cb,
+ .enable_vblank = mtk_ovl_enable_vblank,
+ .disable_vblank = mtk_ovl_disable_vblank,
+ .supported_rotations = mtk_ovl_supported_rotations,
+@@ -292,6 +294,8 @@ static const struct mtk_ddp_comp_funcs ddp_rdma = {
+ .config = mtk_rdma_config,
+ .start = mtk_rdma_start,
+ .stop = mtk_rdma_stop,
++ .register_vblank_cb = mtk_rdma_register_vblank_cb,
++ .unregister_vblank_cb = mtk_rdma_unregister_vblank_cb,
+ .enable_vblank = mtk_rdma_enable_vblank,
+ .disable_vblank = mtk_rdma_disable_vblank,
+ .layer_nr = mtk_rdma_layer_nr,
+diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
+index bb914d976cf5d..25cb50f2391fa 100644
+--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
++++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h
+@@ -47,9 +47,11 @@ struct mtk_ddp_comp_funcs {
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
+ void (*start)(struct device *dev);
+ void (*stop)(struct device *dev);
+- void (*enable_vblank)(struct device *dev,
+- void (*vblank_cb)(void *),
+- void *vblank_cb_data);
++ void (*register_vblank_cb)(struct device *dev,
++ void (*vblank_cb)(void *),
++ void *vblank_cb_data);
++ void (*unregister_vblank_cb)(struct device *dev);
++ void (*enable_vblank)(struct device *dev);
+ void (*disable_vblank)(struct device *dev);
+ unsigned int (*supported_rotations)(struct device *dev);
+ unsigned int (*layer_nr)(struct device *dev);
+@@ -110,12 +112,25 @@ static inline void mtk_ddp_comp_stop(struct mtk_ddp_comp *comp)
+ comp->funcs->stop(comp->dev);
+ }
+
+-static inline void mtk_ddp_comp_enable_vblank(struct mtk_ddp_comp *comp,
+- void (*vblank_cb)(void *),
+- void *vblank_cb_data)
++static inline void mtk_ddp_comp_register_vblank_cb(struct mtk_ddp_comp *comp,
++ void (*vblank_cb)(void *),
++ void *vblank_cb_data)
++{
++ if (comp->funcs && comp->funcs->register_vblank_cb)
++ comp->funcs->register_vblank_cb(comp->dev, vblank_cb,
++ vblank_cb_data);
++}
++
++static inline void mtk_ddp_comp_unregister_vblank_cb(struct mtk_ddp_comp *comp)
++{
++ if (comp->funcs && comp->funcs->unregister_vblank_cb)
++ comp->funcs->unregister_vblank_cb(comp->dev);
++}
++
++static inline void mtk_ddp_comp_enable_vblank(struct mtk_ddp_comp *comp)
+ {
+ if (comp->funcs && comp->funcs->enable_vblank)
+- comp->funcs->enable_vblank(comp->dev, vblank_cb, vblank_cb_data);
++ comp->funcs->enable_vblank(comp->dev);
+ }
+
+ static inline void mtk_ddp_comp_disable_vblank(struct mtk_ddp_comp *comp)
+diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
+index b4c1ad19cdaec..3d6f8ee355bfc 100644
+--- a/drivers/i2c/busses/i2c-cadence.c
++++ b/drivers/i2c/busses/i2c-cadence.c
+@@ -1338,6 +1338,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
+ return 0;
+
+ err_clk_dis:
++ clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
+ clk_disable_unprepare(id->clk);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
+index ac8e7d60672a1..39cb1b7bb8656 100644
+--- a/drivers/i2c/busses/i2c-piix4.c
++++ b/drivers/i2c/busses/i2c-piix4.c
+@@ -161,7 +161,6 @@ static const char *piix4_aux_port_name_sb800 = " port 1";
+
+ struct sb800_mmio_cfg {
+ void __iomem *addr;
+- struct resource *res;
+ bool use_mmio;
+ };
+
+@@ -179,13 +178,11 @@ static int piix4_sb800_region_request(struct device *dev,
+ struct sb800_mmio_cfg *mmio_cfg)
+ {
+ if (mmio_cfg->use_mmio) {
+- struct resource *res;
+ void __iomem *addr;
+
+- res = request_mem_region_muxed(SB800_PIIX4_FCH_PM_ADDR,
+- SB800_PIIX4_FCH_PM_SIZE,
+- "sb800_piix4_smb");
+- if (!res) {
++ if (!request_mem_region_muxed(SB800_PIIX4_FCH_PM_ADDR,
++ SB800_PIIX4_FCH_PM_SIZE,
++ "sb800_piix4_smb")) {
+ dev_err(dev,
+ "SMBus base address memory region 0x%x already in use.\n",
+ SB800_PIIX4_FCH_PM_ADDR);
+@@ -195,12 +192,12 @@ static int piix4_sb800_region_request(struct device *dev,
+ addr = ioremap(SB800_PIIX4_FCH_PM_ADDR,
+ SB800_PIIX4_FCH_PM_SIZE);
+ if (!addr) {
+- release_resource(res);
++ release_mem_region(SB800_PIIX4_FCH_PM_ADDR,
++ SB800_PIIX4_FCH_PM_SIZE);
+ dev_err(dev, "SMBus base address mapping failed.\n");
+ return -ENOMEM;
+ }
+
+- mmio_cfg->res = res;
+ mmio_cfg->addr = addr;
+
+ return 0;
+@@ -222,7 +219,8 @@ static void piix4_sb800_region_release(struct device *dev,
+ {
+ if (mmio_cfg->use_mmio) {
+ iounmap(mmio_cfg->addr);
+- release_resource(mmio_cfg->res);
++ release_mem_region(SB800_PIIX4_FCH_PM_ADDR,
++ SB800_PIIX4_FCH_PM_SIZE);
+ return;
+ }
+
+diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
+index 373b59557afe9..1f46a73aafeac 100644
+--- a/drivers/iio/accel/mma8452.c
++++ b/drivers/iio/accel/mma8452.c
+@@ -380,8 +380,8 @@ static ssize_t mma8452_show_scale_avail(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+ {
+- struct mma8452_data *data = iio_priv(i2c_get_clientdata(
+- to_i2c_client(dev)));
++ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
++ struct mma8452_data *data = iio_priv(indio_dev);
+
+ return mma8452_show_int_plus_micros(buf, data->chip_info->mma_scales,
+ ARRAY_SIZE(data->chip_info->mma_scales));
+diff --git a/drivers/input/misc/cpcap-pwrbutton.c b/drivers/input/misc/cpcap-pwrbutton.c
+index 0abef63217e21..372cb44d06357 100644
+--- a/drivers/input/misc/cpcap-pwrbutton.c
++++ b/drivers/input/misc/cpcap-pwrbutton.c
+@@ -54,9 +54,13 @@ static irqreturn_t powerbutton_irq(int irq, void *_button)
+ static int cpcap_power_button_probe(struct platform_device *pdev)
+ {
+ struct cpcap_power_button *button;
+- int irq = platform_get_irq(pdev, 0);
++ int irq;
+ int err;
+
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0)
++ return irq;
++
+ button = devm_kmalloc(&pdev->dev, sizeof(*button), GFP_KERNEL);
+ if (!button)
+ return -ENOMEM;
+diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
+index 5051a1766aac6..3667f7e51fde4 100644
+--- a/drivers/input/touchscreen/goodix.c
++++ b/drivers/input/touchscreen/goodix.c
+@@ -14,20 +14,15 @@
+ #include <linux/kernel.h>
+ #include <linux/dmi.h>
+ #include <linux/firmware.h>
+-#include <linux/gpio/consumer.h>
+-#include <linux/i2c.h>
+-#include <linux/input.h>
+-#include <linux/input/mt.h>
+-#include <linux/input/touchscreen.h>
+ #include <linux/module.h>
+ #include <linux/delay.h>
+ #include <linux/irq.h>
+ #include <linux/interrupt.h>
+-#include <linux/regulator/consumer.h>
+ #include <linux/slab.h>
+ #include <linux/acpi.h>
+ #include <linux/of.h>
+ #include <asm/unaligned.h>
++#include "goodix.h"
+
+ #define GOODIX_GPIO_INT_NAME "irq"
+ #define GOODIX_GPIO_RST_NAME "reset"
+@@ -38,22 +33,11 @@
+ #define GOODIX_CONTACT_SIZE 8
+ #define GOODIX_MAX_CONTACT_SIZE 9
+ #define GOODIX_MAX_CONTACTS 10
+-#define GOODIX_MAX_KEYS 7
+
+ #define GOODIX_CONFIG_MIN_LENGTH 186
+ #define GOODIX_CONFIG_911_LENGTH 186
+ #define GOODIX_CONFIG_967_LENGTH 228
+ #define GOODIX_CONFIG_GT9X_LENGTH 240
+-#define GOODIX_CONFIG_MAX_LENGTH 240
+-
+-/* Register defines */
+-#define GOODIX_REG_COMMAND 0x8040
+-#define GOODIX_CMD_SCREEN_OFF 0x05
+-
+-#define GOODIX_READ_COOR_ADDR 0x814E
+-#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050
+-#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047
+-#define GOODIX_REG_ID 0x8140
+
+ #define GOODIX_BUFFER_STATUS_READY BIT(7)
+ #define GOODIX_HAVE_KEY BIT(4)
+@@ -68,55 +52,11 @@
+ #define ACPI_GPIO_SUPPORT
+ #endif
+
+-struct goodix_ts_data;
+-
+-enum goodix_irq_pin_access_method {
+- IRQ_PIN_ACCESS_NONE,
+- IRQ_PIN_ACCESS_GPIO,
+- IRQ_PIN_ACCESS_ACPI_GPIO,
+- IRQ_PIN_ACCESS_ACPI_METHOD,
+-};
+-
+-struct goodix_chip_data {
+- u16 config_addr;
+- int config_len;
+- int (*check_config)(struct goodix_ts_data *ts, const u8 *cfg, int len);
+- void (*calc_config_checksum)(struct goodix_ts_data *ts);
+-};
+-
+ struct goodix_chip_id {
+ const char *id;
+ const struct goodix_chip_data *data;
+ };
+
+-#define GOODIX_ID_MAX_LEN 4
+-
+-struct goodix_ts_data {
+- struct i2c_client *client;
+- struct input_dev *input_dev;
+- const struct goodix_chip_data *chip;
+- struct touchscreen_properties prop;
+- unsigned int max_touch_num;
+- unsigned int int_trigger_type;
+- struct regulator *avdd28;
+- struct regulator *vddio;
+- struct gpio_desc *gpiod_int;
+- struct gpio_desc *gpiod_rst;
+- int gpio_count;
+- int gpio_int_idx;
+- char id[GOODIX_ID_MAX_LEN + 1];
+- u16 version;
+- const char *cfg_name;
+- bool reset_controller_at_probe;
+- bool load_cfg_from_disk;
+- struct completion firmware_loading_complete;
+- unsigned long irq_flags;
+- enum goodix_irq_pin_access_method irq_pin_access_method;
+- unsigned int contact_size;
+- u8 config[GOODIX_CONFIG_MAX_LENGTH];
+- unsigned short keymap[GOODIX_MAX_KEYS];
+-};
+-
+ static int goodix_check_cfg_8(struct goodix_ts_data *ts,
+ const u8 *cfg, int len);
+ static int goodix_check_cfg_16(struct goodix_ts_data *ts,
+@@ -216,8 +156,7 @@ static const struct dmi_system_id inverted_x_screen[] = {
+ * @buf: raw write data buffer.
+ * @len: length of the buffer to write
+ */
+-static int goodix_i2c_read(struct i2c_client *client,
+- u16 reg, u8 *buf, int len)
++int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len)
+ {
+ struct i2c_msg msgs[2];
+ __be16 wbuf = cpu_to_be16(reg);
+@@ -245,8 +184,7 @@ static int goodix_i2c_read(struct i2c_client *client,
+ * @buf: raw data buffer to write.
+ * @len: length of the buffer to write
+ */
+-static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf,
+- unsigned len)
++int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len)
+ {
+ u8 *addr_buf;
+ struct i2c_msg msg;
+@@ -270,7 +208,7 @@ static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf,
+ return ret < 0 ? ret : (ret != 1 ? -EIO : 0);
+ }
+
+-static int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value)
++int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value)
+ {
+ return goodix_i2c_write(client, reg, &value, sizeof(value));
+ }
+@@ -554,7 +492,7 @@ static int goodix_check_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
+ * @cfg: config firmware to write to device
+ * @len: config data length
+ */
+-static int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
++int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
+ {
+ int error;
+
+@@ -652,62 +590,88 @@ static int goodix_irq_direction_input(struct goodix_ts_data *ts)
+ return -EINVAL; /* Never reached */
+ }
+
+-static int goodix_int_sync(struct goodix_ts_data *ts)
++int goodix_int_sync(struct goodix_ts_data *ts)
+ {
+ int error;
+
+ error = goodix_irq_direction_output(ts, 0);
+ if (error)
+- return error;
++ goto error;
+
+ msleep(50); /* T5: 50ms */
+
+ error = goodix_irq_direction_input(ts);
+ if (error)
+- return error;
++ goto error;
+
+ return 0;
++
++error:
++ dev_err(&ts->client->dev, "Controller irq sync failed.\n");
++ return error;
+ }
+
+ /**
+- * goodix_reset - Reset device during power on
++ * goodix_reset_no_int_sync - Reset device, leaving interrupt line in output mode
+ *
+ * @ts: goodix_ts_data pointer
+ */
+-static int goodix_reset(struct goodix_ts_data *ts)
++int goodix_reset_no_int_sync(struct goodix_ts_data *ts)
+ {
+ int error;
+
+ /* begin select I2C slave addr */
+ error = gpiod_direction_output(ts->gpiod_rst, 0);
+ if (error)
+- return error;
++ goto error;
+
+ msleep(20); /* T2: > 10ms */
+
+ /* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
+ error = goodix_irq_direction_output(ts, ts->client->addr == 0x14);
+ if (error)
+- return error;
++ goto error;
+
+ usleep_range(100, 2000); /* T3: > 100us */
+
+ error = gpiod_direction_output(ts->gpiod_rst, 1);
+ if (error)
+- return error;
++ goto error;
+
+ usleep_range(6000, 10000); /* T4: > 5ms */
+
+- /* end select I2C slave addr */
+- error = gpiod_direction_input(ts->gpiod_rst);
+- if (error)
+- return error;
++ /*
++ * Put the reset pin back in to input / high-impedance mode to save
++ * power. Only do this in the non ACPI case since some ACPI boards
++ * don't have a pull-up, so there the reset pin must stay active-high.
++ */
++ if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_GPIO) {
++ error = gpiod_direction_input(ts->gpiod_rst);
++ if (error)
++ goto error;
++ }
+
+- error = goodix_int_sync(ts);
++ return 0;
++
++error:
++ dev_err(&ts->client->dev, "Controller reset failed.\n");
++ return error;
++}
++
++/**
++ * goodix_reset - Reset device during power on
++ *
++ * @ts: goodix_ts_data pointer
++ */
++static int goodix_reset(struct goodix_ts_data *ts)
++{
++ int error;
++
++ error = goodix_reset_no_int_sync(ts);
+ if (error)
+ return error;
+
+- return 0;
++ return goodix_int_sync(ts);
+ }
+
+ #ifdef ACPI_GPIO_SUPPORT
+@@ -819,6 +783,14 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
+ return -EINVAL;
+ }
+
++ /*
++ * Normally we put the reset pin in input / high-impedance mode to save
++ * power. But some x86/ACPI boards don't have a pull-up, so for the ACPI
++ * case, leave the pin as is. This results in the pin not being touched
++ * at all on x86/ACPI boards, except when needed for error-recover.
++ */
++ ts->gpiod_rst_flags = GPIOD_ASIS;
++
+ return devm_acpi_dev_add_driver_gpios(dev, gpio_mapping);
+ }
+ #else
+@@ -844,6 +816,12 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)
+ return -EINVAL;
+ dev = &ts->client->dev;
+
++ /*
++ * By default we request the reset pin as input, leaving it in
++ * high-impedance when not resetting the controller to save power.
++ */
++ ts->gpiod_rst_flags = GPIOD_IN;
++
+ ts->avdd28 = devm_regulator_get(dev, "AVDD28");
+ if (IS_ERR(ts->avdd28)) {
+ error = PTR_ERR(ts->avdd28);
+@@ -881,7 +859,7 @@ retry_get_irq_gpio:
+ ts->gpiod_int = gpiod;
+
+ /* Get the reset line GPIO pin number */
+- gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, GPIOD_IN);
++ gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, ts->gpiod_rst_flags);
+ if (IS_ERR(gpiod)) {
+ error = PTR_ERR(gpiod);
+ if (error != -EPROBE_DEFER)
+@@ -1206,10 +1184,8 @@ reset:
+ if (ts->reset_controller_at_probe) {
+ /* reset the controller */
+ error = goodix_reset(ts);
+- if (error) {
+- dev_err(&client->dev, "Controller reset failed.\n");
++ if (error)
+ return error;
+- }
+ }
+
+ error = goodix_i2c_test(client);
+@@ -1351,10 +1327,8 @@ static int __maybe_unused goodix_resume(struct device *dev)
+
+ if (error != 0 || config_ver != ts->config[0]) {
+ error = goodix_reset(ts);
+- if (error) {
+- dev_err(dev, "Controller reset failed.\n");
++ if (error)
+ return error;
+- }
+
+ error = goodix_send_cfg(ts, ts->config, ts->chip->config_len);
+ if (error)
+diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h
+new file mode 100644
+index 0000000000000..1a1571ad2cd23
+--- /dev/null
++++ b/drivers/input/touchscreen/goodix.h
+@@ -0,0 +1,75 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++#ifndef __GOODIX_H__
++#define __GOODIX_H__
++
++#include <linux/gpio/consumer.h>
++#include <linux/i2c.h>
++#include <linux/input.h>
++#include <linux/input/mt.h>
++#include <linux/input/touchscreen.h>
++#include <linux/regulator/consumer.h>
++
++/* Register defines */
++#define GOODIX_REG_COMMAND 0x8040
++#define GOODIX_CMD_SCREEN_OFF 0x05
++
++#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050
++#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047
++#define GOODIX_REG_ID 0x8140
++#define GOODIX_READ_COOR_ADDR 0x814E
++
++#define GOODIX_ID_MAX_LEN 4
++#define GOODIX_CONFIG_MAX_LENGTH 240
++#define GOODIX_MAX_KEYS 7
++
++enum goodix_irq_pin_access_method {
++ IRQ_PIN_ACCESS_NONE,
++ IRQ_PIN_ACCESS_GPIO,
++ IRQ_PIN_ACCESS_ACPI_GPIO,
++ IRQ_PIN_ACCESS_ACPI_METHOD,
++};
++
++struct goodix_ts_data;
++
++struct goodix_chip_data {
++ u16 config_addr;
++ int config_len;
++ int (*check_config)(struct goodix_ts_data *ts, const u8 *cfg, int len);
++ void (*calc_config_checksum)(struct goodix_ts_data *ts);
++};
++
++struct goodix_ts_data {
++ struct i2c_client *client;
++ struct input_dev *input_dev;
++ const struct goodix_chip_data *chip;
++ struct touchscreen_properties prop;
++ unsigned int max_touch_num;
++ unsigned int int_trigger_type;
++ struct regulator *avdd28;
++ struct regulator *vddio;
++ struct gpio_desc *gpiod_int;
++ struct gpio_desc *gpiod_rst;
++ int gpio_count;
++ int gpio_int_idx;
++ enum gpiod_flags gpiod_rst_flags;
++ char id[GOODIX_ID_MAX_LEN + 1];
++ u16 version;
++ const char *cfg_name;
++ bool reset_controller_at_probe;
++ bool load_cfg_from_disk;
++ struct completion firmware_loading_complete;
++ unsigned long irq_flags;
++ enum goodix_irq_pin_access_method irq_pin_access_method;
++ unsigned int contact_size;
++ u8 config[GOODIX_CONFIG_MAX_LENGTH];
++ unsigned short keymap[GOODIX_MAX_KEYS];
++};
++
++int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len);
++int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len);
++int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value);
++int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len);
++int goodix_int_sync(struct goodix_ts_data *ts);
++int goodix_reset_no_int_sync(struct goodix_ts_data *ts);
++
++#endif
+diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
+index b7708b93f3fa1..3d9cb711e87b8 100644
+--- a/drivers/iommu/intel/dmar.c
++++ b/drivers/iommu/intel/dmar.c
+@@ -385,7 +385,7 @@ static int dmar_pci_bus_notifier(struct notifier_block *nb,
+
+ static struct notifier_block dmar_pci_bus_nb = {
+ .notifier_call = dmar_pci_bus_notifier,
+- .priority = INT_MIN,
++ .priority = 1,
+ };
+
+ static struct dmar_drhd_unit *
+diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
+index fd4fb1b357871..9507989bf2e1e 100644
+--- a/drivers/irqchip/irq-gic-v3.c
++++ b/drivers/irqchip/irq-gic-v3.c
+@@ -556,7 +556,8 @@ static void gic_irq_nmi_teardown(struct irq_data *d)
+
+ static void gic_eoi_irq(struct irq_data *d)
+ {
+- gic_write_eoir(gic_irq(d));
++ write_gicreg(gic_irq(d), ICC_EOIR1_EL1);
++ isb();
+ }
+
+ static void gic_eoimode1_eoi_irq(struct irq_data *d)
+@@ -640,10 +641,38 @@ static void gic_deactivate_unhandled(u32 irqnr)
+ if (irqnr < 8192)
+ gic_write_dir(irqnr);
+ } else {
+- gic_write_eoir(irqnr);
++ write_gicreg(irqnr, ICC_EOIR1_EL1);
++ isb();
+ }
+ }
+
++/*
++ * Follow a read of the IAR with any HW maintenance that needs to happen prior
++ * to invoking the relevant IRQ handler. We must do two things:
++ *
++ * (1) Ensure instruction ordering between a read of IAR and subsequent
++ * instructions in the IRQ handler using an ISB.
++ *
++ * It is possible for the IAR to report an IRQ which was signalled *after*
++ * the CPU took an IRQ exception as multiple interrupts can race to be
++ * recognized by the GIC, earlier interrupts could be withdrawn, and/or
++ * later interrupts could be prioritized by the GIC.
++ *
++ * For devices which are tightly coupled to the CPU, such as PMUs, a
++ * context synchronization event is necessary to ensure that system
++ * register state is not stale, as these may have been indirectly written
++ * *after* exception entry.
++ *
++ * (2) Deactivate the interrupt when EOI mode 1 is in use.
++ */
++static inline void gic_complete_ack(u32 irqnr)
++{
++ if (static_branch_likely(&supports_deactivate_key))
++ write_gicreg(irqnr, ICC_EOIR1_EL1);
++
++ isb();
++}
++
+ static inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs)
+ {
+ bool irqs_enabled = interrupts_enabled(regs);
+@@ -652,8 +681,8 @@ static inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs)
+ if (irqs_enabled)
+ nmi_enter();
+
+- if (static_branch_likely(&supports_deactivate_key))
+- gic_write_eoir(irqnr);
++ gic_complete_ack(irqnr);
++
+ /*
+ * Leave the PSR.I bit set to prevent other NMIs to be
+ * received while handling this one.
+@@ -723,10 +752,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
+ gic_arch_enable_irqs();
+ }
+
+- if (static_branch_likely(&supports_deactivate_key))
+- gic_write_eoir(irqnr);
+- else
+- isb();
++ gic_complete_ack(irqnr);
+
+ if (handle_domain_irq(gic_data.domain, irqnr, regs)) {
+ WARN_ONCE(true, "Unexpected interrupt received!\n");
+diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c
+index 5658c7f148d79..8ffc01c606d0c 100644
+--- a/drivers/media/platform/davinci/vpif.c
++++ b/drivers/media/platform/davinci/vpif.c
+@@ -41,6 +41,11 @@ MODULE_ALIAS("platform:" VPIF_DRIVER_NAME);
+ #define VPIF_CH2_MAX_MODES 15
+ #define VPIF_CH3_MAX_MODES 2
+
++struct vpif_data {
++ struct platform_device *capture;
++ struct platform_device *display;
++};
++
+ DEFINE_SPINLOCK(vpif_lock);
+ EXPORT_SYMBOL_GPL(vpif_lock);
+
+@@ -423,11 +428,19 @@ int vpif_channel_getfid(u8 channel_id)
+ }
+ EXPORT_SYMBOL(vpif_channel_getfid);
+
++static void vpif_pdev_release(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++
++ kfree(pdev);
++}
++
+ static int vpif_probe(struct platform_device *pdev)
+ {
+ static struct resource *res, *res_irq;
+ struct platform_device *pdev_capture, *pdev_display;
+ struct device_node *endpoint = NULL;
++ struct vpif_data *data;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+@@ -435,6 +448,12 @@ static int vpif_probe(struct platform_device *pdev)
+ if (IS_ERR(vpif_base))
+ return PTR_ERR(vpif_base);
+
++ data = kzalloc(sizeof(*data), GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++
++ platform_set_drvdata(pdev, data);
++
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get(&pdev->dev);
+
+@@ -462,49 +481,75 @@ static int vpif_probe(struct platform_device *pdev)
+ goto err_put_rpm;
+ }
+
+- pdev_capture = devm_kzalloc(&pdev->dev, sizeof(*pdev_capture),
+- GFP_KERNEL);
+- if (pdev_capture) {
+- pdev_capture->name = "vpif_capture";
+- pdev_capture->id = -1;
+- pdev_capture->resource = res_irq;
+- pdev_capture->num_resources = 1;
+- pdev_capture->dev.dma_mask = pdev->dev.dma_mask;
+- pdev_capture->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask;
+- pdev_capture->dev.parent = &pdev->dev;
+- platform_device_register(pdev_capture);
+- } else {
+- dev_warn(&pdev->dev, "Unable to allocate memory for pdev_capture.\n");
++ pdev_capture = kzalloc(sizeof(*pdev_capture), GFP_KERNEL);
++ if (!pdev_capture) {
++ ret = -ENOMEM;
++ goto err_put_rpm;
+ }
+
+- pdev_display = devm_kzalloc(&pdev->dev, sizeof(*pdev_display),
+- GFP_KERNEL);
+- if (pdev_display) {
+- pdev_display->name = "vpif_display";
+- pdev_display->id = -1;
+- pdev_display->resource = res_irq;
+- pdev_display->num_resources = 1;
+- pdev_display->dev.dma_mask = pdev->dev.dma_mask;
+- pdev_display->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask;
+- pdev_display->dev.parent = &pdev->dev;
+- platform_device_register(pdev_display);
+- } else {
+- dev_warn(&pdev->dev, "Unable to allocate memory for pdev_display.\n");
++ pdev_capture->name = "vpif_capture";
++ pdev_capture->id = -1;
++ pdev_capture->resource = res_irq;
++ pdev_capture->num_resources = 1;
++ pdev_capture->dev.dma_mask = pdev->dev.dma_mask;
++ pdev_capture->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask;
++ pdev_capture->dev.parent = &pdev->dev;
++ pdev_capture->dev.release = vpif_pdev_release;
++
++ ret = platform_device_register(pdev_capture);
++ if (ret)
++ goto err_put_pdev_capture;
++
++ pdev_display = kzalloc(sizeof(*pdev_display), GFP_KERNEL);
++ if (!pdev_display) {
++ ret = -ENOMEM;
++ goto err_put_pdev_capture;
+ }
+
++ pdev_display->name = "vpif_display";
++ pdev_display->id = -1;
++ pdev_display->resource = res_irq;
++ pdev_display->num_resources = 1;
++ pdev_display->dev.dma_mask = pdev->dev.dma_mask;
++ pdev_display->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask;
++ pdev_display->dev.parent = &pdev->dev;
++ pdev_display->dev.release = vpif_pdev_release;
++
++ ret = platform_device_register(pdev_display);
++ if (ret)
++ goto err_put_pdev_display;
++
++ data->capture = pdev_capture;
++ data->display = pdev_display;
++
+ return 0;
+
++err_put_pdev_display:
++ platform_device_put(pdev_display);
++err_put_pdev_capture:
++ platform_device_put(pdev_capture);
+ err_put_rpm:
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
++ kfree(data);
+
+ return ret;
+ }
+
+ static int vpif_remove(struct platform_device *pdev)
+ {
++ struct vpif_data *data = platform_get_drvdata(pdev);
++
++ if (data->capture)
++ platform_device_unregister(data->capture);
++ if (data->display)
++ platform_device_unregister(data->display);
++
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
++
++ kfree(data);
++
+ return 0;
+ }
+
+diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c
+index 5b9b57f4d9bf8..68cf68dbcace2 100644
+--- a/drivers/media/platform/omap3isp/ispstat.c
++++ b/drivers/media/platform/omap3isp/ispstat.c
+@@ -512,7 +512,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat,
+ int omap3isp_stat_request_statistics_time32(struct ispstat *stat,
+ struct omap3isp_stat_data_time32 *data)
+ {
+- struct omap3isp_stat_data data64;
++ struct omap3isp_stat_data data64 = { };
+ int ret;
+
+ ret = omap3isp_stat_request_statistics(stat, &data64);
+@@ -521,7 +521,8 @@ int omap3isp_stat_request_statistics_time32(struct ispstat *stat,
+
+ data->ts.tv_sec = data64.ts.tv_sec;
+ data->ts.tv_usec = data64.ts.tv_usec;
+- memcpy(&data->buf, &data64.buf, sizeof(*data) - sizeof(data->ts));
++ data->buf = (uintptr_t)data64.buf;
++ memcpy(&data->frame, &data64.frame, sizeof(data->frame));
+
+ return 0;
+ }
+diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c
+index 7f394277478b3..53ae19fa103ab 100644
+--- a/drivers/media/rc/ir_toy.c
++++ b/drivers/media/rc/ir_toy.c
+@@ -310,7 +310,7 @@ static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count)
+ buf[i] = cpu_to_be16(v);
+ }
+
+- buf[count] = cpu_to_be16(0xffff);
++ buf[count] = 0xffff;
+
+ irtoy->tx_buf = buf;
+ irtoy->tx_len = size;
+diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c
+index 3a416705f61cb..c77b23b68a931 100644
+--- a/drivers/memory/renesas-rpc-if.c
++++ b/drivers/memory/renesas-rpc-if.c
+@@ -199,7 +199,6 @@ static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val)
+
+ *val = readl(rpc->base + reg);
+ return 0;
+-
+ }
+
+ static int rpcif_reg_write(void *context, unsigned int reg, unsigned int val)
+@@ -577,6 +576,48 @@ err_out:
+ }
+ EXPORT_SYMBOL(rpcif_manual_xfer);
+
++static void memcpy_fromio_readw(void *to,
++ const void __iomem *from,
++ size_t count)
++{
++ const int maxw = (IS_ENABLED(CONFIG_64BIT)) ? 8 : 4;
++ u8 buf[2];
++
++ if (count && ((unsigned long)from & 1)) {
++ *(u16 *)buf = __raw_readw((void __iomem *)((unsigned long)from & ~1));
++ *(u8 *)to = buf[1];
++ from++;
++ to++;
++ count--;
++ }
++ while (count >= 2 && !IS_ALIGNED((unsigned long)from, maxw)) {
++ *(u16 *)to = __raw_readw(from);
++ from += 2;
++ to += 2;
++ count -= 2;
++ }
++ while (count >= maxw) {
++#ifdef CONFIG_64BIT
++ *(u64 *)to = __raw_readq(from);
++#else
++ *(u32 *)to = __raw_readl(from);
++#endif
++ from += maxw;
++ to += maxw;
++ count -= maxw;
++ }
++ while (count >= 2) {
++ *(u16 *)to = __raw_readw(from);
++ from += 2;
++ to += 2;
++ count -= 2;
++ }
++ if (count) {
++ *(u16 *)buf = __raw_readw(from);
++ *(u8 *)to = buf[0];
++ }
++}
++
+ ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf)
+ {
+ loff_t from = offs & (RPCIF_DIRMAP_SIZE - 1);
+@@ -598,7 +639,10 @@ ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf)
+ regmap_write(rpc->regmap, RPCIF_DRDMCR, rpc->dummy);
+ regmap_write(rpc->regmap, RPCIF_DRDRENR, rpc->ddr);
+
+- memcpy_fromio(buf, rpc->dirmap + from, len);
++ if (rpc->bus_size == 2)
++ memcpy_fromio_readw(buf, rpc->dirmap + from, len);
++ else
++ memcpy_fromio(buf, rpc->dirmap + from, len);
+
+ pm_runtime_put(rpc->dev);
+
+diff --git a/drivers/misc/cardreader/rtsx_usb.c b/drivers/misc/cardreader/rtsx_usb.c
+index 1ef9b61077c44..f150d8769f198 100644
+--- a/drivers/misc/cardreader/rtsx_usb.c
++++ b/drivers/misc/cardreader/rtsx_usb.c
+@@ -631,16 +631,20 @@ static int rtsx_usb_probe(struct usb_interface *intf,
+
+ ucr->pusb_dev = usb_dev;
+
+- ucr->iobuf = usb_alloc_coherent(ucr->pusb_dev, IOBUF_SIZE,
+- GFP_KERNEL, &ucr->iobuf_dma);
+- if (!ucr->iobuf)
++ ucr->cmd_buf = kmalloc(IOBUF_SIZE, GFP_KERNEL);
++ if (!ucr->cmd_buf)
+ return -ENOMEM;
+
++ ucr->rsp_buf = kmalloc(IOBUF_SIZE, GFP_KERNEL);
++ if (!ucr->rsp_buf) {
++ ret = -ENOMEM;
++ goto out_free_cmd_buf;
++ }
++
+ usb_set_intfdata(intf, ucr);
+
+ ucr->vendor_id = id->idVendor;
+ ucr->product_id = id->idProduct;
+- ucr->cmd_buf = ucr->rsp_buf = ucr->iobuf;
+
+ mutex_init(&ucr->dev_mutex);
+
+@@ -668,8 +672,11 @@ static int rtsx_usb_probe(struct usb_interface *intf,
+
+ out_init_fail:
+ usb_set_intfdata(ucr->pusb_intf, NULL);
+- usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
+- ucr->iobuf_dma);
++ kfree(ucr->rsp_buf);
++ ucr->rsp_buf = NULL;
++out_free_cmd_buf:
++ kfree(ucr->cmd_buf);
++ ucr->cmd_buf = NULL;
+ return ret;
+ }
+
+@@ -682,8 +689,12 @@ static void rtsx_usb_disconnect(struct usb_interface *intf)
+ mfd_remove_devices(&intf->dev);
+
+ usb_set_intfdata(ucr->pusb_intf, NULL);
+- usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
+- ucr->iobuf_dma);
++
++ kfree(ucr->cmd_buf);
++ ucr->cmd_buf = NULL;
++
++ kfree(ucr->rsp_buf);
++ ucr->rsp_buf = NULL;
+ }
+
+ #ifdef CONFIG_PM
+diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
+index 90f39aabc1ff8..d97cdbc2b9de3 100644
+--- a/drivers/mtd/spi-nor/core.c
++++ b/drivers/mtd/spi-nor/core.c
+@@ -3148,7 +3148,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
+ mtd->writesize = nor->params->writesize;
+ mtd->flags = MTD_CAP_NORFLASH;
+ mtd->size = nor->params->size;
+- mtd->_erase = spi_nor_erase;
+ mtd->_read = spi_nor_read;
+ mtd->_suspend = spi_nor_suspend;
+ mtd->_resume = spi_nor_resume;
+@@ -3178,6 +3177,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
+
+ if (info->flags & SPI_NOR_NO_ERASE)
+ mtd->flags |= MTD_NO_ERASE;
++ else
++ mtd->_erase = spi_nor_erase;
+
+ mtd->dev.parent = dev;
+ nor->page_size = nor->params->page_size;
+diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
+index daee3652ac8b3..e098f594a7492 100644
+--- a/drivers/net/can/grcan.c
++++ b/drivers/net/can/grcan.c
+@@ -1659,7 +1659,6 @@ static int grcan_probe(struct platform_device *ofdev)
+ */
+ sysid_parent = of_find_node_by_path("/ambapp0");
+ if (sysid_parent) {
+- of_node_get(sysid_parent);
+ err = of_property_read_u32(sysid_parent, "systemid", &sysid);
+ if (!err && ((sysid & GRLIB_VERSION_MASK) >=
+ GRCAN_TXBUG_SAFE_GRLIB_VERSION))
+diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
+index bff33a619acde..c4596fbe6d2f8 100644
+--- a/drivers/net/can/m_can/m_can.c
++++ b/drivers/net/can/m_can/m_can.c
+@@ -532,7 +532,7 @@ static int m_can_read_fifo(struct net_device *dev, u32 rxfs)
+ stats->rx_packets++;
+ stats->rx_bytes += cf->len;
+
+- timestamp = FIELD_GET(RX_BUF_RXTS_MASK, fifo_header.dlc);
++ timestamp = FIELD_GET(RX_BUF_RXTS_MASK, fifo_header.dlc) << 16;
+
+ m_can_receive_skb(cdev, skb, timestamp);
+
+@@ -1043,7 +1043,7 @@ static int m_can_echo_tx_event(struct net_device *dev)
+ }
+
+ msg_mark = FIELD_GET(TX_EVENT_MM_MASK, txe);
+- timestamp = FIELD_GET(TX_EVENT_TXTS_MASK, txe);
++ timestamp = FIELD_GET(TX_EVENT_TXTS_MASK, txe) << 16;
+
+ /* ack txe element */
+ m_can_write(cdev, M_CAN_TXEFA, FIELD_PREP(TXEFA_EFAI_MASK,
+@@ -1367,7 +1367,9 @@ static void m_can_chip_config(struct net_device *dev)
+ /* enable internal timestamp generation, with a prescalar of 16. The
+ * prescalar is applied to the nominal bit timing
+ */
+- m_can_write(cdev, M_CAN_TSCC, FIELD_PREP(TSCC_TCP_MASK, 0xf));
++ m_can_write(cdev, M_CAN_TSCC,
++ FIELD_PREP(TSCC_TCP_MASK, 0xf) |
++ FIELD_PREP(TSCC_TSS_MASK, TSCC_TSS_INTERNAL));
+
+ m_can_config_endisable(cdev, false);
+
+diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-regmap.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-regmap.c
+index 297491516a265..bb559663a3fa5 100644
+--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-regmap.c
++++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-regmap.c
+@@ -325,19 +325,21 @@ mcp251xfd_regmap_crc_read(void *context,
+ * register. It increments once per SYS clock tick,
+ * which is 20 or 40 MHz.
+ *
+- * Observation shows that if the lowest byte (which is
+- * transferred first on the SPI bus) of that register
+- * is 0x00 or 0x80 the calculated CRC doesn't always
+- * match the transferred one.
++ * Observation on the mcp2518fd shows that if the
++ * lowest byte (which is transferred first on the SPI
++ * bus) of that register is 0x00 or 0x80 the
++ * calculated CRC doesn't always match the transferred
++ * one. On the mcp2517fd this problem is not limited
++ * to the first byte being 0x00 or 0x80.
+ *
+ * If the highest bit in the lowest byte is flipped
+ * the transferred CRC matches the calculated one. We
+- * assume for now the CRC calculation in the chip
+- * works on wrong data and the transferred data is
+- * correct.
++ * assume for now the CRC operates on the correct
++ * data.
+ */
+ if (reg == MCP251XFD_REG_TBC &&
+- (buf_rx->data[0] == 0x0 || buf_rx->data[0] == 0x80)) {
++ ((buf_rx->data[0] & 0xf8) == 0x0 ||
++ (buf_rx->data[0] & 0xf8) == 0x80)) {
+ /* Flip highest bit in lowest byte of le32 */
+ buf_rx->data[0] ^= 0x80;
+
+@@ -347,10 +349,8 @@ mcp251xfd_regmap_crc_read(void *context,
+ val_len);
+ if (!err) {
+ /* If CRC is now correct, assume
+- * transferred data was OK, flip bit
+- * back to original value.
++ * flipped data is OK.
+ */
+- buf_rx->data[0] ^= 0x80;
+ goto out;
+ }
+ }
+diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
+index d68d698f2606b..e26b3d6f5b482 100644
+--- a/drivers/net/can/usb/gs_usb.c
++++ b/drivers/net/can/usb/gs_usb.c
+@@ -185,6 +185,8 @@ struct gs_can {
+
+ struct usb_anchor tx_submitted;
+ atomic_t active_tx_urbs;
++ void *rxbuf[GS_MAX_RX_URBS];
++ dma_addr_t rxbuf_dma[GS_MAX_RX_URBS];
+ };
+
+ /* usb interface struct */
+@@ -594,6 +596,7 @@ static int gs_can_open(struct net_device *netdev)
+ for (i = 0; i < GS_MAX_RX_URBS; i++) {
+ struct urb *urb;
+ u8 *buf;
++ dma_addr_t buf_dma;
+
+ /* alloc rx urb */
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+@@ -604,7 +607,7 @@ static int gs_can_open(struct net_device *netdev)
+ buf = usb_alloc_coherent(dev->udev,
+ sizeof(struct gs_host_frame),
+ GFP_KERNEL,
+- &urb->transfer_dma);
++ &buf_dma);
+ if (!buf) {
+ netdev_err(netdev,
+ "No memory left for USB buffer\n");
+@@ -612,6 +615,8 @@ static int gs_can_open(struct net_device *netdev)
+ return -ENOMEM;
+ }
+
++ urb->transfer_dma = buf_dma;
++
+ /* fill, anchor, and submit rx urb */
+ usb_fill_bulk_urb(urb,
+ dev->udev,
+@@ -635,10 +640,17 @@ static int gs_can_open(struct net_device *netdev)
+ rc);
+
+ usb_unanchor_urb(urb);
++ usb_free_coherent(dev->udev,
++ sizeof(struct gs_host_frame),
++ buf,
++ buf_dma);
+ usb_free_urb(urb);
+ break;
+ }
+
++ dev->rxbuf[i] = buf;
++ dev->rxbuf_dma[i] = buf_dma;
++
+ /* Drop reference,
+ * USB core will take care of freeing it
+ */
+@@ -703,13 +715,20 @@ static int gs_can_close(struct net_device *netdev)
+ int rc;
+ struct gs_can *dev = netdev_priv(netdev);
+ struct gs_usb *parent = dev->parent;
++ unsigned int i;
+
+ netif_stop_queue(netdev);
+
+ /* Stop polling */
+ parent->active_channels--;
+- if (!parent->active_channels)
++ if (!parent->active_channels) {
+ usb_kill_anchored_urbs(&parent->rx_submitted);
++ for (i = 0; i < GS_MAX_RX_URBS; i++)
++ usb_free_coherent(dev->udev,
++ sizeof(struct gs_host_frame),
++ dev->rxbuf[i],
++ dev->rxbuf_dma[i]);
++ }
+
+ /* Stop sending URBs */
+ usb_kill_anchored_urbs(&dev->tx_submitted);
+diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h
+index 390b6bde883c8..61e67986b625e 100644
+--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h
++++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h
+@@ -35,9 +35,10 @@
+ #define KVASER_USB_RX_BUFFER_SIZE 3072
+ #define KVASER_USB_MAX_NET_DEVICES 5
+
+-/* USB devices features */
+-#define KVASER_USB_HAS_SILENT_MODE BIT(0)
+-#define KVASER_USB_HAS_TXRX_ERRORS BIT(1)
++/* Kvaser USB device quirks */
++#define KVASER_USB_QUIRK_HAS_SILENT_MODE BIT(0)
++#define KVASER_USB_QUIRK_HAS_TXRX_ERRORS BIT(1)
++#define KVASER_USB_QUIRK_IGNORE_CLK_FREQ BIT(2)
+
+ /* Device capabilities */
+ #define KVASER_USB_CAP_BERR_CAP 0x01
+@@ -65,12 +66,7 @@ struct kvaser_usb_dev_card_data_hydra {
+ struct kvaser_usb_dev_card_data {
+ u32 ctrlmode_supported;
+ u32 capabilities;
+- union {
+- struct {
+- enum kvaser_usb_leaf_family family;
+- } leaf;
+- struct kvaser_usb_dev_card_data_hydra hydra;
+- };
++ struct kvaser_usb_dev_card_data_hydra hydra;
+ };
+
+ /* Context for an outstanding, not yet ACKed, transmission */
+@@ -84,7 +80,7 @@ struct kvaser_usb {
+ struct usb_device *udev;
+ struct usb_interface *intf;
+ struct kvaser_usb_net_priv *nets[KVASER_USB_MAX_NET_DEVICES];
+- const struct kvaser_usb_dev_ops *ops;
++ const struct kvaser_usb_driver_info *driver_info;
+ const struct kvaser_usb_dev_cfg *cfg;
+
+ struct usb_endpoint_descriptor *bulk_in, *bulk_out;
+@@ -166,6 +162,12 @@ struct kvaser_usb_dev_ops {
+ int *cmd_len, u16 transid);
+ };
+
++struct kvaser_usb_driver_info {
++ u32 quirks;
++ enum kvaser_usb_leaf_family family;
++ const struct kvaser_usb_dev_ops *ops;
++};
++
+ struct kvaser_usb_dev_cfg {
+ const struct can_clock clock;
+ const unsigned int timestamp_freq;
+@@ -185,4 +187,7 @@ int kvaser_usb_send_cmd_async(struct kvaser_usb_net_priv *priv, void *cmd,
+ int len);
+
+ int kvaser_usb_can_rx_over_error(struct net_device *netdev);
++
++extern const struct can_bittiming_const kvaser_usb_flexc_bittiming_const;
++
+ #endif /* KVASER_USB_H */
+diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
+index 0cc0fc866a2a9..e570f5a76bbfd 100644
+--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
++++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
+@@ -61,8 +61,6 @@
+ #define USB_USBCAN_R_V2_PRODUCT_ID 294
+ #define USB_LEAF_LIGHT_R_V2_PRODUCT_ID 295
+ #define USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID 296
+-#define USB_LEAF_PRODUCT_ID_END \
+- USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID
+
+ /* Kvaser USBCan-II devices product ids */
+ #define USB_USBCAN_REVB_PRODUCT_ID 2
+@@ -89,116 +87,153 @@
+ #define USB_USBCAN_PRO_4HS_PRODUCT_ID 276
+ #define USB_HYBRID_CANLIN_PRODUCT_ID 277
+ #define USB_HYBRID_PRO_CANLIN_PRODUCT_ID 278
+-#define USB_HYDRA_PRODUCT_ID_END \
+- USB_HYBRID_PRO_CANLIN_PRODUCT_ID
+
+-static inline bool kvaser_is_leaf(const struct usb_device_id *id)
+-{
+- return (id->idProduct >= USB_LEAF_DEVEL_PRODUCT_ID &&
+- id->idProduct <= USB_CAN_R_PRODUCT_ID) ||
+- (id->idProduct >= USB_LEAF_LITE_V2_PRODUCT_ID &&
+- id->idProduct <= USB_LEAF_PRODUCT_ID_END);
+-}
++static const struct kvaser_usb_driver_info kvaser_usb_driver_info_hydra = {
++ .quirks = 0,
++ .ops = &kvaser_usb_hydra_dev_ops,
++};
+
+-static inline bool kvaser_is_usbcan(const struct usb_device_id *id)
+-{
+- return id->idProduct >= USB_USBCAN_REVB_PRODUCT_ID &&
+- id->idProduct <= USB_MEMORATOR_PRODUCT_ID;
+-}
++static const struct kvaser_usb_driver_info kvaser_usb_driver_info_usbcan = {
++ .quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
++ KVASER_USB_QUIRK_HAS_SILENT_MODE,
++ .family = KVASER_USBCAN,
++ .ops = &kvaser_usb_leaf_dev_ops,
++};
+
+-static inline bool kvaser_is_hydra(const struct usb_device_id *id)
+-{
+- return id->idProduct >= USB_BLACKBIRD_V2_PRODUCT_ID &&
+- id->idProduct <= USB_HYDRA_PRODUCT_ID_END;
+-}
++static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf = {
++ .quirks = KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
++ .family = KVASER_LEAF,
++ .ops = &kvaser_usb_leaf_dev_ops,
++};
++
++static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf_err = {
++ .quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
++ KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
++ .family = KVASER_LEAF,
++ .ops = &kvaser_usb_leaf_dev_ops,
++};
++
++static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf_err_listen = {
++ .quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
++ KVASER_USB_QUIRK_HAS_SILENT_MODE |
++ KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
++ .family = KVASER_LEAF,
++ .ops = &kvaser_usb_leaf_dev_ops,
++};
++
++static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leafimx = {
++ .quirks = 0,
++ .ops = &kvaser_usb_leaf_dev_ops,
++};
+
+ static const struct usb_device_id kvaser_usb_table[] = {
+- /* Leaf USB product IDs */
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
++ /* Leaf M32C USB product IDs */
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
+- KVASER_USB_HAS_SILENT_MODE },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
+- KVASER_USB_HAS_SILENT_MODE },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
+- KVASER_USB_HAS_SILENT_MODE },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
+- KVASER_USB_HAS_SILENT_MODE },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
+- KVASER_USB_HAS_SILENT_MODE },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
+- KVASER_USB_HAS_SILENT_MODE },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
+- KVASER_USB_HAS_SILENT_MODE },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
+- KVASER_USB_HAS_SILENT_MODE },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
+- KVASER_USB_HAS_SILENT_MODE },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID) },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
+- KVASER_USB_HAS_SILENT_MODE },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_2HS_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_2HS_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_R_V2_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_R_V2_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID) },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
++
++ /* Leaf i.MX28 USB product IDs */
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_2HS_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_2HS_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_R_V2_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_R_V2_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+
+ /* USBCANII USB product IDs */
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID),
+- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
+
+ /* Minihydra USB product IDs */
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_V2_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_5HS_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_5HS_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_4HS_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_HS_V2_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_2HS_V2_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_2HS_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_2HS_V2_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_2CANLIN_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_USBCAN_PRO_2HS_V2_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_MEMO_PRO_2HS_V2_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_2CANLIN_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_U100_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_U100P_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_U100S_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_4HS_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_CANLIN_PRODUCT_ID) },
+- { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_CANLIN_PRODUCT_ID) },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_V2_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_5HS_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_5HS_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_4HS_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_HS_V2_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_2HS_V2_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_2HS_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_2HS_V2_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_2CANLIN_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_USBCAN_PRO_2HS_V2_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_MEMO_PRO_2HS_V2_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_2CANLIN_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_U100_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_U100P_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_U100S_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_4HS_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_CANLIN_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
++ { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_CANLIN_PRODUCT_ID),
++ .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+ { }
+ };
+ MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
+@@ -289,6 +324,7 @@ int kvaser_usb_can_rx_over_error(struct net_device *netdev)
+ static void kvaser_usb_read_bulk_callback(struct urb *urb)
+ {
+ struct kvaser_usb *dev = urb->context;
++ const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
+ int err;
+ unsigned int i;
+
+@@ -305,8 +341,8 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb)
+ goto resubmit_urb;
+ }
+
+- dev->ops->dev_read_bulk_callback(dev, urb->transfer_buffer,
+- urb->actual_length);
++ ops->dev_read_bulk_callback(dev, urb->transfer_buffer,
++ urb->actual_length);
+
+ resubmit_urb:
+ usb_fill_bulk_urb(urb, dev->udev,
+@@ -400,6 +436,7 @@ static int kvaser_usb_open(struct net_device *netdev)
+ {
+ struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+ struct kvaser_usb *dev = priv->dev;
++ const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
+ int err;
+
+ err = open_candev(netdev);
+@@ -410,11 +447,11 @@ static int kvaser_usb_open(struct net_device *netdev)
+ if (err)
+ goto error;
+
+- err = dev->ops->dev_set_opt_mode(priv);
++ err = ops->dev_set_opt_mode(priv);
+ if (err)
+ goto error;
+
+- err = dev->ops->dev_start_chip(priv);
++ err = ops->dev_start_chip(priv);
+ if (err) {
+ netdev_warn(netdev, "Cannot start device, error %d\n", err);
+ goto error;
+@@ -471,22 +508,23 @@ static int kvaser_usb_close(struct net_device *netdev)
+ {
+ struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+ struct kvaser_usb *dev = priv->dev;
++ const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
+ int err;
+
+ netif_stop_queue(netdev);
+
+- err = dev->ops->dev_flush_queue(priv);
++ err = ops->dev_flush_queue(priv);
+ if (err)
+ netdev_warn(netdev, "Cannot flush queue, error %d\n", err);
+
+- if (dev->ops->dev_reset_chip) {
+- err = dev->ops->dev_reset_chip(dev, priv->channel);
++ if (ops->dev_reset_chip) {
++ err = ops->dev_reset_chip(dev, priv->channel);
+ if (err)
+ netdev_warn(netdev, "Cannot reset card, error %d\n",
+ err);
+ }
+
+- err = dev->ops->dev_stop_chip(priv);
++ err = ops->dev_stop_chip(priv);
+ if (err)
+ netdev_warn(netdev, "Cannot stop device, error %d\n", err);
+
+@@ -525,6 +563,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
+ {
+ struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+ struct kvaser_usb *dev = priv->dev;
++ const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
+ struct net_device_stats *stats = &netdev->stats;
+ struct kvaser_usb_tx_urb_context *context = NULL;
+ struct urb *urb;
+@@ -567,8 +606,8 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
+ goto freeurb;
+ }
+
+- buf = dev->ops->dev_frame_to_cmd(priv, skb, &context->dlc, &cmd_len,
+- context->echo_index);
++ buf = ops->dev_frame_to_cmd(priv, skb, &context->dlc, &cmd_len,
++ context->echo_index);
+ if (!buf) {
+ stats->tx_dropped++;
+ dev_kfree_skb(skb);
+@@ -652,15 +691,16 @@ static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev)
+ }
+ }
+
+-static int kvaser_usb_init_one(struct kvaser_usb *dev,
+- const struct usb_device_id *id, int channel)
++static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
+ {
+ struct net_device *netdev;
+ struct kvaser_usb_net_priv *priv;
++ const struct kvaser_usb_driver_info *driver_info = dev->driver_info;
++ const struct kvaser_usb_dev_ops *ops = driver_info->ops;
+ int err;
+
+- if (dev->ops->dev_reset_chip) {
+- err = dev->ops->dev_reset_chip(dev, channel);
++ if (ops->dev_reset_chip) {
++ err = ops->dev_reset_chip(dev, channel);
+ if (err)
+ return err;
+ }
+@@ -689,20 +729,19 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev,
+ priv->can.state = CAN_STATE_STOPPED;
+ priv->can.clock.freq = dev->cfg->clock.freq;
+ priv->can.bittiming_const = dev->cfg->bittiming_const;
+- priv->can.do_set_bittiming = dev->ops->dev_set_bittiming;
+- priv->can.do_set_mode = dev->ops->dev_set_mode;
+- if ((id->driver_info & KVASER_USB_HAS_TXRX_ERRORS) ||
++ priv->can.do_set_bittiming = ops->dev_set_bittiming;
++ priv->can.do_set_mode = ops->dev_set_mode;
++ if ((driver_info->quirks & KVASER_USB_QUIRK_HAS_TXRX_ERRORS) ||
+ (priv->dev->card_data.capabilities & KVASER_USB_CAP_BERR_CAP))
+- priv->can.do_get_berr_counter = dev->ops->dev_get_berr_counter;
+- if (id->driver_info & KVASER_USB_HAS_SILENT_MODE)
++ priv->can.do_get_berr_counter = ops->dev_get_berr_counter;
++ if (driver_info->quirks & KVASER_USB_QUIRK_HAS_SILENT_MODE)
+ priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
+
+ priv->can.ctrlmode_supported |= dev->card_data.ctrlmode_supported;
+
+ if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
+ priv->can.data_bittiming_const = dev->cfg->data_bittiming_const;
+- priv->can.do_set_data_bittiming =
+- dev->ops->dev_set_data_bittiming;
++ priv->can.do_set_data_bittiming = ops->dev_set_data_bittiming;
+ }
+
+ netdev->flags |= IFF_ECHO;
+@@ -733,29 +772,22 @@ static int kvaser_usb_probe(struct usb_interface *intf,
+ struct kvaser_usb *dev;
+ int err;
+ int i;
++ const struct kvaser_usb_driver_info *driver_info;
++ const struct kvaser_usb_dev_ops *ops;
++
++ driver_info = (const struct kvaser_usb_driver_info *)id->driver_info;
++ if (!driver_info)
++ return -ENODEV;
+
+ dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+- if (kvaser_is_leaf(id)) {
+- dev->card_data.leaf.family = KVASER_LEAF;
+- dev->ops = &kvaser_usb_leaf_dev_ops;
+- } else if (kvaser_is_usbcan(id)) {
+- dev->card_data.leaf.family = KVASER_USBCAN;
+- dev->ops = &kvaser_usb_leaf_dev_ops;
+- } else if (kvaser_is_hydra(id)) {
+- dev->ops = &kvaser_usb_hydra_dev_ops;
+- } else {
+- dev_err(&intf->dev,
+- "Product ID (%d) is not a supported Kvaser USB device\n",
+- id->idProduct);
+- return -ENODEV;
+- }
+-
+ dev->intf = intf;
++ dev->driver_info = driver_info;
++ ops = driver_info->ops;
+
+- err = dev->ops->dev_setup_endpoints(dev);
++ err = ops->dev_setup_endpoints(dev);
+ if (err) {
+ dev_err(&intf->dev, "Cannot get usb endpoint(s)");
+ return err;
+@@ -769,22 +801,22 @@ static int kvaser_usb_probe(struct usb_interface *intf,
+
+ dev->card_data.ctrlmode_supported = 0;
+ dev->card_data.capabilities = 0;
+- err = dev->ops->dev_init_card(dev);
++ err = ops->dev_init_card(dev);
+ if (err) {
+ dev_err(&intf->dev,
+ "Failed to initialize card, error %d\n", err);
+ return err;
+ }
+
+- err = dev->ops->dev_get_software_info(dev);
++ err = ops->dev_get_software_info(dev);
+ if (err) {
+ dev_err(&intf->dev,
+ "Cannot get software info, error %d\n", err);
+ return err;
+ }
+
+- if (dev->ops->dev_get_software_details) {
+- err = dev->ops->dev_get_software_details(dev);
++ if (ops->dev_get_software_details) {
++ err = ops->dev_get_software_details(dev);
+ if (err) {
+ dev_err(&intf->dev,
+ "Cannot get software details, error %d\n", err);
+@@ -802,14 +834,14 @@ static int kvaser_usb_probe(struct usb_interface *intf,
+
+ dev_dbg(&intf->dev, "Max outstanding tx = %d URBs\n", dev->max_tx_urbs);
+
+- err = dev->ops->dev_get_card_info(dev);
++ err = ops->dev_get_card_info(dev);
+ if (err) {
+ dev_err(&intf->dev, "Cannot get card info, error %d\n", err);
+ return err;
+ }
+
+- if (dev->ops->dev_get_capabilities) {
+- err = dev->ops->dev_get_capabilities(dev);
++ if (ops->dev_get_capabilities) {
++ err = ops->dev_get_capabilities(dev);
+ if (err) {
+ dev_err(&intf->dev,
+ "Cannot get capabilities, error %d\n", err);
+@@ -819,7 +851,7 @@ static int kvaser_usb_probe(struct usb_interface *intf,
+ }
+
+ for (i = 0; i < dev->nchannels; i++) {
+- err = kvaser_usb_init_one(dev, id, i);
++ err = kvaser_usb_init_one(dev, i);
+ if (err) {
+ kvaser_usb_remove_interfaces(dev);
+ return err;
+diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
+index dcee8dc828ecc..fce3f069cdbc0 100644
+--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
++++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
+@@ -373,7 +373,7 @@ static const struct can_bittiming_const kvaser_usb_hydra_kcan_bittiming_c = {
+ .brp_inc = 1,
+ };
+
+-static const struct can_bittiming_const kvaser_usb_hydra_flexc_bittiming_c = {
++const struct can_bittiming_const kvaser_usb_flexc_bittiming_const = {
+ .name = "kvaser_usb_flex",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+@@ -2052,7 +2052,7 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_flexc = {
+ .freq = 24000000,
+ },
+ .timestamp_freq = 1,
+- .bittiming_const = &kvaser_usb_hydra_flexc_bittiming_c,
++ .bittiming_const = &kvaser_usb_flexc_bittiming_const,
+ };
+
+ static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_rt = {
+diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+index f7af1bf5ab46d..b9c2231e4b43e 100644
+--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
++++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+@@ -100,16 +100,6 @@
+ #define USBCAN_ERROR_STATE_RX_ERROR BIT(1)
+ #define USBCAN_ERROR_STATE_BUSERROR BIT(2)
+
+-/* bittiming parameters */
+-#define KVASER_USB_TSEG1_MIN 1
+-#define KVASER_USB_TSEG1_MAX 16
+-#define KVASER_USB_TSEG2_MIN 1
+-#define KVASER_USB_TSEG2_MAX 8
+-#define KVASER_USB_SJW_MAX 4
+-#define KVASER_USB_BRP_MIN 1
+-#define KVASER_USB_BRP_MAX 64
+-#define KVASER_USB_BRP_INC 1
+-
+ /* ctrl modes */
+ #define KVASER_CTRL_MODE_NORMAL 1
+ #define KVASER_CTRL_MODE_SILENT 2
+@@ -342,48 +332,68 @@ struct kvaser_usb_err_summary {
+ };
+ };
+
+-static const struct can_bittiming_const kvaser_usb_leaf_bittiming_const = {
+- .name = "kvaser_usb",
+- .tseg1_min = KVASER_USB_TSEG1_MIN,
+- .tseg1_max = KVASER_USB_TSEG1_MAX,
+- .tseg2_min = KVASER_USB_TSEG2_MIN,
+- .tseg2_max = KVASER_USB_TSEG2_MAX,
+- .sjw_max = KVASER_USB_SJW_MAX,
+- .brp_min = KVASER_USB_BRP_MIN,
+- .brp_max = KVASER_USB_BRP_MAX,
+- .brp_inc = KVASER_USB_BRP_INC,
++static const struct can_bittiming_const kvaser_usb_leaf_m16c_bittiming_const = {
++ .name = "kvaser_usb_ucii",
++ .tseg1_min = 4,
++ .tseg1_max = 16,
++ .tseg2_min = 2,
++ .tseg2_max = 8,
++ .sjw_max = 4,
++ .brp_min = 1,
++ .brp_max = 16,
++ .brp_inc = 1,
++};
++
++static const struct can_bittiming_const kvaser_usb_leaf_m32c_bittiming_const = {
++ .name = "kvaser_usb_leaf",
++ .tseg1_min = 3,
++ .tseg1_max = 16,
++ .tseg2_min = 2,
++ .tseg2_max = 8,
++ .sjw_max = 4,
++ .brp_min = 2,
++ .brp_max = 128,
++ .brp_inc = 2,
+ };
+
+-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_8mhz = {
++static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_usbcan_dev_cfg = {
+ .clock = {
+ .freq = 8000000,
+ },
+ .timestamp_freq = 1,
+- .bittiming_const = &kvaser_usb_leaf_bittiming_const,
++ .bittiming_const = &kvaser_usb_leaf_m16c_bittiming_const,
++};
++
++static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_m32c_dev_cfg = {
++ .clock = {
++ .freq = 16000000,
++ },
++ .timestamp_freq = 1,
++ .bittiming_const = &kvaser_usb_leaf_m32c_bittiming_const,
+ };
+
+-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_16mhz = {
++static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_16mhz = {
+ .clock = {
+ .freq = 16000000,
+ },
+ .timestamp_freq = 1,
+- .bittiming_const = &kvaser_usb_leaf_bittiming_const,
++ .bittiming_const = &kvaser_usb_flexc_bittiming_const,
+ };
+
+-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_24mhz = {
++static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_24mhz = {
+ .clock = {
+ .freq = 24000000,
+ },
+ .timestamp_freq = 1,
+- .bittiming_const = &kvaser_usb_leaf_bittiming_const,
++ .bittiming_const = &kvaser_usb_flexc_bittiming_const,
+ };
+
+-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_32mhz = {
++static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_32mhz = {
+ .clock = {
+ .freq = 32000000,
+ },
+ .timestamp_freq = 1,
+- .bittiming_const = &kvaser_usb_leaf_bittiming_const,
++ .bittiming_const = &kvaser_usb_flexc_bittiming_const,
+ };
+
+ static void *
+@@ -405,7 +415,7 @@ kvaser_usb_leaf_frame_to_cmd(const struct kvaser_usb_net_priv *priv,
+ sizeof(struct kvaser_cmd_tx_can);
+ cmd->u.tx_can.channel = priv->channel;
+
+- switch (dev->card_data.leaf.family) {
++ switch (dev->driver_info->family) {
+ case KVASER_LEAF:
+ cmd_tx_can_flags = &cmd->u.tx_can.leaf.flags;
+ break;
+@@ -525,16 +535,23 @@ static void kvaser_usb_leaf_get_software_info_leaf(struct kvaser_usb *dev,
+ dev->fw_version = le32_to_cpu(softinfo->fw_version);
+ dev->max_tx_urbs = le16_to_cpu(softinfo->max_outstanding_tx);
+
+- switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
+- case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
+- dev->cfg = &kvaser_usb_leaf_dev_cfg_16mhz;
+- break;
+- case KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK:
+- dev->cfg = &kvaser_usb_leaf_dev_cfg_24mhz;
+- break;
+- case KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK:
+- dev->cfg = &kvaser_usb_leaf_dev_cfg_32mhz;
+- break;
++ if (dev->driver_info->quirks & KVASER_USB_QUIRK_IGNORE_CLK_FREQ) {
++ /* Firmware expects bittiming parameters calculated for 16MHz
++ * clock, regardless of the actual clock
++ */
++ dev->cfg = &kvaser_usb_leaf_m32c_dev_cfg;
++ } else {
++ switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
++ case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
++ dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_16mhz;
++ break;
++ case KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK:
++ dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_24mhz;
++ break;
++ case KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK:
++ dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_32mhz;
++ break;
++ }
+ }
+ }
+
+@@ -551,7 +568,7 @@ static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev)
+ if (err)
+ return err;
+
+- switch (dev->card_data.leaf.family) {
++ switch (dev->driver_info->family) {
+ case KVASER_LEAF:
+ kvaser_usb_leaf_get_software_info_leaf(dev, &cmd.u.leaf.softinfo);
+ break;
+@@ -559,7 +576,7 @@ static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev)
+ dev->fw_version = le32_to_cpu(cmd.u.usbcan.softinfo.fw_version);
+ dev->max_tx_urbs =
+ le16_to_cpu(cmd.u.usbcan.softinfo.max_outstanding_tx);
+- dev->cfg = &kvaser_usb_leaf_dev_cfg_8mhz;
++ dev->cfg = &kvaser_usb_leaf_usbcan_dev_cfg;
+ break;
+ }
+
+@@ -598,7 +615,7 @@ static int kvaser_usb_leaf_get_card_info(struct kvaser_usb *dev)
+
+ dev->nchannels = cmd.u.cardinfo.nchannels;
+ if (dev->nchannels > KVASER_USB_MAX_NET_DEVICES ||
+- (dev->card_data.leaf.family == KVASER_USBCAN &&
++ (dev->driver_info->family == KVASER_USBCAN &&
+ dev->nchannels > MAX_USBCAN_NET_DEVICES))
+ return -EINVAL;
+
+@@ -734,7 +751,7 @@ kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
+ new_state < CAN_STATE_BUS_OFF)
+ priv->can.can_stats.restarts++;
+
+- switch (dev->card_data.leaf.family) {
++ switch (dev->driver_info->family) {
+ case KVASER_LEAF:
+ if (es->leaf.error_factor) {
+ priv->can.can_stats.bus_error++;
+@@ -813,7 +830,7 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,
+ }
+ }
+
+- switch (dev->card_data.leaf.family) {
++ switch (dev->driver_info->family) {
+ case KVASER_LEAF:
+ if (es->leaf.error_factor) {
+ cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
+@@ -1005,7 +1022,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
+ stats = &priv->netdev->stats;
+
+ if ((cmd->u.rx_can_header.flag & MSG_FLAG_ERROR_FRAME) &&
+- (dev->card_data.leaf.family == KVASER_LEAF &&
++ (dev->driver_info->family == KVASER_LEAF &&
+ cmd->id == CMD_LEAF_LOG_MESSAGE)) {
+ kvaser_usb_leaf_leaf_rx_error(dev, cmd);
+ return;
+@@ -1021,7 +1038,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
+ return;
+ }
+
+- switch (dev->card_data.leaf.family) {
++ switch (dev->driver_info->family) {
+ case KVASER_LEAF:
+ rx_data = cmd->u.leaf.rx_can.data;
+ break;
+@@ -1036,7 +1053,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
+ return;
+ }
+
+- if (dev->card_data.leaf.family == KVASER_LEAF && cmd->id ==
++ if (dev->driver_info->family == KVASER_LEAF && cmd->id ==
+ CMD_LEAF_LOG_MESSAGE) {
+ cf->can_id = le32_to_cpu(cmd->u.leaf.log_message.id);
+ if (cf->can_id & KVASER_EXTENDED_FRAME)
+@@ -1133,14 +1150,14 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
+ break;
+
+ case CMD_LEAF_LOG_MESSAGE:
+- if (dev->card_data.leaf.family != KVASER_LEAF)
++ if (dev->driver_info->family != KVASER_LEAF)
+ goto warn;
+ kvaser_usb_leaf_rx_can_msg(dev, cmd);
+ break;
+
+ case CMD_CHIP_STATE_EVENT:
+ case CMD_CAN_ERROR_EVENT:
+- if (dev->card_data.leaf.family == KVASER_LEAF)
++ if (dev->driver_info->family == KVASER_LEAF)
+ kvaser_usb_leaf_leaf_rx_error(dev, cmd);
+ else
+ kvaser_usb_leaf_usbcan_rx_error(dev, cmd);
+@@ -1152,12 +1169,12 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
+
+ /* Ignored commands */
+ case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
+- if (dev->card_data.leaf.family != KVASER_USBCAN)
++ if (dev->driver_info->family != KVASER_USBCAN)
+ goto warn;
+ break;
+
+ case CMD_FLUSH_QUEUE_REPLY:
+- if (dev->card_data.leaf.family != KVASER_LEAF)
++ if (dev->driver_info->family != KVASER_LEAF)
+ goto warn;
+ break;
+
+diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
+index a984f06f6f04f..67869c8cbeaa8 100644
+--- a/drivers/net/dsa/qca8k.c
++++ b/drivers/net/dsa/qca8k.c
+@@ -1599,7 +1599,7 @@ static int
+ qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
+ {
+ struct qca8k_priv *priv = ds->priv;
+- int i, mtu = 0;
++ int ret, i, mtu = 0;
+
+ priv->port_mtu[port] = new_mtu;
+
+@@ -1607,8 +1607,27 @@ qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
+ if (priv->port_mtu[i] > mtu)
+ mtu = priv->port_mtu[i];
+
++ /* To change the MAX_FRAME_SIZE the cpu ports must be off or
++ * the switch panics.
++ * Turn off both cpu ports before applying the new value to prevent
++ * this.
++ */
++ if (priv->port_sts[0].enabled)
++ qca8k_port_set_status(priv, 0, 0);
++
++ if (priv->port_sts[6].enabled)
++ qca8k_port_set_status(priv, 6, 0);
++
+ /* Include L2 header / FCS length */
+- return qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, mtu + ETH_HLEN + ETH_FCS_LEN);
++ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, mtu + ETH_HLEN + ETH_FCS_LEN);
++
++ if (priv->port_sts[0].enabled)
++ qca8k_port_set_status(priv, 0, 1);
++
++ if (priv->port_sts[6].enabled)
++ qca8k_port_set_status(priv, 6, 1);
++
++ return ret;
+ }
+
+ static int
+diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
+index b262aa84b6a24..4a070724a8fb6 100644
+--- a/drivers/net/ethernet/ibm/ibmvnic.c
++++ b/drivers/net/ethernet/ibm/ibmvnic.c
+@@ -2063,6 +2063,19 @@ static const char *reset_reason_to_string(enum ibmvnic_reset_reason reason)
+ return "UNKNOWN";
+ }
+
++/*
++ * Initialize the init_done completion and return code values. We
++ * can get a transport event just after registering the CRQ and the
++ * tasklet will use this to communicate the transport event. To ensure
++ * we don't miss the notification/error, initialize these _before_
++ * regisering the CRQ.
++ */
++static inline void reinit_init_done(struct ibmvnic_adapter *adapter)
++{
++ reinit_completion(&adapter->init_done);
++ adapter->init_done_rc = 0;
++}
++
+ /*
+ * do_reset returns zero if we are able to keep processing reset events, or
+ * non-zero if we hit a fatal error and must halt.
+@@ -2169,6 +2182,8 @@ static int do_reset(struct ibmvnic_adapter *adapter,
+ */
+ adapter->state = VNIC_PROBED;
+
++ reinit_init_done(adapter);
++
+ if (adapter->reset_reason == VNIC_RESET_CHANGE_PARAM) {
+ rc = init_crq_queue(adapter);
+ } else if (adapter->reset_reason == VNIC_RESET_MOBILITY) {
+@@ -2314,7 +2329,8 @@ static int do_hard_reset(struct ibmvnic_adapter *adapter,
+ */
+ adapter->state = VNIC_PROBED;
+
+- reinit_completion(&adapter->init_done);
++ reinit_init_done(adapter);
++
+ rc = init_crq_queue(adapter);
+ if (rc) {
+ netdev_err(adapter->netdev,
+@@ -2455,23 +2471,82 @@ out:
+ static void __ibmvnic_reset(struct work_struct *work)
+ {
+ struct ibmvnic_adapter *adapter;
+- bool saved_state = false;
++ unsigned int timeout = 5000;
+ struct ibmvnic_rwi *tmprwi;
++ bool saved_state = false;
+ struct ibmvnic_rwi *rwi;
+ unsigned long flags;
+- u32 reset_state;
++ struct device *dev;
++ bool need_reset;
+ int num_fails = 0;
++ u32 reset_state;
+ int rc = 0;
+
+ adapter = container_of(work, struct ibmvnic_adapter, ibmvnic_reset);
++ dev = &adapter->vdev->dev;
+
+- if (test_and_set_bit_lock(0, &adapter->resetting)) {
++ /* Wait for ibmvnic_probe() to complete. If probe is taking too long
++ * or if another reset is in progress, defer work for now. If probe
++ * eventually fails it will flush and terminate our work.
++ *
++ * Three possibilities here:
++ * 1. Adpater being removed - just return
++ * 2. Timed out on probe or another reset in progress - delay the work
++ * 3. Completed probe - perform any resets in queue
++ */
++ if (adapter->state == VNIC_PROBING &&
++ !wait_for_completion_timeout(&adapter->probe_done, timeout)) {
++ dev_err(dev, "Reset thread timed out on probe");
+ queue_delayed_work(system_long_wq,
+ &adapter->ibmvnic_delayed_reset,
+ IBMVNIC_RESET_DELAY);
+ return;
+ }
+
++ /* adapter is done with probe (i.e state is never VNIC_PROBING now) */
++ if (adapter->state == VNIC_REMOVING)
++ return;
++
++ /* ->rwi_list is stable now (no one else is removing entries) */
++
++ /* ibmvnic_probe() may have purged the reset queue after we were
++ * scheduled to process a reset so there maybe no resets to process.
++ * Before setting the ->resetting bit though, we have to make sure
++ * that there is infact a reset to process. Otherwise we may race
++ * with ibmvnic_open() and end up leaving the vnic down:
++ *
++ * __ibmvnic_reset() ibmvnic_open()
++ * ----------------- --------------
++ *
++ * set ->resetting bit
++ * find ->resetting bit is set
++ * set ->state to IBMVNIC_OPEN (i.e
++ * assume reset will open device)
++ * return
++ * find reset queue empty
++ * return
++ *
++ * Neither performed vnic login/open and vnic stays down
++ *
++ * If we hold the lock and conditionally set the bit, either we
++ * or ibmvnic_open() will complete the open.
++ */
++ need_reset = false;
++ spin_lock(&adapter->rwi_lock);
++ if (!list_empty(&adapter->rwi_list)) {
++ if (test_and_set_bit_lock(0, &adapter->resetting)) {
++ queue_delayed_work(system_long_wq,
++ &adapter->ibmvnic_delayed_reset,
++ IBMVNIC_RESET_DELAY);
++ } else {
++ need_reset = true;
++ }
++ }
++ spin_unlock(&adapter->rwi_lock);
++
++ if (!need_reset)
++ return;
++
+ rwi = get_next_rwi(adapter);
+ while (rwi) {
+ spin_lock_irqsave(&adapter->state_lock, flags);
+@@ -2623,13 +2698,6 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
+ goto err;
+ }
+
+- if (adapter->state == VNIC_PROBING) {
+- netdev_warn(netdev, "Adapter reset during probe\n");
+- adapter->init_done_rc = -EAGAIN;
+- ret = EAGAIN;
+- goto err;
+- }
+-
+ list_for_each_entry(tmp, &adapter->rwi_list, list) {
+ if (tmp->reset_reason == reason) {
+ netdev_dbg(netdev, "Skipping matching reset, reason=%s\n",
+@@ -5485,10 +5553,6 @@ static int ibmvnic_reset_init(struct ibmvnic_adapter *adapter, bool reset)
+
+ adapter->from_passive_init = false;
+
+- if (reset)
+- reinit_completion(&adapter->init_done);
+-
+- adapter->init_done_rc = 0;
+ rc = ibmvnic_send_crq_init(adapter);
+ if (rc) {
+ dev_err(dev, "Send crq init failed with error %d\n", rc);
+@@ -5502,12 +5566,14 @@ static int ibmvnic_reset_init(struct ibmvnic_adapter *adapter, bool reset)
+
+ if (adapter->init_done_rc) {
+ release_crq_queue(adapter);
++ dev_err(dev, "CRQ-init failed, %d\n", adapter->init_done_rc);
+ return adapter->init_done_rc;
+ }
+
+ if (adapter->from_passive_init) {
+ adapter->state = VNIC_OPEN;
+ adapter->from_passive_init = false;
++ dev_err(dev, "CRQ-init failed, passive-init\n");
+ return -1;
+ }
+
+@@ -5519,6 +5585,15 @@ static int ibmvnic_reset_init(struct ibmvnic_adapter *adapter, bool reset)
+ release_sub_crqs(adapter, 0);
+ rc = init_sub_crqs(adapter);
+ } else {
++ /* no need to reinitialize completely, but we do
++ * need to clean up transmits that were in flight
++ * when we processed the reset. Failure to do so
++ * will confound the upper layer, usually TCP, by
++ * creating the illusion of transmits that are
++ * awaiting completion.
++ */
++ clean_tx_pools(adapter);
++
+ rc = reset_sub_crq_queues(adapter);
+ }
+ } else {
+@@ -5547,6 +5622,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
+ struct ibmvnic_adapter *adapter;
+ struct net_device *netdev;
+ unsigned char *mac_addr_p;
++ unsigned long flags;
+ bool init_success;
+ int rc;
+
+@@ -5588,6 +5664,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
+ spin_lock_init(&adapter->rwi_lock);
+ spin_lock_init(&adapter->state_lock);
+ mutex_init(&adapter->fw_lock);
++ init_completion(&adapter->probe_done);
+ init_completion(&adapter->init_done);
+ init_completion(&adapter->fw_done);
+ init_completion(&adapter->reset_done);
+@@ -5596,6 +5673,33 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
+
+ init_success = false;
+ do {
++ reinit_init_done(adapter);
++
++ /* clear any failovers we got in the previous pass
++ * since we are reinitializing the CRQ
++ */
++ adapter->failover_pending = false;
++
++ /* If we had already initialized CRQ, we may have one or
++ * more resets queued already. Discard those and release
++ * the CRQ before initializing the CRQ again.
++ */
++ release_crq_queue(adapter);
++
++ /* Since we are still in PROBING state, __ibmvnic_reset()
++ * will not access the ->rwi_list and since we released CRQ,
++ * we won't get _new_ transport events. But there maybe an
++ * ongoing ibmvnic_reset() call. So serialize access to
++ * rwi_list. If we win the race, ibvmnic_reset() could add
++ * a reset after we purged but thats ok - we just may end
++ * up with an extra reset (i.e similar to having two or more
++ * resets in the queue at once).
++ * CHECK.
++ */
++ spin_lock_irqsave(&adapter->rwi_lock, flags);
++ flush_reset_queue(adapter);
++ spin_unlock_irqrestore(&adapter->rwi_lock, flags);
++
+ rc = init_crq_queue(adapter);
+ if (rc) {
+ dev_err(&dev->dev, "Couldn't initialize crq. rc=%d\n",
+@@ -5647,6 +5751,8 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
+ }
+ dev_info(&dev->dev, "ibmvnic registered\n");
+
++ complete(&adapter->probe_done);
++
+ return 0;
+
+ ibmvnic_register_fail:
+@@ -5661,6 +5767,17 @@ ibmvnic_stats_fail:
+ ibmvnic_init_fail:
+ release_sub_crqs(adapter, 1);
+ release_crq_queue(adapter);
++
++ /* cleanup worker thread after releasing CRQ so we don't get
++ * transport events (i.e new work items for the worker thread).
++ */
++ adapter->state = VNIC_REMOVING;
++ complete(&adapter->probe_done);
++ flush_work(&adapter->ibmvnic_reset);
++ flush_delayed_work(&adapter->ibmvnic_delayed_reset);
++
++ flush_reset_queue(adapter);
++
+ mutex_destroy(&adapter->fw_lock);
+ free_netdev(netdev);
+
+diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
+index 1a9ed9202654f..b01c439965ff9 100644
+--- a/drivers/net/ethernet/ibm/ibmvnic.h
++++ b/drivers/net/ethernet/ibm/ibmvnic.h
+@@ -927,6 +927,7 @@ struct ibmvnic_adapter {
+
+ struct ibmvnic_tx_pool *tx_pool;
+ struct ibmvnic_tx_pool *tso_pool;
++ struct completion probe_done;
+ struct completion init_done;
+ int init_done_rc;
+
+diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
+index 56a3a6d1dbe41..210f09118edea 100644
+--- a/drivers/net/ethernet/intel/i40e/i40e.h
++++ b/drivers/net/ethernet/intel/i40e/i40e.h
+@@ -37,6 +37,7 @@
+ #include <net/tc_act/tc_mirred.h>
+ #include <net/udp_tunnel.h>
+ #include <net/xdp_sock.h>
++#include <linux/bitfield.h>
+ #include "i40e_type.h"
+ #include "i40e_prototype.h"
+ #include <linux/net/intel/i40e_client.h>
+@@ -1087,6 +1088,21 @@ static inline void i40e_write_fd_input_set(struct i40e_pf *pf,
+ (u32)(val & 0xFFFFFFFFULL));
+ }
+
++/**
++ * i40e_get_pf_count - get PCI PF count.
++ * @hw: pointer to a hw.
++ *
++ * Reports the function number of the highest PCI physical
++ * function plus 1 as it is loaded from the NVM.
++ *
++ * Return: PCI PF count.
++ **/
++static inline u32 i40e_get_pf_count(struct i40e_hw *hw)
++{
++ return FIELD_GET(I40E_GLGEN_PCIFCNCNT_PCIPFCNT_MASK,
++ rd32(hw, I40E_GLGEN_PCIFCNCNT));
++}
++
+ /* needed by i40e_ethtool.c */
+ int i40e_up(struct i40e_vsi *vsi);
+ void i40e_down(struct i40e_vsi *vsi);
+diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
+index 9bc05d671ad5f..02594e4d6258c 100644
+--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
++++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
+@@ -549,6 +549,47 @@ void i40e_pf_reset_stats(struct i40e_pf *pf)
+ pf->hw_csum_rx_error = 0;
+ }
+
++/**
++ * i40e_compute_pci_to_hw_id - compute index form PCI function.
++ * @vsi: ptr to the VSI to read from.
++ * @hw: ptr to the hardware info.
++ **/
++static u32 i40e_compute_pci_to_hw_id(struct i40e_vsi *vsi, struct i40e_hw *hw)
++{
++ int pf_count = i40e_get_pf_count(hw);
++
++ if (vsi->type == I40E_VSI_SRIOV)
++ return (hw->port * BIT(7)) / pf_count + vsi->vf_id;
++
++ return hw->port + BIT(7);
++}
++
++/**
++ * i40e_stat_update64 - read and update a 64 bit stat from the chip.
++ * @hw: ptr to the hardware info.
++ * @hireg: the high 32 bit reg to read.
++ * @loreg: the low 32 bit reg to read.
++ * @offset_loaded: has the initial offset been loaded yet.
++ * @offset: ptr to current offset value.
++ * @stat: ptr to the stat.
++ *
++ * Since the device stats are not reset at PFReset, they will not
++ * be zeroed when the driver starts. We'll save the first values read
++ * and use them as offsets to be subtracted from the raw values in order
++ * to report stats that count from zero.
++ **/
++static void i40e_stat_update64(struct i40e_hw *hw, u32 hireg, u32 loreg,
++ bool offset_loaded, u64 *offset, u64 *stat)
++{
++ u64 new_data;
++
++ new_data = rd64(hw, loreg);
++
++ if (!offset_loaded || new_data < *offset)
++ *offset = new_data;
++ *stat = new_data - *offset;
++}
++
+ /**
+ * i40e_stat_update48 - read and update a 48 bit stat from the chip
+ * @hw: ptr to the hardware info
+@@ -620,6 +661,34 @@ static void i40e_stat_update_and_clear32(struct i40e_hw *hw, u32 reg, u64 *stat)
+ *stat += new_data;
+ }
+
++/**
++ * i40e_stats_update_rx_discards - update rx_discards.
++ * @vsi: ptr to the VSI to be updated.
++ * @hw: ptr to the hardware info.
++ * @stat_idx: VSI's stat_counter_idx.
++ * @offset_loaded: ptr to the VSI's stat_offsets_loaded.
++ * @stat_offset: ptr to stat_offset to store first read of specific register.
++ * @stat: ptr to VSI's stat to be updated.
++ **/
++static void
++i40e_stats_update_rx_discards(struct i40e_vsi *vsi, struct i40e_hw *hw,
++ int stat_idx, bool offset_loaded,
++ struct i40e_eth_stats *stat_offset,
++ struct i40e_eth_stats *stat)
++{
++ u64 rx_rdpc, rx_rxerr;
++
++ i40e_stat_update32(hw, I40E_GLV_RDPC(stat_idx), offset_loaded,
++ &stat_offset->rx_discards, &rx_rdpc);
++ i40e_stat_update64(hw,
++ I40E_GL_RXERR1H(i40e_compute_pci_to_hw_id(vsi, hw)),
++ I40E_GL_RXERR1L(i40e_compute_pci_to_hw_id(vsi, hw)),
++ offset_loaded, &stat_offset->rx_discards_other,
++ &rx_rxerr);
++
++ stat->rx_discards = rx_rdpc + rx_rxerr;
++}
++
+ /**
+ * i40e_update_eth_stats - Update VSI-specific ethernet statistics counters.
+ * @vsi: the VSI to be updated
+@@ -679,6 +748,10 @@ void i40e_update_eth_stats(struct i40e_vsi *vsi)
+ I40E_GLV_BPTCL(stat_idx),
+ vsi->stat_offsets_loaded,
+ &oes->tx_broadcast, &es->tx_broadcast);
++
++ i40e_stats_update_rx_discards(vsi, hw, stat_idx,
++ vsi->stat_offsets_loaded, oes, es);
++
+ vsi->stat_offsets_loaded = true;
+ }
+
+diff --git a/drivers/net/ethernet/intel/i40e/i40e_register.h b/drivers/net/ethernet/intel/i40e/i40e_register.h
+index 1908eed4fa5ee..7339003aa17cd 100644
+--- a/drivers/net/ethernet/intel/i40e/i40e_register.h
++++ b/drivers/net/ethernet/intel/i40e/i40e_register.h
+@@ -211,6 +211,11 @@
+ #define I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT 0
+ #define I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT 16
+ #define I40E_GLGEN_MSRWD_MDIRDDATA_MASK I40E_MASK(0xFFFF, I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT)
++#define I40E_GLGEN_PCIFCNCNT 0x001C0AB4 /* Reset: PCIR */
++#define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT 0
++#define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_MASK I40E_MASK(0x1F, I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT)
++#define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT 16
++#define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_MASK I40E_MASK(0xFF, I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT)
+ #define I40E_GLGEN_RSTAT 0x000B8188 /* Reset: POR */
+ #define I40E_GLGEN_RSTAT_DEVSTATE_SHIFT 0
+ #define I40E_GLGEN_RSTAT_DEVSTATE_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_DEVSTATE_SHIFT)
+@@ -643,6 +648,14 @@
+ #define I40E_VFQF_HKEY1_MAX_INDEX 12
+ #define I40E_VFQF_HLUT1(_i, _VF) (0x00220000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...15, _VF=0...127 */ /* Reset: CORER */
+ #define I40E_VFQF_HLUT1_MAX_INDEX 15
++#define I40E_GL_RXERR1H(_i) (0x00318004 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */
++#define I40E_GL_RXERR1H_MAX_INDEX 143
++#define I40E_GL_RXERR1H_RXERR1H_SHIFT 0
++#define I40E_GL_RXERR1H_RXERR1H_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_RXERR1H_RXERR1H_SHIFT)
++#define I40E_GL_RXERR1L(_i) (0x00318000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */
++#define I40E_GL_RXERR1L_MAX_INDEX 143
++#define I40E_GL_RXERR1L_RXERR1L_SHIFT 0
++#define I40E_GL_RXERR1L_RXERR1L_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_RXERR1L_RXERR1L_SHIFT)
+ #define I40E_GLPRT_BPRCH(_i) (0x003005E4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */
+ #define I40E_GLPRT_BPRCL(_i) (0x003005E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */
+ #define I40E_GLPRT_BPTCH(_i) (0x00300A04 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */
+diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
+index 36a4ca1ffb1a9..7b3f30beb757a 100644
+--- a/drivers/net/ethernet/intel/i40e/i40e_type.h
++++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
+@@ -1172,6 +1172,7 @@ struct i40e_eth_stats {
+ u64 tx_broadcast; /* bptc */
+ u64 tx_discards; /* tdpc */
+ u64 tx_errors; /* tepc */
++ u64 rx_discards_other; /* rxerr1 */
+ };
+
+ /* Statistics collected per VEB per TC */
+diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+index 6c1e668f4ebf2..d78ac5e7f658f 100644
+--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
++++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+@@ -2147,6 +2147,10 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
+ /* VFs only use TC 0 */
+ vfres->vsi_res[0].qset_handle
+ = le16_to_cpu(vsi->info.qs_handle[0]);
++ if (!(vf->driver_caps & VIRTCHNL_VF_OFFLOAD_USO) && !vf->pf_set_mac) {
++ i40e_del_mac_filter(vsi, vf->default_lan_addr.addr);
++ eth_zero_addr(vf->default_lan_addr.addr);
++ }
+ ether_addr_copy(vfres->vsi_res[0].default_mac_addr,
+ vf->default_lan_addr.addr);
+ }
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+index 3aa8d0b83d108..843c8435387f3 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+@@ -3291,37 +3291,68 @@ out_ok:
+ return true;
+ }
+
+-static bool actions_match_supported(struct mlx5e_priv *priv,
+- struct flow_action *flow_action,
+- struct mlx5e_tc_flow_parse_attr *parse_attr,
+- struct mlx5e_tc_flow *flow,
+- struct netlink_ext_ack *extack)
++static bool
++actions_match_supported_fdb(struct mlx5e_priv *priv,
++ struct mlx5e_tc_flow_parse_attr *parse_attr,
++ struct mlx5e_tc_flow *flow,
++ struct netlink_ext_ack *extack)
+ {
+- bool ct_flow = false, ct_clear = false;
+- u32 actions;
++ bool ct_flow, ct_clear;
+
+- ct_clear = flow->attr->ct_attr.ct_action &
+- TCA_CT_ACT_CLEAR;
++ ct_clear = flow->attr->ct_attr.ct_action & TCA_CT_ACT_CLEAR;
+ ct_flow = flow_flag_test(flow, CT) && !ct_clear;
+- actions = flow->attr->action;
+
+- if (mlx5e_is_eswitch_flow(flow)) {
+- if (flow->attr->esw_attr->split_count && ct_flow &&
+- !MLX5_CAP_GEN(flow->attr->esw_attr->in_mdev, reg_c_preserve)) {
+- /* All registers used by ct are cleared when using
+- * split rules.
+- */
+- NL_SET_ERR_MSG_MOD(extack,
+- "Can't offload mirroring with action ct");
+- return false;
+- }
++ if (flow->attr->esw_attr->split_count && ct_flow &&
++ !MLX5_CAP_GEN(flow->attr->esw_attr->in_mdev, reg_c_preserve)) {
++ /* All registers used by ct are cleared when using
++ * split rules.
++ */
++ NL_SET_ERR_MSG_MOD(extack, "Can't offload mirroring with action ct");
++ return false;
++ }
++
++ return true;
++}
++
++static bool
++actions_match_supported(struct mlx5e_priv *priv,
++ struct flow_action *flow_action,
++ struct mlx5e_tc_flow_parse_attr *parse_attr,
++ struct mlx5e_tc_flow *flow,
++ struct netlink_ext_ack *extack)
++{
++ u32 actions = flow->attr->action;
++ bool ct_flow, ct_clear;
++
++ ct_clear = flow->attr->ct_attr.ct_action & TCA_CT_ACT_CLEAR;
++ ct_flow = flow_flag_test(flow, CT) && !ct_clear;
++
++ if (!(actions &
++ (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) {
++ NL_SET_ERR_MSG_MOD(extack, "Rule must have at least one forward/drop action");
++ return false;
++ }
++
++ if (!(~actions &
++ (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) {
++ NL_SET_ERR_MSG_MOD(extack, "Rule cannot support forward+drop action");
++ return false;
+ }
+
+- if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
+- return modify_header_match_supported(priv, &parse_attr->spec,
+- flow_action, actions,
+- ct_flow, ct_clear,
+- extack);
++ if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR &&
++ actions & MLX5_FLOW_CONTEXT_ACTION_DROP) {
++ NL_SET_ERR_MSG_MOD(extack, "Drop with modify header action is not supported");
++ return false;
++ }
++
++ if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR &&
++ !modify_header_match_supported(priv, &parse_attr->spec, flow_action,
++ actions, ct_flow, ct_clear, extack))
++ return false;
++
++ if (mlx5e_is_eswitch_flow(flow) &&
++ !actions_match_supported_fdb(priv, parse_attr, flow, extack))
++ return false;
+
+ return true;
+ }
+@@ -4207,13 +4238,6 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
+ attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+ }
+
+- if (!(attr->action &
+- (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) {
+- NL_SET_ERR_MSG_MOD(extack,
+- "Rule must have at least one forward/drop action");
+- return -EOPNOTSUPP;
+- }
+-
+ if (esw_attr->split_count > 0 && !mlx5_esw_has_fwd_fdb(priv->mdev)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "current firmware doesn't support split rule for port mirroring");
+diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c
+index dfaf10edfabfd..ba8c7a31cce1f 100644
+--- a/drivers/net/ethernet/qlogic/qed/qed_l2.c
++++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c
+@@ -2763,25 +2763,6 @@ static int qed_configure_filter_mcast(struct qed_dev *cdev,
+ return qed_filter_mcast_cmd(cdev, &mcast, QED_SPQ_MODE_CB, NULL);
+ }
+
+-static int qed_configure_filter(struct qed_dev *cdev,
+- struct qed_filter_params *params)
+-{
+- enum qed_filter_rx_mode_type accept_flags;
+-
+- switch (params->type) {
+- case QED_FILTER_TYPE_UCAST:
+- return qed_configure_filter_ucast(cdev, &params->filter.ucast);
+- case QED_FILTER_TYPE_MCAST:
+- return qed_configure_filter_mcast(cdev, &params->filter.mcast);
+- case QED_FILTER_TYPE_RX_MODE:
+- accept_flags = params->filter.accept_flags;
+- return qed_configure_filter_rx_mode(cdev, accept_flags);
+- default:
+- DP_NOTICE(cdev, "Unknown filter type %d\n", (int)params->type);
+- return -EINVAL;
+- }
+-}
+-
+ static int qed_configure_arfs_searcher(struct qed_dev *cdev,
+ enum qed_filter_config_mode mode)
+ {
+@@ -2904,7 +2885,9 @@ static const struct qed_eth_ops qed_eth_ops_pass = {
+ .q_rx_stop = &qed_stop_rxq,
+ .q_tx_start = &qed_start_txq,
+ .q_tx_stop = &qed_stop_txq,
+- .filter_config = &qed_configure_filter,
++ .filter_config_rx_mode = &qed_configure_filter_rx_mode,
++ .filter_config_ucast = &qed_configure_filter_ucast,
++ .filter_config_mcast = &qed_configure_filter_mcast,
+ .fastpath_stop = &qed_fastpath_stop,
+ .eth_cqe_completion = &qed_fp_cqe_completion,
+ .get_vport_stats = &qed_get_vport_stats,
+diff --git a/drivers/net/ethernet/qlogic/qede/qede_filter.c b/drivers/net/ethernet/qlogic/qede/qede_filter.c
+index a2e4dfb5cb44e..f99b085b56a54 100644
+--- a/drivers/net/ethernet/qlogic/qede/qede_filter.c
++++ b/drivers/net/ethernet/qlogic/qede/qede_filter.c
+@@ -619,30 +619,28 @@ static int qede_set_ucast_rx_mac(struct qede_dev *edev,
+ enum qed_filter_xcast_params_type opcode,
+ unsigned char mac[ETH_ALEN])
+ {
+- struct qed_filter_params filter_cmd;
++ struct qed_filter_ucast_params ucast;
+
+- memset(&filter_cmd, 0, sizeof(filter_cmd));
+- filter_cmd.type = QED_FILTER_TYPE_UCAST;
+- filter_cmd.filter.ucast.type = opcode;
+- filter_cmd.filter.ucast.mac_valid = 1;
+- ether_addr_copy(filter_cmd.filter.ucast.mac, mac);
++ memset(&ucast, 0, sizeof(ucast));
++ ucast.type = opcode;
++ ucast.mac_valid = 1;
++ ether_addr_copy(ucast.mac, mac);
+
+- return edev->ops->filter_config(edev->cdev, &filter_cmd);
++ return edev->ops->filter_config_ucast(edev->cdev, &ucast);
+ }
+
+ static int qede_set_ucast_rx_vlan(struct qede_dev *edev,
+ enum qed_filter_xcast_params_type opcode,
+ u16 vid)
+ {
+- struct qed_filter_params filter_cmd;
++ struct qed_filter_ucast_params ucast;
+
+- memset(&filter_cmd, 0, sizeof(filter_cmd));
+- filter_cmd.type = QED_FILTER_TYPE_UCAST;
+- filter_cmd.filter.ucast.type = opcode;
+- filter_cmd.filter.ucast.vlan_valid = 1;
+- filter_cmd.filter.ucast.vlan = vid;
++ memset(&ucast, 0, sizeof(ucast));
++ ucast.type = opcode;
++ ucast.vlan_valid = 1;
++ ucast.vlan = vid;
+
+- return edev->ops->filter_config(edev->cdev, &filter_cmd);
++ return edev->ops->filter_config_ucast(edev->cdev, &ucast);
+ }
+
+ static int qede_config_accept_any_vlan(struct qede_dev *edev, bool action)
+@@ -1057,18 +1055,17 @@ static int qede_set_mcast_rx_mac(struct qede_dev *edev,
+ enum qed_filter_xcast_params_type opcode,
+ unsigned char *mac, int num_macs)
+ {
+- struct qed_filter_params filter_cmd;
++ struct qed_filter_mcast_params mcast;
+ int i;
+
+- memset(&filter_cmd, 0, sizeof(filter_cmd));
+- filter_cmd.type = QED_FILTER_TYPE_MCAST;
+- filter_cmd.filter.mcast.type = opcode;
+- filter_cmd.filter.mcast.num = num_macs;
++ memset(&mcast, 0, sizeof(mcast));
++ mcast.type = opcode;
++ mcast.num = num_macs;
+
+ for (i = 0; i < num_macs; i++, mac += ETH_ALEN)
+- ether_addr_copy(filter_cmd.filter.mcast.mac[i], mac);
++ ether_addr_copy(mcast.mac[i], mac);
+
+- return edev->ops->filter_config(edev->cdev, &filter_cmd);
++ return edev->ops->filter_config_mcast(edev->cdev, &mcast);
+ }
+
+ int qede_set_mac_addr(struct net_device *ndev, void *p)
+@@ -1194,7 +1191,6 @@ void qede_config_rx_mode(struct net_device *ndev)
+ {
+ enum qed_filter_rx_mode_type accept_flags;
+ struct qede_dev *edev = netdev_priv(ndev);
+- struct qed_filter_params rx_mode;
+ unsigned char *uc_macs, *temp;
+ struct netdev_hw_addr *ha;
+ int rc, uc_count;
+@@ -1220,10 +1216,6 @@ void qede_config_rx_mode(struct net_device *ndev)
+
+ netif_addr_unlock_bh(ndev);
+
+- /* Configure the struct for the Rx mode */
+- memset(&rx_mode, 0, sizeof(struct qed_filter_params));
+- rx_mode.type = QED_FILTER_TYPE_RX_MODE;
+-
+ /* Remove all previous unicast secondary macs and multicast macs
+ * (configure / leave the primary mac)
+ */
+@@ -1271,8 +1263,7 @@ void qede_config_rx_mode(struct net_device *ndev)
+ qede_config_accept_any_vlan(edev, false);
+ }
+
+- rx_mode.filter.accept_flags = accept_flags;
+- edev->ops->filter_config(edev->cdev, &rx_mode);
++ edev->ops->filter_config_rx_mode(edev->cdev, accept_flags);
+ out:
+ kfree(uc_macs);
+ }
+diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
+index 2918947dd57c9..2af4c76bcf027 100644
+--- a/drivers/net/ethernet/realtek/r8169_main.c
++++ b/drivers/net/ethernet/realtek/r8169_main.c
+@@ -4177,7 +4177,6 @@ static void rtl8169_tso_csum_v1(struct sk_buff *skb, u32 *opts)
+ static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
+ struct sk_buff *skb, u32 *opts)
+ {
+- u32 transport_offset = (u32)skb_transport_offset(skb);
+ struct skb_shared_info *shinfo = skb_shinfo(skb);
+ u32 mss = shinfo->gso_size;
+
+@@ -4194,7 +4193,7 @@ static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
+ WARN_ON_ONCE(1);
+ }
+
+- opts[0] |= transport_offset << GTTCPHO_SHIFT;
++ opts[0] |= skb_transport_offset(skb) << GTTCPHO_SHIFT;
+ opts[1] |= mss << TD1_MSS_SHIFT;
+ } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ u8 ip_protocol;
+@@ -4222,7 +4221,7 @@ static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
+ else
+ WARN_ON_ONCE(1);
+
+- opts[1] |= transport_offset << TCPHO_SHIFT;
++ opts[1] |= skb_transport_offset(skb) << TCPHO_SHIFT;
+ } else {
+ unsigned int padto = rtl_quirk_packet_padto(tp, skb);
+
+@@ -4389,14 +4388,13 @@ static netdev_features_t rtl8169_features_check(struct sk_buff *skb,
+ struct net_device *dev,
+ netdev_features_t features)
+ {
+- int transport_offset = skb_transport_offset(skb);
+ struct rtl8169_private *tp = netdev_priv(dev);
+
+ if (skb_is_gso(skb)) {
+ if (tp->mac_version == RTL_GIGA_MAC_VER_34)
+ features = rtl8168evl_fix_tso(skb, features);
+
+- if (transport_offset > GTTCPHO_MAX &&
++ if (skb_transport_offset(skb) > GTTCPHO_MAX &&
+ rtl_chip_supports_csum_v2(tp))
+ features &= ~NETIF_F_ALL_TSO;
+ } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+@@ -4407,7 +4405,7 @@ static netdev_features_t rtl8169_features_check(struct sk_buff *skb,
+ if (rtl_quirk_packet_padto(tp, skb))
+ features &= ~NETIF_F_CSUM_MASK;
+
+- if (transport_offset > TCPHO_MAX &&
++ if (skb_transport_offset(skb) > TCPHO_MAX &&
+ rtl_chip_supports_csum_v2(tp))
+ features &= ~NETIF_F_CSUM_MASK;
+ }
+diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
+index a0ea236ac60e0..71bb0849ce480 100644
+--- a/drivers/net/usb/usbnet.c
++++ b/drivers/net/usb/usbnet.c
+@@ -2135,7 +2135,7 @@ static void usbnet_async_cmd_cb(struct urb *urb)
+ int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype,
+ u16 value, u16 index, const void *data, u16 size)
+ {
+- struct usb_ctrlrequest *req = NULL;
++ struct usb_ctrlrequest *req;
+ struct urb *urb;
+ int err = -ENOMEM;
+ void *buf = NULL;
+@@ -2153,7 +2153,7 @@ int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype,
+ if (!buf) {
+ netdev_err(dev->net, "Error allocating buffer"
+ " in %s!\n", __func__);
+- goto fail_free;
++ goto fail_free_urb;
+ }
+ }
+
+@@ -2177,14 +2177,21 @@ int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype,
+ if (err < 0) {
+ netdev_err(dev->net, "Error submitting the control"
+ " message: status=%d\n", err);
+- goto fail_free;
++ goto fail_free_all;
+ }
+ return 0;
+
++fail_free_all:
++ kfree(req);
+ fail_free_buf:
+ kfree(buf);
+-fail_free:
+- kfree(req);
++ /*
++ * avoid a double free
++ * needed because the flag can be set only
++ * after filling the URB
++ */
++ urb->transfer_flags = 0;
++fail_free_urb:
+ usb_free_urb(urb);
+ fail:
+ return err;
+diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
+index 7dcf6b13f7949..48b4151e13a3e 100644
+--- a/drivers/net/wireless/ath/ath11k/core.c
++++ b/drivers/net/wireless/ath/ath11k/core.c
+@@ -71,6 +71,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
+ .supports_suspend = false,
+ .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
+ .fix_l1ss = true,
++ .wakeup_mhi = false,
+ },
+ {
+ .hw_rev = ATH11K_HW_IPQ6018_HW10,
+@@ -112,6 +113,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
+ .supports_suspend = false,
+ .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
+ .fix_l1ss = true,
++ .wakeup_mhi = false,
+ },
+ {
+ .name = "qca6390 hw2.0",
+@@ -152,6 +154,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
+ .supports_suspend = true,
+ .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
+ .fix_l1ss = true,
++ .wakeup_mhi = true,
+ },
+ {
+ .name = "qcn9074 hw1.0",
+@@ -190,6 +193,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
+ .supports_suspend = false,
+ .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074),
+ .fix_l1ss = true,
++ .wakeup_mhi = false,
+ },
+ {
+ .name = "wcn6855 hw2.0",
+@@ -230,6 +234,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
+ .supports_suspend = true,
+ .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),
+ .fix_l1ss = false,
++ .wakeup_mhi = true,
+ },
+ };
+
+diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
+index 62f5978b30055..4fe051625edfb 100644
+--- a/drivers/net/wireless/ath/ath11k/hw.h
++++ b/drivers/net/wireless/ath/ath11k/hw.h
+@@ -163,6 +163,7 @@ struct ath11k_hw_params {
+ bool supports_suspend;
+ u32 hal_desc_sz;
+ bool fix_l1ss;
++ bool wakeup_mhi;
+ };
+
+ struct ath11k_hw_ops {
+diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
+index 353a2d669fcd5..7d0be9388f893 100644
+--- a/drivers/net/wireless/ath/ath11k/pci.c
++++ b/drivers/net/wireless/ath/ath11k/pci.c
+@@ -182,7 +182,8 @@ void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
+ /* for offset beyond BAR + 4K - 32, may
+ * need to wakeup MHI to access.
+ */
+- if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
++ if (ab->hw_params.wakeup_mhi &&
++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
+ offset >= ACCESS_ALWAYS_OFF)
+ mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
+
+@@ -206,7 +207,8 @@ void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
+ }
+ }
+
+- if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
++ if (ab->hw_params.wakeup_mhi &&
++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
+ offset >= ACCESS_ALWAYS_OFF)
+ mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
+ }
+@@ -219,7 +221,8 @@ u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
+ /* for offset beyond BAR + 4K - 32, may
+ * need to wakeup MHI to access.
+ */
+- if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
++ if (ab->hw_params.wakeup_mhi &&
++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
+ offset >= ACCESS_ALWAYS_OFF)
+ mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
+
+@@ -243,7 +246,8 @@ u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
+ }
+ }
+
+- if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
++ if (ab->hw_params.wakeup_mhi &&
++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
+ offset >= ACCESS_ALWAYS_OFF)
+ mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
+index af43bcb545781..306e9eaea9177 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
+@@ -7,9 +7,6 @@ int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm)
+ {
+ struct mt76_dev *dev = phy->dev;
+
+- if (!pm->enable)
+- return 0;
+-
+ if (mt76_is_usb(dev))
+ return 0;
+
+diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+index 77d4435e4581e..72a70a7046fbc 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+@@ -556,7 +556,7 @@ enum {
+ MCU_CMD_SET_BSS_CONNECTED = MCU_CE_PREFIX | 0x16,
+ MCU_CMD_SET_BSS_ABORT = MCU_CE_PREFIX | 0x17,
+ MCU_CMD_CANCEL_HW_SCAN = MCU_CE_PREFIX | 0x1b,
+- MCU_CMD_SET_ROC = MCU_CE_PREFIX | 0x1d,
++ MCU_CMD_SET_ROC = MCU_CE_PREFIX | 0x1c,
+ MCU_CMD_SET_P2P_OPPPS = MCU_CE_PREFIX | 0x33,
+ MCU_CMD_SET_RATE_TX_POWER = MCU_CE_PREFIX | 0x5d,
+ MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61,
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
+index 8d5e261cd10f6..cfcf7964c6881 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
+@@ -262,31 +262,44 @@ mt7921_txpwr(struct seq_file *s, void *data)
+ return 0;
+ }
+
++static void
++mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
++{
++ struct mt7921_dev *dev = priv;
++
++ mt7921_mcu_set_beacon_filter(dev, vif, dev->pm.enable);
++}
++
+ static int
+ mt7921_pm_set(void *data, u64 val)
+ {
+ struct mt7921_dev *dev = data;
+ struct mt76_connac_pm *pm = &dev->pm;
+- struct mt76_phy *mphy = dev->phy.mt76;
+
+- if (val == pm->enable)
+- return 0;
++ mutex_lock(&dev->mt76.mutex);
+
+- mt7921_mutex_acquire(dev);
++ if (val == pm->enable)
++ goto out;
+
+ if (!pm->enable) {
+ pm->stats.last_wake_event = jiffies;
+ pm->stats.last_doze_event = jiffies;
+ }
+- pm->enable = val;
++ /* make sure the chip is awake here and ps_work is scheduled
++ * just at end of the this routine.
++ */
++ pm->enable = false;
++ mt76_connac_pm_wake(&dev->mphy, pm);
+
+- ieee80211_iterate_active_interfaces(mphy->hw,
++ pm->enable = val;
++ ieee80211_iterate_active_interfaces(mt76_hw(dev),
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+- mt7921_pm_interface_iter, mphy->priv);
++ mt7921_pm_interface_iter, dev);
+
+ mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable);
+-
+- mt7921_mutex_release(dev);
++ mt76_connac_power_save_sched(&dev->mphy, pm);
++out:
++ mutex_unlock(&dev->mt76.mutex);
+
+ return 0;
+ }
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+index bef8d4a76ed90..426e7a32bdc86 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+@@ -1573,34 +1573,6 @@ out:
+ queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta);
+ }
+
+-int mt7921_mac_set_beacon_filter(struct mt7921_phy *phy,
+- struct ieee80211_vif *vif,
+- bool enable)
+-{
+- struct mt7921_dev *dev = phy->dev;
+- bool ext_phy = phy != &dev->phy;
+- int err;
+-
+- if (!dev->pm.enable)
+- return -EOPNOTSUPP;
+-
+- err = mt7921_mcu_set_bss_pm(dev, vif, enable);
+- if (err)
+- return err;
+-
+- if (enable) {
+- vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+- mt76_set(dev, MT_WF_RFCR(ext_phy),
+- MT_WF_RFCR_DROP_OTHER_BEACON);
+- } else {
+- vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
+- mt76_clear(dev, MT_WF_RFCR(ext_phy),
+- MT_WF_RFCR_DROP_OTHER_BEACON);
+- }
+-
+- return 0;
+-}
+-
+ void mt7921_coredump_work(struct work_struct *work)
+ {
+ struct mt7921_dev *dev;
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+index 30252f408ddc4..13a7ae3d83516 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+@@ -528,36 +528,6 @@ static void mt7921_configure_filter(struct ieee80211_hw *hw,
+ mt7921_mutex_release(dev);
+ }
+
+-static int
+-mt7921_bss_bcnft_apply(struct mt7921_dev *dev, struct ieee80211_vif *vif,
+- bool assoc)
+-{
+- int ret;
+-
+- if (!dev->pm.enable)
+- return 0;
+-
+- if (assoc) {
+- ret = mt7921_mcu_uni_bss_bcnft(dev, vif, true);
+- if (ret)
+- return ret;
+-
+- vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+- mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
+-
+- return 0;
+- }
+-
+- ret = mt7921_mcu_set_bss_pm(dev, vif, false);
+- if (ret)
+- return ret;
+-
+- vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
+- mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
+-
+- return 0;
+-}
+-
+ static void mt7921_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+@@ -587,7 +557,8 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw,
+ if (changed & BSS_CHANGED_ASSOC) {
+ mt7921_mcu_sta_update(dev, NULL, vif, true,
+ MT76_STA_INFO_STATE_ASSOC);
+- mt7921_bss_bcnft_apply(dev, vif, info->assoc);
++ if (dev->pm.enable)
++ mt7921_mcu_set_beacon_filter(dev, vif, info->assoc);
+ }
+
+ if (changed & BSS_CHANGED_ARP_FILTER) {
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+index 4119f8efd896b..dabc0de2ec65d 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+@@ -1205,8 +1205,9 @@ int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif)
+ &ps_req, sizeof(ps_req), true);
+ }
+
+-int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif,
+- bool enable)
++static int
++mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif,
++ bool enable)
+ {
+ struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct {
+@@ -1240,8 +1241,9 @@ int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif,
+ &bcnft_req, sizeof(bcnft_req), true);
+ }
+
+-int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
+- bool enable)
++static int
++mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
++ bool enable)
+ {
+ struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ struct {
+@@ -1390,31 +1392,34 @@ out:
+ return err;
+ }
+
+-void
+-mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
++int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev,
++ struct ieee80211_vif *vif,
++ bool enable)
+ {
+- struct mt7921_phy *phy = priv;
+- struct mt7921_dev *dev = phy->dev;
+ struct ieee80211_hw *hw = mt76_hw(dev);
+- int ret;
+-
+- if (dev->pm.enable)
+- ret = mt7921_mcu_uni_bss_bcnft(dev, vif, true);
+- else
+- ret = mt7921_mcu_set_bss_pm(dev, vif, false);
++ int err;
+
+- if (ret)
+- return;
++ if (enable) {
++ err = mt7921_mcu_uni_bss_bcnft(dev, vif, true);
++ if (err)
++ return err;
+
+- if (dev->pm.enable) {
+ vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+ ieee80211_hw_set(hw, CONNECTION_MONITOR);
+ mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
+- } else {
+- vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
+- __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags);
+- mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
++
++ return 0;
+ }
++
++ err = mt7921_mcu_set_bss_pm(dev, vif, false);
++ if (err)
++ return err;
++
++ vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
++ __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags);
++ mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
++
++ return 0;
+ }
+
+ int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr)
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+index 2d8bd6bfc820a..32d4f2cab94e2 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+@@ -363,6 +363,9 @@ void mt7921_set_stream_he_caps(struct mt7921_phy *phy);
+ void mt7921_update_channel(struct mt76_phy *mphy);
+ int mt7921_init_debugfs(struct mt7921_dev *dev);
+
++int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev,
++ struct ieee80211_vif *vif,
++ bool enable);
+ int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev,
+ struct ieee80211_ampdu_params *params,
+ bool enable);
+@@ -371,20 +374,12 @@ int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev,
+ bool enable);
+ void mt7921_scan_work(struct work_struct *work);
+ int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif);
+-int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif,
+- bool enable);
+-int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
+- bool enable);
+ int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev);
+ int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev);
+ int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev);
+ void mt7921_pm_wake_work(struct work_struct *work);
+ void mt7921_pm_power_save_work(struct work_struct *work);
+ bool mt7921_wait_for_mcu_init(struct mt7921_dev *dev);
+-int mt7921_mac_set_beacon_filter(struct mt7921_phy *phy,
+- struct ieee80211_vif *vif,
+- bool enable);
+-void mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif);
+ void mt7921_coredump_work(struct work_struct *work);
+ int mt7921_wfsys_reset(struct mt7921_dev *dev);
+ int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr);
+diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
+index 10d7e7e1b5530..e0a614acee059 100644
+--- a/drivers/pci/hotplug/pciehp.h
++++ b/drivers/pci/hotplug/pciehp.h
+@@ -192,6 +192,8 @@ int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status);
+ int pciehp_set_raw_indicator_status(struct hotplug_slot *h_slot, u8 status);
+ int pciehp_get_raw_indicator_status(struct hotplug_slot *h_slot, u8 *status);
+
++int pciehp_slot_reset(struct pcie_device *dev);
++
+ static inline const char *slot_name(struct controller *ctrl)
+ {
+ return hotplug_slot_name(&ctrl->hotplug_slot);
+diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
+index e7fe4b42f0394..4042d87d539dd 100644
+--- a/drivers/pci/hotplug/pciehp_core.c
++++ b/drivers/pci/hotplug/pciehp_core.c
+@@ -351,6 +351,8 @@ static struct pcie_port_service_driver hpdriver_portdrv = {
+ .runtime_suspend = pciehp_runtime_suspend,
+ .runtime_resume = pciehp_runtime_resume,
+ #endif /* PM */
++
++ .slot_reset = pciehp_slot_reset,
+ };
+
+ int __init pcie_hp_init(void)
+diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
+index 8bedbc77fe95f..60098a701e83a 100644
+--- a/drivers/pci/hotplug/pciehp_hpc.c
++++ b/drivers/pci/hotplug/pciehp_hpc.c
+@@ -865,6 +865,32 @@ void pcie_disable_interrupt(struct controller *ctrl)
+ pcie_write_cmd(ctrl, 0, mask);
+ }
+
++/**
++ * pciehp_slot_reset() - ignore link event caused by error-induced hot reset
++ * @dev: PCI Express port service device
++ *
++ * Called from pcie_portdrv_slot_reset() after AER or DPC initiated a reset
++ * further up in the hierarchy to recover from an error. The reset was
++ * propagated down to this hotplug port. Ignore the resulting link flap.
++ * If the link failed to retrain successfully, synthesize the ignored event.
++ * Surprise removal during reset is detected through Presence Detect Changed.
++ */
++int pciehp_slot_reset(struct pcie_device *dev)
++{
++ struct controller *ctrl = get_service_data(dev);
++
++ if (ctrl->state != ON_STATE)
++ return 0;
++
++ pcie_capability_write_word(dev->port, PCI_EXP_SLTSTA,
++ PCI_EXP_SLTSTA_DLLSC);
++
++ if (!pciehp_check_link_active(ctrl))
++ pciehp_request(ctrl, PCI_EXP_SLTSTA_DLLSC);
++
++ return 0;
++}
++
+ /*
+ * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary
+ * bus reset of the bridge, but at the same time we want to ensure that it is
+diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
+index 2ff5724b8f13f..41fe1ffd59078 100644
+--- a/drivers/pci/pcie/portdrv.h
++++ b/drivers/pci/pcie/portdrv.h
+@@ -85,6 +85,8 @@ struct pcie_port_service_driver {
+ int (*runtime_suspend)(struct pcie_device *dev);
+ int (*runtime_resume)(struct pcie_device *dev);
+
++ int (*slot_reset)(struct pcie_device *dev);
++
+ /* Device driver may resume normal operations */
+ void (*error_resume)(struct pci_dev *dev);
+
+@@ -110,6 +112,7 @@ void pcie_port_service_unregister(struct pcie_port_service_driver *new);
+
+ extern struct bus_type pcie_port_bus_type;
+ int pcie_port_device_register(struct pci_dev *dev);
++int pcie_port_device_iter(struct device *dev, void *data);
+ #ifdef CONFIG_PM
+ int pcie_port_device_suspend(struct device *dev);
+ int pcie_port_device_resume_noirq(struct device *dev);
+diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
+index 3ee63968deaa5..604feeb84ee40 100644
+--- a/drivers/pci/pcie/portdrv_core.c
++++ b/drivers/pci/pcie/portdrv_core.c
+@@ -367,24 +367,24 @@ error_disable:
+ return status;
+ }
+
+-#ifdef CONFIG_PM
+-typedef int (*pcie_pm_callback_t)(struct pcie_device *);
++typedef int (*pcie_callback_t)(struct pcie_device *);
+
+-static int pm_iter(struct device *dev, void *data)
++int pcie_port_device_iter(struct device *dev, void *data)
+ {
+ struct pcie_port_service_driver *service_driver;
+ size_t offset = *(size_t *)data;
+- pcie_pm_callback_t cb;
++ pcie_callback_t cb;
+
+ if ((dev->bus == &pcie_port_bus_type) && dev->driver) {
+ service_driver = to_service_driver(dev->driver);
+- cb = *(pcie_pm_callback_t *)((void *)service_driver + offset);
++ cb = *(pcie_callback_t *)((void *)service_driver + offset);
+ if (cb)
+ return cb(to_pcie_device(dev));
+ }
+ return 0;
+ }
+
++#ifdef CONFIG_PM
+ /**
+ * pcie_port_device_suspend - suspend port services associated with a PCIe port
+ * @dev: PCI Express port to handle
+@@ -392,13 +392,13 @@ static int pm_iter(struct device *dev, void *data)
+ int pcie_port_device_suspend(struct device *dev)
+ {
+ size_t off = offsetof(struct pcie_port_service_driver, suspend);
+- return device_for_each_child(dev, &off, pm_iter);
++ return device_for_each_child(dev, &off, pcie_port_device_iter);
+ }
+
+ int pcie_port_device_resume_noirq(struct device *dev)
+ {
+ size_t off = offsetof(struct pcie_port_service_driver, resume_noirq);
+- return device_for_each_child(dev, &off, pm_iter);
++ return device_for_each_child(dev, &off, pcie_port_device_iter);
+ }
+
+ /**
+@@ -408,7 +408,7 @@ int pcie_port_device_resume_noirq(struct device *dev)
+ int pcie_port_device_resume(struct device *dev)
+ {
+ size_t off = offsetof(struct pcie_port_service_driver, resume);
+- return device_for_each_child(dev, &off, pm_iter);
++ return device_for_each_child(dev, &off, pcie_port_device_iter);
+ }
+
+ /**
+@@ -418,7 +418,7 @@ int pcie_port_device_resume(struct device *dev)
+ int pcie_port_device_runtime_suspend(struct device *dev)
+ {
+ size_t off = offsetof(struct pcie_port_service_driver, runtime_suspend);
+- return device_for_each_child(dev, &off, pm_iter);
++ return device_for_each_child(dev, &off, pcie_port_device_iter);
+ }
+
+ /**
+@@ -428,7 +428,7 @@ int pcie_port_device_runtime_suspend(struct device *dev)
+ int pcie_port_device_runtime_resume(struct device *dev)
+ {
+ size_t off = offsetof(struct pcie_port_service_driver, runtime_resume);
+- return device_for_each_child(dev, &off, pm_iter);
++ return device_for_each_child(dev, &off, pcie_port_device_iter);
+ }
+ #endif /* PM */
+
+diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
+index c7ff1eea225ab..1af74c3d9d5db 100644
+--- a/drivers/pci/pcie/portdrv_pci.c
++++ b/drivers/pci/pcie/portdrv_pci.c
+@@ -160,6 +160,9 @@ static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev,
+
+ static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
+ {
++ size_t off = offsetof(struct pcie_port_service_driver, slot_reset);
++ device_for_each_child(&dev->dev, &off, pcie_port_device_iter);
++
+ pci_restore_state(dev);
+ pci_save_state(dev);
+ return PCI_ERS_RESULT_RECOVERED;
+diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c
+index 4ada80317a3bd..b5c1a8f363f32 100644
+--- a/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c
++++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c
+@@ -158,26 +158,26 @@ static const struct sunxi_desc_pin sun8i_a83t_pins[] = {
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+- SUNXI_FUNCTION(0x2, "nand"), /* DQ6 */
++ SUNXI_FUNCTION(0x2, "nand0"), /* DQ6 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+- SUNXI_FUNCTION(0x2, "nand"), /* DQ7 */
++ SUNXI_FUNCTION(0x2, "nand0"), /* DQ7 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+- SUNXI_FUNCTION(0x2, "nand"), /* DQS */
++ SUNXI_FUNCTION(0x2, "nand0"), /* DQS */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* RST */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+- SUNXI_FUNCTION(0x2, "nand")), /* CE2 */
++ SUNXI_FUNCTION(0x2, "nand0")), /* CE2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 18),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+- SUNXI_FUNCTION(0x2, "nand")), /* CE3 */
++ SUNXI_FUNCTION(0x2, "nand0")), /* CE3 */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+index ce3f9ea415117..1431ab21aca6f 100644
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+@@ -544,6 +544,8 @@ static int sunxi_pconf_set(struct pinctrl_dev *pctldev, unsigned pin,
+ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ int i;
+
++ pin -= pctl->desc->pin_base;
++
+ for (i = 0; i < num_configs; i++) {
+ enum pin_config_param param;
+ unsigned long flags;
+diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
+index 1b65bb61ce888..c4f917d45b51d 100644
+--- a/drivers/platform/x86/wmi.c
++++ b/drivers/platform/x86/wmi.c
+@@ -51,6 +51,11 @@ struct guid_block {
+ u8 flags;
+ };
+
++enum { /* wmi_block flags */
++ WMI_READ_TAKES_NO_ARGS,
++ WMI_PROBED,
++};
++
+ struct wmi_block {
+ struct wmi_device dev;
+ struct list_head list;
+@@ -61,8 +66,7 @@ struct wmi_block {
+ wmi_notify_handler handler;
+ void *handler_data;
+ u64 req_buf_size;
+-
+- bool read_takes_no_args;
++ unsigned long flags;
+ };
+
+
+@@ -325,7 +329,7 @@ static acpi_status __query_block(struct wmi_block *wblock, u8 instance,
+ wq_params[0].type = ACPI_TYPE_INTEGER;
+ wq_params[0].integer.value = instance;
+
+- if (instance == 0 && wblock->read_takes_no_args)
++ if (instance == 0 && test_bit(WMI_READ_TAKES_NO_ARGS, &wblock->flags))
+ input.count = 0;
+
+ /*
+@@ -676,6 +680,11 @@ static struct wmi_device *dev_to_wdev(struct device *dev)
+ return container_of(dev, struct wmi_device, dev);
+ }
+
++static inline struct wmi_driver *drv_to_wdrv(struct device_driver *drv)
++{
++ return container_of(drv, struct wmi_driver, driver);
++}
++
+ /*
+ * sysfs interface
+ */
+@@ -794,8 +803,7 @@ static void wmi_dev_release(struct device *dev)
+
+ static int wmi_dev_match(struct device *dev, struct device_driver *driver)
+ {
+- struct wmi_driver *wmi_driver =
+- container_of(driver, struct wmi_driver, driver);
++ struct wmi_driver *wmi_driver = drv_to_wdrv(driver);
+ struct wmi_block *wblock = dev_to_wblock(dev);
+ const struct wmi_device_id *id = wmi_driver->id_table;
+
+@@ -892,8 +900,7 @@ static long wmi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+ }
+
+ /* let the driver do any filtering and do the call */
+- wdriver = container_of(wblock->dev.dev.driver,
+- struct wmi_driver, driver);
++ wdriver = drv_to_wdrv(wblock->dev.dev.driver);
+ if (!try_module_get(wdriver->driver.owner)) {
+ ret = -EBUSY;
+ goto out_ioctl;
+@@ -926,8 +933,7 @@ static const struct file_operations wmi_fops = {
+ static int wmi_dev_probe(struct device *dev)
+ {
+ struct wmi_block *wblock = dev_to_wblock(dev);
+- struct wmi_driver *wdriver =
+- container_of(dev->driver, struct wmi_driver, driver);
++ struct wmi_driver *wdriver = drv_to_wdrv(dev->driver);
+ int ret = 0;
+ char *buf;
+
+@@ -975,6 +981,7 @@ static int wmi_dev_probe(struct device *dev)
+ }
+ }
+
++ set_bit(WMI_PROBED, &wblock->flags);
+ return 0;
+
+ probe_misc_failure:
+@@ -990,8 +997,9 @@ probe_failure:
+ static void wmi_dev_remove(struct device *dev)
+ {
+ struct wmi_block *wblock = dev_to_wblock(dev);
+- struct wmi_driver *wdriver =
+- container_of(dev->driver, struct wmi_driver, driver);
++ struct wmi_driver *wdriver = drv_to_wdrv(dev->driver);
++
++ clear_bit(WMI_PROBED, &wblock->flags);
+
+ if (wdriver->filter_callback) {
+ misc_deregister(&wblock->char_dev);
+@@ -1086,7 +1094,7 @@ static int wmi_create_device(struct device *wmi_bus_dev,
+ * laptops, WQxx may not be a method at all.)
+ */
+ if (info->type != ACPI_TYPE_METHOD || info->param_count == 0)
+- wblock->read_takes_no_args = true;
++ set_bit(WMI_READ_TAKES_NO_ARGS, &wblock->flags);
+
+ kfree(info);
+
+@@ -1295,16 +1303,13 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event,
+ return;
+
+ /* If a driver is bound, then notify the driver. */
+- if (wblock->dev.dev.driver) {
+- struct wmi_driver *driver;
++ if (test_bit(WMI_PROBED, &wblock->flags) && wblock->dev.dev.driver) {
++ struct wmi_driver *driver = drv_to_wdrv(wblock->dev.dev.driver);
+ struct acpi_object_list input;
+ union acpi_object params[1];
+ struct acpi_buffer evdata = { ACPI_ALLOCATE_BUFFER, NULL };
+ acpi_status status;
+
+- driver = container_of(wblock->dev.dev.driver,
+- struct wmi_driver, driver);
+-
+ input.count = 1;
+ input.pointer = params;
+ params[0].type = ACPI_TYPE_INTEGER;
+diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
+index 2ea35e47ea441..303ad60d1d49d 100644
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -3759,6 +3759,7 @@ struct qla_qpair {
+ struct qla_fw_resources fwres ____cacheline_aligned;
+ u32 cmd_cnt;
+ u32 cmd_completion_cnt;
++ u32 prev_completion_cnt;
+ };
+
+ /* Place holder for FW buffer parameters */
+@@ -4618,7 +4619,9 @@ struct qla_hw_data {
+ struct qla_chip_state_84xx *cs84xx;
+ struct isp_operations *isp_ops;
+ struct workqueue_struct *wq;
++ struct work_struct heartbeat_work;
+ struct qlfc_fw fw_buf;
++ unsigned long last_heartbeat_run_jiffies;
+
+ /* FCP_CMND priority support */
+ struct qla_fcp_prio_cfg *fcp_prio_cfg;
+@@ -4719,7 +4722,6 @@ struct qla_hw_data {
+
+ struct qla_hw_data_stat stat;
+ pci_error_state_t pci_error_state;
+- u64 prev_cmd_cnt;
+ struct dma_pool *purex_dma_pool;
+ struct btree_head32 host_map;
+
+@@ -4865,7 +4867,6 @@ typedef struct scsi_qla_host {
+ #define SET_ZIO_THRESHOLD_NEEDED 32
+ #define ISP_ABORT_TO_ROM 33
+ #define VPORT_DELETE 34
+-#define HEARTBEAT_CHK 38
+
+ #define PROCESS_PUREX_IOCB 63
+
+diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c
+index a00fe88c60218..e40b9cc382146 100644
+--- a/drivers/scsi/qla2xxx/qla_edif.c
++++ b/drivers/scsi/qla2xxx/qla_edif.c
+@@ -1684,41 +1684,25 @@ static struct enode *
+ qla_enode_find(scsi_qla_host_t *vha, uint32_t ntype, uint32_t p1, uint32_t p2)
+ {
+ struct enode *node_rtn = NULL;
+- struct enode *list_node = NULL;
++ struct enode *list_node, *q;
+ unsigned long flags;
+- struct list_head *pos, *q;
+ uint32_t sid;
+- uint32_t rw_flag;
+ struct purexevent *purex;
+
+ /* secure the list from moving under us */
+ spin_lock_irqsave(&vha->pur_cinfo.pur_lock, flags);
+
+- list_for_each_safe(pos, q, &vha->pur_cinfo.head) {
+- list_node = list_entry(pos, struct enode, list);
++ list_for_each_entry_safe(list_node, q, &vha->pur_cinfo.head, list) {
+
+ /* node type determines what p1 and p2 are */
+ purex = &list_node->u.purexinfo;
+ sid = p1;
+- rw_flag = p2;
+
+ if (purex->pur_info.pur_sid.b24 == sid) {
+- if (purex->pur_info.pur_pend == 1 &&
+- rw_flag == PUR_GET) {
+- /*
+- * if the receive is in progress
+- * and its a read/get then can't
+- * transfer yet
+- */
+- ql_dbg(ql_dbg_edif, vha, 0x9106,
+- "%s purex xfer in progress for sid=%x\n",
+- __func__, sid);
+- } else {
+- /* found it and its complete */
+- node_rtn = list_node;
+- list_del(pos);
+- break;
+- }
++ /* found it and its complete */
++ node_rtn = list_node;
++ list_del(&list_node->list);
++ break;
+ }
+ }
+
+@@ -2428,7 +2412,6 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
+
+ purex = &ptr->u.purexinfo;
+ purex->pur_info.pur_sid = a.did;
+- purex->pur_info.pur_pend = 0;
+ purex->pur_info.pur_bytes_rcvd = totlen;
+ purex->pur_info.pur_rx_xchg_address = le32_to_cpu(p->rx_xchg_addr);
+ purex->pur_info.pur_nphdl = le16_to_cpu(p->nport_handle);
+@@ -3180,18 +3163,14 @@ static uint16_t qla_edif_sadb_get_sa_index(fc_port_t *fcport,
+ /* release any sadb entries -- only done at teardown */
+ void qla_edif_sadb_release(struct qla_hw_data *ha)
+ {
+- struct list_head *pos;
+- struct list_head *tmp;
+- struct edif_sa_index_entry *entry;
++ struct edif_sa_index_entry *entry, *tmp;
+
+- list_for_each_safe(pos, tmp, &ha->sadb_rx_index_list) {
+- entry = list_entry(pos, struct edif_sa_index_entry, next);
++ list_for_each_entry_safe(entry, tmp, &ha->sadb_rx_index_list, next) {
+ list_del(&entry->next);
+ kfree(entry);
+ }
+
+- list_for_each_safe(pos, tmp, &ha->sadb_tx_index_list) {
+- entry = list_entry(pos, struct edif_sa_index_entry, next);
++ list_for_each_entry_safe(entry, tmp, &ha->sadb_tx_index_list, next) {
+ list_del(&entry->next);
+ kfree(entry);
+ }
+diff --git a/drivers/scsi/qla2xxx/qla_edif.h b/drivers/scsi/qla2xxx/qla_edif.h
+index 45cf87e337780..32800bfb32a38 100644
+--- a/drivers/scsi/qla2xxx/qla_edif.h
++++ b/drivers/scsi/qla2xxx/qla_edif.h
+@@ -101,7 +101,6 @@ struct dinfo {
+ };
+
+ struct pur_ninfo {
+- unsigned int pur_pend:1;
+ port_id_t pur_sid;
+ port_id_t pur_did;
+ uint8_t vp_idx;
+diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
+index af8df5a800c61..c3ba2995209bd 100644
+--- a/drivers/scsi/qla2xxx/qla_init.c
++++ b/drivers/scsi/qla2xxx/qla_init.c
+@@ -7096,12 +7096,14 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
+ ha->chip_reset++;
+ ha->base_qpair->chip_reset = ha->chip_reset;
+ ha->base_qpair->cmd_cnt = ha->base_qpair->cmd_completion_cnt = 0;
++ ha->base_qpair->prev_completion_cnt = 0;
+ for (i = 0; i < ha->max_qpairs; i++) {
+ if (ha->queue_pair_map[i]) {
+ ha->queue_pair_map[i]->chip_reset =
+ ha->base_qpair->chip_reset;
+ ha->queue_pair_map[i]->cmd_cnt =
+ ha->queue_pair_map[i]->cmd_completion_cnt = 0;
++ ha->base_qpair->prev_completion_cnt = 0;
+ }
+ }
+
+diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
+index 42b29f4fd9371..1bf3ab10846aa 100644
+--- a/drivers/scsi/qla2xxx/qla_nvme.c
++++ b/drivers/scsi/qla2xxx/qla_nvme.c
+@@ -775,7 +775,6 @@ int qla_nvme_register_hba(struct scsi_qla_host *vha)
+ ha = vha->hw;
+ tmpl = &qla_nvme_fc_transport;
+
+- WARN_ON(vha->nvme_local_port);
+
+ qla_nvme_fc_transport.max_hw_queues =
+ min((uint8_t)(qla_nvme_fc_transport.max_hw_queues),
+@@ -786,13 +785,25 @@ int qla_nvme_register_hba(struct scsi_qla_host *vha)
+ pinfo.port_role = FC_PORT_ROLE_NVME_INITIATOR;
+ pinfo.port_id = vha->d_id.b24;
+
+- ql_log(ql_log_info, vha, 0xffff,
+- "register_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n",
+- pinfo.node_name, pinfo.port_name, pinfo.port_id);
+- qla_nvme_fc_transport.dma_boundary = vha->host->dma_boundary;
+-
+- ret = nvme_fc_register_localport(&pinfo, tmpl,
+- get_device(&ha->pdev->dev), &vha->nvme_local_port);
++ mutex_lock(&ha->vport_lock);
++ /*
++ * Check again for nvme_local_port to see if any other thread raced
++ * with this one and finished registration.
++ */
++ if (!vha->nvme_local_port) {
++ ql_log(ql_log_info, vha, 0xffff,
++ "register_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n",
++ pinfo.node_name, pinfo.port_name, pinfo.port_id);
++ qla_nvme_fc_transport.dma_boundary = vha->host->dma_boundary;
++
++ ret = nvme_fc_register_localport(&pinfo, tmpl,
++ get_device(&ha->pdev->dev),
++ &vha->nvme_local_port);
++ mutex_unlock(&ha->vport_lock);
++ } else {
++ mutex_unlock(&ha->vport_lock);
++ return 0;
++ }
+ if (ret) {
+ ql_log(ql_log_warn, vha, 0xffff,
+ "register_localport failed: ret=%x\n", ret);
+diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
+index 77c0bf06f162b..e683b1c01c9f5 100644
+--- a/drivers/scsi/qla2xxx/qla_os.c
++++ b/drivers/scsi/qla2xxx/qla_os.c
+@@ -2779,6 +2779,16 @@ qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
+ return atomic_read(&vha->loop_state) == LOOP_READY;
+ }
+
++static void qla_heartbeat_work_fn(struct work_struct *work)
++{
++ struct qla_hw_data *ha = container_of(work,
++ struct qla_hw_data, heartbeat_work);
++ struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
++
++ if (!ha->flags.mbox_busy && base_vha->flags.init_done)
++ qla_no_op_mb(base_vha);
++}
++
+ static void qla2x00_iocb_work_fn(struct work_struct *work)
+ {
+ struct scsi_qla_host *vha = container_of(work,
+@@ -3217,6 +3227,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+ host->transportt, sht->vendor_id);
+
+ INIT_WORK(&base_vha->iocb_work, qla2x00_iocb_work_fn);
++ INIT_WORK(&ha->heartbeat_work, qla_heartbeat_work_fn);
+
+ /* Set up the irqs */
+ ret = qla2x00_request_irqs(ha, rsp);
+@@ -3875,13 +3886,15 @@ qla2x00_remove_one(struct pci_dev *pdev)
+ static inline void
+ qla24xx_free_purex_list(struct purex_list *list)
+ {
+- struct list_head *item, *next;
++ struct purex_item *item, *next;
+ ulong flags;
+
+ spin_lock_irqsave(&list->lock, flags);
+- list_for_each_safe(item, next, &list->head) {
+- list_del(item);
+- kfree(list_entry(item, struct purex_item, list));
++ list_for_each_entry_safe(item, next, &list->head, list) {
++ list_del(&item->list);
++ if (item == &item->vha->default_item)
++ continue;
++ kfree(item);
+ }
+ spin_unlock_irqrestore(&list->lock, flags);
+ }
+@@ -7103,17 +7116,6 @@ intr_on_check:
+ qla2x00_lip_reset(base_vha);
+ }
+
+- if (test_bit(HEARTBEAT_CHK, &base_vha->dpc_flags)) {
+- /*
+- * if there is a mb in progress then that's
+- * enough of a check to see if fw is still ticking.
+- */
+- if (!ha->flags.mbox_busy && base_vha->flags.init_done)
+- qla_no_op_mb(base_vha);
+-
+- clear_bit(HEARTBEAT_CHK, &base_vha->dpc_flags);
+- }
+-
+ ha->dpc_active = 0;
+ end_loop:
+ set_current_state(TASK_INTERRUPTIBLE);
+@@ -7172,56 +7174,61 @@ qla2x00_rst_aen(scsi_qla_host_t *vha)
+
+ static bool qla_do_heartbeat(struct scsi_qla_host *vha)
+ {
+- u64 cmd_cnt, prev_cmd_cnt;
+- bool do_hb = false;
+ struct qla_hw_data *ha = vha->hw;
+- int i;
++ u32 cmpl_cnt;
++ u16 i;
++ bool do_heartbeat = false;
+
+- /* if cmds are still pending down in fw, then do hb */
+- if (ha->base_qpair->cmd_cnt != ha->base_qpair->cmd_completion_cnt) {
+- do_hb = true;
++ /*
++ * Allow do_heartbeat only if we don’t have any active interrupts,
++ * but there are still IOs outstanding with firmware.
++ */
++ cmpl_cnt = ha->base_qpair->cmd_completion_cnt;
++ if (cmpl_cnt == ha->base_qpair->prev_completion_cnt &&
++ cmpl_cnt != ha->base_qpair->cmd_cnt) {
++ do_heartbeat = true;
+ goto skip;
+ }
++ ha->base_qpair->prev_completion_cnt = cmpl_cnt;
+
+ for (i = 0; i < ha->max_qpairs; i++) {
+- if (ha->queue_pair_map[i] &&
+- ha->queue_pair_map[i]->cmd_cnt !=
+- ha->queue_pair_map[i]->cmd_completion_cnt) {
+- do_hb = true;
+- break;
++ if (ha->queue_pair_map[i]) {
++ cmpl_cnt = ha->queue_pair_map[i]->cmd_completion_cnt;
++ if (cmpl_cnt == ha->queue_pair_map[i]->prev_completion_cnt &&
++ cmpl_cnt != ha->queue_pair_map[i]->cmd_cnt) {
++ do_heartbeat = true;
++ break;
++ }
++ ha->queue_pair_map[i]->prev_completion_cnt = cmpl_cnt;
+ }
+ }
+
+ skip:
+- prev_cmd_cnt = ha->prev_cmd_cnt;
+- cmd_cnt = ha->base_qpair->cmd_cnt;
+- for (i = 0; i < ha->max_qpairs; i++) {
+- if (ha->queue_pair_map[i])
+- cmd_cnt += ha->queue_pair_map[i]->cmd_cnt;
+- }
+- ha->prev_cmd_cnt = cmd_cnt;
+-
+- if (!do_hb && ((cmd_cnt - prev_cmd_cnt) > 50))
+- /*
+- * IOs are completing before periodic hb check.
+- * IOs seems to be running, do hb for sanity check.
+- */
+- do_hb = true;
+-
+- return do_hb;
++ return do_heartbeat;
+ }
+
+-static void qla_heart_beat(struct scsi_qla_host *vha)
++static void qla_heart_beat(struct scsi_qla_host *vha, u16 dpc_started)
+ {
++ struct qla_hw_data *ha = vha->hw;
++
+ if (vha->vp_idx)
+ return;
+
+ if (vha->hw->flags.eeh_busy || qla2x00_chip_is_down(vha))
+ return;
+
++ /*
++ * dpc thread cannot run if heartbeat is running at the same time.
++ * We also do not want to starve heartbeat task. Therefore, do
++ * heartbeat task at least once every 5 seconds.
++ */
++ if (dpc_started &&
++ time_before(jiffies, ha->last_heartbeat_run_jiffies + 5 * HZ))
++ return;
++
+ if (qla_do_heartbeat(vha)) {
+- set_bit(HEARTBEAT_CHK, &vha->dpc_flags);
+- qla2xxx_wake_dpc(vha);
++ ha->last_heartbeat_run_jiffies = jiffies;
++ queue_work(ha->wq, &ha->heartbeat_work);
+ }
+ }
+
+@@ -7413,6 +7420,8 @@ qla2x00_timer(struct timer_list *t)
+ start_dpc++;
+ }
+
++ /* borrowing w to signify dpc will run */
++ w = 0;
+ /* Schedule the DPC routine if needed */
+ if ((test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
+ test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) ||
+@@ -7445,9 +7454,10 @@ qla2x00_timer(struct timer_list *t)
+ test_bit(RELOGIN_NEEDED, &vha->dpc_flags),
+ test_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags));
+ qla2xxx_wake_dpc(vha);
++ w = 1;
+ }
+
+- qla_heart_beat(vha);
++ qla_heart_beat(vha, w);
+
+ qla2x00_restart_timer(vha, WATCH_INTERVAL);
+ }
+diff --git a/drivers/soc/atmel/soc.c b/drivers/soc/atmel/soc.c
+index a490ad7e090f2..9e3d370114474 100644
+--- a/drivers/soc/atmel/soc.c
++++ b/drivers/soc/atmel/soc.c
+@@ -91,14 +91,14 @@ static const struct at91_soc socs[] __initconst = {
+ AT91_SOC(SAM9X60_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
+ AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH,
+ "sam9x60", "sam9x60"),
+- AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D5M_EXID_MATCH,
+- AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH,
++ AT91_SOC(SAM9X60_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
++ AT91_CIDR_VERSION_MASK, SAM9X60_D5M_EXID_MATCH,
+ "sam9x60 64MiB DDR2 SiP", "sam9x60"),
+- AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D1G_EXID_MATCH,
+- AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH,
++ AT91_SOC(SAM9X60_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
++ AT91_CIDR_VERSION_MASK, SAM9X60_D1G_EXID_MATCH,
+ "sam9x60 128MiB DDR2 SiP", "sam9x60"),
+- AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D6K_EXID_MATCH,
+- AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH,
++ AT91_SOC(SAM9X60_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
++ AT91_CIDR_VERSION_MASK, SAM9X60_D6K_EXID_MATCH,
+ "sam9x60 8MiB SDRAM SiP", "sam9x60"),
+ #endif
+ #ifdef CONFIG_SOC_SAMA5
+diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
+index 6734ef22c304a..4946a241e323f 100644
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -137,6 +137,7 @@ struct gsm_dlci {
+ int retries;
+ /* Uplink tty if active */
+ struct tty_port port; /* The tty bound to this DLCI if there is one */
++#define TX_SIZE 4096 /* Must be power of 2. */
+ struct kfifo fifo; /* Queue fifo for the DLCI */
+ int adaption; /* Adaption layer in use */
+ int prev_adaption;
+@@ -221,7 +222,6 @@ struct gsm_mux {
+ int encoding;
+ u8 control;
+ u8 fcs;
+- u8 received_fcs;
+ u8 *txframe; /* TX framing buffer */
+
+ /* Method for the receiver side */
+@@ -274,6 +274,10 @@ static DEFINE_SPINLOCK(gsm_mux_lock);
+
+ static struct tty_driver *gsm_tty_driver;
+
++/* Save dlci open address */
++static int addr_open[256] = { 0 };
++/* Save dlci open count */
++static int addr_cnt;
+ /*
+ * This section of the driver logic implements the GSM encodings
+ * both the basic and the 'advanced'. Reliable transport is not
+@@ -368,6 +372,7 @@ static const u8 gsm_fcs8[256] = {
+ #define GOOD_FCS 0xCF
+
+ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len);
++static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk);
+
+ /**
+ * gsm_fcs_add - update FCS
+@@ -466,7 +471,7 @@ static void gsm_hex_dump_bytes(const char *fname, const u8 *data,
+ * gsm_print_packet - display a frame for debug
+ * @hdr: header to print before decode
+ * @addr: address EA from the frame
+- * @cr: C/R bit from the frame
++ * @cr: C/R bit seen as initiator
+ * @control: control including PF bit
+ * @data: following data bytes
+ * @dlen: length of data
+@@ -566,7 +571,7 @@ static int gsm_stuff_frame(const u8 *input, u8 *output, int len)
+ * gsm_send - send a control frame
+ * @gsm: our GSM mux
+ * @addr: address for control frame
+- * @cr: command/response bit
++ * @cr: command/response bit seen as initiator
+ * @control: control byte including PF bit
+ *
+ * Format up and transmit a control frame. These do not go via the
+@@ -581,11 +586,15 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
+ int len;
+ u8 cbuf[10];
+ u8 ibuf[3];
++ int ocr;
++
++ /* toggle C/R coding if not initiator */
++ ocr = cr ^ (gsm->initiator ? 0 : 1);
+
+ switch (gsm->encoding) {
+ case 0:
+ cbuf[0] = GSM0_SOF;
+- cbuf[1] = (addr << 2) | (cr << 1) | EA;
++ cbuf[1] = (addr << 2) | (ocr << 1) | EA;
+ cbuf[2] = control;
+ cbuf[3] = EA; /* Length of data = 0 */
+ cbuf[4] = 0xFF - gsm_fcs_add_block(INIT_FCS, cbuf + 1, 3);
+@@ -595,7 +604,7 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
+ case 1:
+ case 2:
+ /* Control frame + packing (but not frame stuffing) in mode 1 */
+- ibuf[0] = (addr << 2) | (cr << 1) | EA;
++ ibuf[0] = (addr << 2) | (ocr << 1) | EA;
+ ibuf[1] = control;
+ ibuf[2] = 0xFF - gsm_fcs_add_block(INIT_FCS, ibuf, 2);
+ /* Stuffing may double the size worst case */
+@@ -924,6 +933,66 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
+ return size;
+ }
+
++/**
++ * gsm_dlci_modem_output - try and push modem status out of a DLCI
++ * @gsm: mux
++ * @dlci: the DLCI to pull modem status from
++ * @brk: break signal
++ *
++ * Push an empty frame in to the transmit queue to update the modem status
++ * bits and to transmit an optional break.
++ *
++ * Caller must hold the tx_lock of the mux.
++ */
++
++static int gsm_dlci_modem_output(struct gsm_mux *gsm, struct gsm_dlci *dlci,
++ u8 brk)
++{
++ u8 *dp = NULL;
++ struct gsm_msg *msg;
++ int size = 0;
++
++ /* for modem bits without break data */
++ switch (dlci->adaption) {
++ case 1: /* Unstructured */
++ break;
++ case 2: /* Unstructured with modem bits. */
++ size++;
++ if (brk > 0)
++ size++;
++ break;
++ default:
++ pr_err("%s: unsupported adaption %d\n", __func__,
++ dlci->adaption);
++ return -EINVAL;
++ }
++
++ msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
++ if (!msg) {
++ pr_err("%s: gsm_data_alloc error", __func__);
++ return -ENOMEM;
++ }
++ dp = msg->data;
++ switch (dlci->adaption) {
++ case 1: /* Unstructured */
++ break;
++ case 2: /* Unstructured with modem bits. */
++ if (brk == 0) {
++ *dp++ = (gsm_encode_modem(dlci) << 1) | EA;
++ } else {
++ *dp++ = gsm_encode_modem(dlci) << 1;
++ *dp++ = (brk << 4) | 2 | EA; /* Length, Break, EA */
++ }
++ break;
++ default:
++ /* Handled above */
++ break;
++ }
++
++ __gsm_data_queue(dlci, msg);
++ return size;
++}
++
+ /**
+ * gsm_dlci_data_sweep - look for data to send
+ * @gsm: the GSM mux
+@@ -1191,6 +1260,7 @@ static void gsm_control_rls(struct gsm_mux *gsm, const u8 *data, int clen)
+ }
+
+ static void gsm_dlci_begin_close(struct gsm_dlci *dlci);
++static void gsm_dlci_close(struct gsm_dlci *dlci);
+
+ /**
+ * gsm_control_message - DLCI 0 control processing
+@@ -1209,15 +1279,28 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
+ {
+ u8 buf[1];
+ unsigned long flags;
++ struct gsm_dlci *dlci;
++ int i;
++ int address;
+
+ switch (command) {
+ case CMD_CLD: {
+- struct gsm_dlci *dlci = gsm->dlci[0];
++ if (addr_cnt > 0) {
++ for (i = 0; i < addr_cnt; i++) {
++ address = addr_open[i];
++ dlci = gsm->dlci[address];
++ gsm_dlci_close(dlci);
++ addr_open[i] = 0;
++ }
++ }
+ /* Modem wishes to close down */
++ dlci = gsm->dlci[0];
+ if (dlci) {
+ dlci->dead = true;
+ gsm->dead = true;
+- gsm_dlci_begin_close(dlci);
++ gsm_dlci_close(dlci);
++ addr_cnt = 0;
++ gsm_response(gsm, 0, UA|PF);
+ }
+ }
+ break;
+@@ -1472,6 +1555,9 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
+ dlci->state = DLCI_OPEN;
+ if (debug & 8)
+ pr_debug("DLCI %d goes open.\n", dlci->addr);
++ /* Send current modem state */
++ if (dlci->addr)
++ gsm_modem_update(dlci, 0);
+ wake_up(&dlci->gsm->event);
+ }
+
+@@ -1677,7 +1763,7 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
+ return NULL;
+ spin_lock_init(&dlci->lock);
+ mutex_init(&dlci->mutex);
+- if (kfifo_alloc(&dlci->fifo, 4096, GFP_KERNEL) < 0) {
++ if (kfifo_alloc(&dlci->fifo, TX_SIZE, GFP_KERNEL) < 0) {
+ kfree(dlci);
+ return NULL;
+ }
+@@ -1780,18 +1866,8 @@ static void gsm_queue(struct gsm_mux *gsm)
+ struct gsm_dlci *dlci;
+ u8 cr;
+ int address;
+- /* We have to sneak a look at the packet body to do the FCS.
+- A somewhat layering violation in the spec */
++ int i, j, k, address_tmp;
+
+- if ((gsm->control & ~PF) == UI)
+- gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
+- if (gsm->encoding == 0) {
+- /* WARNING: gsm->received_fcs is used for
+- gsm->encoding = 0 only.
+- In this case it contain the last piece of data
+- required to generate final CRC */
+- gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs);
+- }
+ if (gsm->fcs != GOOD_FCS) {
+ gsm->bad_fcs++;
+ if (debug & 4)
+@@ -1803,10 +1879,10 @@ static void gsm_queue(struct gsm_mux *gsm)
+ goto invalid;
+
+ cr = gsm->address & 1; /* C/R bit */
++ cr ^= gsm->initiator ? 0 : 1; /* Flip so 1 always means command */
+
+ gsm_print_packet("<--", address, cr, gsm->control, gsm->buf, gsm->len);
+
+- cr ^= 1 - gsm->initiator; /* Flip so 1 always means command */
+ dlci = gsm->dlci[address];
+
+ switch (gsm->control) {
+@@ -1818,22 +1894,52 @@ static void gsm_queue(struct gsm_mux *gsm)
+ if (dlci == NULL)
+ return;
+ if (dlci->dead)
+- gsm_response(gsm, address, DM);
++ gsm_response(gsm, address, DM|PF);
+ else {
+- gsm_response(gsm, address, UA);
++ gsm_response(gsm, address, UA|PF);
+ gsm_dlci_open(dlci);
++ /* Save dlci open address */
++ if (address) {
++ addr_open[addr_cnt] = address;
++ addr_cnt++;
++ }
+ }
+ break;
+ case DISC|PF:
+ if (cr == 0)
+ goto invalid;
+ if (dlci == NULL || dlci->state == DLCI_CLOSED) {
+- gsm_response(gsm, address, DM);
++ gsm_response(gsm, address, DM|PF);
+ return;
+ }
+ /* Real close complete */
+- gsm_response(gsm, address, UA);
+- gsm_dlci_close(dlci);
++ if (!address) {
++ if (addr_cnt > 0) {
++ for (i = 0; i < addr_cnt; i++) {
++ address = addr_open[i];
++ dlci = gsm->dlci[address];
++ gsm_dlci_close(dlci);
++ addr_open[i] = 0;
++ }
++ }
++ dlci = gsm->dlci[0];
++ gsm_dlci_close(dlci);
++ addr_cnt = 0;
++ gsm_response(gsm, 0, UA|PF);
++ } else {
++ gsm_response(gsm, address, UA|PF);
++ gsm_dlci_close(dlci);
++ /* clear dlci address */
++ for (j = 0; j < addr_cnt; j++) {
++ address_tmp = addr_open[j];
++ if (address_tmp == address) {
++ for (k = j; k < addr_cnt; k++)
++ addr_open[k] = addr_open[k+1];
++ addr_cnt--;
++ break;
++ }
++ }
++ }
+ break;
+ case UA|PF:
+ if (cr == 0 || dlci == NULL)
+@@ -1948,19 +2054,25 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
+ break;
+ case GSM_DATA: /* Data */
+ gsm->buf[gsm->count++] = c;
+- if (gsm->count == gsm->len)
++ if (gsm->count == gsm->len) {
++ /* Calculate final FCS for UI frames over all data */
++ if ((gsm->control & ~PF) != UIH) {
++ gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf,
++ gsm->count);
++ }
+ gsm->state = GSM_FCS;
++ }
+ break;
+ case GSM_FCS: /* FCS follows the packet */
+- gsm->received_fcs = c;
+- gsm_queue(gsm);
++ gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+ gsm->state = GSM_SSOF;
+ break;
+ case GSM_SSOF:
+- if (c == GSM0_SOF) {
+- gsm->state = GSM_SEARCH;
+- break;
+- }
++ gsm->state = GSM_SEARCH;
++ if (c == GSM0_SOF)
++ gsm_queue(gsm);
++ else
++ gsm->bad_size++;
+ break;
+ default:
+ pr_debug("%s: unhandled state: %d\n", __func__, gsm->state);
+@@ -1989,11 +2101,24 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
+ return;
+ }
+ if (c == GSM1_SOF) {
+- /* EOF is only valid in frame if we have got to the data state
+- and received at least one byte (the FCS) */
+- if (gsm->state == GSM_DATA && gsm->count) {
+- /* Extract the FCS */
++ /* EOF is only valid in frame if we have got to the data state */
++ if (gsm->state == GSM_DATA) {
++ if (gsm->count < 1) {
++ /* Missing FSC */
++ gsm->malformed++;
++ gsm->state = GSM_START;
++ return;
++ }
++ /* Remove the FCS from data */
+ gsm->count--;
++ if ((gsm->control & ~PF) != UIH) {
++ /* Calculate final FCS for UI frames over all
++ * data but FCS
++ */
++ gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf,
++ gsm->count);
++ }
++ /* Add the FCS itself to test against GOOD_FCS */
+ gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->buf[gsm->count]);
+ gsm->len = gsm->count;
+ gsm_queue(gsm);
+@@ -2915,14 +3040,43 @@ static struct tty_ldisc_ops tty_ldisc_packet = {
+ * Virtual tty side
+ */
+
+-#define TX_SIZE 512
++/**
++ * gsm_modem_upd_via_data - send modem bits via convergence layer
++ * @dlci: channel
++ * @brk: break signal
++ *
++ * Send an empty frame to signal mobile state changes and to transmit the
++ * break signal for adaption 2.
++ */
++
++static void gsm_modem_upd_via_data(struct gsm_dlci *dlci, u8 brk)
++{
++ struct gsm_mux *gsm = dlci->gsm;
++ unsigned long flags;
++
++ if (dlci->state != DLCI_OPEN || dlci->adaption != 2)
++ return;
++
++ spin_lock_irqsave(&gsm->tx_lock, flags);
++ gsm_dlci_modem_output(gsm, dlci, brk);
++ spin_unlock_irqrestore(&gsm->tx_lock, flags);
++}
++
++/**
++ * gsm_modem_upd_via_msc - send modem bits via control frame
++ * @dlci: channel
++ * @brk: break signal
++ */
+
+-static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
++static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk)
+ {
+ u8 modembits[3];
+ struct gsm_control *ctrl;
+ int len = 2;
+
++ if (dlci->gsm->encoding != 0)
++ return 0;
++
+ modembits[0] = (dlci->addr << 2) | 2 | EA; /* DLCI, Valid, EA */
+ if (!brk) {
+ modembits[1] = (gsm_encode_modem(dlci) << 1) | EA;
+@@ -2937,6 +3091,27 @@ static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
+ return gsm_control_wait(dlci->gsm, ctrl);
+ }
+
++/**
++ * gsm_modem_update - send modem status line state
++ * @dlci: channel
++ * @brk: break signal
++ */
++
++static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk)
++{
++ if (dlci->adaption == 2) {
++ /* Send convergence layer type 2 empty data frame. */
++ gsm_modem_upd_via_data(dlci, brk);
++ return 0;
++ } else if (dlci->gsm->encoding == 0) {
++ /* Send as MSC control message. */
++ return gsm_modem_upd_via_msc(dlci, brk);
++ }
++
++ /* Modem status lines are not supported. */
++ return -EPROTONOSUPPORT;
++}
++
+ static int gsm_carrier_raised(struct tty_port *port)
+ {
+ struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
+@@ -2969,7 +3144,7 @@ static void gsm_dtr_rts(struct tty_port *port, int onoff)
+ modem_tx &= ~(TIOCM_DTR | TIOCM_RTS);
+ if (modem_tx != dlci->modem_tx) {
+ dlci->modem_tx = modem_tx;
+- gsmtty_modem_update(dlci, 0);
++ gsm_modem_update(dlci, 0);
+ }
+ }
+
+@@ -3102,7 +3277,7 @@ static unsigned int gsmtty_write_room(struct tty_struct *tty)
+ struct gsm_dlci *dlci = tty->driver_data;
+ if (dlci->state == DLCI_CLOSED)
+ return 0;
+- return TX_SIZE - kfifo_len(&dlci->fifo);
++ return kfifo_avail(&dlci->fifo);
+ }
+
+ static unsigned int gsmtty_chars_in_buffer(struct tty_struct *tty)
+@@ -3158,7 +3333,7 @@ static int gsmtty_tiocmset(struct tty_struct *tty,
+
+ if (modem_tx != dlci->modem_tx) {
+ dlci->modem_tx = modem_tx;
+- return gsmtty_modem_update(dlci, 0);
++ return gsm_modem_update(dlci, 0);
+ }
+ return 0;
+ }
+@@ -3219,7 +3394,7 @@ static void gsmtty_throttle(struct tty_struct *tty)
+ dlci->modem_tx &= ~TIOCM_RTS;
+ dlci->throttled = true;
+ /* Send an MSC with RTS cleared */
+- gsmtty_modem_update(dlci, 0);
++ gsm_modem_update(dlci, 0);
+ }
+
+ static void gsmtty_unthrottle(struct tty_struct *tty)
+@@ -3231,7 +3406,7 @@ static void gsmtty_unthrottle(struct tty_struct *tty)
+ dlci->modem_tx |= TIOCM_RTS;
+ dlci->throttled = false;
+ /* Send an MSC with RTS set */
+- gsmtty_modem_update(dlci, 0);
++ gsm_modem_update(dlci, 0);
+ }
+
+ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
+@@ -3249,7 +3424,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
+ if (encode > 0x0F)
+ encode = 0x0F; /* Best effort */
+ }
+- return gsmtty_modem_update(dlci, encode);
++ return gsm_modem_update(dlci, encode);
+ }
+
+ static void gsmtty_cleanup(struct tty_struct *tty)
+diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c
+index 174895372e7f3..467a349dc26c0 100644
+--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c
++++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c
+@@ -1641,7 +1641,7 @@ static void mlx5_vdpa_kick_vq(struct vdpa_device *vdev, u16 idx)
+ return;
+
+ if (unlikely(is_ctrl_vq_idx(mvdev, idx))) {
+- if (!mvdev->cvq.ready)
++ if (!mvdev->wq || !mvdev->cvq.ready)
+ return;
+
+ queue_work(mvdev->wq, &ndev->cvq_ent.work);
+@@ -2626,9 +2626,12 @@ static void mlx5_vdpa_dev_del(struct vdpa_mgmt_dev *v_mdev, struct vdpa_device *
+ struct mlx5_vdpa_mgmtdev *mgtdev = container_of(v_mdev, struct mlx5_vdpa_mgmtdev, mgtdev);
+ struct mlx5_vdpa_dev *mvdev = to_mvdev(dev);
+ struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev);
++ struct workqueue_struct *wq;
+
+ mlx5_notifier_unregister(mvdev->mdev, &ndev->nb);
+- destroy_workqueue(mvdev->wq);
++ wq = mvdev->wq;
++ mvdev->wq = NULL;
++ destroy_workqueue(wq);
+ _vdpa_unregister_device(dev);
+ mgtdev->ndev = NULL;
+ }
+diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
+index a25b63b56223f..bb83e7c53ae0e 100644
+--- a/drivers/video/fbdev/core/fbcon.c
++++ b/drivers/video/fbdev/core/fbcon.c
+@@ -2480,6 +2480,11 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
+ if (charcount != 256 && charcount != 512)
+ return -EINVAL;
+
++ /* font bigger than screen resolution ? */
++ if (w > FBCON_SWAP(info->var.rotate, info->var.xres, info->var.yres) ||
++ h > FBCON_SWAP(info->var.rotate, info->var.yres, info->var.xres))
++ return -EINVAL;
++
+ /* Make sure drawing engine can handle the font */
+ if (!(info->pixmap.blit_x & (1 << (font->width - 1))) ||
+ !(info->pixmap.blit_y & (1 << (font->height - 1))))
+@@ -2742,6 +2747,34 @@ void fbcon_update_vcs(struct fb_info *info, bool all)
+ }
+ EXPORT_SYMBOL(fbcon_update_vcs);
+
++/* let fbcon check if it supports a new screen resolution */
++int fbcon_modechange_possible(struct fb_info *info, struct fb_var_screeninfo *var)
++{
++ struct fbcon_ops *ops = info->fbcon_par;
++ struct vc_data *vc;
++ unsigned int i;
++
++ WARN_CONSOLE_UNLOCKED();
++
++ if (!ops)
++ return 0;
++
++ /* prevent setting a screen size which is smaller than font size */
++ for (i = first_fb_vc; i <= last_fb_vc; i++) {
++ vc = vc_cons[i].d;
++ if (!vc || vc->vc_mode != KD_TEXT ||
++ registered_fb[con2fb_map[i]] != info)
++ continue;
++
++ if (vc->vc_font.width > FBCON_SWAP(var->rotate, var->xres, var->yres) ||
++ vc->vc_font.height > FBCON_SWAP(var->rotate, var->yres, var->xres))
++ return -EINVAL;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(fbcon_modechange_possible);
++
+ int fbcon_mode_deleted(struct fb_info *info,
+ struct fb_videomode *mode)
+ {
+diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
+index 0371ad233fdf2..6d7868cc1fca0 100644
+--- a/drivers/video/fbdev/core/fbmem.c
++++ b/drivers/video/fbdev/core/fbmem.c
+@@ -514,7 +514,7 @@ static int fb_show_logo_line(struct fb_info *info, int rotate,
+
+ while (n && (n * (logo->width + 8) - 8 > xres))
+ --n;
+- image.dx = (xres - n * (logo->width + 8) - 8) / 2;
++ image.dx = (xres - (n * (logo->width + 8) - 8)) / 2;
+ image.dy = y ?: (yres - logo->height) / 2;
+ } else {
+ image.dx = 0;
+@@ -1020,6 +1020,16 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
+ if (ret)
+ return ret;
+
++ /* verify that virtual resolution >= physical resolution */
++ if (var->xres_virtual < var->xres ||
++ var->yres_virtual < var->yres) {
++ pr_warn("WARNING: fbcon: Driver '%s' missed to adjust virtual screen size (%ux%u vs. %ux%u)\n",
++ info->fix.id,
++ var->xres_virtual, var->yres_virtual,
++ var->xres, var->yres);
++ return -EINVAL;
++ }
++
+ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
+ return 0;
+
+@@ -1110,7 +1120,9 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
+ return -EFAULT;
+ console_lock();
+ lock_fb_info(info);
+- ret = fb_set_var(info, &var);
++ ret = fbcon_modechange_possible(info, &var);
++ if (!ret)
++ ret = fb_set_var(info, &var);
+ if (!ret)
+ fbcon_update_vcs(info, var.activate & FB_ACTIVATE_ALL);
+ unlock_fb_info(info);
+diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
+index 37418b183b078..c6c5a22ff6e86 100644
+--- a/fs/btrfs/block-group.c
++++ b/fs/btrfs/block-group.c
+@@ -3400,31 +3400,12 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags)
+ */
+ check_system_chunk(trans, flags);
+
+- bg = btrfs_alloc_chunk(trans, flags);
++ bg = btrfs_create_chunk(trans, flags);
+ if (IS_ERR(bg)) {
+ ret = PTR_ERR(bg);
+ goto out;
+ }
+
+- /*
+- * If this is a system chunk allocation then stop right here and do not
+- * add the chunk item to the chunk btree. This is to prevent a deadlock
+- * because this system chunk allocation can be triggered while COWing
+- * some extent buffer of the chunk btree and while holding a lock on a
+- * parent extent buffer, in which case attempting to insert the chunk
+- * item (or update the device item) would result in a deadlock on that
+- * parent extent buffer. In this case defer the chunk btree updates to
+- * the second phase of chunk allocation and keep our reservation until
+- * the second phase completes.
+- *
+- * This is a rare case and can only be triggered by the very few cases
+- * we have where we need to touch the chunk btree outside chunk allocation
+- * and chunk removal. These cases are basically adding a device, removing
+- * a device or resizing a device.
+- */
+- if (flags & BTRFS_BLOCK_GROUP_SYSTEM)
+- return 0;
+-
+ ret = btrfs_chunk_alloc_add_chunk_item(trans, bg);
+ /*
+ * Normally we are not expected to fail with -ENOSPC here, since we have
+@@ -3461,7 +3442,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags)
+ const u64 sys_flags = btrfs_system_alloc_profile(trans->fs_info);
+ struct btrfs_block_group *sys_bg;
+
+- sys_bg = btrfs_alloc_chunk(trans, sys_flags);
++ sys_bg = btrfs_create_chunk(trans, sys_flags);
+ if (IS_ERR(sys_bg)) {
+ ret = PTR_ERR(sys_bg);
+ btrfs_abort_transaction(trans, ret);
+@@ -3557,14 +3538,14 @@ out:
+ * This has happened before and commit eafa4fd0ad0607 ("btrfs: fix exhaustion of
+ * the system chunk array due to concurrent allocations") provides more details.
+ *
+- * For allocation of system chunks, we defer the updates and insertions into the
+- * chunk btree to phase 2. This is to prevent deadlocks on extent buffers because
+- * if the chunk allocation is triggered while COWing an extent buffer of the
+- * chunk btree, we are holding a lock on the parent of that extent buffer and
+- * doing the chunk btree updates and insertions can require locking that parent.
+- * This is for the very few and rare cases where we update the chunk btree that
+- * are not chunk allocation or chunk removal: adding a device, removing a device
+- * or resizing a device.
++ * Allocation of system chunks does not happen through this function. A task that
++ * needs to update the chunk btree (the only btree that uses system chunks), must
++ * preallocate chunk space by calling either check_system_chunk() or
++ * btrfs_reserve_chunk_metadata() - the former is used when allocating a data or
++ * metadata chunk or when removing a chunk, while the later is used before doing
++ * a modification to the chunk btree - use cases for the later are adding,
++ * removing and resizing a device as well as relocation of a system chunk.
++ * See the comment below for more details.
+ *
+ * The reservation of system space, done through check_system_chunk(), as well
+ * as all the updates and insertions into the chunk btree must be done while
+@@ -3601,11 +3582,27 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,
+ if (trans->allocating_chunk)
+ return -ENOSPC;
+ /*
+- * If we are removing a chunk, don't re-enter or we would deadlock.
+- * System space reservation and system chunk allocation is done by the
+- * chunk remove operation (btrfs_remove_chunk()).
++ * Allocation of system chunks can not happen through this path, as we
++ * could end up in a deadlock if we are allocating a data or metadata
++ * chunk and there is another task modifying the chunk btree.
++ *
++ * This is because while we are holding the chunk mutex, we will attempt
++ * to add the new chunk item to the chunk btree or update an existing
++ * device item in the chunk btree, while the other task that is modifying
++ * the chunk btree is attempting to COW an extent buffer while holding a
++ * lock on it and on its parent - if the COW operation triggers a system
++ * chunk allocation, then we can deadlock because we are holding the
++ * chunk mutex and we may need to access that extent buffer or its parent
++ * in order to add the chunk item or update a device item.
++ *
++ * Tasks that want to modify the chunk tree should reserve system space
++ * before updating the chunk btree, by calling either
++ * btrfs_reserve_chunk_metadata() or check_system_chunk().
++ * It's possible that after a task reserves the space, it still ends up
++ * here - this happens in the cases described above at do_chunk_alloc().
++ * The task will have to either retry or fail.
+ */
+- if (trans->removing_chunk)
++ if (flags & BTRFS_BLOCK_GROUP_SYSTEM)
+ return -ENOSPC;
+
+ space_info = btrfs_find_space_info(fs_info, flags);
+@@ -3704,17 +3701,14 @@ static u64 get_profile_num_devs(struct btrfs_fs_info *fs_info, u64 type)
+ return num_dev;
+ }
+
+-/*
+- * Reserve space in the system space for allocating or removing a chunk
+- */
+-void check_system_chunk(struct btrfs_trans_handle *trans, u64 type)
++static void reserve_chunk_space(struct btrfs_trans_handle *trans,
++ u64 bytes,
++ u64 type)
+ {
+ struct btrfs_fs_info *fs_info = trans->fs_info;
+ struct btrfs_space_info *info;
+ u64 left;
+- u64 thresh;
+ int ret = 0;
+- u64 num_devs;
+
+ /*
+ * Needed because we can end up allocating a system chunk and for an
+@@ -3727,19 +3721,13 @@ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type)
+ left = info->total_bytes - btrfs_space_info_used(info, true);
+ spin_unlock(&info->lock);
+
+- num_devs = get_profile_num_devs(fs_info, type);
+-
+- /* num_devs device items to update and 1 chunk item to add or remove */
+- thresh = btrfs_calc_metadata_size(fs_info, num_devs) +
+- btrfs_calc_insert_metadata_size(fs_info, 1);
+-
+- if (left < thresh && btrfs_test_opt(fs_info, ENOSPC_DEBUG)) {
++ if (left < bytes && btrfs_test_opt(fs_info, ENOSPC_DEBUG)) {
+ btrfs_info(fs_info, "left=%llu, need=%llu, flags=%llu",
+- left, thresh, type);
++ left, bytes, type);
+ btrfs_dump_space_info(fs_info, info, 0, 0);
+ }
+
+- if (left < thresh) {
++ if (left < bytes) {
+ u64 flags = btrfs_system_alloc_profile(fs_info);
+ struct btrfs_block_group *bg;
+
+@@ -3748,21 +3736,20 @@ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type)
+ * needing it, as we might not need to COW all nodes/leafs from
+ * the paths we visit in the chunk tree (they were already COWed
+ * or created in the current transaction for example).
+- *
+- * Also, if our caller is allocating a system chunk, do not
+- * attempt to insert the chunk item in the chunk btree, as we
+- * could deadlock on an extent buffer since our caller may be
+- * COWing an extent buffer from the chunk btree.
+ */
+- bg = btrfs_alloc_chunk(trans, flags);
++ bg = btrfs_create_chunk(trans, flags);
+ if (IS_ERR(bg)) {
+ ret = PTR_ERR(bg);
+- } else if (!(type & BTRFS_BLOCK_GROUP_SYSTEM)) {
++ } else {
+ /*
+ * If we fail to add the chunk item here, we end up
+ * trying again at phase 2 of chunk allocation, at
+ * btrfs_create_pending_block_groups(). So ignore
+- * any error here.
++ * any error here. An ENOSPC here could happen, due to
++ * the cases described at do_chunk_alloc() - the system
++ * block group we just created was just turned into RO
++ * mode by a scrub for example, or a running discard
++ * temporarily removed its free space entries, etc.
+ */
+ btrfs_chunk_alloc_add_chunk_item(trans, bg);
+ }
+@@ -3771,12 +3758,61 @@ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type)
+ if (!ret) {
+ ret = btrfs_block_rsv_add(fs_info->chunk_root,
+ &fs_info->chunk_block_rsv,
+- thresh, BTRFS_RESERVE_NO_FLUSH);
++ bytes, BTRFS_RESERVE_NO_FLUSH);
+ if (!ret)
+- trans->chunk_bytes_reserved += thresh;
++ trans->chunk_bytes_reserved += bytes;
+ }
+ }
+
++/*
++ * Reserve space in the system space for allocating or removing a chunk.
++ * The caller must be holding fs_info->chunk_mutex.
++ */
++void check_system_chunk(struct btrfs_trans_handle *trans, u64 type)
++{
++ struct btrfs_fs_info *fs_info = trans->fs_info;
++ const u64 num_devs = get_profile_num_devs(fs_info, type);
++ u64 bytes;
++
++ /* num_devs device items to update and 1 chunk item to add or remove. */
++ bytes = btrfs_calc_metadata_size(fs_info, num_devs) +
++ btrfs_calc_insert_metadata_size(fs_info, 1);
++
++ reserve_chunk_space(trans, bytes, type);
++}
++
++/*
++ * Reserve space in the system space, if needed, for doing a modification to the
++ * chunk btree.
++ *
++ * @trans: A transaction handle.
++ * @is_item_insertion: Indicate if the modification is for inserting a new item
++ * in the chunk btree or if it's for the deletion or update
++ * of an existing item.
++ *
++ * This is used in a context where we need to update the chunk btree outside
++ * block group allocation and removal, to avoid a deadlock with a concurrent
++ * task that is allocating a metadata or data block group and therefore needs to
++ * update the chunk btree while holding the chunk mutex. After the update to the
++ * chunk btree is done, btrfs_trans_release_chunk_metadata() should be called.
++ *
++ */
++void btrfs_reserve_chunk_metadata(struct btrfs_trans_handle *trans,
++ bool is_item_insertion)
++{
++ struct btrfs_fs_info *fs_info = trans->fs_info;
++ u64 bytes;
++
++ if (is_item_insertion)
++ bytes = btrfs_calc_insert_metadata_size(fs_info, 1);
++ else
++ bytes = btrfs_calc_metadata_size(fs_info, 1);
++
++ mutex_lock(&fs_info->chunk_mutex);
++ reserve_chunk_space(trans, bytes, BTRFS_BLOCK_GROUP_SYSTEM);
++ mutex_unlock(&fs_info->chunk_mutex);
++}
++
+ void btrfs_put_block_group_cache(struct btrfs_fs_info *info)
+ {
+ struct btrfs_block_group *block_group;
+diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h
+index c72a71efcb187..37e55ebde735b 100644
+--- a/fs/btrfs/block-group.h
++++ b/fs/btrfs/block-group.h
+@@ -289,6 +289,8 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,
+ enum btrfs_chunk_alloc_enum force);
+ int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, u64 type);
+ void check_system_chunk(struct btrfs_trans_handle *trans, const u64 type);
++void btrfs_reserve_chunk_metadata(struct btrfs_trans_handle *trans,
++ bool is_item_insertion);
+ u64 btrfs_get_alloc_profile(struct btrfs_fs_info *fs_info, u64 orig_flags);
+ void btrfs_put_block_group_cache(struct btrfs_fs_info *info);
+ int btrfs_free_block_groups(struct btrfs_fs_info *info);
+diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
+index 899f854459252..341ce90d24b15 100644
+--- a/fs/btrfs/ctree.c
++++ b/fs/btrfs/ctree.c
+@@ -462,8 +462,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
+ BUG_ON(ret < 0);
+ rcu_assign_pointer(root->node, cow);
+
+- btrfs_free_tree_block(trans, root, buf, parent_start,
+- last_ref);
++ btrfs_free_tree_block(trans, btrfs_root_id(root), buf,
++ parent_start, last_ref);
+ free_extent_buffer(buf);
+ add_root_to_dirty_list(root);
+ } else {
+@@ -484,8 +484,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
+ return ret;
+ }
+ }
+- btrfs_free_tree_block(trans, root, buf, parent_start,
+- last_ref);
++ btrfs_free_tree_block(trans, btrfs_root_id(root), buf,
++ parent_start, last_ref);
+ }
+ if (unlock_orig)
+ btrfs_tree_unlock(buf);
+@@ -926,7 +926,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
+ free_extent_buffer(mid);
+
+ root_sub_used(root, mid->len);
+- btrfs_free_tree_block(trans, root, mid, 0, 1);
++ btrfs_free_tree_block(trans, btrfs_root_id(root), mid, 0, 1);
+ /* once for the root ptr */
+ free_extent_buffer_stale(mid);
+ return 0;
+@@ -985,7 +985,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
+ btrfs_tree_unlock(right);
+ del_ptr(root, path, level + 1, pslot + 1);
+ root_sub_used(root, right->len);
+- btrfs_free_tree_block(trans, root, right, 0, 1);
++ btrfs_free_tree_block(trans, btrfs_root_id(root), right,
++ 0, 1);
+ free_extent_buffer_stale(right);
+ right = NULL;
+ } else {
+@@ -1030,7 +1031,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
+ btrfs_tree_unlock(mid);
+ del_ptr(root, path, level + 1, pslot);
+ root_sub_used(root, mid->len);
+- btrfs_free_tree_block(trans, root, mid, 0, 1);
++ btrfs_free_tree_block(trans, btrfs_root_id(root), mid, 0, 1);
+ free_extent_buffer_stale(mid);
+ mid = NULL;
+ } else {
+@@ -4059,7 +4060,7 @@ static noinline void btrfs_del_leaf(struct btrfs_trans_handle *trans,
+ root_sub_used(root, leaf->len);
+
+ atomic_inc(&leaf->refs);
+- btrfs_free_tree_block(trans, root, leaf, 0, 1);
++ btrfs_free_tree_block(trans, btrfs_root_id(root), leaf, 0, 1);
+ free_extent_buffer_stale(leaf);
+ }
+ /*
+diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
+index 21c44846b0022..d1838de0b39c0 100644
+--- a/fs/btrfs/ctree.h
++++ b/fs/btrfs/ctree.h
+@@ -1027,6 +1027,7 @@ struct btrfs_fs_info {
+ */
+ spinlock_t relocation_bg_lock;
+ u64 data_reloc_bg;
++ struct mutex zoned_data_reloc_io_lock;
+
+ #ifdef CONFIG_BTRFS_FS_REF_VERIFY
+ spinlock_t ref_verify_lock;
+@@ -2256,6 +2257,11 @@ static inline bool btrfs_root_dead(const struct btrfs_root *root)
+ return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_DEAD)) != 0;
+ }
+
++static inline u64 btrfs_root_id(const struct btrfs_root *root)
++{
++ return root->root_key.objectid;
++}
++
+ /* struct btrfs_root_backup */
+ BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup,
+ tree_root, 64);
+@@ -2718,7 +2724,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
+ u64 empty_size,
+ enum btrfs_lock_nesting nest);
+ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
+- struct btrfs_root *root,
++ u64 root_id,
+ struct extent_buffer *buf,
+ u64 parent, int last_ref);
+ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
+diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h
+index e22fba272e4fd..31266ba1d4300 100644
+--- a/fs/btrfs/delayed-ref.h
++++ b/fs/btrfs/delayed-ref.h
+@@ -271,7 +271,7 @@ static inline void btrfs_init_generic_ref(struct btrfs_ref *generic_ref,
+ }
+
+ static inline void btrfs_init_tree_ref(struct btrfs_ref *generic_ref,
+- int level, u64 root)
++ int level, u64 root, u64 mod_root, bool skip_qgroup)
+ {
+ /* If @real_root not set, use @root as fallback */
+ if (!generic_ref->real_root)
+@@ -282,7 +282,8 @@ static inline void btrfs_init_tree_ref(struct btrfs_ref *generic_ref,
+ }
+
+ static inline void btrfs_init_data_ref(struct btrfs_ref *generic_ref,
+- u64 ref_root, u64 ino, u64 offset)
++ u64 ref_root, u64 ino, u64 offset, u64 mod_root,
++ bool skip_qgroup)
+ {
+ /* If @real_root not set, use @root as fallback */
+ if (!generic_ref->real_root)
+diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
+index bdbc310a8f8c5..781556e2a37f2 100644
+--- a/fs/btrfs/dev-replace.c
++++ b/fs/btrfs/dev-replace.c
+@@ -70,6 +70,7 @@ static int btrfs_dev_replace_kthread(void *data);
+
+ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info)
+ {
++ struct btrfs_dev_lookup_args args = { .devid = BTRFS_DEV_REPLACE_DEVID };
+ struct btrfs_key key;
+ struct btrfs_root *dev_root = fs_info->dev_root;
+ struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+@@ -100,8 +101,7 @@ no_valid_dev_replace_entry_found:
+ * We don't have a replace item or it's corrupted. If there is
+ * a replace target, fail the mount.
+ */
+- if (btrfs_find_device(fs_info->fs_devices,
+- BTRFS_DEV_REPLACE_DEVID, NULL, NULL)) {
++ if (btrfs_find_device(fs_info->fs_devices, &args)) {
+ btrfs_err(fs_info,
+ "found replace target device without a valid replace item");
+ ret = -EUCLEAN;
+@@ -163,8 +163,7 @@ no_valid_dev_replace_entry_found:
+ * We don't have an active replace item but if there is a
+ * replace target, fail the mount.
+ */
+- if (btrfs_find_device(fs_info->fs_devices,
+- BTRFS_DEV_REPLACE_DEVID, NULL, NULL)) {
++ if (btrfs_find_device(fs_info->fs_devices, &args)) {
+ btrfs_err(fs_info,
+ "replace devid present without an active replace item");
+ ret = -EUCLEAN;
+@@ -175,11 +174,10 @@ no_valid_dev_replace_entry_found:
+ break;
+ case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
+ case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
+- dev_replace->srcdev = btrfs_find_device(fs_info->fs_devices,
+- src_devid, NULL, NULL);
+- dev_replace->tgtdev = btrfs_find_device(fs_info->fs_devices,
+- BTRFS_DEV_REPLACE_DEVID,
+- NULL, NULL);
++ dev_replace->tgtdev = btrfs_find_device(fs_info->fs_devices, &args);
++ args.devid = src_devid;
++ dev_replace->srcdev = btrfs_find_device(fs_info->fs_devices, &args);
++
+ /*
+ * allow 'btrfs dev replace_cancel' if src/tgt device is
+ * missing
+diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
+index 233d894f6feba..909d19656316f 100644
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -2914,6 +2914,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
+ mutex_init(&fs_info->reloc_mutex);
+ mutex_init(&fs_info->delalloc_root_mutex);
+ mutex_init(&fs_info->zoned_meta_io_lock);
++ mutex_init(&fs_info->zoned_data_reloc_io_lock);
+ seqlock_init(&fs_info->profiles_lock);
+
+ INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
+diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
+index 514adc83577f0..f11616f61dd62 100644
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -2440,7 +2440,8 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
+ num_bytes, parent);
+ generic_ref.real_root = root->root_key.objectid;
+ btrfs_init_data_ref(&generic_ref, ref_root, key.objectid,
+- key.offset);
++ key.offset, root->root_key.objectid,
++ for_reloc);
+ generic_ref.skip_qgroup = for_reloc;
+ if (inc)
+ ret = btrfs_inc_extent_ref(trans, &generic_ref);
+@@ -2454,7 +2455,8 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
+ btrfs_init_generic_ref(&generic_ref, action, bytenr,
+ num_bytes, parent);
+ generic_ref.real_root = root->root_key.objectid;
+- btrfs_init_tree_ref(&generic_ref, level - 1, ref_root);
++ btrfs_init_tree_ref(&generic_ref, level - 1, ref_root,
++ root->root_key.objectid, for_reloc);
+ generic_ref.skip_qgroup = for_reloc;
+ if (inc)
+ ret = btrfs_inc_extent_ref(trans, &generic_ref);
+@@ -3278,20 +3280,20 @@ out_delayed_unlock:
+ }
+
+ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
+- struct btrfs_root *root,
++ u64 root_id,
+ struct extent_buffer *buf,
+ u64 parent, int last_ref)
+ {
+- struct btrfs_fs_info *fs_info = root->fs_info;
++ struct btrfs_fs_info *fs_info = trans->fs_info;
+ struct btrfs_ref generic_ref = { 0 };
+ int ret;
+
+ btrfs_init_generic_ref(&generic_ref, BTRFS_DROP_DELAYED_REF,
+ buf->start, buf->len, parent);
+ btrfs_init_tree_ref(&generic_ref, btrfs_header_level(buf),
+- root->root_key.objectid);
++ root_id, 0, false);
+
+- if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
++ if (root_id != BTRFS_TREE_LOG_OBJECTID) {
+ btrfs_ref_tree_mod(fs_info, &generic_ref);
+ ret = btrfs_add_delayed_tree_ref(trans, &generic_ref, NULL);
+ BUG_ON(ret); /* -ENOMEM */
+@@ -3301,7 +3303,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
+ struct btrfs_block_group *cache;
+ bool must_pin = false;
+
+- if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
++ if (root_id != BTRFS_TREE_LOG_OBJECTID) {
+ ret = check_ref_cleanup(trans, buf->start);
+ if (!ret) {
+ btrfs_redirty_list_add(trans->transaction, buf);
+@@ -4705,7 +4707,8 @@ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
+
+ btrfs_init_generic_ref(&generic_ref, BTRFS_ADD_DELAYED_EXTENT,
+ ins->objectid, ins->offset, 0);
+- btrfs_init_data_ref(&generic_ref, root->root_key.objectid, owner, offset);
++ btrfs_init_data_ref(&generic_ref, root->root_key.objectid, owner,
++ offset, 0, false);
+ btrfs_ref_tree_mod(root->fs_info, &generic_ref);
+
+ return btrfs_add_delayed_data_ref(trans, &generic_ref, ram_bytes);
+@@ -4898,7 +4901,8 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
+ btrfs_init_generic_ref(&generic_ref, BTRFS_ADD_DELAYED_EXTENT,
+ ins.objectid, ins.offset, parent);
+ generic_ref.real_root = root->root_key.objectid;
+- btrfs_init_tree_ref(&generic_ref, level, root_objectid);
++ btrfs_init_tree_ref(&generic_ref, level, root_objectid,
++ root->root_key.objectid, false);
+ btrfs_ref_tree_mod(fs_info, &generic_ref);
+ ret = btrfs_add_delayed_tree_ref(trans, &generic_ref, extent_op);
+ if (ret)
+@@ -5315,7 +5319,8 @@ skip:
+
+ btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, bytenr,
+ fs_info->nodesize, parent);
+- btrfs_init_tree_ref(&ref, level - 1, root->root_key.objectid);
++ btrfs_init_tree_ref(&ref, level - 1, root->root_key.objectid,
++ 0, false);
+ ret = btrfs_free_extent(trans, &ref);
+ if (ret)
+ goto out_unlock;
+@@ -5436,7 +5441,8 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
+ goto owner_mismatch;
+ }
+
+- btrfs_free_tree_block(trans, root, eb, parent, wc->refs[level] == 1);
++ btrfs_free_tree_block(trans, btrfs_root_id(root), eb, parent,
++ wc->refs[level] == 1);
+ out:
+ wc->refs[level] = 0;
+ wc->flags[level] = 0;
+diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
+index 6dd375ed6e3d5..059bd0753e27f 100644
+--- a/fs/btrfs/extent_io.c
++++ b/fs/btrfs/extent_io.c
+@@ -5139,8 +5139,6 @@ int extent_writepages(struct address_space *mapping,
+ struct writeback_control *wbc)
+ {
+ struct inode *inode = mapping->host;
+- const bool data_reloc = btrfs_is_data_reloc_root(BTRFS_I(inode)->root);
+- const bool zoned = btrfs_is_zoned(BTRFS_I(inode)->root->fs_info);
+ int ret = 0;
+ struct extent_page_data epd = {
+ .bio_ctrl = { 0 },
+@@ -5152,11 +5150,9 @@ int extent_writepages(struct address_space *mapping,
+ * Allow only a single thread to do the reloc work in zoned mode to
+ * protect the write pointer updates.
+ */
+- if (data_reloc && zoned)
+- btrfs_inode_lock(inode, 0);
++ btrfs_zoned_data_reloc_lock(BTRFS_I(inode));
+ ret = extent_write_cache_pages(mapping, wbc, &epd);
+- if (data_reloc && zoned)
+- btrfs_inode_unlock(inode, 0);
++ btrfs_zoned_data_reloc_unlock(BTRFS_I(inode));
+ ASSERT(ret <= 0);
+ if (ret < 0) {
+ end_write_bio(&epd, ret);
+diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
+index a06c8366a8f4e..1c597cd6c0247 100644
+--- a/fs/btrfs/file.c
++++ b/fs/btrfs/file.c
+@@ -869,7 +869,8 @@ next_slot:
+ btrfs_init_data_ref(&ref,
+ root->root_key.objectid,
+ new_key.objectid,
+- args->start - extent_offset);
++ args->start - extent_offset,
++ 0, false);
+ ret = btrfs_inc_extent_ref(trans, &ref);
+ BUG_ON(ret); /* -ENOMEM */
+ }
+@@ -955,7 +956,8 @@ delete_extent_item:
+ btrfs_init_data_ref(&ref,
+ root->root_key.objectid,
+ key.objectid,
+- key.offset - extent_offset);
++ key.offset - extent_offset, 0,
++ false);
+ ret = btrfs_free_extent(trans, &ref);
+ BUG_ON(ret); /* -ENOMEM */
+ args->bytes_found += extent_end - key.offset;
+@@ -1232,7 +1234,7 @@ again:
+ btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF, bytenr,
+ num_bytes, 0);
+ btrfs_init_data_ref(&ref, root->root_key.objectid, ino,
+- orig_offset);
++ orig_offset, 0, false);
+ ret = btrfs_inc_extent_ref(trans, &ref);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+@@ -1257,7 +1259,8 @@ again:
+ other_end = 0;
+ btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, bytenr,
+ num_bytes, 0);
+- btrfs_init_data_ref(&ref, root->root_key.objectid, ino, orig_offset);
++ btrfs_init_data_ref(&ref, root->root_key.objectid, ino, orig_offset,
++ 0, false);
+ if (extent_mergeable(leaf, path->slots[0] + 1,
+ ino, bytenr, orig_offset,
+ &other_start, &other_end)) {
+@@ -2715,7 +2718,7 @@ static int btrfs_insert_replace_extent(struct btrfs_trans_handle *trans,
+ extent_info->disk_len, 0);
+ ref_offset = extent_info->file_offset - extent_info->data_offset;
+ btrfs_init_data_ref(&ref, root->root_key.objectid,
+- btrfs_ino(inode), ref_offset);
++ btrfs_ino(inode), ref_offset, 0, false);
+ ret = btrfs_inc_extent_ref(trans, &ref);
+ }
+
+diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
+index a33bca94d133e..3abec44c62559 100644
+--- a/fs/btrfs/free-space-tree.c
++++ b/fs/btrfs/free-space-tree.c
+@@ -1256,8 +1256,8 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
+ btrfs_tree_lock(free_space_root->node);
+ btrfs_clean_tree_block(free_space_root->node);
+ btrfs_tree_unlock(free_space_root->node);
+- btrfs_free_tree_block(trans, free_space_root, free_space_root->node,
+- 0, 1);
++ btrfs_free_tree_block(trans, btrfs_root_id(free_space_root),
++ free_space_root->node, 0, 1);
+
+ btrfs_put_root(free_space_root);
+
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index 044d584c3467c..d644dcaf30040 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -4919,7 +4919,8 @@ delete:
+ extent_start, extent_num_bytes, 0);
+ ref.real_root = root->root_key.objectid;
+ btrfs_init_data_ref(&ref, btrfs_header_owner(leaf),
+- ino, extent_offset);
++ ino, extent_offset,
++ root->root_key.objectid, false);
+ ret = btrfs_free_extent(trans, &ref);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
+index bf53af8694f8e..b9dcaae7c8d51 100644
+--- a/fs/btrfs/ioctl.c
++++ b/fs/btrfs/ioctl.c
+@@ -615,11 +615,13 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
+ * Since we don't abort the transaction in this case, free the
+ * tree block so that we don't leak space and leave the
+ * filesystem in an inconsistent state (an extent item in the
+- * extent tree without backreferences). Also no need to have
+- * the tree block locked since it is not in any tree at this
+- * point, so no other task can find it and use it.
++ * extent tree with a backreference for a root that does not
++ * exists).
+ */
+- btrfs_free_tree_block(trans, root, leaf, 0, 1);
++ btrfs_tree_lock(leaf);
++ btrfs_clean_tree_block(leaf);
++ btrfs_tree_unlock(leaf);
++ btrfs_free_tree_block(trans, objectid, leaf, 0, 1);
+ free_extent_buffer(leaf);
+ goto fail;
+ }
+@@ -1655,6 +1657,7 @@ static int exclop_start_or_cancel_reloc(struct btrfs_fs_info *fs_info,
+ static noinline int btrfs_ioctl_resize(struct file *file,
+ void __user *arg)
+ {
++ BTRFS_DEV_LOOKUP_ARGS(args);
+ struct inode *inode = file_inode(file);
+ struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ u64 new_size;
+@@ -1710,7 +1713,8 @@ static noinline int btrfs_ioctl_resize(struct file *file,
+ btrfs_info(fs_info, "resizing devid %llu", devid);
+ }
+
+- device = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL);
++ args.devid = devid;
++ device = btrfs_find_device(fs_info->fs_devices, &args);
+ if (!device) {
+ btrfs_info(fs_info, "resizer unable to find device %llu",
+ devid);
+@@ -3214,6 +3218,7 @@ out:
+
+ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
+ {
++ BTRFS_DEV_LOOKUP_ARGS(args);
+ struct inode *inode = file_inode(file);
+ struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ struct btrfs_ioctl_vol_args_v2 *vol_args;
+@@ -3225,35 +3230,37 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+- ret = mnt_want_write_file(file);
+- if (ret)
+- return ret;
+-
+ vol_args = memdup_user(arg, sizeof(*vol_args));
+- if (IS_ERR(vol_args)) {
+- ret = PTR_ERR(vol_args);
+- goto err_drop;
+- }
++ if (IS_ERR(vol_args))
++ return PTR_ERR(vol_args);
+
+ if (vol_args->flags & ~BTRFS_DEVICE_REMOVE_ARGS_MASK) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
++
+ vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0';
+- if (!(vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) &&
+- strcmp("cancel", vol_args->name) == 0)
++ if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) {
++ args.devid = vol_args->devid;
++ } else if (!strcmp("cancel", vol_args->name)) {
+ cancel = true;
++ } else {
++ ret = btrfs_get_dev_args_from_path(fs_info, &args, vol_args->name);
++ if (ret)
++ goto out;
++ }
++
++ ret = mnt_want_write_file(file);
++ if (ret)
++ goto out;
+
+ ret = exclop_start_or_cancel_reloc(fs_info, BTRFS_EXCLOP_DEV_REMOVE,
+ cancel);
+ if (ret)
+- goto out;
+- /* Exclusive operation is now claimed */
++ goto err_drop;
+
+- if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID)
+- ret = btrfs_rm_device(fs_info, NULL, vol_args->devid, &bdev, &mode);
+- else
+- ret = btrfs_rm_device(fs_info, vol_args->name, 0, &bdev, &mode);
++ /* Exclusive operation is now claimed */
++ ret = btrfs_rm_device(fs_info, &args, &bdev, &mode);
+
+ btrfs_exclop_finish(fs_info);
+
+@@ -3265,54 +3272,62 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
+ btrfs_info(fs_info, "device deleted: %s",
+ vol_args->name);
+ }
+-out:
+- kfree(vol_args);
+ err_drop:
+ mnt_drop_write_file(file);
+ if (bdev)
+ blkdev_put(bdev, mode);
++out:
++ btrfs_put_dev_args_from_path(&args);
++ kfree(vol_args);
+ return ret;
+ }
+
+ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
+ {
++ BTRFS_DEV_LOOKUP_ARGS(args);
+ struct inode *inode = file_inode(file);
+ struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ struct btrfs_ioctl_vol_args *vol_args;
+ struct block_device *bdev = NULL;
+ fmode_t mode;
+ int ret;
+- bool cancel;
++ bool cancel = false;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+- ret = mnt_want_write_file(file);
+- if (ret)
+- return ret;
+-
+ vol_args = memdup_user(arg, sizeof(*vol_args));
+- if (IS_ERR(vol_args)) {
+- ret = PTR_ERR(vol_args);
+- goto out_drop_write;
+- }
++ if (IS_ERR(vol_args))
++ return PTR_ERR(vol_args);
++
+ vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
+- cancel = (strcmp("cancel", vol_args->name) == 0);
++ if (!strcmp("cancel", vol_args->name)) {
++ cancel = true;
++ } else {
++ ret = btrfs_get_dev_args_from_path(fs_info, &args, vol_args->name);
++ if (ret)
++ goto out;
++ }
++
++ ret = mnt_want_write_file(file);
++ if (ret)
++ goto out;
+
+ ret = exclop_start_or_cancel_reloc(fs_info, BTRFS_EXCLOP_DEV_REMOVE,
+ cancel);
+ if (ret == 0) {
+- ret = btrfs_rm_device(fs_info, vol_args->name, 0, &bdev, &mode);
++ ret = btrfs_rm_device(fs_info, &args, &bdev, &mode);
+ if (!ret)
+ btrfs_info(fs_info, "disk deleted %s", vol_args->name);
+ btrfs_exclop_finish(fs_info);
+ }
+
+- kfree(vol_args);
+-out_drop_write:
+ mnt_drop_write_file(file);
+ if (bdev)
+ blkdev_put(bdev, mode);
++out:
++ btrfs_put_dev_args_from_path(&args);
++ kfree(vol_args);
+ return ret;
+ }
+
+@@ -3373,22 +3388,21 @@ static long btrfs_ioctl_fs_info(struct btrfs_fs_info *fs_info,
+ static long btrfs_ioctl_dev_info(struct btrfs_fs_info *fs_info,
+ void __user *arg)
+ {
++ BTRFS_DEV_LOOKUP_ARGS(args);
+ struct btrfs_ioctl_dev_info_args *di_args;
+ struct btrfs_device *dev;
+ int ret = 0;
+- char *s_uuid = NULL;
+
+ di_args = memdup_user(arg, sizeof(*di_args));
+ if (IS_ERR(di_args))
+ return PTR_ERR(di_args);
+
++ args.devid = di_args->devid;
+ if (!btrfs_is_empty_uuid(di_args->uuid))
+- s_uuid = di_args->uuid;
++ args.uuid = di_args->uuid;
+
+ rcu_read_lock();
+- dev = btrfs_find_device(fs_info->fs_devices, di_args->devid, s_uuid,
+- NULL);
+-
++ dev = btrfs_find_device(fs_info->fs_devices, &args);
+ if (!dev) {
+ ret = -ENODEV;
+ goto out;
+diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
+index 2c803108ea944..4ca809fa80eaf 100644
+--- a/fs/btrfs/qgroup.c
++++ b/fs/btrfs/qgroup.c
+@@ -1259,7 +1259,8 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
+ btrfs_tree_lock(quota_root->node);
+ btrfs_clean_tree_block(quota_root->node);
+ btrfs_tree_unlock(quota_root->node);
+- btrfs_free_tree_block(trans, quota_root, quota_root->node, 0, 1);
++ btrfs_free_tree_block(trans, btrfs_root_id(quota_root),
++ quota_root->node, 0, 1);
+
+ btrfs_put_root(quota_root);
+
+diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
+index a6661f2ad2c00..429a198f8937d 100644
+--- a/fs/btrfs/relocation.c
++++ b/fs/btrfs/relocation.c
+@@ -1147,7 +1147,8 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
+ num_bytes, parent);
+ ref.real_root = root->root_key.objectid;
+ btrfs_init_data_ref(&ref, btrfs_header_owner(leaf),
+- key.objectid, key.offset);
++ key.objectid, key.offset,
++ root->root_key.objectid, false);
+ ret = btrfs_inc_extent_ref(trans, &ref);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+@@ -1158,7 +1159,8 @@ int replace_file_extents(struct btrfs_trans_handle *trans,
+ num_bytes, parent);
+ ref.real_root = root->root_key.objectid;
+ btrfs_init_data_ref(&ref, btrfs_header_owner(leaf),
+- key.objectid, key.offset);
++ key.objectid, key.offset,
++ root->root_key.objectid, false);
+ ret = btrfs_free_extent(trans, &ref);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+@@ -1368,7 +1370,8 @@ again:
+ btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF, old_bytenr,
+ blocksize, path->nodes[level]->start);
+ ref.skip_qgroup = true;
+- btrfs_init_tree_ref(&ref, level - 1, src->root_key.objectid);
++ btrfs_init_tree_ref(&ref, level - 1, src->root_key.objectid,
++ 0, true);
+ ret = btrfs_inc_extent_ref(trans, &ref);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+@@ -1377,7 +1380,8 @@ again:
+ btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF, new_bytenr,
+ blocksize, 0);
+ ref.skip_qgroup = true;
+- btrfs_init_tree_ref(&ref, level - 1, dest->root_key.objectid);
++ btrfs_init_tree_ref(&ref, level - 1, dest->root_key.objectid, 0,
++ true);
+ ret = btrfs_inc_extent_ref(trans, &ref);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+@@ -1386,7 +1390,8 @@ again:
+
+ btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, new_bytenr,
+ blocksize, path->nodes[level]->start);
+- btrfs_init_tree_ref(&ref, level - 1, src->root_key.objectid);
++ btrfs_init_tree_ref(&ref, level - 1, src->root_key.objectid,
++ 0, true);
+ ref.skip_qgroup = true;
+ ret = btrfs_free_extent(trans, &ref);
+ if (ret) {
+@@ -1396,7 +1401,8 @@ again:
+
+ btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, old_bytenr,
+ blocksize, 0);
+- btrfs_init_tree_ref(&ref, level - 1, dest->root_key.objectid);
++ btrfs_init_tree_ref(&ref, level - 1, dest->root_key.objectid,
++ 0, true);
+ ref.skip_qgroup = true;
+ ret = btrfs_free_extent(trans, &ref);
+ if (ret) {
+@@ -2475,7 +2481,8 @@ static int do_relocation(struct btrfs_trans_handle *trans,
+ upper->eb->start);
+ ref.real_root = root->root_key.objectid;
+ btrfs_init_tree_ref(&ref, node->level,
+- btrfs_header_owner(upper->eb));
++ btrfs_header_owner(upper->eb),
++ root->root_key.objectid, false);
+ ret = btrfs_inc_extent_ref(trans, &ref);
+ if (!ret)
+ ret = btrfs_drop_subtree(trans, root, eb,
+@@ -2691,8 +2698,12 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans,
+ list_add_tail(&node->list, &rc->backref_cache.changed);
+ } else {
+ path->lowest_level = node->level;
++ if (root == root->fs_info->chunk_root)
++ btrfs_reserve_chunk_metadata(trans, false);
+ ret = btrfs_search_slot(trans, root, key, path, 0, 1);
+ btrfs_release_path(path);
++ if (root == root->fs_info->chunk_root)
++ btrfs_trans_release_chunk_metadata(trans);
+ if (ret > 0)
+ ret = 0;
+ }
+diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
+index 62f4bafbe54bb..6f2787b21530f 100644
+--- a/fs/btrfs/scrub.c
++++ b/fs/btrfs/scrub.c
+@@ -4068,6 +4068,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
+ u64 end, struct btrfs_scrub_progress *progress,
+ int readonly, int is_dev_replace)
+ {
++ struct btrfs_dev_lookup_args args = { .devid = devid };
+ struct scrub_ctx *sctx;
+ int ret;
+ struct btrfs_device *dev;
+@@ -4115,7 +4116,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
+ goto out_free_ctx;
+
+ mutex_lock(&fs_info->fs_devices->device_list_mutex);
+- dev = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL);
++ dev = btrfs_find_device(fs_info->fs_devices, &args);
+ if (!dev || (test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state) &&
+ !is_dev_replace)) {
+ mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+@@ -4288,11 +4289,12 @@ int btrfs_scrub_cancel_dev(struct btrfs_device *dev)
+ int btrfs_scrub_progress(struct btrfs_fs_info *fs_info, u64 devid,
+ struct btrfs_scrub_progress *progress)
+ {
++ struct btrfs_dev_lookup_args args = { .devid = devid };
+ struct btrfs_device *dev;
+ struct scrub_ctx *sctx = NULL;
+
+ mutex_lock(&fs_info->fs_devices->device_list_mutex);
+- dev = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL);
++ dev = btrfs_find_device(fs_info->fs_devices, &args);
+ if (dev)
+ sctx = dev->scrub_ctx;
+ if (sctx)
+diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
+index 1221d8483d63b..bed6811476b09 100644
+--- a/fs/btrfs/tree-log.c
++++ b/fs/btrfs/tree-log.c
+@@ -761,7 +761,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
+ ins.objectid, ins.offset, 0);
+ btrfs_init_data_ref(&ref,
+ root->root_key.objectid,
+- key->objectid, offset);
++ key->objectid, offset, 0, false);
+ ret = btrfs_inc_extent_ref(trans, &ref);
+ if (ret)
+ goto out;
+diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
+index 378e03a93e101..89ce0b449c22a 100644
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -844,9 +844,13 @@ static noinline struct btrfs_device *device_list_add(const char *path,
+
+ device = NULL;
+ } else {
++ struct btrfs_dev_lookup_args args = {
++ .devid = devid,
++ .uuid = disk_super->dev_item.uuid,
++ };
++
+ mutex_lock(&fs_devices->device_list_mutex);
+- device = btrfs_find_device(fs_devices, devid,
+- disk_super->dev_item.uuid, NULL);
++ device = btrfs_find_device(fs_devices, &args);
+
+ /*
+ * If this disk has been pulled into an fs devices created by
+@@ -951,6 +955,11 @@ static noinline struct btrfs_device *device_list_add(const char *path,
+ /*
+ * We are going to replace the device path for a given devid,
+ * make sure it's the same device if the device is mounted
++ *
++ * NOTE: the device->fs_info may not be reliable here so pass
++ * in a NULL to message helpers instead. This avoids a possible
++ * use-after-free when the fs_info and fs_info->sb are already
++ * torn down.
+ */
+ if (device->bdev) {
+ int error;
+@@ -964,12 +973,6 @@ static noinline struct btrfs_device *device_list_add(const char *path,
+
+ if (device->bdev->bd_dev != path_dev) {
+ mutex_unlock(&fs_devices->device_list_mutex);
+- /*
+- * device->fs_info may not be reliable here, so
+- * pass in a NULL instead. This avoids a
+- * possible use-after-free when the fs_info and
+- * fs_info->sb are already torn down.
+- */
+ btrfs_warn_in_rcu(NULL,
+ "duplicate device %s devid %llu generation %llu scanned by %s (%d)",
+ path, devid, found_transid,
+@@ -977,7 +980,7 @@ static noinline struct btrfs_device *device_list_add(const char *path,
+ task_pid_nr(current));
+ return ERR_PTR(-EEXIST);
+ }
+- btrfs_info_in_rcu(device->fs_info,
++ btrfs_info_in_rcu(NULL,
+ "devid %llu device path %s changed to %s scanned by %s (%d)",
+ devid, rcu_str_deref(device->name),
+ path, current->comm,
+@@ -1879,8 +1882,10 @@ static int btrfs_add_dev_item(struct btrfs_trans_handle *trans,
+ key.type = BTRFS_DEV_ITEM_KEY;
+ key.offset = device->devid;
+
++ btrfs_reserve_chunk_metadata(trans, true);
+ ret = btrfs_insert_empty_item(trans, trans->fs_info->chunk_root, path,
+ &key, sizeof(*dev_item));
++ btrfs_trans_release_chunk_metadata(trans);
+ if (ret)
+ goto out;
+
+@@ -1936,46 +1941,34 @@ static void update_dev_time(const char *device_path)
+ path_put(&path);
+ }
+
+-static int btrfs_rm_dev_item(struct btrfs_device *device)
++static int btrfs_rm_dev_item(struct btrfs_trans_handle *trans,
++ struct btrfs_device *device)
+ {
+ struct btrfs_root *root = device->fs_info->chunk_root;
+ int ret;
+ struct btrfs_path *path;
+ struct btrfs_key key;
+- struct btrfs_trans_handle *trans;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+- trans = btrfs_start_transaction(root, 0);
+- if (IS_ERR(trans)) {
+- btrfs_free_path(path);
+- return PTR_ERR(trans);
+- }
+ key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
+ key.type = BTRFS_DEV_ITEM_KEY;
+ key.offset = device->devid;
+
++ btrfs_reserve_chunk_metadata(trans, false);
+ ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
++ btrfs_trans_release_chunk_metadata(trans);
+ if (ret) {
+ if (ret > 0)
+ ret = -ENOENT;
+- btrfs_abort_transaction(trans, ret);
+- btrfs_end_transaction(trans);
+ goto out;
+ }
+
+ ret = btrfs_del_item(trans, root, path);
+- if (ret) {
+- btrfs_abort_transaction(trans, ret);
+- btrfs_end_transaction(trans);
+- }
+-
+ out:
+ btrfs_free_path(path);
+- if (!ret)
+- ret = btrfs_commit_transaction(trans);
+ return ret;
+ }
+
+@@ -2112,9 +2105,11 @@ void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
+ update_dev_time(device_path);
+ }
+
+-int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
+- u64 devid, struct block_device **bdev, fmode_t *mode)
++int btrfs_rm_device(struct btrfs_fs_info *fs_info,
++ struct btrfs_dev_lookup_args *args,
++ struct block_device **bdev, fmode_t *mode)
+ {
++ struct btrfs_trans_handle *trans;
+ struct btrfs_device *device;
+ struct btrfs_fs_devices *cur_devices;
+ struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
+@@ -2130,37 +2125,30 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
+
+ ret = btrfs_check_raid_min_devices(fs_info, num_devices - 1);
+ if (ret)
+- goto out;
+-
+- device = btrfs_find_device_by_devspec(fs_info, devid, device_path);
++ return ret;
+
+- if (IS_ERR(device)) {
+- if (PTR_ERR(device) == -ENOENT &&
+- device_path && strcmp(device_path, "missing") == 0)
++ device = btrfs_find_device(fs_info->fs_devices, args);
++ if (!device) {
++ if (args->missing)
+ ret = BTRFS_ERROR_DEV_MISSING_NOT_FOUND;
+ else
+- ret = PTR_ERR(device);
+- goto out;
++ ret = -ENOENT;
++ return ret;
+ }
+
+ if (btrfs_pinned_by_swapfile(fs_info, device)) {
+ btrfs_warn_in_rcu(fs_info,
+ "cannot remove device %s (devid %llu) due to active swapfile",
+ rcu_str_deref(device->name), device->devid);
+- ret = -ETXTBSY;
+- goto out;
++ return -ETXTBSY;
+ }
+
+- if (test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state)) {
+- ret = BTRFS_ERROR_DEV_TGT_REPLACE;
+- goto out;
+- }
++ if (test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state))
++ return BTRFS_ERROR_DEV_TGT_REPLACE;
+
+ if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state) &&
+- fs_info->fs_devices->rw_devices == 1) {
+- ret = BTRFS_ERROR_DEV_ONLY_WRITABLE;
+- goto out;
+- }
++ fs_info->fs_devices->rw_devices == 1)
++ return BTRFS_ERROR_DEV_ONLY_WRITABLE;
+
+ if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) {
+ mutex_lock(&fs_info->chunk_mutex);
+@@ -2175,14 +2163,22 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
+ if (ret)
+ goto error_undo;
+
+- /*
+- * TODO: the superblock still includes this device in its num_devices
+- * counter although write_all_supers() is not locked out. This
+- * could give a filesystem state which requires a degraded mount.
+- */
+- ret = btrfs_rm_dev_item(device);
+- if (ret)
++ trans = btrfs_start_transaction(fs_info->chunk_root, 0);
++ if (IS_ERR(trans)) {
++ ret = PTR_ERR(trans);
+ goto error_undo;
++ }
++
++ ret = btrfs_rm_dev_item(trans, device);
++ if (ret) {
++ /* Any error in dev item removal is critical */
++ btrfs_crit(fs_info,
++ "failed to remove device item for devid %llu: %d",
++ device->devid, ret);
++ btrfs_abort_transaction(trans, ret);
++ btrfs_end_transaction(trans);
++ return ret;
++ }
+
+ clear_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state);
+ btrfs_scrub_cancel_dev(device);
+@@ -2257,7 +2253,8 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
+ free_fs_devices(cur_devices);
+ }
+
+-out:
++ ret = btrfs_commit_transaction(trans);
++
+ return ret;
+
+ error_undo:
+@@ -2269,7 +2266,7 @@ error_undo:
+ device->fs_devices->rw_devices++;
+ mutex_unlock(&fs_info->chunk_mutex);
+ }
+- goto out;
++ return ret;
+ }
+
+ void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_device *srcdev)
+@@ -2353,69 +2350,98 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev)
+ btrfs_free_device(tgtdev);
+ }
+
+-static struct btrfs_device *btrfs_find_device_by_path(
+- struct btrfs_fs_info *fs_info, const char *device_path)
++/**
++ * Populate args from device at path
++ *
++ * @fs_info: the filesystem
++ * @args: the args to populate
++ * @path: the path to the device
++ *
++ * This will read the super block of the device at @path and populate @args with
++ * the devid, fsid, and uuid. This is meant to be used for ioctls that need to
++ * lookup a device to operate on, but need to do it before we take any locks.
++ * This properly handles the special case of "missing" that a user may pass in,
++ * and does some basic sanity checks. The caller must make sure that @path is
++ * properly NUL terminated before calling in, and must call
++ * btrfs_put_dev_args_from_path() in order to free up the temporary fsid and
++ * uuid buffers.
++ *
++ * Return: 0 for success, -errno for failure
++ */
++int btrfs_get_dev_args_from_path(struct btrfs_fs_info *fs_info,
++ struct btrfs_dev_lookup_args *args,
++ const char *path)
+ {
+- int ret = 0;
+ struct btrfs_super_block *disk_super;
+- u64 devid;
+- u8 *dev_uuid;
+ struct block_device *bdev;
+- struct btrfs_device *device;
++ int ret;
+
+- ret = btrfs_get_bdev_and_sb(device_path, FMODE_READ,
+- fs_info->bdev_holder, 0, &bdev, &disk_super);
+- if (ret)
+- return ERR_PTR(ret);
++ if (!path || !path[0])
++ return -EINVAL;
++ if (!strcmp(path, "missing")) {
++ args->missing = true;
++ return 0;
++ }
+
+- devid = btrfs_stack_device_id(&disk_super->dev_item);
+- dev_uuid = disk_super->dev_item.uuid;
++ args->uuid = kzalloc(BTRFS_UUID_SIZE, GFP_KERNEL);
++ args->fsid = kzalloc(BTRFS_FSID_SIZE, GFP_KERNEL);
++ if (!args->uuid || !args->fsid) {
++ btrfs_put_dev_args_from_path(args);
++ return -ENOMEM;
++ }
++
++ ret = btrfs_get_bdev_and_sb(path, FMODE_READ, fs_info->bdev_holder, 0,
++ &bdev, &disk_super);
++ if (ret)
++ return ret;
++ args->devid = btrfs_stack_device_id(&disk_super->dev_item);
++ memcpy(args->uuid, disk_super->dev_item.uuid, BTRFS_UUID_SIZE);
+ if (btrfs_fs_incompat(fs_info, METADATA_UUID))
+- device = btrfs_find_device(fs_info->fs_devices, devid, dev_uuid,
+- disk_super->metadata_uuid);
++ memcpy(args->fsid, disk_super->metadata_uuid, BTRFS_FSID_SIZE);
+ else
+- device = btrfs_find_device(fs_info->fs_devices, devid, dev_uuid,
+- disk_super->fsid);
+-
++ memcpy(args->fsid, disk_super->fsid, BTRFS_FSID_SIZE);
+ btrfs_release_disk_super(disk_super);
+- if (!device)
+- device = ERR_PTR(-ENOENT);
+ blkdev_put(bdev, FMODE_READ);
+- return device;
++ return 0;
+ }
+
+ /*
+- * Lookup a device given by device id, or the path if the id is 0.
++ * Only use this jointly with btrfs_get_dev_args_from_path() because we will
++ * allocate our ->uuid and ->fsid pointers, everybody else uses local variables
++ * that don't need to be freed.
+ */
++void btrfs_put_dev_args_from_path(struct btrfs_dev_lookup_args *args)
++{
++ kfree(args->uuid);
++ kfree(args->fsid);
++ args->uuid = NULL;
++ args->fsid = NULL;
++}
++
+ struct btrfs_device *btrfs_find_device_by_devspec(
+ struct btrfs_fs_info *fs_info, u64 devid,
+ const char *device_path)
+ {
++ BTRFS_DEV_LOOKUP_ARGS(args);
+ struct btrfs_device *device;
++ int ret;
+
+ if (devid) {
+- device = btrfs_find_device(fs_info->fs_devices, devid, NULL,
+- NULL);
++ args.devid = devid;
++ device = btrfs_find_device(fs_info->fs_devices, &args);
+ if (!device)
+ return ERR_PTR(-ENOENT);
+ return device;
+ }
+
+- if (!device_path || !device_path[0])
+- return ERR_PTR(-EINVAL);
+-
+- if (strcmp(device_path, "missing") == 0) {
+- /* Find first missing device */
+- list_for_each_entry(device, &fs_info->fs_devices->devices,
+- dev_list) {
+- if (test_bit(BTRFS_DEV_STATE_IN_FS_METADATA,
+- &device->dev_state) && !device->bdev)
+- return device;
+- }
++ ret = btrfs_get_dev_args_from_path(fs_info, &args, device_path);
++ if (ret)
++ return ERR_PTR(ret);
++ device = btrfs_find_device(fs_info->fs_devices, &args);
++ btrfs_put_dev_args_from_path(&args);
++ if (!device)
+ return ERR_PTR(-ENOENT);
+- }
+-
+- return btrfs_find_device_by_path(fs_info, device_path);
++ return device;
+ }
+
+ /*
+@@ -2492,6 +2518,7 @@ static int btrfs_prepare_sprout(struct btrfs_fs_info *fs_info)
+ */
+ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans)
+ {
++ BTRFS_DEV_LOOKUP_ARGS(args);
+ struct btrfs_fs_info *fs_info = trans->fs_info;
+ struct btrfs_root *root = fs_info->chunk_root;
+ struct btrfs_path *path;
+@@ -2501,7 +2528,6 @@ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans)
+ struct btrfs_key key;
+ u8 fs_uuid[BTRFS_FSID_SIZE];
+ u8 dev_uuid[BTRFS_UUID_SIZE];
+- u64 devid;
+ int ret;
+
+ path = btrfs_alloc_path();
+@@ -2513,7 +2539,9 @@ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans)
+ key.type = BTRFS_DEV_ITEM_KEY;
+
+ while (1) {
++ btrfs_reserve_chunk_metadata(trans, false);
+ ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
++ btrfs_trans_release_chunk_metadata(trans);
+ if (ret < 0)
+ goto error;
+
+@@ -2538,13 +2566,14 @@ next_slot:
+
+ dev_item = btrfs_item_ptr(leaf, path->slots[0],
+ struct btrfs_dev_item);
+- devid = btrfs_device_id(leaf, dev_item);
++ args.devid = btrfs_device_id(leaf, dev_item);
+ read_extent_buffer(leaf, dev_uuid, btrfs_device_uuid(dev_item),
+ BTRFS_UUID_SIZE);
+ read_extent_buffer(leaf, fs_uuid, btrfs_device_fsid(dev_item),
+ BTRFS_FSID_SIZE);
+- device = btrfs_find_device(fs_info->fs_devices, devid, dev_uuid,
+- fs_uuid);
++ args.uuid = dev_uuid;
++ args.fsid = fs_uuid;
++ device = btrfs_find_device(fs_info->fs_devices, &args);
+ BUG_ON(!device); /* Logic error */
+
+ if (device->fs_devices->seeding) {
+@@ -2861,6 +2890,7 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans,
+ struct btrfs_super_block *super_copy = fs_info->super_copy;
+ u64 old_total;
+ u64 diff;
++ int ret;
+
+ if (!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state))
+ return -EACCES;
+@@ -2889,7 +2919,11 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans,
+ &trans->transaction->dev_update_list);
+ mutex_unlock(&fs_info->chunk_mutex);
+
+- return btrfs_update_device(trans, device);
++ btrfs_reserve_chunk_metadata(trans, false);
++ ret = btrfs_update_device(trans, device);
++ btrfs_trans_release_chunk_metadata(trans);
++
++ return ret;
+ }
+
+ static int btrfs_free_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset)
+@@ -3131,7 +3165,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset)
+ const u64 sys_flags = btrfs_system_alloc_profile(fs_info);
+ struct btrfs_block_group *sys_bg;
+
+- sys_bg = btrfs_alloc_chunk(trans, sys_flags);
++ sys_bg = btrfs_create_chunk(trans, sys_flags);
+ if (IS_ERR(sys_bg)) {
+ ret = PTR_ERR(sys_bg);
+ btrfs_abort_transaction(trans, ret);
+@@ -4926,8 +4960,10 @@ again:
+ round_down(old_total - diff, fs_info->sectorsize));
+ mutex_unlock(&fs_info->chunk_mutex);
+
++ btrfs_reserve_chunk_metadata(trans, false);
+ /* Now btrfs_update_device() will change the on-disk size. */
+ ret = btrfs_update_device(trans, device);
++ btrfs_trans_release_chunk_metadata(trans);
+ if (ret < 0) {
+ btrfs_abort_transaction(trans, ret);
+ btrfs_end_transaction(trans);
+@@ -5010,7 +5046,7 @@ static void check_raid1c34_incompat_flag(struct btrfs_fs_info *info, u64 type)
+ }
+
+ /*
+- * Structure used internally for __btrfs_alloc_chunk() function.
++ * Structure used internally for btrfs_create_chunk() function.
+ * Wraps needed parameters.
+ */
+ struct alloc_chunk_ctl {
+@@ -5414,7 +5450,7 @@ error_del_extent:
+ return block_group;
+ }
+
+-struct btrfs_block_group *btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
++struct btrfs_block_group *btrfs_create_chunk(struct btrfs_trans_handle *trans,
+ u64 type)
+ {
+ struct btrfs_fs_info *info = trans->fs_info;
+@@ -5615,12 +5651,12 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans)
+ */
+
+ alloc_profile = btrfs_metadata_alloc_profile(fs_info);
+- meta_bg = btrfs_alloc_chunk(trans, alloc_profile);
++ meta_bg = btrfs_create_chunk(trans, alloc_profile);
+ if (IS_ERR(meta_bg))
+ return PTR_ERR(meta_bg);
+
+ alloc_profile = btrfs_system_alloc_profile(fs_info);
+- sys_bg = btrfs_alloc_chunk(trans, alloc_profile);
++ sys_bg = btrfs_create_chunk(trans, alloc_profile);
+ if (IS_ERR(sys_bg))
+ return PTR_ERR(sys_bg);
+
+@@ -6792,6 +6828,33 @@ blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
+ return BLK_STS_OK;
+ }
+
++static bool dev_args_match_fs_devices(const struct btrfs_dev_lookup_args *args,
++ const struct btrfs_fs_devices *fs_devices)
++{
++ if (args->fsid == NULL)
++ return true;
++ if (memcmp(fs_devices->metadata_uuid, args->fsid, BTRFS_FSID_SIZE) == 0)
++ return true;
++ return false;
++}
++
++static bool dev_args_match_device(const struct btrfs_dev_lookup_args *args,
++ const struct btrfs_device *device)
++{
++ ASSERT((args->devid != (u64)-1) || args->missing);
++
++ if ((args->devid != (u64)-1) && device->devid != args->devid)
++ return false;
++ if (args->uuid && memcmp(device->uuid, args->uuid, BTRFS_UUID_SIZE) != 0)
++ return false;
++ if (!args->missing)
++ return true;
++ if (test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state) &&
++ !device->bdev)
++ return true;
++ return false;
++}
++
+ /*
+ * Find a device specified by @devid or @uuid in the list of @fs_devices, or
+ * return NULL.
+@@ -6799,31 +6862,25 @@ blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
+ * If devid and uuid are both specified, the match must be exact, otherwise
+ * only devid is used.
+ */
+-struct btrfs_device *btrfs_find_device(struct btrfs_fs_devices *fs_devices,
+- u64 devid, u8 *uuid, u8 *fsid)
++struct btrfs_device *btrfs_find_device(const struct btrfs_fs_devices *fs_devices,
++ const struct btrfs_dev_lookup_args *args)
+ {
+ struct btrfs_device *device;
+ struct btrfs_fs_devices *seed_devs;
+
+- if (!fsid || !memcmp(fs_devices->metadata_uuid, fsid, BTRFS_FSID_SIZE)) {
++ if (dev_args_match_fs_devices(args, fs_devices)) {
+ list_for_each_entry(device, &fs_devices->devices, dev_list) {
+- if (device->devid == devid &&
+- (!uuid || memcmp(device->uuid, uuid,
+- BTRFS_UUID_SIZE) == 0))
++ if (dev_args_match_device(args, device))
+ return device;
+ }
+ }
+
+ list_for_each_entry(seed_devs, &fs_devices->seed_list, seed_list) {
+- if (!fsid ||
+- !memcmp(seed_devs->metadata_uuid, fsid, BTRFS_FSID_SIZE)) {
+- list_for_each_entry(device, &seed_devs->devices,
+- dev_list) {
+- if (device->devid == devid &&
+- (!uuid || memcmp(device->uuid, uuid,
+- BTRFS_UUID_SIZE) == 0))
+- return device;
+- }
++ if (!dev_args_match_fs_devices(args, seed_devs))
++ continue;
++ list_for_each_entry(device, &seed_devs->devices, dev_list) {
++ if (dev_args_match_device(args, device))
++ return device;
+ }
+ }
+
+@@ -6989,6 +7046,7 @@ static void warn_32bit_meta_chunk(struct btrfs_fs_info *fs_info,
+ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
+ struct btrfs_chunk *chunk)
+ {
++ BTRFS_DEV_LOOKUP_ARGS(args);
+ struct btrfs_fs_info *fs_info = leaf->fs_info;
+ struct extent_map_tree *map_tree = &fs_info->mapping_tree;
+ struct map_lookup *map;
+@@ -7066,11 +7124,12 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
+ map->stripes[i].physical =
+ btrfs_stripe_offset_nr(leaf, chunk, i);
+ devid = btrfs_stripe_devid_nr(leaf, chunk, i);
++ args.devid = devid;
+ read_extent_buffer(leaf, uuid, (unsigned long)
+ btrfs_stripe_dev_uuid_nr(chunk, i),
+ BTRFS_UUID_SIZE);
+- map->stripes[i].dev = btrfs_find_device(fs_info->fs_devices,
+- devid, uuid, NULL);
++ args.uuid = uuid;
++ map->stripes[i].dev = btrfs_find_device(fs_info->fs_devices, &args);
+ if (!map->stripes[i].dev &&
+ !btrfs_test_opt(fs_info, DEGRADED)) {
+ free_extent_map(em);
+@@ -7188,6 +7247,7 @@ static struct btrfs_fs_devices *open_seed_devices(struct btrfs_fs_info *fs_info,
+ static int read_one_dev(struct extent_buffer *leaf,
+ struct btrfs_dev_item *dev_item)
+ {
++ BTRFS_DEV_LOOKUP_ARGS(args);
+ struct btrfs_fs_info *fs_info = leaf->fs_info;
+ struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
+ struct btrfs_device *device;
+@@ -7196,11 +7256,13 @@ static int read_one_dev(struct extent_buffer *leaf,
+ u8 fs_uuid[BTRFS_FSID_SIZE];
+ u8 dev_uuid[BTRFS_UUID_SIZE];
+
+- devid = btrfs_device_id(leaf, dev_item);
++ devid = args.devid = btrfs_device_id(leaf, dev_item);
+ read_extent_buffer(leaf, dev_uuid, btrfs_device_uuid(dev_item),
+ BTRFS_UUID_SIZE);
+ read_extent_buffer(leaf, fs_uuid, btrfs_device_fsid(dev_item),
+ BTRFS_FSID_SIZE);
++ args.uuid = dev_uuid;
++ args.fsid = fs_uuid;
+
+ if (memcmp(fs_uuid, fs_devices->metadata_uuid, BTRFS_FSID_SIZE)) {
+ fs_devices = open_seed_devices(fs_info, fs_uuid);
+@@ -7208,8 +7270,7 @@ static int read_one_dev(struct extent_buffer *leaf,
+ return PTR_ERR(fs_devices);
+ }
+
+- device = btrfs_find_device(fs_info->fs_devices, devid, dev_uuid,
+- fs_uuid);
++ device = btrfs_find_device(fs_info->fs_devices, &args);
+ if (!device) {
+ if (!btrfs_test_opt(fs_info, DEGRADED)) {
+ btrfs_report_missing_device(fs_info, devid,
+@@ -7886,12 +7947,14 @@ static void btrfs_dev_stat_print_on_load(struct btrfs_device *dev)
+ int btrfs_get_dev_stats(struct btrfs_fs_info *fs_info,
+ struct btrfs_ioctl_get_dev_stats *stats)
+ {
++ BTRFS_DEV_LOOKUP_ARGS(args);
+ struct btrfs_device *dev;
+ struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
+ int i;
+
+ mutex_lock(&fs_devices->device_list_mutex);
+- dev = btrfs_find_device(fs_info->fs_devices, stats->devid, NULL, NULL);
++ args.devid = stats->devid;
++ dev = btrfs_find_device(fs_info->fs_devices, &args);
+ mutex_unlock(&fs_devices->device_list_mutex);
+
+ if (!dev) {
+@@ -7967,6 +8030,7 @@ static int verify_one_dev_extent(struct btrfs_fs_info *fs_info,
+ u64 chunk_offset, u64 devid,
+ u64 physical_offset, u64 physical_len)
+ {
++ struct btrfs_dev_lookup_args args = { .devid = devid };
+ struct extent_map_tree *em_tree = &fs_info->mapping_tree;
+ struct extent_map *em;
+ struct map_lookup *map;
+@@ -8022,7 +8086,7 @@ static int verify_one_dev_extent(struct btrfs_fs_info *fs_info,
+ }
+
+ /* Make sure no dev extent is beyond device boundary */
+- dev = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL);
++ dev = btrfs_find_device(fs_info->fs_devices, &args);
+ if (!dev) {
+ btrfs_err(fs_info, "failed to find devid %llu", devid);
+ ret = -EUCLEAN;
+diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
+index 4db10d071d67f..30288b728bbbd 100644
+--- a/fs/btrfs/volumes.h
++++ b/fs/btrfs/volumes.h
+@@ -418,6 +418,22 @@ struct btrfs_balance_control {
+ struct btrfs_balance_progress stat;
+ };
+
++/*
++ * Search for a given device by the set parameters
++ */
++struct btrfs_dev_lookup_args {
++ u64 devid;
++ u8 *uuid;
++ u8 *fsid;
++ bool missing;
++};
++
++/* We have to initialize to -1 because BTRFS_DEV_REPLACE_DEVID is 0 */
++#define BTRFS_DEV_LOOKUP_ARGS_INIT { .devid = (u64)-1 }
++
++#define BTRFS_DEV_LOOKUP_ARGS(name) \
++ struct btrfs_dev_lookup_args name = BTRFS_DEV_LOOKUP_ARGS_INIT
++
+ enum btrfs_map_op {
+ BTRFS_MAP_READ,
+ BTRFS_MAP_WRITE,
+@@ -454,7 +470,7 @@ int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *map,
+ struct btrfs_io_geometry *io_geom);
+ int btrfs_read_sys_array(struct btrfs_fs_info *fs_info);
+ int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info);
+-struct btrfs_block_group *btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
++struct btrfs_block_group *btrfs_create_chunk(struct btrfs_trans_handle *trans,
+ u64 type);
+ void btrfs_mapping_tree_free(struct extent_map_tree *tree);
+ blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
+@@ -471,19 +487,23 @@ void btrfs_assign_next_active_device(struct btrfs_device *device,
+ struct btrfs_device *btrfs_find_device_by_devspec(struct btrfs_fs_info *fs_info,
+ u64 devid,
+ const char *devpath);
++int btrfs_get_dev_args_from_path(struct btrfs_fs_info *fs_info,
++ struct btrfs_dev_lookup_args *args,
++ const char *path);
+ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
+ const u64 *devid,
+ const u8 *uuid);
++void btrfs_put_dev_args_from_path(struct btrfs_dev_lookup_args *args);
+ void btrfs_free_device(struct btrfs_device *device);
+ int btrfs_rm_device(struct btrfs_fs_info *fs_info,
+- const char *device_path, u64 devid,
++ struct btrfs_dev_lookup_args *args,
+ struct block_device **bdev, fmode_t *mode);
+ void __exit btrfs_cleanup_fs_uuids(void);
+ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len);
+ int btrfs_grow_device(struct btrfs_trans_handle *trans,
+ struct btrfs_device *device, u64 new_size);
+-struct btrfs_device *btrfs_find_device(struct btrfs_fs_devices *fs_devices,
+- u64 devid, u8 *uuid, u8 *fsid);
++struct btrfs_device *btrfs_find_device(const struct btrfs_fs_devices *fs_devices,
++ const struct btrfs_dev_lookup_args *args);
+ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
+ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *path);
+ int btrfs_balance(struct btrfs_fs_info *fs_info,
+diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
+index 596b2148807d4..3bc2f92cd197a 100644
+--- a/fs/btrfs/zoned.c
++++ b/fs/btrfs/zoned.c
+@@ -636,7 +636,7 @@ int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info)
+
+ /*
+ * stripe_size is always aligned to BTRFS_STRIPE_LEN in
+- * __btrfs_alloc_chunk(). Since we want stripe_len == zone_size,
++ * btrfs_create_chunk(). Since we want stripe_len == zone_size,
+ * check the alignment here.
+ */
+ if (!IS_ALIGNED(zone_size, BTRFS_STRIPE_LEN)) {
+diff --git a/fs/btrfs/zoned.h b/fs/btrfs/zoned.h
+index 813aa3cddc11f..3a826f7c20403 100644
+--- a/fs/btrfs/zoned.h
++++ b/fs/btrfs/zoned.h
+@@ -8,6 +8,7 @@
+ #include "volumes.h"
+ #include "disk-io.h"
+ #include "block-group.h"
++#include "btrfs_inode.h"
+
+ /*
+ * Block groups with more than this value (percents) of unusable space will be
+@@ -324,4 +325,20 @@ static inline void btrfs_clear_treelog_bg(struct btrfs_block_group *bg)
+ spin_unlock(&fs_info->treelog_bg_lock);
+ }
+
++static inline void btrfs_zoned_data_reloc_lock(struct btrfs_inode *inode)
++{
++ struct btrfs_root *root = inode->root;
++
++ if (btrfs_is_data_reloc_root(root) && btrfs_is_zoned(root->fs_info))
++ mutex_lock(&root->fs_info->zoned_data_reloc_io_lock);
++}
++
++static inline void btrfs_zoned_data_reloc_unlock(struct btrfs_inode *inode)
++{
++ struct btrfs_root *root = inode->root;
++
++ if (btrfs_is_data_reloc_root(root) && btrfs_is_zoned(root->fs_info))
++ mutex_unlock(&root->fs_info->zoned_data_reloc_io_lock);
++}
++
+ #endif
+diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
+index 60390f9dc31f4..e93185d804e0a 100644
+--- a/fs/gfs2/file.c
++++ b/fs/gfs2/file.c
+@@ -1086,6 +1086,7 @@ out_uninit:
+ gfs2_holder_uninit(gh);
+ if (statfs_gh)
+ kfree(statfs_gh);
++ from->count = orig_count - read;
+ return read ? read : ret;
+ }
+
+diff --git a/fs/io_uring.c b/fs/io_uring.c
+index 1893237403247..9bff14c5e2b26 100644
+--- a/fs/io_uring.c
++++ b/fs/io_uring.c
+@@ -2686,8 +2686,12 @@ static bool io_rw_should_reissue(struct io_kiocb *req)
+
+ static bool __io_complete_rw_common(struct io_kiocb *req, long res)
+ {
+- if (req->rw.kiocb.ki_flags & IOCB_WRITE)
++ if (req->rw.kiocb.ki_flags & IOCB_WRITE) {
+ kiocb_end_write(req);
++ fsnotify_modify(req->file);
++ } else {
++ fsnotify_access(req->file);
++ }
+ if (res != req->result) {
+ if ((res == -EAGAIN || res == -EOPNOTSUPP) &&
+ io_rw_should_reissue(req)) {
+@@ -4183,6 +4187,8 @@ static int io_fallocate(struct io_kiocb *req, unsigned int issue_flags)
+ req->sync.len);
+ if (ret < 0)
+ req_set_fail(req);
++ else
++ fsnotify_modify(req->file);
+ io_req_complete(req, ret);
+ return 0;
+ }
+@@ -6860,7 +6866,7 @@ static void io_wq_submit_work(struct io_wq_work *work)
+ * forcing a sync submission from here, since we can't
+ * wait for request slots on the block side.
+ */
+- if (ret != -EAGAIN)
++ if (ret != -EAGAIN || !(req->ctx->flags & IORING_SETUP_IOPOLL))
+ break;
+ cond_resched();
+ } while (1);
+diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
+index b540489ea240d..936eebd4c56dc 100644
+--- a/fs/nfsd/nfs3proc.c
++++ b/fs/nfsd/nfs3proc.c
+@@ -660,15 +660,9 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
+ argp->count,
+ (unsigned long long) argp->offset);
+
+- if (argp->offset > NFS_OFFSET_MAX) {
+- resp->status = nfserr_inval;
+- goto out;
+- }
+-
+ fh_copy(&resp->fh, &argp->fh);
+ resp->status = nfsd_commit(rqstp, &resp->fh, argp->offset,
+ argp->count, resp->verf);
+-out:
+ return rpc_success;
+ }
+
+diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
+index 5f62fa0963ced..abfbb6953e89a 100644
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -1108,44 +1108,64 @@ out:
+ }
+
+ #ifdef CONFIG_NFSD_V3
+-/*
+- * Commit all pending writes to stable storage.
++/**
++ * nfsd_commit - Commit pending writes to stable storage
++ * @rqstp: RPC request being processed
++ * @fhp: NFS filehandle
++ * @offset: raw offset from beginning of file
++ * @count: raw count of bytes to sync
++ * @verf: filled in with the server's current write verifier
+ *
+- * Note: we only guarantee that data that lies within the range specified
+- * by the 'offset' and 'count' parameters will be synced.
++ * Note: we guarantee that data that lies within the range specified
++ * by the 'offset' and 'count' parameters will be synced. The server
++ * is permitted to sync data that lies outside this range at the
++ * same time.
+ *
+ * Unfortunately we cannot lock the file to make sure we return full WCC
+ * data to the client, as locking happens lower down in the filesystem.
++ *
++ * Return values:
++ * An nfsstat value in network byte order.
+ */
+ __be32
+-nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
+- loff_t offset, unsigned long count, __be32 *verf)
++nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset,
++ u32 count, __be32 *verf)
+ {
++ u64 maxbytes;
++ loff_t start, end;
++ struct nfsd_net *nn;
+ struct nfsd_file *nf;
+- loff_t end = LLONG_MAX;
+- __be32 err = nfserr_inval;
+-
+- if (offset < 0)
+- goto out;
+- if (count != 0) {
+- end = offset + (loff_t)count - 1;
+- if (end < offset)
+- goto out;
+- }
++ __be32 err;
+
+ err = nfsd_file_acquire(rqstp, fhp,
+ NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &nf);
+ if (err)
+ goto out;
++
++ /*
++ * Convert the client-provided (offset, count) range to a
++ * (start, end) range. If the client-provided range falls
++ * outside the maximum file size of the underlying FS,
++ * clamp the sync range appropriately.
++ */
++ start = 0;
++ end = LLONG_MAX;
++ maxbytes = (u64)fhp->fh_dentry->d_sb->s_maxbytes;
++ if (offset < maxbytes) {
++ start = offset;
++ if (count && (offset + count - 1 < maxbytes))
++ end = offset + count - 1;
++ }
++
++ nn = net_generic(nf->nf_net, nfsd_net_id);
+ if (EX_ISSYNC(fhp->fh_export)) {
+ errseq_t since = READ_ONCE(nf->nf_file->f_wb_err);
+ int err2;
+
+- err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
++ err2 = vfs_fsync_range(nf->nf_file, start, end, 0);
+ switch (err2) {
+ case 0:
+- nfsd_copy_boot_verifier(verf, net_generic(nf->nf_net,
+- nfsd_net_id));
++ nfsd_copy_boot_verifier(verf, nn);
+ err2 = filemap_check_wb_err(nf->nf_file->f_mapping,
+ since);
+ err = nfserrno(err2);
+@@ -1154,13 +1174,11 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ err = nfserr_notsupp;
+ break;
+ default:
+- nfsd_reset_boot_verifier(net_generic(nf->nf_net,
+- nfsd_net_id));
++ nfsd_reset_boot_verifier(nn);
+ err = nfserrno(err2);
+ }
+ } else
+- nfsd_copy_boot_verifier(verf, net_generic(nf->nf_net,
+- nfsd_net_id));
++ nfsd_copy_boot_verifier(verf, nn);
+
+ nfsd_file_put(nf);
+ out:
+diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
+index b21b76e6b9a87..3cf5a8a13da50 100644
+--- a/fs/nfsd/vfs.h
++++ b/fs/nfsd/vfs.h
+@@ -73,8 +73,8 @@ __be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *,
+ char *name, int len, struct iattr *attrs,
+ struct svc_fh *res, int createmode,
+ u32 *verifier, bool *truncp, bool *created);
+-__be32 nfsd_commit(struct svc_rqst *, struct svc_fh *,
+- loff_t, unsigned long, __be32 *verf);
++__be32 nfsd_commit(struct svc_rqst *rqst, struct svc_fh *fhp,
++ u64 offset, u32 count, __be32 *verf);
+ #endif /* CONFIG_NFSD_V3 */
+ #ifdef CONFIG_NFSD_V4
+ __be32 nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
+diff --git a/fs/seq_file.c b/fs/seq_file.c
+index 4a2cda04d3e29..b17ee4c4f618a 100644
+--- a/fs/seq_file.c
++++ b/fs/seq_file.c
+@@ -947,6 +947,38 @@ struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos)
+ }
+ EXPORT_SYMBOL(seq_list_next);
+
++struct list_head *seq_list_start_rcu(struct list_head *head, loff_t pos)
++{
++ struct list_head *lh;
++
++ list_for_each_rcu(lh, head)
++ if (pos-- == 0)
++ return lh;
++
++ return NULL;
++}
++EXPORT_SYMBOL(seq_list_start_rcu);
++
++struct list_head *seq_list_start_head_rcu(struct list_head *head, loff_t pos)
++{
++ if (!pos)
++ return head;
++
++ return seq_list_start_rcu(head, pos - 1);
++}
++EXPORT_SYMBOL(seq_list_start_head_rcu);
++
++struct list_head *seq_list_next_rcu(void *v, struct list_head *head,
++ loff_t *ppos)
++{
++ struct list_head *lh;
++
++ lh = list_next_rcu((struct list_head *)v);
++ ++*ppos;
++ return lh == head ? NULL : lh;
++}
++EXPORT_SYMBOL(seq_list_next_rcu);
++
+ /**
+ * seq_hlist_start - start an iteration of a hlist
+ * @head: the head of the hlist
+diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
+index 2477e301fa828..c19f3ca605af6 100644
+--- a/fs/xfs/xfs_inode.c
++++ b/fs/xfs/xfs_inode.c
+@@ -3128,7 +3128,6 @@ xfs_rename(
+ * appropriately.
+ */
+ if (flags & RENAME_WHITEOUT) {
+- ASSERT(!(flags & (RENAME_NOREPLACE | RENAME_EXCHANGE)));
+ error = xfs_rename_alloc_whiteout(mnt_userns, target_dp, &wip);
+ if (error)
+ return error;
+diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
+index 17c92c0f15b20..36ce3d0fb9f3b 100644
+--- a/include/linux/blk_types.h
++++ b/include/linux/blk_types.h
+@@ -294,7 +294,8 @@ enum {
+ BIO_TRACE_COMPLETION, /* bio_endio() should trace the final completion
+ * of this bio. */
+ BIO_CGROUP_ACCT, /* has been accounted to a cgroup */
+- BIO_TRACKED, /* set if bio goes through the rq_qos path */
++ BIO_QOS_THROTTLED, /* bio went through rq_qos throttle path */
++ BIO_QOS_MERGED, /* but went through rq_qos merge path */
+ BIO_REMAPPED,
+ BIO_ZONE_WRITE_LOCKED, /* Owns a zoned device zone write lock */
+ BIO_PERCPU_CACHE, /* can participate in per-cpu alloc cache */
+diff --git a/include/linux/bpf.h b/include/linux/bpf.h
+index bb766a0b9b51e..818cd594e9229 100644
+--- a/include/linux/bpf.h
++++ b/include/linux/bpf.h
+@@ -533,6 +533,12 @@ bpf_ctx_record_field_size(struct bpf_insn_access_aux *aux, u32 size)
+ aux->ctx_field_size = size;
+ }
+
++static inline bool bpf_pseudo_func(const struct bpf_insn *insn)
++{
++ return insn->code == (BPF_LD | BPF_IMM | BPF_DW) &&
++ insn->src_reg == BPF_PSEUDO_FUNC;
++}
++
+ struct bpf_prog_ops {
+ int (*test_run)(struct bpf_prog *prog, const union bpf_attr *kattr,
+ union bpf_attr __user *uattr);
+diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
+index bd2b881c6b63a..b9d5f9c373a09 100644
+--- a/include/linux/compiler-gcc.h
++++ b/include/linux/compiler-gcc.h
+@@ -144,3 +144,11 @@
+ #else
+ #define __diag_GCC_8(s)
+ #endif
++
++/*
++ * Prior to 9.1, -Wno-alloc-size-larger-than (and therefore the "alloc_size"
++ * attribute) do not work, and must be disabled.
++ */
++#if GCC_VERSION < 90100
++#undef __alloc_size__
++#endif
+diff --git a/include/linux/compiler_attributes.h b/include/linux/compiler_attributes.h
+index e6ec634039658..3de06a8fae73b 100644
+--- a/include/linux/compiler_attributes.h
++++ b/include/linux/compiler_attributes.h
+@@ -33,6 +33,15 @@
+ #define __aligned(x) __attribute__((__aligned__(x)))
+ #define __aligned_largest __attribute__((__aligned__))
+
++/*
++ * Note: do not use this directly. Instead, use __alloc_size() since it is conditionally
++ * available and includes other attributes.
++ *
++ * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-alloc_005fsize-function-attribute
++ * clang: https://clang.llvm.org/docs/AttributeReference.html#alloc-size
++ */
++#define __alloc_size__(x, ...) __attribute__((__alloc_size__(x, ## __VA_ARGS__)))
++
+ /*
+ * Note: users of __always_inline currently do not write "inline" themselves,
+ * which seems to be required by gcc to apply the attribute according
+@@ -153,6 +162,7 @@
+
+ /*
+ * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-malloc-function-attribute
++ * clang: https://clang.llvm.org/docs/AttributeReference.html#malloc
+ */
+ #define __malloc __attribute__((__malloc__))
+
+diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
+index b6ff83a714ca9..4f2203c4a2574 100644
+--- a/include/linux/compiler_types.h
++++ b/include/linux/compiler_types.h
+@@ -250,6 +250,18 @@ struct ftrace_likely_data {
+ # define __cficanonical
+ #endif
+
++/*
++ * Any place that could be marked with the "alloc_size" attribute is also
++ * a place to be marked with the "malloc" attribute. Do this as part of the
++ * __alloc_size macro to avoid redundant attributes and to avoid missing a
++ * __malloc marking.
++ */
++#ifdef __alloc_size__
++# define __alloc_size(x, ...) __alloc_size__(x, ## __VA_ARGS__) __malloc
++#else
++# define __alloc_size(x, ...) __malloc
++#endif
++
+ #ifndef asm_volatile_goto
+ #define asm_volatile_goto(x...) asm goto(x)
+ #endif
+diff --git a/include/linux/fbcon.h b/include/linux/fbcon.h
+index ff5596dd30f85..2382dec6d6ab8 100644
+--- a/include/linux/fbcon.h
++++ b/include/linux/fbcon.h
+@@ -15,6 +15,8 @@ void fbcon_new_modelist(struct fb_info *info);
+ void fbcon_get_requirement(struct fb_info *info,
+ struct fb_blit_caps *caps);
+ void fbcon_fb_blanked(struct fb_info *info, int blank);
++int fbcon_modechange_possible(struct fb_info *info,
++ struct fb_var_screeninfo *var);
+ void fbcon_update_vcs(struct fb_info *info, bool all);
+ void fbcon_remap_all(struct fb_info *info);
+ int fbcon_set_con2fb_map_ioctl(void __user *argp);
+@@ -33,6 +35,8 @@ static inline void fbcon_new_modelist(struct fb_info *info) {}
+ static inline void fbcon_get_requirement(struct fb_info *info,
+ struct fb_blit_caps *caps) {}
+ static inline void fbcon_fb_blanked(struct fb_info *info, int blank) {}
++static inline int fbcon_modechange_possible(struct fb_info *info,
++ struct fb_var_screeninfo *var) { return 0; }
+ static inline void fbcon_update_vcs(struct fb_info *info, bool all) {}
+ static inline void fbcon_remap_all(struct fb_info *info) {}
+ static inline int fbcon_set_con2fb_map_ioctl(void __user *argp) { return 0; }
+diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
+index 1faebe1cd0ed5..22c1d935e22dd 100644
+--- a/include/linux/hugetlb.h
++++ b/include/linux/hugetlb.h
+@@ -167,6 +167,7 @@ long hugetlb_unreserve_pages(struct inode *inode, long start, long end,
+ long freed);
+ bool isolate_huge_page(struct page *page, struct list_head *list);
+ int get_hwpoison_huge_page(struct page *page, bool *hugetlb);
++int get_huge_page_for_hwpoison(unsigned long pfn, int flags);
+ void putback_active_hugepage(struct page *page);
+ void move_hugetlb_state(struct page *oldpage, struct page *newpage, int reason);
+ void free_huge_page(struct page *page);
+@@ -362,6 +363,11 @@ static inline int get_hwpoison_huge_page(struct page *page, bool *hugetlb)
+ return 0;
+ }
+
++static inline int get_huge_page_for_hwpoison(unsigned long pfn, int flags)
++{
++ return 0;
++}
++
+ static inline void putback_active_hugepage(struct page *page)
+ {
+ }
+diff --git a/include/linux/list.h b/include/linux/list.h
+index a119dd1990d4e..d206ae93c06da 100644
+--- a/include/linux/list.h
++++ b/include/linux/list.h
+@@ -577,6 +577,16 @@ static inline void list_splice_tail_init(struct list_head *list,
+ #define list_for_each(pos, head) \
+ for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next)
+
++/**
++ * list_for_each_rcu - Iterate over a list in an RCU-safe fashion
++ * @pos: the &struct list_head to use as a loop cursor.
++ * @head: the head for your list.
++ */
++#define list_for_each_rcu(pos, head) \
++ for (pos = rcu_dereference((head)->next); \
++ !list_is_head(pos, (head)); \
++ pos = rcu_dereference(pos->next))
++
+ /**
+ * list_for_each_continue - continue iteration over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+diff --git a/include/linux/memregion.h b/include/linux/memregion.h
+index e11595256cac0..c04c4fd2e2091 100644
+--- a/include/linux/memregion.h
++++ b/include/linux/memregion.h
+@@ -16,7 +16,7 @@ static inline int memregion_alloc(gfp_t gfp)
+ {
+ return -ENOMEM;
+ }
+-void memregion_free(int id)
++static inline void memregion_free(int id)
+ {
+ }
+ #endif
+diff --git a/include/linux/mm.h b/include/linux/mm.h
+index 85205adcdd0d1..e4e1817bb3b89 100644
+--- a/include/linux/mm.h
++++ b/include/linux/mm.h
+@@ -3132,6 +3132,14 @@ extern int sysctl_memory_failure_recovery;
+ extern void shake_page(struct page *p);
+ extern atomic_long_t num_poisoned_pages __read_mostly;
+ extern int soft_offline_page(unsigned long pfn, int flags);
++#ifdef CONFIG_MEMORY_FAILURE
++extern int __get_huge_page_for_hwpoison(unsigned long pfn, int flags);
++#else
++static inline int __get_huge_page_for_hwpoison(unsigned long pfn, int flags)
++{
++ return 0;
++}
++#endif
+
+
+ /*
+diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
+index 016de5776b6db..90eaff8b78fc9 100644
+--- a/include/linux/pm_runtime.h
++++ b/include/linux/pm_runtime.h
+@@ -58,7 +58,7 @@ extern void pm_runtime_get_suppliers(struct device *dev);
+ extern void pm_runtime_put_suppliers(struct device *dev);
+ extern void pm_runtime_new_link(struct device *dev);
+ extern void pm_runtime_drop_link(struct device_link *link);
+-extern void pm_runtime_release_supplier(struct device_link *link, bool check_idle);
++extern void pm_runtime_release_supplier(struct device_link *link);
+
+ extern int devm_pm_runtime_enable(struct device *dev);
+
+@@ -284,8 +284,7 @@ static inline void pm_runtime_get_suppliers(struct device *dev) {}
+ static inline void pm_runtime_put_suppliers(struct device *dev) {}
+ static inline void pm_runtime_new_link(struct device *dev) {}
+ static inline void pm_runtime_drop_link(struct device_link *link) {}
+-static inline void pm_runtime_release_supplier(struct device_link *link,
+- bool check_idle) {}
++static inline void pm_runtime_release_supplier(struct device_link *link) {}
+
+ #endif /* !CONFIG_PM */
+
+diff --git a/include/linux/qed/qed_eth_if.h b/include/linux/qed/qed_eth_if.h
+index 812a4d7511633..4df0bf0a0864e 100644
+--- a/include/linux/qed/qed_eth_if.h
++++ b/include/linux/qed/qed_eth_if.h
+@@ -145,12 +145,6 @@ struct qed_filter_mcast_params {
+ unsigned char mac[64][ETH_ALEN];
+ };
+
+-union qed_filter_type_params {
+- enum qed_filter_rx_mode_type accept_flags;
+- struct qed_filter_ucast_params ucast;
+- struct qed_filter_mcast_params mcast;
+-};
+-
+ enum qed_filter_type {
+ QED_FILTER_TYPE_UCAST,
+ QED_FILTER_TYPE_MCAST,
+@@ -158,11 +152,6 @@ enum qed_filter_type {
+ QED_MAX_FILTER_TYPES,
+ };
+
+-struct qed_filter_params {
+- enum qed_filter_type type;
+- union qed_filter_type_params filter;
+-};
+-
+ struct qed_tunn_params {
+ u16 vxlan_port;
+ u8 update_vxlan_port;
+@@ -314,8 +303,14 @@ struct qed_eth_ops {
+
+ int (*q_tx_stop)(struct qed_dev *cdev, u8 rss_id, void *handle);
+
+- int (*filter_config)(struct qed_dev *cdev,
+- struct qed_filter_params *params);
++ int (*filter_config_rx_mode)(struct qed_dev *cdev,
++ enum qed_filter_rx_mode_type type);
++
++ int (*filter_config_ucast)(struct qed_dev *cdev,
++ struct qed_filter_ucast_params *params);
++
++ int (*filter_config_mcast)(struct qed_dev *cdev,
++ struct qed_filter_mcast_params *params);
+
+ int (*fastpath_stop)(struct qed_dev *cdev);
+
+diff --git a/include/linux/rtsx_usb.h b/include/linux/rtsx_usb.h
+index 159729cffd8e1..3247ed8e9ff0f 100644
+--- a/include/linux/rtsx_usb.h
++++ b/include/linux/rtsx_usb.h
+@@ -54,8 +54,6 @@ struct rtsx_ucr {
+ struct usb_device *pusb_dev;
+ struct usb_interface *pusb_intf;
+ struct usb_sg_request current_sg;
+- unsigned char *iobuf;
+- dma_addr_t iobuf_dma;
+
+ struct timer_list sg_timer;
+ struct mutex dev_mutex;
+diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
+index 5733890df64f5..0b429111f85e4 100644
+--- a/include/linux/seq_file.h
++++ b/include/linux/seq_file.h
+@@ -261,6 +261,10 @@ extern struct list_head *seq_list_start_head(struct list_head *head,
+ extern struct list_head *seq_list_next(void *v, struct list_head *head,
+ loff_t *ppos);
+
++extern struct list_head *seq_list_start_rcu(struct list_head *head, loff_t pos);
++extern struct list_head *seq_list_start_head_rcu(struct list_head *head, loff_t pos);
++extern struct list_head *seq_list_next_rcu(void *v, struct list_head *head, loff_t *ppos);
++
+ /*
+ * Helpers for iteration over hlist_head-s in seq_files
+ */
+diff --git a/include/linux/stddef.h b/include/linux/stddef.h
+index 998a4ba28eba4..31fdbb784c24e 100644
+--- a/include/linux/stddef.h
++++ b/include/linux/stddef.h
+@@ -36,4 +36,65 @@ enum {
+ #define offsetofend(TYPE, MEMBER) \
+ (offsetof(TYPE, MEMBER) + sizeof_field(TYPE, MEMBER))
+
++/**
++ * struct_group() - Wrap a set of declarations in a mirrored struct
++ *
++ * @NAME: The identifier name of the mirrored sub-struct
++ * @MEMBERS: The member declarations for the mirrored structs
++ *
++ * Used to create an anonymous union of two structs with identical
++ * layout and size: one anonymous and one named. The former can be
++ * used normally without sub-struct naming, and the latter can be
++ * used to reason about the start, end, and size of the group of
++ * struct members.
++ */
++#define struct_group(NAME, MEMBERS...) \
++ __struct_group(/* no tag */, NAME, /* no attrs */, MEMBERS)
++
++/**
++ * struct_group_attr() - Create a struct_group() with trailing attributes
++ *
++ * @NAME: The identifier name of the mirrored sub-struct
++ * @ATTRS: Any struct attributes to apply
++ * @MEMBERS: The member declarations for the mirrored structs
++ *
++ * Used to create an anonymous union of two structs with identical
++ * layout and size: one anonymous and one named. The former can be
++ * used normally without sub-struct naming, and the latter can be
++ * used to reason about the start, end, and size of the group of
++ * struct members. Includes structure attributes argument.
++ */
++#define struct_group_attr(NAME, ATTRS, MEMBERS...) \
++ __struct_group(/* no tag */, NAME, ATTRS, MEMBERS)
++
++/**
++ * struct_group_tagged() - Create a struct_group with a reusable tag
++ *
++ * @TAG: The tag name for the named sub-struct
++ * @NAME: The identifier name of the mirrored sub-struct
++ * @MEMBERS: The member declarations for the mirrored structs
++ *
++ * Used to create an anonymous union of two structs with identical
++ * layout and size: one anonymous and one named. The former can be
++ * used normally without sub-struct naming, and the latter can be
++ * used to reason about the start, end, and size of the group of
++ * struct members. Includes struct tag argument for the named copy,
++ * so the specified layout can be reused later.
++ */
++#define struct_group_tagged(TAG, NAME, MEMBERS...) \
++ __struct_group(TAG, NAME, /* no attrs */, MEMBERS)
++
++/**
++ * DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union
++ *
++ * @TYPE: The type of each flexible array element
++ * @NAME: The name of the flexible array member
++ *
++ * In order to have a flexible array member in a union or alone in a
++ * struct, it needs to be wrapped in an anonymous struct with at least 1
++ * named member, but that member can be empty.
++ */
++#define DECLARE_FLEX_ARRAY(TYPE, NAME) \
++ __DECLARE_FLEX_ARRAY(TYPE, NAME)
++
+ #endif
+diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
+index 4fe9e885bbfac..5535be1012a28 100644
+--- a/include/linux/vmalloc.h
++++ b/include/linux/vmalloc.h
+@@ -159,6 +159,11 @@ void *__vmalloc_node(unsigned long size, unsigned long align, gfp_t gfp_mask,
+ int node, const void *caller);
+ void *vmalloc_no_huge(unsigned long size);
+
++extern void *__vmalloc_array(size_t n, size_t size, gfp_t flags) __alloc_size(1, 2);
++extern void *vmalloc_array(size_t n, size_t size) __alloc_size(1, 2);
++extern void *__vcalloc(size_t n, size_t size, gfp_t flags) __alloc_size(1, 2);
++extern void *vcalloc(size_t n, size_t size) __alloc_size(1, 2);
++
+ extern void vfree(const void *addr);
+ extern void vfree_atomic(const void *addr);
+
+diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
+index 2af1c2c64128e..bcfee89012a18 100644
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -21,13 +21,19 @@ struct module;
+
+ #define NFT_JUMP_STACK_SIZE 16
+
++enum {
++ NFT_PKTINFO_L4PROTO = (1 << 0),
++ NFT_PKTINFO_INNER = (1 << 1),
++};
++
+ struct nft_pktinfo {
+ struct sk_buff *skb;
+ const struct nf_hook_state *state;
+- bool tprot_set;
++ u8 flags;
+ u8 tprot;
+ u16 fragoff;
+ unsigned int thoff;
++ unsigned int inneroff;
+ };
+
+ static inline struct sock *nft_sk(const struct nft_pktinfo *pkt)
+@@ -75,7 +81,7 @@ static inline void nft_set_pktinfo(struct nft_pktinfo *pkt,
+
+ static inline void nft_set_pktinfo_unspec(struct nft_pktinfo *pkt)
+ {
+- pkt->tprot_set = false;
++ pkt->flags = 0;
+ pkt->tprot = 0;
+ pkt->thoff = 0;
+ pkt->fragoff = 0;
+diff --git a/include/net/netfilter/nf_tables_ipv4.h b/include/net/netfilter/nf_tables_ipv4.h
+index eb4c094cd54d2..c4a6147b0ef8c 100644
+--- a/include/net/netfilter/nf_tables_ipv4.h
++++ b/include/net/netfilter/nf_tables_ipv4.h
+@@ -10,7 +10,7 @@ static inline void nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt)
+ struct iphdr *ip;
+
+ ip = ip_hdr(pkt->skb);
+- pkt->tprot_set = true;
++ pkt->flags = NFT_PKTINFO_L4PROTO;
+ pkt->tprot = ip->protocol;
+ pkt->thoff = ip_hdrlen(pkt->skb);
+ pkt->fragoff = ntohs(ip->frag_off) & IP_OFFSET;
+@@ -36,7 +36,7 @@ static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt)
+ else if (len < thoff)
+ return -1;
+
+- pkt->tprot_set = true;
++ pkt->flags = NFT_PKTINFO_L4PROTO;
+ pkt->tprot = iph->protocol;
+ pkt->thoff = thoff;
+ pkt->fragoff = ntohs(iph->frag_off) & IP_OFFSET;
+@@ -71,7 +71,7 @@ static inline int nft_set_pktinfo_ipv4_ingress(struct nft_pktinfo *pkt)
+ goto inhdr_error;
+ }
+
+- pkt->tprot_set = true;
++ pkt->flags = NFT_PKTINFO_L4PROTO;
+ pkt->tprot = iph->protocol;
+ pkt->thoff = thoff;
+ pkt->fragoff = ntohs(iph->frag_off) & IP_OFFSET;
+@@ -82,4 +82,5 @@ inhdr_error:
+ __IP_INC_STATS(nft_net(pkt), IPSTATS_MIB_INHDRERRORS);
+ return -1;
+ }
++
+ #endif
+diff --git a/include/net/netfilter/nf_tables_ipv6.h b/include/net/netfilter/nf_tables_ipv6.h
+index 7595e02b00ba0..ec7eaeaf4f04c 100644
+--- a/include/net/netfilter/nf_tables_ipv6.h
++++ b/include/net/netfilter/nf_tables_ipv6.h
+@@ -18,7 +18,7 @@ static inline void nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt)
+ return;
+ }
+
+- pkt->tprot_set = true;
++ pkt->flags = NFT_PKTINFO_L4PROTO;
+ pkt->tprot = protohdr;
+ pkt->thoff = thoff;
+ pkt->fragoff = frag_off;
+@@ -50,7 +50,7 @@ static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt)
+ if (protohdr < 0)
+ return -1;
+
+- pkt->tprot_set = true;
++ pkt->flags = NFT_PKTINFO_L4PROTO;
+ pkt->tprot = protohdr;
+ pkt->thoff = thoff;
+ pkt->fragoff = frag_off;
+@@ -96,7 +96,7 @@ static inline int nft_set_pktinfo_ipv6_ingress(struct nft_pktinfo *pkt)
+ if (protohdr < 0)
+ goto inhdr_error;
+
+- pkt->tprot_set = true;
++ pkt->flags = NFT_PKTINFO_L4PROTO;
+ pkt->tprot = protohdr;
+ pkt->thoff = thoff;
+ pkt->fragoff = frag_off;
+diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
+index e94d1fa554cb2..07871c8a06014 100644
+--- a/include/uapi/linux/netfilter/nf_tables.h
++++ b/include/uapi/linux/netfilter/nf_tables.h
+@@ -753,11 +753,13 @@ enum nft_dynset_attributes {
+ * @NFT_PAYLOAD_LL_HEADER: link layer header
+ * @NFT_PAYLOAD_NETWORK_HEADER: network header
+ * @NFT_PAYLOAD_TRANSPORT_HEADER: transport header
++ * @NFT_PAYLOAD_INNER_HEADER: inner header / payload
+ */
+ enum nft_payload_bases {
+ NFT_PAYLOAD_LL_HEADER,
+ NFT_PAYLOAD_NETWORK_HEADER,
+ NFT_PAYLOAD_TRANSPORT_HEADER,
++ NFT_PAYLOAD_INNER_HEADER,
+ };
+
+ /**
+diff --git a/include/uapi/linux/omap3isp.h b/include/uapi/linux/omap3isp.h
+index 87b55755f4ffe..d9db7ad438908 100644
+--- a/include/uapi/linux/omap3isp.h
++++ b/include/uapi/linux/omap3isp.h
+@@ -162,6 +162,7 @@ struct omap3isp_h3a_aewb_config {
+ * struct omap3isp_stat_data - Statistic data sent to or received from user
+ * @ts: Timestamp of returned framestats.
+ * @buf: Pointer to pass to user.
++ * @buf_size: Size of buffer.
+ * @frame_number: Frame number of requested stats.
+ * @cur_frame: Current frame number being processed.
+ * @config_counter: Number of the configuration associated with the data.
+@@ -176,10 +177,12 @@ struct omap3isp_stat_data {
+ struct timeval ts;
+ #endif
+ void __user *buf;
+- __u32 buf_size;
+- __u16 frame_number;
+- __u16 cur_frame;
+- __u16 config_counter;
++ __struct_group(/* no tag */, frame, /* no attrs */,
++ __u32 buf_size;
++ __u16 frame_number;
++ __u16 cur_frame;
++ __u16 config_counter;
++ );
+ };
+
+ #ifdef __KERNEL__
+@@ -189,10 +192,12 @@ struct omap3isp_stat_data_time32 {
+ __s32 tv_usec;
+ } ts;
+ __u32 buf;
+- __u32 buf_size;
+- __u16 frame_number;
+- __u16 cur_frame;
+- __u16 config_counter;
++ __struct_group(/* no tag */, frame, /* no attrs */,
++ __u32 buf_size;
++ __u16 frame_number;
++ __u16 cur_frame;
++ __u16 config_counter;
++ );
+ };
+ #endif
+
+diff --git a/include/uapi/linux/stddef.h b/include/uapi/linux/stddef.h
+index ee8220f8dcf5f..7837ba4fe7289 100644
+--- a/include/uapi/linux/stddef.h
++++ b/include/uapi/linux/stddef.h
+@@ -1,6 +1,47 @@
+ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
++#ifndef _UAPI_LINUX_STDDEF_H
++#define _UAPI_LINUX_STDDEF_H
++
+ #include <linux/compiler_types.h>
+
+ #ifndef __always_inline
+ #define __always_inline inline
+ #endif
++
++/**
++ * __struct_group() - Create a mirrored named and anonyomous struct
++ *
++ * @TAG: The tag name for the named sub-struct (usually empty)
++ * @NAME: The identifier name of the mirrored sub-struct
++ * @ATTRS: Any struct attributes (usually empty)
++ * @MEMBERS: The member declarations for the mirrored structs
++ *
++ * Used to create an anonymous union of two structs with identical layout
++ * and size: one anonymous and one named. The former's members can be used
++ * normally without sub-struct naming, and the latter can be used to
++ * reason about the start, end, and size of the group of struct members.
++ * The named struct can also be explicitly tagged for layer reuse, as well
++ * as both having struct attributes appended.
++ */
++#define __struct_group(TAG, NAME, ATTRS, MEMBERS...) \
++ union { \
++ struct { MEMBERS } ATTRS; \
++ struct TAG { MEMBERS } ATTRS NAME; \
++ }
++
++/**
++ * __DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union
++ *
++ * @TYPE: The type of each flexible array element
++ * @NAME: The name of the flexible array member
++ *
++ * In order to have a flexible array member in a union or alone in a
++ * struct, it needs to be wrapped in an anonymous struct with at least 1
++ * named member, but that member can be empty.
++ */
++#define __DECLARE_FLEX_ARRAY(TYPE, NAME) \
++ struct { \
++ struct { } __empty_ ## NAME; \
++ TYPE NAME[]; \
++ }
++#endif
+diff --git a/include/video/of_display_timing.h b/include/video/of_display_timing.h
+index e1126a74882a5..eff166fdd81b9 100644
+--- a/include/video/of_display_timing.h
++++ b/include/video/of_display_timing.h
+@@ -8,6 +8,8 @@
+ #ifndef __LINUX_OF_DISPLAY_TIMING_H
+ #define __LINUX_OF_DISPLAY_TIMING_H
+
++#include <linux/errno.h>
++
+ struct device_node;
+ struct display_timing;
+ struct display_timings;
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index 48eb9c329da60..15946c11524e7 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -389,6 +389,13 @@ static int bpf_adj_branches(struct bpf_prog *prog, u32 pos, s32 end_old,
+ i = end_new;
+ insn = prog->insnsi + end_old;
+ }
++ if (bpf_pseudo_func(insn)) {
++ ret = bpf_adj_delta_to_imm(insn, pos, end_old,
++ end_new, i, probe_pass);
++ if (ret)
++ return ret;
++ continue;
++ }
+ code = insn->code;
+ if ((BPF_CLASS(code) != BPF_JMP &&
+ BPF_CLASS(code) != BPF_JMP32) ||
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 25ee8d9572c6f..346d36c905a90 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -240,12 +240,6 @@ static bool bpf_pseudo_kfunc_call(const struct bpf_insn *insn)
+ insn->src_reg == BPF_PSEUDO_KFUNC_CALL;
+ }
+
+-static bool bpf_pseudo_func(const struct bpf_insn *insn)
+-{
+- return insn->code == (BPF_LD | BPF_IMM | BPF_DW) &&
+- insn->src_reg == BPF_PSEUDO_FUNC;
+-}
+-
+ struct bpf_call_arg_meta {
+ struct bpf_map *map_ptr;
+ bool raw_mode;
+@@ -1333,6 +1327,21 @@ static void __reg_bound_offset(struct bpf_reg_state *reg)
+ reg->var_off = tnum_or(tnum_clear_subreg(var64_off), var32_off);
+ }
+
++static void reg_bounds_sync(struct bpf_reg_state *reg)
++{
++ /* We might have learned new bounds from the var_off. */
++ __update_reg_bounds(reg);
++ /* We might have learned something about the sign bit. */
++ __reg_deduce_bounds(reg);
++ /* We might have learned some bits from the bounds. */
++ __reg_bound_offset(reg);
++ /* Intersecting with the old var_off might have improved our bounds
++ * slightly, e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
++ * then new var_off is (0; 0x7f...fc) which improves our umax.
++ */
++ __update_reg_bounds(reg);
++}
++
+ static bool __reg32_bound_s64(s32 a)
+ {
+ return a >= 0 && a <= S32_MAX;
+@@ -1374,16 +1383,8 @@ static void __reg_combine_32_into_64(struct bpf_reg_state *reg)
+ * so they do not impact tnum bounds calculation.
+ */
+ __mark_reg64_unbounded(reg);
+- __update_reg_bounds(reg);
+ }
+-
+- /* Intersecting with the old var_off might have improved our bounds
+- * slightly. e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
+- * then new var_off is (0; 0x7f...fc) which improves our umax.
+- */
+- __reg_deduce_bounds(reg);
+- __reg_bound_offset(reg);
+- __update_reg_bounds(reg);
++ reg_bounds_sync(reg);
+ }
+
+ static bool __reg64_bound_s32(s64 a)
+@@ -1399,7 +1400,6 @@ static bool __reg64_bound_u32(u64 a)
+ static void __reg_combine_64_into_32(struct bpf_reg_state *reg)
+ {
+ __mark_reg32_unbounded(reg);
+-
+ if (__reg64_bound_s32(reg->smin_value) && __reg64_bound_s32(reg->smax_value)) {
+ reg->s32_min_value = (s32)reg->smin_value;
+ reg->s32_max_value = (s32)reg->smax_value;
+@@ -1408,14 +1408,7 @@ static void __reg_combine_64_into_32(struct bpf_reg_state *reg)
+ reg->u32_min_value = (u32)reg->umin_value;
+ reg->u32_max_value = (u32)reg->umax_value;
+ }
+-
+- /* Intersecting with the old var_off might have improved our bounds
+- * slightly. e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
+- * then new var_off is (0; 0x7f...fc) which improves our umax.
+- */
+- __reg_deduce_bounds(reg);
+- __reg_bound_offset(reg);
+- __update_reg_bounds(reg);
++ reg_bounds_sync(reg);
+ }
+
+ /* Mark a register as having a completely unknown (scalar) value. */
+@@ -1789,16 +1782,10 @@ static int add_subprog_and_kfunc(struct bpf_verifier_env *env)
+ return -EPERM;
+ }
+
+- if (bpf_pseudo_func(insn)) {
+- ret = add_subprog(env, i + insn->imm + 1);
+- if (ret >= 0)
+- /* remember subprog */
+- insn[1].imm = ret;
+- } else if (bpf_pseudo_call(insn)) {
++ if (bpf_pseudo_func(insn) || bpf_pseudo_call(insn))
+ ret = add_subprog(env, i + insn->imm + 1);
+- } else {
++ else
+ ret = add_kfunc_call(env, insn->imm);
+- }
+
+ if (ret < 0)
+ return ret;
+@@ -6054,9 +6041,7 @@ static void do_refine_retval_range(struct bpf_reg_state *regs, int ret_type,
+ ret_reg->s32_max_value = meta->msize_max_value;
+ ret_reg->smin_value = -MAX_ERRNO;
+ ret_reg->s32_min_value = -MAX_ERRNO;
+- __reg_deduce_bounds(ret_reg);
+- __reg_bound_offset(ret_reg);
+- __update_reg_bounds(ret_reg);
++ reg_bounds_sync(ret_reg);
+ }
+
+ static int
+@@ -7216,11 +7201,7 @@ reject:
+
+ if (!check_reg_sane_offset(env, dst_reg, ptr_reg->type))
+ return -EINVAL;
+-
+- __update_reg_bounds(dst_reg);
+- __reg_deduce_bounds(dst_reg);
+- __reg_bound_offset(dst_reg);
+-
++ reg_bounds_sync(dst_reg);
+ if (sanitize_check_bounds(env, insn, dst_reg) < 0)
+ return -EACCES;
+ if (sanitize_needed(opcode)) {
+@@ -7958,10 +7939,7 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
+ /* ALU32 ops are zero extended into 64bit register */
+ if (alu32)
+ zext_32_to_64(dst_reg);
+-
+- __update_reg_bounds(dst_reg);
+- __reg_deduce_bounds(dst_reg);
+- __reg_bound_offset(dst_reg);
++ reg_bounds_sync(dst_reg);
+ return 0;
+ }
+
+@@ -8150,10 +8128,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
+ insn->dst_reg);
+ }
+ zext_32_to_64(dst_reg);
+-
+- __update_reg_bounds(dst_reg);
+- __reg_deduce_bounds(dst_reg);
+- __reg_bound_offset(dst_reg);
++ reg_bounds_sync(dst_reg);
+ }
+ } else {
+ /* case: R = imm
+@@ -8591,26 +8566,33 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg,
+ return;
+
+ switch (opcode) {
++ /* JEQ/JNE comparison doesn't change the register equivalence.
++ *
++ * r1 = r2;
++ * if (r1 == 42) goto label;
++ * ...
++ * label: // here both r1 and r2 are known to be 42.
++ *
++ * Hence when marking register as known preserve it's ID.
++ */
+ case BPF_JEQ:
++ if (is_jmp32) {
++ __mark_reg32_known(true_reg, val32);
++ true_32off = tnum_subreg(true_reg->var_off);
++ } else {
++ ___mark_reg_known(true_reg, val);
++ true_64off = true_reg->var_off;
++ }
++ break;
+ case BPF_JNE:
+- {
+- struct bpf_reg_state *reg =
+- opcode == BPF_JEQ ? true_reg : false_reg;
+-
+- /* JEQ/JNE comparison doesn't change the register equivalence.
+- * r1 = r2;
+- * if (r1 == 42) goto label;
+- * ...
+- * label: // here both r1 and r2 are known to be 42.
+- *
+- * Hence when marking register as known preserve it's ID.
+- */
+- if (is_jmp32)
+- __mark_reg32_known(reg, val32);
+- else
+- ___mark_reg_known(reg, val);
++ if (is_jmp32) {
++ __mark_reg32_known(false_reg, val32);
++ false_32off = tnum_subreg(false_reg->var_off);
++ } else {
++ ___mark_reg_known(false_reg, val);
++ false_64off = false_reg->var_off;
++ }
+ break;
+- }
+ case BPF_JSET:
+ if (is_jmp32) {
+ false_32off = tnum_and(false_32off, tnum_const(~val32));
+@@ -8749,21 +8731,8 @@ static void __reg_combine_min_max(struct bpf_reg_state *src_reg,
+ dst_reg->smax_value);
+ src_reg->var_off = dst_reg->var_off = tnum_intersect(src_reg->var_off,
+ dst_reg->var_off);
+- /* We might have learned new bounds from the var_off. */
+- __update_reg_bounds(src_reg);
+- __update_reg_bounds(dst_reg);
+- /* We might have learned something about the sign bit. */
+- __reg_deduce_bounds(src_reg);
+- __reg_deduce_bounds(dst_reg);
+- /* We might have learned some bits from the bounds. */
+- __reg_bound_offset(src_reg);
+- __reg_bound_offset(dst_reg);
+- /* Intersecting with the old var_off might have improved our bounds
+- * slightly. e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
+- * then new var_off is (0; 0x7f...fc) which improves our umax.
+- */
+- __update_reg_bounds(src_reg);
+- __update_reg_bounds(dst_reg);
++ reg_bounds_sync(src_reg);
++ reg_bounds_sync(dst_reg);
+ }
+
+ static void reg_combine_min_max(struct bpf_reg_state *true_src,
+@@ -9241,7 +9210,8 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn)
+
+ if (insn->src_reg == BPF_PSEUDO_FUNC) {
+ struct bpf_prog_aux *aux = env->prog->aux;
+- u32 subprogno = insn[1].imm;
++ u32 subprogno = find_subprog(env,
++ env->insn_idx + insn->imm + 1);
+
+ if (!aux->func_info) {
+ verbose(env, "missing btf func_info\n");
+@@ -12411,14 +12381,9 @@ static int jit_subprogs(struct bpf_verifier_env *env)
+ return 0;
+
+ for (i = 0, insn = prog->insnsi; i < prog->len; i++, insn++) {
+- if (bpf_pseudo_func(insn)) {
+- env->insn_aux_data[i].call_imm = insn->imm;
+- /* subprog is encoded in insn[1].imm */
++ if (!bpf_pseudo_func(insn) && !bpf_pseudo_call(insn))
+ continue;
+- }
+
+- if (!bpf_pseudo_call(insn))
+- continue;
+ /* Upon error here we cannot fall back to interpreter but
+ * need a hard reject of the program. Thus -EFAULT is
+ * propagated in any case.
+@@ -12439,6 +12404,12 @@ static int jit_subprogs(struct bpf_verifier_env *env)
+ env->insn_aux_data[i].call_imm = insn->imm;
+ /* point imm to __bpf_call_base+1 from JITs point of view */
+ insn->imm = 1;
++ if (bpf_pseudo_func(insn))
++ /* jit (e.g. x86_64) may emit fewer instructions
++ * if it learns a u32 imm is the same as a u64 imm.
++ * Force a non zero here.
++ */
++ insn[1].imm = 1;
+ }
+
+ err = bpf_prog_alloc_jited_linfo(prog);
+@@ -12522,7 +12493,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
+ insn = func[i]->insnsi;
+ for (j = 0; j < func[i]->len; j++, insn++) {
+ if (bpf_pseudo_func(insn)) {
+- subprog = insn[1].imm;
++ subprog = insn->off;
+ insn[0].imm = (u32)(long)func[subprog]->bpf_func;
+ insn[1].imm = ((u64)(long)func[subprog]->bpf_func) >> 32;
+ continue;
+@@ -12574,7 +12545,8 @@ static int jit_subprogs(struct bpf_verifier_env *env)
+ for (i = 0, insn = prog->insnsi; i < prog->len; i++, insn++) {
+ if (bpf_pseudo_func(insn)) {
+ insn[0].imm = env->insn_aux_data[i].call_imm;
+- insn[1].imm = find_subprog(env, i + insn[0].imm + 1);
++ insn[1].imm = insn->off;
++ insn->off = 0;
+ continue;
+ }
+ if (!bpf_pseudo_call(insn))
+diff --git a/kernel/module.c b/kernel/module.c
+index 83991c2d5af9e..ef79f4dbda876 100644
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -2967,14 +2967,29 @@ static int elf_validity_check(struct load_info *info)
+ Elf_Shdr *shdr, *strhdr;
+ int err;
+
+- if (info->len < sizeof(*(info->hdr)))
+- return -ENOEXEC;
++ if (info->len < sizeof(*(info->hdr))) {
++ pr_err("Invalid ELF header len %lu\n", info->len);
++ goto no_exec;
++ }
+
+- if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0
+- || info->hdr->e_type != ET_REL
+- || !elf_check_arch(info->hdr)
+- || info->hdr->e_shentsize != sizeof(Elf_Shdr))
+- return -ENOEXEC;
++ if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0) {
++ pr_err("Invalid ELF header magic: != %s\n", ELFMAG);
++ goto no_exec;
++ }
++ if (info->hdr->e_type != ET_REL) {
++ pr_err("Invalid ELF header type: %u != %u\n",
++ info->hdr->e_type, ET_REL);
++ goto no_exec;
++ }
++ if (!elf_check_arch(info->hdr)) {
++ pr_err("Invalid architecture in ELF header: %u\n",
++ info->hdr->e_machine);
++ goto no_exec;
++ }
++ if (info->hdr->e_shentsize != sizeof(Elf_Shdr)) {
++ pr_err("Invalid ELF section header size\n");
++ goto no_exec;
++ }
+
+ /*
+ * e_shnum is 16 bits, and sizeof(Elf_Shdr) is
+@@ -2983,8 +2998,10 @@ static int elf_validity_check(struct load_info *info)
+ */
+ if (info->hdr->e_shoff >= info->len
+ || (info->hdr->e_shnum * sizeof(Elf_Shdr) >
+- info->len - info->hdr->e_shoff))
+- return -ENOEXEC;
++ info->len - info->hdr->e_shoff)) {
++ pr_err("Invalid ELF section header overflow\n");
++ goto no_exec;
++ }
+
+ info->sechdrs = (void *)info->hdr + info->hdr->e_shoff;
+
+@@ -2992,13 +3009,19 @@ static int elf_validity_check(struct load_info *info)
+ * Verify if the section name table index is valid.
+ */
+ if (info->hdr->e_shstrndx == SHN_UNDEF
+- || info->hdr->e_shstrndx >= info->hdr->e_shnum)
+- return -ENOEXEC;
++ || info->hdr->e_shstrndx >= info->hdr->e_shnum) {
++ pr_err("Invalid ELF section name index: %d || e_shstrndx (%d) >= e_shnum (%d)\n",
++ info->hdr->e_shstrndx, info->hdr->e_shstrndx,
++ info->hdr->e_shnum);
++ goto no_exec;
++ }
+
+ strhdr = &info->sechdrs[info->hdr->e_shstrndx];
+ err = validate_section_offset(info, strhdr);
+- if (err < 0)
++ if (err < 0) {
++ pr_err("Invalid ELF section hdr(type %u)\n", strhdr->sh_type);
+ return err;
++ }
+
+ /*
+ * The section name table must be NUL-terminated, as required
+@@ -3006,8 +3029,14 @@ static int elf_validity_check(struct load_info *info)
+ * strings in the section safe.
+ */
+ info->secstrings = (void *)info->hdr + strhdr->sh_offset;
+- if (info->secstrings[strhdr->sh_size - 1] != '\0')
+- return -ENOEXEC;
++ if (strhdr->sh_size == 0) {
++ pr_err("empty section name table\n");
++ goto no_exec;
++ }
++ if (info->secstrings[strhdr->sh_size - 1] != '\0') {
++ pr_err("ELF Spec violation: section name table isn't null terminated\n");
++ goto no_exec;
++ }
+
+ /*
+ * The code assumes that section 0 has a length of zero and
+@@ -3015,8 +3044,11 @@ static int elf_validity_check(struct load_info *info)
+ */
+ if (info->sechdrs[0].sh_type != SHT_NULL
+ || info->sechdrs[0].sh_size != 0
+- || info->sechdrs[0].sh_addr != 0)
+- return -ENOEXEC;
++ || info->sechdrs[0].sh_addr != 0) {
++ pr_err("ELF Spec violation: section 0 type(%d)!=SH_NULL or non-zero len or addr\n",
++ info->sechdrs[0].sh_type);
++ goto no_exec;
++ }
+
+ for (i = 1; i < info->hdr->e_shnum; i++) {
+ shdr = &info->sechdrs[i];
+@@ -3026,8 +3058,12 @@ static int elf_validity_check(struct load_info *info)
+ continue;
+ case SHT_SYMTAB:
+ if (shdr->sh_link == SHN_UNDEF
+- || shdr->sh_link >= info->hdr->e_shnum)
+- return -ENOEXEC;
++ || shdr->sh_link >= info->hdr->e_shnum) {
++ pr_err("Invalid ELF sh_link!=SHN_UNDEF(%d) or (sh_link(%d) >= hdr->e_shnum(%d)\n",
++ shdr->sh_link, shdr->sh_link,
++ info->hdr->e_shnum);
++ goto no_exec;
++ }
+ fallthrough;
+ default:
+ err = validate_section_offset(info, shdr);
+@@ -3049,6 +3085,9 @@ static int elf_validity_check(struct load_info *info)
+ }
+
+ return 0;
++
++no_exec:
++ return -ENOEXEC;
+ }
+
+ #define COPY_CHUNK_SIZE (16*PAGE_SIZE)
+@@ -3925,10 +3964,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
+ * sections.
+ */
+ err = elf_validity_check(info);
+- if (err) {
+- pr_err("Module has invalid ELF structures\n");
++ if (err)
+ goto free_copy;
+- }
+
+ /*
+ * Everything checks out, so set up the section info
+diff --git a/lib/idr.c b/lib/idr.c
+index f4ab4f4aa3c7f..7ecdfdb5309e7 100644
+--- a/lib/idr.c
++++ b/lib/idr.c
+@@ -491,7 +491,8 @@ void ida_free(struct ida *ida, unsigned int id)
+ struct ida_bitmap *bitmap;
+ unsigned long flags;
+
+- BUG_ON((int)id < 0);
++ if ((int)id < 0)
++ return;
+
+ xas_lock_irqsave(&xas, flags);
+ bitmap = xas_load(&xas);
+diff --git a/mm/filemap.c b/mm/filemap.c
+index 00e391e758801..dbc461703ff45 100644
+--- a/mm/filemap.c
++++ b/mm/filemap.c
+@@ -2090,7 +2090,11 @@ unsigned find_lock_entries(struct address_space *mapping, pgoff_t start,
+
+ rcu_read_lock();
+ while ((page = find_get_entry(&xas, end, XA_PRESENT))) {
++ unsigned long next_idx = xas.xa_index + 1;
++
+ if (!xa_is_value(page)) {
++ if (PageTransHuge(page))
++ next_idx = page->index + thp_nr_pages(page);
+ if (page->index < start)
+ goto put;
+ if (page->index + thp_nr_pages(page) - 1 > end)
+@@ -2111,13 +2115,11 @@ unlock:
+ put:
+ put_page(page);
+ next:
+- if (!xa_is_value(page) && PageTransHuge(page)) {
+- unsigned int nr_pages = thp_nr_pages(page);
+-
++ if (next_idx != xas.xa_index + 1) {
+ /* Final THP may cross MAX_LFS_FILESIZE on 32-bit */
+- xas_set(&xas, page->index + nr_pages);
+- if (xas.xa_index < nr_pages)
++ if (next_idx < xas.xa_index)
+ break;
++ xas_set(&xas, next_idx);
+ }
+ }
+ rcu_read_unlock();
+diff --git a/mm/hugetlb.c b/mm/hugetlb.c
+index e4c717b08cfe0..eed96302897ae 100644
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -6290,6 +6290,16 @@ int get_hwpoison_huge_page(struct page *page, bool *hugetlb)
+ return ret;
+ }
+
++int get_huge_page_for_hwpoison(unsigned long pfn, int flags)
++{
++ int ret;
++
++ spin_lock_irq(&hugetlb_lock);
++ ret = __get_huge_page_for_hwpoison(pfn, flags);
++ spin_unlock_irq(&hugetlb_lock);
++ return ret;
++}
++
+ void putback_active_hugepage(struct page *page)
+ {
+ spin_lock_irq(&hugetlb_lock);
+diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c
+index aff4d27ec2352..a1d6fc3c78b9c 100644
+--- a/mm/hwpoison-inject.c
++++ b/mm/hwpoison-inject.c
+@@ -48,7 +48,8 @@ static int hwpoison_inject(void *data, u64 val)
+
+ inject:
+ pr_info("Injecting memory failure at pfn %#lx\n", pfn);
+- return memory_failure(pfn, 0);
++ err = memory_failure(pfn, 0);
++ return (err == -EOPNOTSUPP) ? 0 : err;
+ }
+
+ static int hwpoison_unpoison(void *data, u64 val)
+diff --git a/mm/madvise.c b/mm/madvise.c
+index 8e5ca01a6cc07..882767d58c273 100644
+--- a/mm/madvise.c
++++ b/mm/madvise.c
+@@ -968,6 +968,8 @@ static int madvise_inject_error(int behavior,
+ pr_info("Injecting memory failure for pfn %#lx at process virtual address %#lx\n",
+ pfn, start);
+ ret = memory_failure(pfn, MF_COUNT_INCREASED);
++ if (ret == -EOPNOTSUPP)
++ ret = 0;
+ }
+
+ if (ret)
+diff --git a/mm/memory-failure.c b/mm/memory-failure.c
+index c3ceb74369334..c71135edd0a10 100644
+--- a/mm/memory-failure.c
++++ b/mm/memory-failure.c
+@@ -1418,59 +1418,115 @@ static int try_to_split_thp_page(struct page *page, const char *msg)
+ return 0;
+ }
+
+-static int memory_failure_hugetlb(unsigned long pfn, int flags)
++/*
++ * Called from hugetlb code with hugetlb_lock held.
++ *
++ * Return values:
++ * 0 - free hugepage
++ * 1 - in-use hugepage
++ * 2 - not a hugepage
++ * -EBUSY - the hugepage is busy (try to retry)
++ * -EHWPOISON - the hugepage is already hwpoisoned
++ */
++int __get_huge_page_for_hwpoison(unsigned long pfn, int flags)
++{
++ struct page *page = pfn_to_page(pfn);
++ struct page *head = compound_head(page);
++ int ret = 2; /* fallback to normal page handling */
++ bool count_increased = false;
++
++ if (!PageHeadHuge(head))
++ goto out;
++
++ if (flags & MF_COUNT_INCREASED) {
++ ret = 1;
++ count_increased = true;
++ } else if (HPageFreed(head) || HPageMigratable(head)) {
++ ret = get_page_unless_zero(head);
++ if (ret)
++ count_increased = true;
++ } else {
++ ret = -EBUSY;
++ goto out;
++ }
++
++ if (TestSetPageHWPoison(head)) {
++ ret = -EHWPOISON;
++ goto out;
++ }
++
++ return ret;
++out:
++ if (count_increased)
++ put_page(head);
++ return ret;
++}
++
++#ifdef CONFIG_HUGETLB_PAGE
++/*
++ * Taking refcount of hugetlb pages needs extra care about race conditions
++ * with basic operations like hugepage allocation/free/demotion.
++ * So some of prechecks for hwpoison (pinning, and testing/setting
++ * PageHWPoison) should be done in single hugetlb_lock range.
++ */
++static int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb)
+ {
+- struct page *p = pfn_to_page(pfn);
+- struct page *head = compound_head(p);
+ int res;
++ struct page *p = pfn_to_page(pfn);
++ struct page *head;
+ unsigned long page_flags;
++ bool retry = true;
+
+- if (TestSetPageHWPoison(head)) {
+- pr_err("Memory failure: %#lx: already hardware poisoned\n",
+- pfn);
+- res = -EHWPOISON;
+- if (flags & MF_ACTION_REQUIRED)
++ *hugetlb = 1;
++retry:
++ res = get_huge_page_for_hwpoison(pfn, flags);
++ if (res == 2) { /* fallback to normal page handling */
++ *hugetlb = 0;
++ return 0;
++ } else if (res == -EHWPOISON) {
++ pr_err("Memory failure: %#lx: already hardware poisoned\n", pfn);
++ if (flags & MF_ACTION_REQUIRED) {
++ head = compound_head(p);
+ res = kill_accessing_process(current, page_to_pfn(head), flags);
++ }
++ return res;
++ } else if (res == -EBUSY) {
++ if (retry) {
++ retry = false;
++ goto retry;
++ }
++ action_result(pfn, MF_MSG_UNKNOWN, MF_IGNORED);
+ return res;
+ }
+
+- num_poisoned_pages_inc();
++ head = compound_head(p);
++ lock_page(head);
+
+- if (!(flags & MF_COUNT_INCREASED)) {
+- res = get_hwpoison_page(p, flags);
+- if (!res) {
+- lock_page(head);
+- if (hwpoison_filter(p)) {
+- if (TestClearPageHWPoison(head))
+- num_poisoned_pages_dec();
+- unlock_page(head);
+- return 0;
+- }
+- unlock_page(head);
+- res = MF_FAILED;
+- if (__page_handle_poison(p)) {
+- page_ref_inc(p);
+- res = MF_RECOVERED;
+- }
+- action_result(pfn, MF_MSG_FREE_HUGE, res);
+- return res == MF_RECOVERED ? 0 : -EBUSY;
+- } else if (res < 0) {
+- action_result(pfn, MF_MSG_UNKNOWN, MF_IGNORED);
+- return -EBUSY;
+- }
++ if (hwpoison_filter(p)) {
++ ClearPageHWPoison(head);
++ res = -EOPNOTSUPP;
++ goto out;
+ }
+
+- lock_page(head);
+- page_flags = head->flags;
++ num_poisoned_pages_inc();
+
+- if (!PageHWPoison(head)) {
+- pr_err("Memory failure: %#lx: just unpoisoned\n", pfn);
+- num_poisoned_pages_dec();
++ /*
++ * Handling free hugepage. The possible race with hugepage allocation
++ * or demotion can be prevented by PageHWPoison flag.
++ */
++ if (res == 0) {
+ unlock_page(head);
+- put_page(head);
+- return 0;
++ res = MF_FAILED;
++ if (__page_handle_poison(p)) {
++ page_ref_inc(p);
++ res = MF_RECOVERED;
++ }
++ action_result(pfn, MF_MSG_FREE_HUGE, res);
++ return res == MF_RECOVERED ? 0 : -EBUSY;
+ }
+
++ page_flags = head->flags;
++
+ /*
+ * TODO: hwpoison for pud-sized hugetlb doesn't work right now, so
+ * simply disable it. In order to make it work properly, we need
+@@ -1497,6 +1553,12 @@ out:
+ unlock_page(head);
+ return res;
+ }
++#else
++static inline int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb)
++{
++ return 0;
++}
++#endif
+
+ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
+ struct dev_pagemap *pgmap)
+@@ -1533,7 +1595,7 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags,
+ goto out;
+
+ if (hwpoison_filter(page)) {
+- rc = 0;
++ rc = -EOPNOTSUPP;
+ goto unlock;
+ }
+
+@@ -1584,6 +1646,8 @@ out:
+ return rc;
+ }
+
++static DEFINE_MUTEX(mf_mutex);
++
+ /**
+ * memory_failure - Handle memory failure of a page.
+ * @pfn: Page Number of the corrupted page
+@@ -1600,6 +1664,10 @@ out:
+ *
+ * Must run in process context (e.g. a work queue) with interrupts
+ * enabled and no spinlocks hold.
++ *
++ * Return: 0 for successfully handled the memory error,
++ * -EOPNOTSUPP for memory_filter() filtered the error event,
++ * < 0(except -EOPNOTSUPP) on failure.
+ */
+ int memory_failure(unsigned long pfn, int flags)
+ {
+@@ -1610,7 +1678,7 @@ int memory_failure(unsigned long pfn, int flags)
+ int res = 0;
+ unsigned long page_flags;
+ bool retry = true;
+- static DEFINE_MUTEX(mf_mutex);
++ int hugetlb = 0;
+
+ if (!sysctl_memory_failure_recovery)
+ panic("Memory failure on page %lx", pfn);
+@@ -1631,10 +1699,9 @@ int memory_failure(unsigned long pfn, int flags)
+ mutex_lock(&mf_mutex);
+
+ try_again:
+- if (PageHuge(p)) {
+- res = memory_failure_hugetlb(pfn, flags);
++ res = try_memory_failure_hugetlb(pfn, flags, &hugetlb);
++ if (hugetlb)
+ goto unlock_mutex;
+- }
+
+ if (TestSetPageHWPoison(p)) {
+ pr_err("Memory failure: %#lx: already hardware poisoned\n",
+@@ -1744,21 +1811,12 @@ try_again:
+ */
+ page_flags = p->flags;
+
+- /*
+- * unpoison always clear PG_hwpoison inside page lock
+- */
+- if (!PageHWPoison(p)) {
+- pr_err("Memory failure: %#lx: just unpoisoned\n", pfn);
+- num_poisoned_pages_dec();
+- unlock_page(p);
+- put_page(p);
+- goto unlock_mutex;
+- }
+ if (hwpoison_filter(p)) {
+ if (TestClearPageHWPoison(p))
+ num_poisoned_pages_dec();
+ unlock_page(p);
+ put_page(p);
++ res = -EOPNOTSUPP;
+ goto unlock_mutex;
+ }
+
+@@ -1934,6 +1992,7 @@ int unpoison_memory(unsigned long pfn)
+ struct page *page;
+ struct page *p;
+ int freeit = 0;
++ int ret = 0;
+ unsigned long flags = 0;
+ static DEFINE_RATELIMIT_STATE(unpoison_rs, DEFAULT_RATELIMIT_INTERVAL,
+ DEFAULT_RATELIMIT_BURST);
+@@ -1944,39 +2003,30 @@ int unpoison_memory(unsigned long pfn)
+ p = pfn_to_page(pfn);
+ page = compound_head(p);
+
++ mutex_lock(&mf_mutex);
++
+ if (!PageHWPoison(p)) {
+ unpoison_pr_info("Unpoison: Page was already unpoisoned %#lx\n",
+ pfn, &unpoison_rs);
+- return 0;
++ goto unlock_mutex;
+ }
+
+ if (page_count(page) > 1) {
+ unpoison_pr_info("Unpoison: Someone grabs the hwpoison page %#lx\n",
+ pfn, &unpoison_rs);
+- return 0;
++ goto unlock_mutex;
+ }
+
+ if (page_mapped(page)) {
+ unpoison_pr_info("Unpoison: Someone maps the hwpoison page %#lx\n",
+ pfn, &unpoison_rs);
+- return 0;
++ goto unlock_mutex;
+ }
+
+ if (page_mapping(page)) {
+ unpoison_pr_info("Unpoison: the hwpoison page has non-NULL mapping %#lx\n",
+ pfn, &unpoison_rs);
+- return 0;
+- }
+-
+- /*
+- * unpoison_memory() can encounter thp only when the thp is being
+- * worked by memory_failure() and the page lock is not held yet.
+- * In such case, we yield to memory_failure() and make unpoison fail.
+- */
+- if (!PageHuge(page) && PageTransHuge(page)) {
+- unpoison_pr_info("Unpoison: Memory failure is now running on %#lx\n",
+- pfn, &unpoison_rs);
+- return 0;
++ goto unlock_mutex;
+ }
+
+ if (!get_hwpoison_page(p, flags)) {
+@@ -1984,29 +2034,23 @@ int unpoison_memory(unsigned long pfn)
+ num_poisoned_pages_dec();
+ unpoison_pr_info("Unpoison: Software-unpoisoned free page %#lx\n",
+ pfn, &unpoison_rs);
+- return 0;
++ goto unlock_mutex;
+ }
+
+- lock_page(page);
+- /*
+- * This test is racy because PG_hwpoison is set outside of page lock.
+- * That's acceptable because that won't trigger kernel panic. Instead,
+- * the PG_hwpoison page will be caught and isolated on the entrance to
+- * the free buddy page pool.
+- */
+ if (TestClearPageHWPoison(page)) {
+ unpoison_pr_info("Unpoison: Software-unpoisoned page %#lx\n",
+ pfn, &unpoison_rs);
+ num_poisoned_pages_dec();
+ freeit = 1;
+ }
+- unlock_page(page);
+
+ put_page(page);
+ if (freeit && !(pfn == my_zero_pfn(0) && page_count(p) == 1))
+ put_page(page);
+
+- return 0;
++unlock_mutex:
++ mutex_unlock(&mf_mutex);
++ return ret;
+ }
+ EXPORT_SYMBOL(unpoison_memory);
+
+@@ -2187,9 +2231,12 @@ int soft_offline_page(unsigned long pfn, int flags)
+ return -EIO;
+ }
+
++ mutex_lock(&mf_mutex);
++
+ if (PageHWPoison(page)) {
+ pr_info("%s: %#lx page already poisoned\n", __func__, pfn);
+ put_ref_page(ref_page);
++ mutex_unlock(&mf_mutex);
+ return 0;
+ }
+
+@@ -2208,5 +2255,7 @@ retry:
+ }
+ }
+
++ mutex_unlock(&mf_mutex);
++
+ return ret;
+ }
+diff --git a/mm/slub.c b/mm/slub.c
+index b75eebc0350e7..519bbbad7b2f6 100644
+--- a/mm/slub.c
++++ b/mm/slub.c
+@@ -2935,6 +2935,7 @@ redo:
+
+ if (!freelist) {
+ c->page = NULL;
++ c->tid = next_tid(c->tid);
+ local_unlock_irqrestore(&s->cpu_slab->lock, flags);
+ stat(s, DEACTIVATE_BYPASS);
+ goto new_slab;
+@@ -2967,6 +2968,7 @@ deactivate_slab:
+ freelist = c->freelist;
+ c->page = NULL;
+ c->freelist = NULL;
++ c->tid = next_tid(c->tid);
+ local_unlock_irqrestore(&s->cpu_slab->lock, flags);
+ deactivate_slab(s, page, freelist);
+
+diff --git a/mm/util.c b/mm/util.c
+index 3073de05c2bd4..ea04979f131e2 100644
+--- a/mm/util.c
++++ b/mm/util.c
+@@ -698,6 +698,56 @@ static inline void *__page_rmapping(struct page *page)
+ return (void *)mapping;
+ }
+
++/**
++ * __vmalloc_array - allocate memory for a virtually contiguous array.
++ * @n: number of elements.
++ * @size: element size.
++ * @flags: the type of memory to allocate (see kmalloc).
++ */
++void *__vmalloc_array(size_t n, size_t size, gfp_t flags)
++{
++ size_t bytes;
++
++ if (unlikely(check_mul_overflow(n, size, &bytes)))
++ return NULL;
++ return __vmalloc(bytes, flags);
++}
++EXPORT_SYMBOL(__vmalloc_array);
++
++/**
++ * vmalloc_array - allocate memory for a virtually contiguous array.
++ * @n: number of elements.
++ * @size: element size.
++ */
++void *vmalloc_array(size_t n, size_t size)
++{
++ return __vmalloc_array(n, size, GFP_KERNEL);
++}
++EXPORT_SYMBOL(vmalloc_array);
++
++/**
++ * __vcalloc - allocate and zero memory for a virtually contiguous array.
++ * @n: number of elements.
++ * @size: element size.
++ * @flags: the type of memory to allocate (see kmalloc).
++ */
++void *__vcalloc(size_t n, size_t size, gfp_t flags)
++{
++ return __vmalloc_array(n, size, flags | __GFP_ZERO);
++}
++EXPORT_SYMBOL(__vcalloc);
++
++/**
++ * vcalloc - allocate and zero memory for a virtually contiguous array.
++ * @n: number of elements.
++ * @size: element size.
++ */
++void *vcalloc(size_t n, size_t size)
++{
++ return __vmalloc_array(n, size, GFP_KERNEL | __GFP_ZERO);
++}
++EXPORT_SYMBOL(vcalloc);
++
+ /* Neutral page->mapping pointer to address_space or anon_vma or other */
+ void *page_rmapping(struct page *page)
+ {
+diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
+index 17687848daec5..11f6ef657d822 100644
+--- a/net/batman-adv/bridge_loop_avoidance.c
++++ b/net/batman-adv/bridge_loop_avoidance.c
+@@ -443,7 +443,7 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, u8 *mac,
+ batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES,
+ skb->len + ETH_HLEN);
+
+- netif_rx_any_context(skb);
++ netif_rx(skb);
+ out:
+ batadv_hardif_put(primary_if);
+ }
+diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
+index 5ac3aca6deeb3..2337e9275863e 100644
+--- a/net/bluetooth/hci_event.c
++++ b/net/bluetooth/hci_event.c
+@@ -1559,7 +1559,9 @@ static void hci_cc_le_clear_accept_list(struct hci_dev *hdev,
+ if (status)
+ return;
+
++ hci_dev_lock(hdev);
+ hci_bdaddr_list_clear(&hdev->le_accept_list);
++ hci_dev_unlock(hdev);
+ }
+
+ static void hci_cc_le_add_to_accept_list(struct hci_dev *hdev,
+@@ -1577,8 +1579,10 @@ static void hci_cc_le_add_to_accept_list(struct hci_dev *hdev,
+ if (!sent)
+ return;
+
++ hci_dev_lock(hdev);
+ hci_bdaddr_list_add(&hdev->le_accept_list, &sent->bdaddr,
+ sent->bdaddr_type);
++ hci_dev_unlock(hdev);
+ }
+
+ static void hci_cc_le_del_from_accept_list(struct hci_dev *hdev,
+@@ -1596,8 +1600,10 @@ static void hci_cc_le_del_from_accept_list(struct hci_dev *hdev,
+ if (!sent)
+ return;
+
++ hci_dev_lock(hdev);
+ hci_bdaddr_list_del(&hdev->le_accept_list, &sent->bdaddr,
+ sent->bdaddr_type);
++ hci_dev_unlock(hdev);
+ }
+
+ static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
+@@ -1661,9 +1667,11 @@ static void hci_cc_le_add_to_resolv_list(struct hci_dev *hdev,
+ if (!sent)
+ return;
+
++ hci_dev_lock(hdev);
+ hci_bdaddr_list_add_with_irk(&hdev->le_resolv_list, &sent->bdaddr,
+ sent->bdaddr_type, sent->peer_irk,
+ sent->local_irk);
++ hci_dev_unlock(hdev);
+ }
+
+ static void hci_cc_le_del_from_resolv_list(struct hci_dev *hdev,
+@@ -1681,8 +1689,10 @@ static void hci_cc_le_del_from_resolv_list(struct hci_dev *hdev,
+ if (!sent)
+ return;
+
++ hci_dev_lock(hdev);
+ hci_bdaddr_list_del_with_irk(&hdev->le_resolv_list, &sent->bdaddr,
+ sent->bdaddr_type);
++ hci_dev_unlock(hdev);
+ }
+
+ static void hci_cc_le_clear_resolv_list(struct hci_dev *hdev,
+@@ -1695,7 +1705,9 @@ static void hci_cc_le_clear_resolv_list(struct hci_dev *hdev,
+ if (status)
+ return;
+
++ hci_dev_lock(hdev);
+ hci_bdaddr_list_clear(&hdev->le_resolv_list);
++ hci_dev_unlock(hdev);
+ }
+
+ static void hci_cc_le_read_resolv_list_size(struct hci_dev *hdev,
+diff --git a/net/can/bcm.c b/net/can/bcm.c
+index 508f67de0b801..e5ffd2bd62ab8 100644
+--- a/net/can/bcm.c
++++ b/net/can/bcm.c
+@@ -100,6 +100,7 @@ static inline u64 get_u64(const struct canfd_frame *cp, int offset)
+
+ struct bcm_op {
+ struct list_head list;
++ struct rcu_head rcu;
+ int ifindex;
+ canid_t can_id;
+ u32 flags;
+@@ -718,10 +719,9 @@ static struct bcm_op *bcm_find_op(struct list_head *ops,
+ return NULL;
+ }
+
+-static void bcm_remove_op(struct bcm_op *op)
++static void bcm_free_op_rcu(struct rcu_head *rcu_head)
+ {
+- hrtimer_cancel(&op->timer);
+- hrtimer_cancel(&op->thrtimer);
++ struct bcm_op *op = container_of(rcu_head, struct bcm_op, rcu);
+
+ if ((op->frames) && (op->frames != &op->sframe))
+ kfree(op->frames);
+@@ -732,6 +732,14 @@ static void bcm_remove_op(struct bcm_op *op)
+ kfree(op);
+ }
+
++static void bcm_remove_op(struct bcm_op *op)
++{
++ hrtimer_cancel(&op->timer);
++ hrtimer_cancel(&op->thrtimer);
++
++ call_rcu(&op->rcu, bcm_free_op_rcu);
++}
++
+ static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op)
+ {
+ if (op->rx_reg_dev == dev) {
+@@ -757,6 +765,9 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
+ if ((op->can_id == mh->can_id) && (op->ifindex == ifindex) &&
+ (op->flags & CAN_FD_FRAME) == (mh->flags & CAN_FD_FRAME)) {
+
++ /* disable automatic timer on frame reception */
++ op->flags |= RX_NO_AUTOTIMER;
++
+ /*
+ * Don't care if we're bound or not (due to netdev
+ * problems) can_rx_unregister() is always a save
+@@ -785,7 +796,6 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
+ bcm_rx_handler, op);
+
+ list_del(&op->list);
+- synchronize_rcu();
+ bcm_remove_op(op);
+ return 1; /* done */
+ }
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index 1b4bc588f8d63..65d96439e2be7 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -5118,13 +5118,20 @@ static int nft_setelem_parse_data(struct nft_ctx *ctx, struct nft_set *set,
+ struct nft_data *data,
+ struct nlattr *attr)
+ {
++ u32 dtype;
+ int err;
+
+ err = nft_data_init(ctx, data, NFT_DATA_VALUE_MAXLEN, desc, attr);
+ if (err < 0)
+ return err;
+
+- if (desc->type != NFT_DATA_VERDICT && desc->len != set->dlen) {
++ if (set->dtype == NFT_DATA_VERDICT)
++ dtype = NFT_DATA_VERDICT;
++ else
++ dtype = NFT_DATA_VALUE;
++
++ if (dtype != desc->type ||
++ set->dlen != desc->len) {
+ nft_data_release(data, desc->type);
+ return -EINVAL;
+ }
+diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
+index 907e848dbc178..d4d8f613af512 100644
+--- a/net/netfilter/nf_tables_core.c
++++ b/net/netfilter/nf_tables_core.c
+@@ -79,7 +79,7 @@ static bool nft_payload_fast_eval(const struct nft_expr *expr,
+ if (priv->base == NFT_PAYLOAD_NETWORK_HEADER)
+ ptr = skb_network_header(skb);
+ else {
+- if (!pkt->tprot_set)
++ if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
+ return false;
+ ptr = skb_network_header(skb) + nft_thoff(pkt);
+ }
+diff --git a/net/netfilter/nf_tables_trace.c b/net/netfilter/nf_tables_trace.c
+index e4fe2f0780eb6..84a7dea46efae 100644
+--- a/net/netfilter/nf_tables_trace.c
++++ b/net/netfilter/nf_tables_trace.c
+@@ -113,13 +113,13 @@ static int nf_trace_fill_pkt_info(struct sk_buff *nlskb,
+ int off = skb_network_offset(skb);
+ unsigned int len, nh_end;
+
+- nh_end = pkt->tprot_set ? nft_thoff(pkt) : skb->len;
++ nh_end = pkt->flags & NFT_PKTINFO_L4PROTO ? nft_thoff(pkt) : skb->len;
+ len = min_t(unsigned int, nh_end - skb_network_offset(skb),
+ NFT_TRACETYPE_NETWORK_HSIZE);
+ if (trace_fill_header(nlskb, NFTA_TRACE_NETWORK_HEADER, skb, off, len))
+ return -1;
+
+- if (pkt->tprot_set) {
++ if (pkt->flags & NFT_PKTINFO_L4PROTO) {
+ len = min_t(unsigned int, skb->len - nft_thoff(pkt),
+ NFT_TRACETYPE_TRANSPORT_HSIZE);
+ if (trace_fill_header(nlskb, NFTA_TRACE_TRANSPORT_HEADER, skb,
+diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c
+index dbe1f2e7dd9ed..9e927ab4df151 100644
+--- a/net/netfilter/nft_exthdr.c
++++ b/net/netfilter/nft_exthdr.c
+@@ -167,7 +167,7 @@ nft_tcp_header_pointer(const struct nft_pktinfo *pkt,
+ {
+ struct tcphdr *tcph;
+
+- if (pkt->tprot != IPPROTO_TCP)
++ if (pkt->tprot != IPPROTO_TCP || pkt->fragoff)
+ return NULL;
+
+ tcph = skb_header_pointer(pkt->skb, nft_thoff(pkt), sizeof(*tcph), buffer);
+diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
+index 44d9b38e5f90c..14412f69a34e8 100644
+--- a/net/netfilter/nft_meta.c
++++ b/net/netfilter/nft_meta.c
+@@ -321,7 +321,7 @@ void nft_meta_get_eval(const struct nft_expr *expr,
+ nft_reg_store8(dest, nft_pf(pkt));
+ break;
+ case NFT_META_L4PROTO:
+- if (!pkt->tprot_set)
++ if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
+ goto err;
+ nft_reg_store8(dest, pkt->tprot);
+ break;
+diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
+index 132875cd7fff2..b46e01365bd96 100644
+--- a/net/netfilter/nft_payload.c
++++ b/net/netfilter/nft_payload.c
+@@ -22,6 +22,7 @@
+ #include <linux/icmpv6.h>
+ #include <linux/ip.h>
+ #include <linux/ipv6.h>
++#include <linux/ip.h>
+ #include <net/sctp/checksum.h>
+
+ static bool nft_payload_rebuild_vlan_hdr(const struct sk_buff *skb, int mac_off,
+@@ -79,6 +80,45 @@ nft_payload_copy_vlan(u32 *d, const struct sk_buff *skb, u8 offset, u8 len)
+ return skb_copy_bits(skb, offset + mac_off, dst_u8, len) == 0;
+ }
+
++static int __nft_payload_inner_offset(struct nft_pktinfo *pkt)
++{
++ unsigned int thoff = nft_thoff(pkt);
++
++ if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff)
++ return -1;
++
++ switch (pkt->tprot) {
++ case IPPROTO_UDP:
++ pkt->inneroff = thoff + sizeof(struct udphdr);
++ break;
++ case IPPROTO_TCP: {
++ struct tcphdr *th, _tcph;
++
++ th = skb_header_pointer(pkt->skb, thoff, sizeof(_tcph), &_tcph);
++ if (!th)
++ return -1;
++
++ pkt->inneroff = thoff + __tcp_hdrlen(th);
++ }
++ break;
++ default:
++ return -1;
++ }
++
++ pkt->flags |= NFT_PKTINFO_INNER;
++
++ return 0;
++}
++
++static int nft_payload_inner_offset(const struct nft_pktinfo *pkt)
++{
++ if (!(pkt->flags & NFT_PKTINFO_INNER) &&
++ __nft_payload_inner_offset((struct nft_pktinfo *)pkt) < 0)
++ return -1;
++
++ return pkt->inneroff;
++}
++
+ void nft_payload_eval(const struct nft_expr *expr,
+ struct nft_regs *regs,
+ const struct nft_pktinfo *pkt)
+@@ -108,10 +148,15 @@ void nft_payload_eval(const struct nft_expr *expr,
+ offset = skb_network_offset(skb);
+ break;
+ case NFT_PAYLOAD_TRANSPORT_HEADER:
+- if (!pkt->tprot_set)
++ if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff)
+ goto err;
+ offset = nft_thoff(pkt);
+ break;
++ case NFT_PAYLOAD_INNER_HEADER:
++ offset = nft_payload_inner_offset(pkt);
++ if (offset < 0)
++ goto err;
++ break;
+ default:
+ BUG();
+ }
+@@ -613,10 +658,15 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
+ offset = skb_network_offset(skb);
+ break;
+ case NFT_PAYLOAD_TRANSPORT_HEADER:
+- if (!pkt->tprot_set)
++ if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff)
+ goto err;
+ offset = nft_thoff(pkt);
+ break;
++ case NFT_PAYLOAD_INNER_HEADER:
++ offset = nft_payload_inner_offset(pkt);
++ if (offset < 0)
++ goto err;
++ break;
+ default:
+ BUG();
+ }
+@@ -625,7 +675,8 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
+ offset += priv->offset;
+
+ if ((priv->csum_type == NFT_PAYLOAD_CSUM_INET || priv->csum_flags) &&
+- (priv->base != NFT_PAYLOAD_TRANSPORT_HEADER ||
++ ((priv->base != NFT_PAYLOAD_TRANSPORT_HEADER &&
++ priv->base != NFT_PAYLOAD_INNER_HEADER) ||
+ skb->ip_summed != CHECKSUM_PARTIAL)) {
+ fsum = skb_checksum(skb, offset, priv->len, 0);
+ tsum = csum_partial(src, priv->len, 0);
+@@ -646,7 +697,8 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
+ if (priv->csum_type == NFT_PAYLOAD_CSUM_SCTP &&
+ pkt->tprot == IPPROTO_SCTP &&
+ skb->ip_summed != CHECKSUM_PARTIAL) {
+- if (nft_payload_csum_sctp(skb, nft_thoff(pkt)))
++ if (pkt->fragoff == 0 &&
++ nft_payload_csum_sctp(skb, nft_thoff(pkt)))
+ goto err;
+ }
+
+@@ -744,6 +796,7 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
+ case NFT_PAYLOAD_LL_HEADER:
+ case NFT_PAYLOAD_NETWORK_HEADER:
+ case NFT_PAYLOAD_TRANSPORT_HEADER:
++ case NFT_PAYLOAD_INNER_HEADER:
+ break;
+ default:
+ return ERR_PTR(-EOPNOTSUPP);
+@@ -762,7 +815,7 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
+ len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
+
+ if (len <= 4 && is_power_of_2(len) && IS_ALIGNED(offset, len) &&
+- base != NFT_PAYLOAD_LL_HEADER)
++ base != NFT_PAYLOAD_LL_HEADER && base != NFT_PAYLOAD_INNER_HEADER)
+ return &nft_payload_fast_ops;
+ else
+ return &nft_payload_ops;
+diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c
+index 2c8051d8cca69..4f9299b9dcddc 100644
+--- a/net/netfilter/nft_set_pipapo.c
++++ b/net/netfilter/nft_set_pipapo.c
+@@ -2124,6 +2124,32 @@ out_scratch:
+ return err;
+ }
+
++/**
++ * nft_set_pipapo_match_destroy() - Destroy elements from key mapping array
++ * @set: nftables API set representation
++ * @m: matching data pointing to key mapping array
++ */
++static void nft_set_pipapo_match_destroy(const struct nft_set *set,
++ struct nft_pipapo_match *m)
++{
++ struct nft_pipapo_field *f;
++ int i, r;
++
++ for (i = 0, f = m->f; i < m->field_count - 1; i++, f++)
++ ;
++
++ for (r = 0; r < f->rules; r++) {
++ struct nft_pipapo_elem *e;
++
++ if (r < f->rules - 1 && f->mt[r + 1].e == f->mt[r].e)
++ continue;
++
++ e = f->mt[r].e;
++
++ nft_set_elem_destroy(set, e, true);
++ }
++}
++
+ /**
+ * nft_pipapo_destroy() - Free private data for set and all committed elements
+ * @set: nftables API set representation
+@@ -2132,26 +2158,13 @@ static void nft_pipapo_destroy(const struct nft_set *set)
+ {
+ struct nft_pipapo *priv = nft_set_priv(set);
+ struct nft_pipapo_match *m;
+- struct nft_pipapo_field *f;
+- int i, r, cpu;
++ int cpu;
+
+ m = rcu_dereference_protected(priv->match, true);
+ if (m) {
+ rcu_barrier();
+
+- for (i = 0, f = m->f; i < m->field_count - 1; i++, f++)
+- ;
+-
+- for (r = 0; r < f->rules; r++) {
+- struct nft_pipapo_elem *e;
+-
+- if (r < f->rules - 1 && f->mt[r + 1].e == f->mt[r].e)
+- continue;
+-
+- e = f->mt[r].e;
+-
+- nft_set_elem_destroy(set, e, true);
+- }
++ nft_set_pipapo_match_destroy(set, m);
+
+ #ifdef NFT_PIPAPO_ALIGN
+ free_percpu(m->scratch_aligned);
+@@ -2165,6 +2178,11 @@ static void nft_pipapo_destroy(const struct nft_set *set)
+ }
+
+ if (priv->clone) {
++ m = priv->clone;
++
++ if (priv->dirty)
++ nft_set_pipapo_match_destroy(set, m);
++
+ #ifdef NFT_PIPAPO_ALIGN
+ free_percpu(priv->clone->scratch_aligned);
+ #endif
+diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
+index c0e04c261a156..764a726debb1f 100644
+--- a/net/rose/rose_route.c
++++ b/net/rose/rose_route.c
+@@ -227,8 +227,8 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
+ {
+ struct rose_neigh *s;
+
+- rose_stop_ftimer(rose_neigh);
+- rose_stop_t0timer(rose_neigh);
++ del_timer_sync(&rose_neigh->ftimer);
++ del_timer_sync(&rose_neigh->t0timer);
+
+ skb_queue_purge(&rose_neigh->queue);
+
+diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
+index dce056adb78cf..f2d593e27b64f 100644
+--- a/net/rxrpc/ar-internal.h
++++ b/net/rxrpc/ar-internal.h
+@@ -68,7 +68,7 @@ struct rxrpc_net {
+ struct proc_dir_entry *proc_net; /* Subdir in /proc/net */
+ u32 epoch; /* Local epoch for detecting local-end reset */
+ struct list_head calls; /* List of calls active in this namespace */
+- rwlock_t call_lock; /* Lock for ->calls */
++ spinlock_t call_lock; /* Lock for ->calls */
+ atomic_t nr_calls; /* Count of allocated calls */
+
+ atomic_t nr_conns;
+diff --git a/net/rxrpc/call_accept.c b/net/rxrpc/call_accept.c
+index 1ae90fb979362..8b24ffbc72efb 100644
+--- a/net/rxrpc/call_accept.c
++++ b/net/rxrpc/call_accept.c
+@@ -140,9 +140,9 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
+ write_unlock(&rx->call_lock);
+
+ rxnet = call->rxnet;
+- write_lock(&rxnet->call_lock);
+- list_add_tail(&call->link, &rxnet->calls);
+- write_unlock(&rxnet->call_lock);
++ spin_lock_bh(&rxnet->call_lock);
++ list_add_tail_rcu(&call->link, &rxnet->calls);
++ spin_unlock_bh(&rxnet->call_lock);
+
+ b->call_backlog[call_head] = call;
+ smp_store_release(&b->call_backlog_head, (call_head + 1) & (size - 1));
+diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c
+index 043508fd8d8a5..25c9a2cbf048c 100644
+--- a/net/rxrpc/call_object.c
++++ b/net/rxrpc/call_object.c
+@@ -337,9 +337,9 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
+ write_unlock(&rx->call_lock);
+
+ rxnet = call->rxnet;
+- write_lock(&rxnet->call_lock);
+- list_add_tail(&call->link, &rxnet->calls);
+- write_unlock(&rxnet->call_lock);
++ spin_lock_bh(&rxnet->call_lock);
++ list_add_tail_rcu(&call->link, &rxnet->calls);
++ spin_unlock_bh(&rxnet->call_lock);
+
+ /* From this point on, the call is protected by its own lock. */
+ release_sock(&rx->sk);
+@@ -631,9 +631,9 @@ void rxrpc_put_call(struct rxrpc_call *call, enum rxrpc_call_trace op)
+ ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE);
+
+ if (!list_empty(&call->link)) {
+- write_lock(&rxnet->call_lock);
++ spin_lock_bh(&rxnet->call_lock);
+ list_del_init(&call->link);
+- write_unlock(&rxnet->call_lock);
++ spin_unlock_bh(&rxnet->call_lock);
+ }
+
+ rxrpc_cleanup_call(call);
+@@ -705,7 +705,7 @@ void rxrpc_destroy_all_calls(struct rxrpc_net *rxnet)
+ _enter("");
+
+ if (!list_empty(&rxnet->calls)) {
+- write_lock(&rxnet->call_lock);
++ spin_lock_bh(&rxnet->call_lock);
+
+ while (!list_empty(&rxnet->calls)) {
+ call = list_entry(rxnet->calls.next,
+@@ -720,12 +720,12 @@ void rxrpc_destroy_all_calls(struct rxrpc_net *rxnet)
+ rxrpc_call_states[call->state],
+ call->flags, call->events);
+
+- write_unlock(&rxnet->call_lock);
++ spin_unlock_bh(&rxnet->call_lock);
+ cond_resched();
+- write_lock(&rxnet->call_lock);
++ spin_lock_bh(&rxnet->call_lock);
+ }
+
+- write_unlock(&rxnet->call_lock);
++ spin_unlock_bh(&rxnet->call_lock);
+ }
+
+ atomic_dec(&rxnet->nr_calls);
+diff --git a/net/rxrpc/net_ns.c b/net/rxrpc/net_ns.c
+index cc7e30733feb0..e4d6d432515bc 100644
+--- a/net/rxrpc/net_ns.c
++++ b/net/rxrpc/net_ns.c
+@@ -50,7 +50,7 @@ static __net_init int rxrpc_init_net(struct net *net)
+ rxnet->epoch |= RXRPC_RANDOM_EPOCH;
+
+ INIT_LIST_HEAD(&rxnet->calls);
+- rwlock_init(&rxnet->call_lock);
++ spin_lock_init(&rxnet->call_lock);
+ atomic_set(&rxnet->nr_calls, 1);
+
+ atomic_set(&rxnet->nr_conns, 1);
+diff --git a/net/rxrpc/proc.c b/net/rxrpc/proc.c
+index e2f990754f882..5a67955cc00f6 100644
+--- a/net/rxrpc/proc.c
++++ b/net/rxrpc/proc.c
+@@ -26,29 +26,23 @@ static const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = {
+ */
+ static void *rxrpc_call_seq_start(struct seq_file *seq, loff_t *_pos)
+ __acquires(rcu)
+- __acquires(rxnet->call_lock)
+ {
+ struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
+
+ rcu_read_lock();
+- read_lock(&rxnet->call_lock);
+- return seq_list_start_head(&rxnet->calls, *_pos);
++ return seq_list_start_head_rcu(&rxnet->calls, *_pos);
+ }
+
+ static void *rxrpc_call_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+ {
+ struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
+
+- return seq_list_next(v, &rxnet->calls, pos);
++ return seq_list_next_rcu(v, &rxnet->calls, pos);
+ }
+
+ static void rxrpc_call_seq_stop(struct seq_file *seq, void *v)
+- __releases(rxnet->call_lock)
+ __releases(rcu)
+ {
+- struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
+-
+- read_unlock(&rxnet->call_lock);
+ rcu_read_unlock();
+ }
+
+diff --git a/net/xdp/xsk_buff_pool.c b/net/xdp/xsk_buff_pool.c
+index fc7fbfc1e5861..ccedbbd27692e 100644
+--- a/net/xdp/xsk_buff_pool.c
++++ b/net/xdp/xsk_buff_pool.c
+@@ -326,6 +326,7 @@ static void __xp_dma_unmap(struct xsk_dma_map *dma_map, unsigned long attrs)
+ for (i = 0; i < dma_map->dma_pages_cnt; i++) {
+ dma = &dma_map->dma_pages[i];
+ if (*dma) {
++ *dma &= ~XSK_NEXT_PG_CONTIG_MASK;
+ dma_unmap_page_attrs(dma_map->dev, *dma, PAGE_SIZE,
+ DMA_BIDIRECTIONAL, attrs);
+ *dma = 0;
+diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
+index c27d2312cfc30..88cb294dc4472 100755
+--- a/scripts/checkpatch.pl
++++ b/scripts/checkpatch.pl
+@@ -489,7 +489,8 @@ our $Attribute = qr{
+ ____cacheline_aligned|
+ ____cacheline_aligned_in_smp|
+ ____cacheline_internodealigned_in_smp|
+- __weak
++ __weak|
++ __alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\)
+ }x;
+ our $Modifier;
+ our $Inline = qr{inline|__always_inline|noinline|__inline|__inline__};
+diff --git a/scripts/kernel-doc b/scripts/kernel-doc
+index cfcb607379577..5d54b57ff90cc 100755
+--- a/scripts/kernel-doc
++++ b/scripts/kernel-doc
+@@ -1245,6 +1245,13 @@ sub dump_struct($$) {
+ $members =~ s/\s*CRYPTO_MINALIGN_ATTR/ /gos;
+ $members =~ s/\s*____cacheline_aligned_in_smp/ /gos;
+ $members =~ s/\s*____cacheline_aligned/ /gos;
++ # unwrap struct_group():
++ # - first eat non-declaration parameters and rewrite for final match
++ # - then remove macro, outer parens, and trailing semicolon
++ $members =~ s/\bstruct_group\s*\(([^,]*,)/STRUCT_GROUP(/gos;
++ $members =~ s/\bstruct_group_(attr|tagged)\s*\(([^,]*,){2}/STRUCT_GROUP(/gos;
++ $members =~ s/\b__struct_group\s*\(([^,]*,){3}/STRUCT_GROUP(/gos;
++ $members =~ s/\bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;/$2/gos;
+
+ my $args = qr{([^,)]+)};
+ # replace DECLARE_BITMAP
+@@ -1256,6 +1263,8 @@ sub dump_struct($$) {
+ $members =~ s/DECLARE_KFIFO\s*\($args,\s*$args,\s*$args\)/$2 \*$1/gos;
+ # replace DECLARE_KFIFO_PTR
+ $members =~ s/DECLARE_KFIFO_PTR\s*\($args,\s*$args\)/$2 \*$1/gos;
++ # replace DECLARE_FLEX_ARRAY
++ $members =~ s/(?:__)?DECLARE_FLEX_ARRAY\s*\($args,\s*$args\)/$1 $2\[\]/gos;
+ my $declaration = $members;
+
+ # Split nested struct/union elements as newer ones
+diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
+index bd60308769ff7..8634004a606b6 100644
+--- a/sound/pci/cs46xx/cs46xx.c
++++ b/sound/pci/cs46xx/cs46xx.c
+@@ -74,36 +74,36 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
+ err = snd_cs46xx_create(card, pci,
+ external_amp[dev], thinkpad[dev]);
+ if (err < 0)
+- return err;
++ goto error;
+ card->private_data = chip;
+ chip->accept_valid = mmap_valid[dev];
+ err = snd_cs46xx_pcm(chip, 0);
+ if (err < 0)
+- return err;
++ goto error;
+ #ifdef CONFIG_SND_CS46XX_NEW_DSP
+ err = snd_cs46xx_pcm_rear(chip, 1);
+ if (err < 0)
+- return err;
++ goto error;
+ err = snd_cs46xx_pcm_iec958(chip, 2);
+ if (err < 0)
+- return err;
++ goto error;
+ #endif
+ err = snd_cs46xx_mixer(chip, 2);
+ if (err < 0)
+- return err;
++ goto error;
+ #ifdef CONFIG_SND_CS46XX_NEW_DSP
+ if (chip->nr_ac97_codecs ==2) {
+ err = snd_cs46xx_pcm_center_lfe(chip, 3);
+ if (err < 0)
+- return err;
++ goto error;
+ }
+ #endif
+ err = snd_cs46xx_midi(chip, 0);
+ if (err < 0)
+- return err;
++ goto error;
+ err = snd_cs46xx_start_dsp(chip);
+ if (err < 0)
+- return err;
++ goto error;
+
+ snd_cs46xx_gameport(chip);
+
+@@ -117,11 +117,15 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
+
+ err = snd_card_register(card);
+ if (err < 0)
+- return err;
++ goto error;
+
+ pci_set_drvdata(pci, card);
+ dev++;
+ return 0;
++
++ error:
++ snd_card_free(card);
++ return err;
+ }
+
+ static struct pci_driver cs46xx_driver = {
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 70664c9832d6f..3c3eac2399da7 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -9001,6 +9001,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1558, 0x70f4, "Clevo NH77EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x70f6, "Clevo NH77DPQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x7716, "Clevo NS50PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
++ SND_PCI_QUIRK(0x1558, 0x7718, "Clevo L140PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x8228, "Clevo NR40BU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x8520, "Clevo NH50D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x8521, "Clevo NH77D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c
+index b9d5d7a0975b3..3d2d7c9ce66df 100644
+--- a/sound/soc/codecs/rt5682-i2c.c
++++ b/sound/soc/codecs/rt5682-i2c.c
+@@ -59,18 +59,12 @@ static void rt5682_jd_check_handler(struct work_struct *work)
+ struct rt5682_priv *rt5682 = container_of(work, struct rt5682_priv,
+ jd_check_work.work);
+
+- if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL)
+- & RT5682_JDH_RS_MASK) {
++ if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL) & RT5682_JDH_RS_MASK)
+ /* jack out */
+- rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0);
+-
+- snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
+- SND_JACK_HEADSET |
+- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+- SND_JACK_BTN_2 | SND_JACK_BTN_3);
+- } else {
++ mod_delayed_work(system_power_efficient_wq,
++ &rt5682->jack_detect_work, 0);
++ else
+ schedule_delayed_work(&rt5682->jd_check_work, 500);
+- }
+ }
+
+ static irqreturn_t rt5682_irq(int irq, void *data)
+@@ -139,6 +133,8 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
+
+ i2c_set_clientdata(i2c, rt5682);
+
++ rt5682->i2c_dev = &i2c->dev;
++
+ rt5682->pdata = i2s_default_platform_data;
+
+ if (pdata)
+@@ -276,6 +272,26 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
+ dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+ }
+
++#ifdef CONFIG_COMMON_CLK
++ /* Check if MCLK provided */
++ rt5682->mclk = devm_clk_get(&i2c->dev, "mclk");
++ if (IS_ERR(rt5682->mclk)) {
++ if (PTR_ERR(rt5682->mclk) != -ENOENT) {
++ ret = PTR_ERR(rt5682->mclk);
++ return ret;
++ }
++ rt5682->mclk = NULL;
++ }
++
++ /* Register CCF DAI clock control */
++ ret = rt5682_register_dai_clks(rt5682);
++ if (ret)
++ return ret;
++
++ /* Initial setup for CCF */
++ rt5682->lrck[RT5682_AIF1] = 48000;
++#endif
++
+ return devm_snd_soc_register_component(&i2c->dev,
+ &rt5682_soc_component_dev,
+ rt5682_dai, ARRAY_SIZE(rt5682_dai));
+diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
+index 6ad3159eceb98..8a9e1a4fa03ea 100644
+--- a/sound/soc/codecs/rt5682.c
++++ b/sound/soc/codecs/rt5682.c
+@@ -48,6 +48,8 @@ static const struct reg_sequence patch_list[] = {
+ {RT5682_SAR_IL_CMD_6, 0x0110},
+ {RT5682_CHARGE_PUMP_1, 0x0210},
+ {RT5682_HP_LOGIC_CTRL_2, 0x0007},
++ {RT5682_SAR_IL_CMD_2, 0xac00},
++ {RT5682_CBJ_CTRL_7, 0x0104},
+ };
+
+ void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev)
+@@ -920,15 +922,13 @@ static void rt5682_enable_push_button_irq(struct snd_soc_component *component,
+ *
+ * Returns detect status.
+ */
+-int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
++static int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
+ {
+ struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm = &component->dapm;
+ unsigned int val, count;
+
+ if (jack_insert) {
+- snd_soc_dapm_mutex_lock(dapm);
+-
+ snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1,
+ RT5682_PWR_VREF2 | RT5682_PWR_MB,
+ RT5682_PWR_VREF2 | RT5682_PWR_MB);
+@@ -942,6 +942,10 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
+ snd_soc_component_update_bits(component,
+ RT5682_HP_CHARGE_PUMP_1,
+ RT5682_OSW_L_MASK | RT5682_OSW_R_MASK, 0);
++ rt5682_enable_push_button_irq(component, false);
++ snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
++ RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_LOW);
++ usleep_range(55000, 60000);
+ snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+ RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_HIGH);
+
+@@ -975,8 +979,6 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
+ snd_soc_component_update_bits(component, RT5682_MICBIAS_2,
+ RT5682_PWR_CLK25M_MASK | RT5682_PWR_CLK1M_MASK,
+ RT5682_PWR_CLK25M_PU | RT5682_PWR_CLK1M_PU);
+-
+- snd_soc_dapm_mutex_unlock(dapm);
+ } else {
+ rt5682_enable_push_button_irq(component, false);
+ snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+@@ -1005,7 +1007,6 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
+ dev_dbg(component->dev, "jack_type = %d\n", rt5682->jack_type);
+ return rt5682->jack_type;
+ }
+-EXPORT_SYMBOL_GPL(rt5682_headset_detect);
+
+ static int rt5682_set_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *hs_jack, void *data)
+@@ -1088,6 +1089,7 @@ void rt5682_jack_detect_handler(struct work_struct *work)
+ {
+ struct rt5682_priv *rt5682 =
+ container_of(work, struct rt5682_priv, jack_detect_work.work);
++ struct snd_soc_dapm_context *dapm;
+ int val, btn_type;
+
+ if (!rt5682->component || !rt5682->component->card ||
+@@ -1098,6 +1100,9 @@ void rt5682_jack_detect_handler(struct work_struct *work)
+ return;
+ }
+
++ dapm = snd_soc_component_get_dapm(rt5682->component);
++
++ snd_soc_dapm_mutex_lock(dapm);
+ mutex_lock(&rt5682->calibrate_mutex);
+
+ val = snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL)
+@@ -1157,6 +1162,9 @@ void rt5682_jack_detect_handler(struct work_struct *work)
+ rt5682->irq_work_delay_time = 50;
+ }
+
++ mutex_unlock(&rt5682->calibrate_mutex);
++ snd_soc_dapm_mutex_unlock(dapm);
++
+ snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+@@ -1169,8 +1177,6 @@ void rt5682_jack_detect_handler(struct work_struct *work)
+ else
+ cancel_delayed_work_sync(&rt5682->jd_check_work);
+ }
+-
+- mutex_unlock(&rt5682->calibrate_mutex);
+ }
+ EXPORT_SYMBOL_GPL(rt5682_jack_detect_handler);
+
+@@ -2556,7 +2562,7 @@ static int rt5682_set_bias_level(struct snd_soc_component *component,
+ static bool rt5682_clk_check(struct rt5682_priv *rt5682)
+ {
+ if (!rt5682->master[RT5682_AIF1]) {
+- dev_dbg(rt5682->component->dev, "sysclk/dai not set correctly\n");
++ dev_dbg(rt5682->i2c_dev, "sysclk/dai not set correctly\n");
+ return false;
+ }
+ return true;
+@@ -2567,13 +2573,15 @@ static int rt5682_wclk_prepare(struct clk_hw *hw)
+ struct rt5682_priv *rt5682 =
+ container_of(hw, struct rt5682_priv,
+ dai_clks_hw[RT5682_DAI_WCLK_IDX]);
+- struct snd_soc_component *component = rt5682->component;
+- struct snd_soc_dapm_context *dapm =
+- snd_soc_component_get_dapm(component);
++ struct snd_soc_component *component;
++ struct snd_soc_dapm_context *dapm;
+
+ if (!rt5682_clk_check(rt5682))
+ return -EINVAL;
+
++ component = rt5682->component;
++ dapm = snd_soc_component_get_dapm(component);
++
+ snd_soc_dapm_mutex_lock(dapm);
+
+ snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS");
+@@ -2603,13 +2611,15 @@ static void rt5682_wclk_unprepare(struct clk_hw *hw)
+ struct rt5682_priv *rt5682 =
+ container_of(hw, struct rt5682_priv,
+ dai_clks_hw[RT5682_DAI_WCLK_IDX]);
+- struct snd_soc_component *component = rt5682->component;
+- struct snd_soc_dapm_context *dapm =
+- snd_soc_component_get_dapm(component);
++ struct snd_soc_component *component;
++ struct snd_soc_dapm_context *dapm;
+
+ if (!rt5682_clk_check(rt5682))
+ return;
+
++ component = rt5682->component;
++ dapm = snd_soc_component_get_dapm(component);
++
+ snd_soc_dapm_mutex_lock(dapm);
+
+ snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS");
+@@ -2633,7 +2643,6 @@ static unsigned long rt5682_wclk_recalc_rate(struct clk_hw *hw,
+ struct rt5682_priv *rt5682 =
+ container_of(hw, struct rt5682_priv,
+ dai_clks_hw[RT5682_DAI_WCLK_IDX]);
+- struct snd_soc_component *component = rt5682->component;
+ const char * const clk_name = clk_hw_get_name(hw);
+
+ if (!rt5682_clk_check(rt5682))
+@@ -2643,7 +2652,7 @@ static unsigned long rt5682_wclk_recalc_rate(struct clk_hw *hw,
+ */
+ if (rt5682->lrck[RT5682_AIF1] != CLK_48 &&
+ rt5682->lrck[RT5682_AIF1] != CLK_44) {
+- dev_warn(component->dev, "%s: clk %s only support %d or %d Hz output\n",
++ dev_warn(rt5682->i2c_dev, "%s: clk %s only support %d or %d Hz output\n",
+ __func__, clk_name, CLK_44, CLK_48);
+ return 0;
+ }
+@@ -2657,7 +2666,6 @@ static long rt5682_wclk_round_rate(struct clk_hw *hw, unsigned long rate,
+ struct rt5682_priv *rt5682 =
+ container_of(hw, struct rt5682_priv,
+ dai_clks_hw[RT5682_DAI_WCLK_IDX]);
+- struct snd_soc_component *component = rt5682->component;
+ const char * const clk_name = clk_hw_get_name(hw);
+
+ if (!rt5682_clk_check(rt5682))
+@@ -2667,7 +2675,7 @@ static long rt5682_wclk_round_rate(struct clk_hw *hw, unsigned long rate,
+ * It will force to 48kHz if not both.
+ */
+ if (rate != CLK_48 && rate != CLK_44) {
+- dev_warn(component->dev, "%s: clk %s only support %d or %d Hz output\n",
++ dev_warn(rt5682->i2c_dev, "%s: clk %s only support %d or %d Hz output\n",
+ __func__, clk_name, CLK_44, CLK_48);
+ rate = CLK_48;
+ }
+@@ -2681,7 +2689,7 @@ static int rt5682_wclk_set_rate(struct clk_hw *hw, unsigned long rate,
+ struct rt5682_priv *rt5682 =
+ container_of(hw, struct rt5682_priv,
+ dai_clks_hw[RT5682_DAI_WCLK_IDX]);
+- struct snd_soc_component *component = rt5682->component;
++ struct snd_soc_component *component;
+ struct clk_hw *parent_hw;
+ const char * const clk_name = clk_hw_get_name(hw);
+ int pre_div;
+@@ -2690,6 +2698,8 @@ static int rt5682_wclk_set_rate(struct clk_hw *hw, unsigned long rate,
+ if (!rt5682_clk_check(rt5682))
+ return -EINVAL;
+
++ component = rt5682->component;
++
+ /*
+ * Whether the wclk's parent clk (mclk) exists or not, please ensure
+ * it is fixed or set to 48MHz before setting wclk rate. It's a
+@@ -2699,12 +2709,12 @@ static int rt5682_wclk_set_rate(struct clk_hw *hw, unsigned long rate,
+ */
+ parent_hw = clk_hw_get_parent(hw);
+ if (!parent_hw)
+- dev_warn(component->dev,
++ dev_warn(rt5682->i2c_dev,
+ "Parent mclk of wclk not acquired in driver. Please ensure mclk was provided as %d Hz.\n",
+ CLK_PLL2_FIN);
+
+ if (parent_rate != CLK_PLL2_FIN)
+- dev_warn(component->dev, "clk %s only support %d Hz input\n",
++ dev_warn(rt5682->i2c_dev, "clk %s only support %d Hz input\n",
+ clk_name, CLK_PLL2_FIN);
+
+ /*
+@@ -2736,10 +2746,9 @@ static unsigned long rt5682_bclk_recalc_rate(struct clk_hw *hw,
+ struct rt5682_priv *rt5682 =
+ container_of(hw, struct rt5682_priv,
+ dai_clks_hw[RT5682_DAI_BCLK_IDX]);
+- struct snd_soc_component *component = rt5682->component;
+ unsigned int bclks_per_wclk;
+
+- bclks_per_wclk = snd_soc_component_read(component, RT5682_TDM_TCON_CTRL);
++ regmap_read(rt5682->regmap, RT5682_TDM_TCON_CTRL, &bclks_per_wclk);
+
+ switch (bclks_per_wclk & RT5682_TDM_BCLK_MS1_MASK) {
+ case RT5682_TDM_BCLK_MS1_256:
+@@ -2800,25 +2809,24 @@ static int rt5682_bclk_set_rate(struct clk_hw *hw, unsigned long rate,
+ struct rt5682_priv *rt5682 =
+ container_of(hw, struct rt5682_priv,
+ dai_clks_hw[RT5682_DAI_BCLK_IDX]);
+- struct snd_soc_component *component = rt5682->component;
++ struct snd_soc_component *component;
+ struct snd_soc_dai *dai;
+ unsigned long factor;
+
+ if (!rt5682_clk_check(rt5682))
+ return -EINVAL;
+
++ component = rt5682->component;
++
+ factor = rt5682_bclk_get_factor(rate, parent_rate);
+
+ for_each_component_dais(component, dai)
+ if (dai->id == RT5682_AIF1)
+- break;
+- if (!dai) {
+- dev_err(component->dev, "dai %d not found in component\n",
+- RT5682_AIF1);
+- return -ENODEV;
+- }
++ return rt5682_set_bclk1_ratio(dai, factor);
+
+- return rt5682_set_bclk1_ratio(dai, factor);
++ dev_err(rt5682->i2c_dev, "dai %d not found in component\n",
++ RT5682_AIF1);
++ return -ENODEV;
+ }
+
+ static const struct clk_ops rt5682_dai_clk_ops[RT5682_DAI_NUM_CLKS] = {
+@@ -2836,10 +2844,9 @@ static const struct clk_ops rt5682_dai_clk_ops[RT5682_DAI_NUM_CLKS] = {
+ },
+ };
+
+-static int rt5682_register_dai_clks(struct snd_soc_component *component)
++int rt5682_register_dai_clks(struct rt5682_priv *rt5682)
+ {
+- struct device *dev = component->dev;
+- struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
++ struct device *dev = rt5682->i2c_dev;
+ struct rt5682_platform_data *pdata = &rt5682->pdata;
+ struct clk_hw *dai_clk_hw;
+ int i, ret;
+@@ -2899,6 +2906,7 @@ static int rt5682_register_dai_clks(struct snd_soc_component *component)
+
+ return 0;
+ }
++EXPORT_SYMBOL_GPL(rt5682_register_dai_clks);
+ #endif /* CONFIG_COMMON_CLK */
+
+ static int rt5682_probe(struct snd_soc_component *component)
+@@ -2908,9 +2916,6 @@ static int rt5682_probe(struct snd_soc_component *component)
+ unsigned long time;
+ struct snd_soc_dapm_context *dapm = &component->dapm;
+
+-#ifdef CONFIG_COMMON_CLK
+- int ret;
+-#endif
+ rt5682->component = component;
+
+ if (rt5682->is_sdw) {
+@@ -2922,26 +2927,6 @@ static int rt5682_probe(struct snd_soc_component *component)
+ dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ return -ETIMEDOUT;
+ }
+- } else {
+-#ifdef CONFIG_COMMON_CLK
+- /* Check if MCLK provided */
+- rt5682->mclk = devm_clk_get(component->dev, "mclk");
+- if (IS_ERR(rt5682->mclk)) {
+- if (PTR_ERR(rt5682->mclk) != -ENOENT) {
+- ret = PTR_ERR(rt5682->mclk);
+- return ret;
+- }
+- rt5682->mclk = NULL;
+- }
+-
+- /* Register CCF DAI clock control */
+- ret = rt5682_register_dai_clks(component);
+- if (ret)
+- return ret;
+-
+- /* Initial setup for CCF */
+- rt5682->lrck[RT5682_AIF1] = CLK_48;
+-#endif
+ }
+
+ snd_soc_dapm_disable_pin(dapm, "MICBIAS");
+@@ -2968,10 +2953,7 @@ static int rt5682_suspend(struct snd_soc_component *component)
+
+ cancel_delayed_work_sync(&rt5682->jack_detect_work);
+ cancel_delayed_work_sync(&rt5682->jd_check_work);
+- if (rt5682->hs_jack && rt5682->jack_type == SND_JACK_HEADSET) {
+- snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+- RT5682_MB1_PATH_MASK | RT5682_MB2_PATH_MASK,
+- RT5682_CTRL_MB1_REG | RT5682_CTRL_MB2_REG);
++ if (rt5682->hs_jack && (rt5682->jack_type & SND_JACK_HEADSET) == SND_JACK_HEADSET) {
+ val = snd_soc_component_read(component,
+ RT5682_CBJ_CTRL_2) & RT5682_JACK_TYPE_MASK;
+
+@@ -2993,10 +2975,17 @@ static int rt5682_suspend(struct snd_soc_component *component)
+ /* enter SAR ADC power saving mode */
+ snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+ RT5682_SAR_BUTT_DET_MASK | RT5682_SAR_BUTDET_MODE_MASK |
+- RT5682_SAR_BUTDET_RST_MASK | RT5682_SAR_SEL_MB1_MB2_MASK, 0);
++ RT5682_SAR_SEL_MB1_MB2_MASK, 0);
++ usleep_range(5000, 6000);
++ snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
++ RT5682_MB1_PATH_MASK | RT5682_MB2_PATH_MASK,
++ RT5682_CTRL_MB1_REG | RT5682_CTRL_MB2_REG);
++ usleep_range(10000, 12000);
+ snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+- RT5682_SAR_BUTT_DET_MASK | RT5682_SAR_BUTDET_MODE_MASK | RT5682_SAR_BUTDET_RST_MASK,
+- RT5682_SAR_BUTT_DET_EN | RT5682_SAR_BUTDET_POW_SAV | RT5682_SAR_BUTDET_RST_NORMAL);
++ RT5682_SAR_BUTT_DET_MASK | RT5682_SAR_BUTDET_MODE_MASK,
++ RT5682_SAR_BUTT_DET_EN | RT5682_SAR_BUTDET_POW_SAV);
++ snd_soc_component_update_bits(component, RT5682_HP_CHARGE_PUMP_1,
++ RT5682_OSW_L_MASK | RT5682_OSW_R_MASK, 0);
+ }
+
+ regcache_cache_only(rt5682->regmap, true);
+@@ -3014,10 +3003,11 @@ static int rt5682_resume(struct snd_soc_component *component)
+ regcache_cache_only(rt5682->regmap, false);
+ regcache_sync(rt5682->regmap);
+
+- if (rt5682->hs_jack && rt5682->jack_type == SND_JACK_HEADSET) {
++ if (rt5682->hs_jack && (rt5682->jack_type & SND_JACK_HEADSET) == SND_JACK_HEADSET) {
+ snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+ RT5682_SAR_BUTDET_MODE_MASK | RT5682_SAR_SEL_MB1_MB2_MASK,
+ RT5682_SAR_BUTDET_POW_NORM | RT5682_SAR_SEL_MB1_MB2_AUTO);
++ usleep_range(5000, 6000);
+ snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+ RT5682_MB1_PATH_MASK | RT5682_MB2_PATH_MASK,
+ RT5682_CTRL_MB1_FSM | RT5682_CTRL_MB2_FSM);
+@@ -3025,8 +3015,9 @@ static int rt5682_resume(struct snd_soc_component *component)
+ RT5682_PWR_CBJ, RT5682_PWR_CBJ);
+ }
+
++ rt5682->jack_type = 0;
+ mod_delayed_work(system_power_efficient_wq,
+- &rt5682->jack_detect_work, msecs_to_jiffies(250));
++ &rt5682->jack_detect_work, msecs_to_jiffies(0));
+
+ return 0;
+ }
+diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h
+index 8e3244a62c160..52ff0d9c36c58 100644
+--- a/sound/soc/codecs/rt5682.h
++++ b/sound/soc/codecs/rt5682.h
+@@ -1428,6 +1428,7 @@ enum {
+
+ struct rt5682_priv {
+ struct snd_soc_component *component;
++ struct device *i2c_dev;
+ struct rt5682_platform_data pdata;
+ struct regmap *regmap;
+ struct regmap *sdw_regmap;
+@@ -1471,7 +1472,6 @@ int rt5682_sel_asrc_clk_src(struct snd_soc_component *component,
+
+ void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev);
+
+-int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert);
+ void rt5682_jack_detect_handler(struct work_struct *work);
+
+ bool rt5682_volatile_register(struct device *dev, unsigned int reg);
+@@ -1482,6 +1482,8 @@ void rt5682_calibrate(struct rt5682_priv *rt5682);
+ void rt5682_reset(struct rt5682_priv *rt5682);
+ int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev);
+
++int rt5682_register_dai_clks(struct rt5682_priv *rt5682);
++
+ #define RT5682_REG_NUM 318
+ extern const struct reg_default rt5682_reg[RT5682_REG_NUM];
+
+diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c
+index 921382724f9cd..614a40247679b 100644
+--- a/sound/soc/codecs/rt700.c
++++ b/sound/soc/codecs/rt700.c
+@@ -315,17 +315,27 @@ static int rt700_set_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *hs_jack, void *data)
+ {
+ struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
++ int ret;
+
+ rt700->hs_jack = hs_jack;
+
+- if (!rt700->hw_init) {
+- dev_dbg(&rt700->slave->dev,
+- "%s hw_init not ready yet\n", __func__);
++ ret = pm_runtime_resume_and_get(component->dev);
++ if (ret < 0) {
++ if (ret != -EACCES) {
++ dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
++ return ret;
++ }
++
++ /* pm_runtime not enabled yet */
++ dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__);
+ return 0;
+ }
+
+ rt700_jack_init(rt700);
+
++ pm_runtime_mark_last_busy(component->dev);
++ pm_runtime_put_autosuspend(component->dev);
++
+ return 0;
+ }
+
+diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c
+index 2e992589f1e42..c15fb98eac86d 100644
+--- a/sound/soc/codecs/rt711-sdca.c
++++ b/sound/soc/codecs/rt711-sdca.c
+@@ -487,16 +487,27 @@ static int rt711_sdca_set_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *hs_jack, void *data)
+ {
+ struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
++ int ret;
+
+ rt711->hs_jack = hs_jack;
+
+- if (!rt711->hw_init) {
+- dev_dbg(&rt711->slave->dev,
+- "%s hw_init not ready yet\n", __func__);
++ ret = pm_runtime_resume_and_get(component->dev);
++ if (ret < 0) {
++ if (ret != -EACCES) {
++ dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
++ return ret;
++ }
++
++ /* pm_runtime not enabled yet */
++ dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__);
+ return 0;
+ }
+
+ rt711_sdca_jack_init(rt711);
++
++ pm_runtime_mark_last_busy(component->dev);
++ pm_runtime_put_autosuspend(component->dev);
++
+ return 0;
+ }
+
+@@ -1190,14 +1201,6 @@ static int rt711_sdca_probe(struct snd_soc_component *component)
+ return 0;
+ }
+
+-static void rt711_sdca_remove(struct snd_soc_component *component)
+-{
+- struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+-
+- regcache_cache_only(rt711->regmap, true);
+- regcache_cache_only(rt711->mbq_regmap, true);
+-}
+-
+ static const struct snd_soc_component_driver soc_sdca_dev_rt711 = {
+ .probe = rt711_sdca_probe,
+ .controls = rt711_sdca_snd_controls,
+@@ -1207,7 +1210,7 @@ static const struct snd_soc_component_driver soc_sdca_dev_rt711 = {
+ .dapm_routes = rt711_sdca_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(rt711_sdca_audio_map),
+ .set_jack = rt711_sdca_set_jack_detect,
+- .remove = rt711_sdca_remove,
++ .endianness = 1,
+ };
+
+ static int rt711_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c
+index a7c5608a0ef87..fafb0ba8349fd 100644
+--- a/sound/soc/codecs/rt711.c
++++ b/sound/soc/codecs/rt711.c
+@@ -450,17 +450,27 @@ static int rt711_set_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *hs_jack, void *data)
+ {
+ struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
++ int ret;
+
+ rt711->hs_jack = hs_jack;
+
+- if (!rt711->hw_init) {
+- dev_dbg(&rt711->slave->dev,
+- "%s hw_init not ready yet\n", __func__);
++ ret = pm_runtime_resume_and_get(component->dev);
++ if (ret < 0) {
++ if (ret != -EACCES) {
++ dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
++ return ret;
++ }
++
++ /* pm_runtime not enabled yet */
++ dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__);
+ return 0;
+ }
+
+ rt711_jack_init(rt711);
+
++ pm_runtime_mark_last_busy(component->dev);
++ pm_runtime_put_autosuspend(component->dev);
++
+ return 0;
+ }
+
+@@ -925,13 +935,6 @@ static int rt711_probe(struct snd_soc_component *component)
+ return 0;
+ }
+
+-static void rt711_remove(struct snd_soc_component *component)
+-{
+- struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
+-
+- regcache_cache_only(rt711->regmap, true);
+-}
+-
+ static const struct snd_soc_component_driver soc_codec_dev_rt711 = {
+ .probe = rt711_probe,
+ .set_bias_level = rt711_set_bias_level,
+@@ -942,7 +945,7 @@ static const struct snd_soc_component_driver soc_codec_dev_rt711 = {
+ .dapm_routes = rt711_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(rt711_audio_map),
+ .set_jack = rt711_set_jack_detect,
+- .remove = rt711_remove,
++ .endianness = 1,
+ };
+
+ static int rt711_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
+index 6ffd23f2ee65d..997425ef0a294 100644
+--- a/sound/usb/mixer_maps.c
++++ b/sound/usb/mixer_maps.c
+@@ -423,6 +423,14 @@ static const struct usbmix_name_map aorus_master_alc1220vb_map[] = {
+ {}
+ };
+
++/* MSI MPG X570S Carbon Max Wifi with ALC4080 */
++static const struct usbmix_name_map msi_mpg_x570s_carbon_max_wifi_alc4080_map[] = {
++ { 29, "Speaker Playback" },
++ { 30, "Front Headphone Playback" },
++ { 32, "IEC958 Playback" },
++ {}
++};
++
+ /*
+ * Control map entries
+ */
+@@ -574,6 +582,14 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
+ .map = trx40_mobo_map,
+ .connector_map = trx40_mobo_connector_map,
+ },
++ { /* MSI MPG X570S Carbon Max Wifi */
++ .id = USB_ID(0x0db0, 0x419c),
++ .map = msi_mpg_x570s_carbon_max_wifi_alc4080_map,
++ },
++ { /* MSI MAG X570S Torpedo Max */
++ .id = USB_ID(0x0db0, 0xa073),
++ .map = msi_mpg_x570s_carbon_max_wifi_alc4080_map,
++ },
+ { /* MSI TRX40 */
+ .id = USB_ID(0x0db0, 0x543d),
+ .map = trx40_mobo_map,
+diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
+index e8468f9b007d1..12ce69b04f634 100644
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -1842,6 +1842,10 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
+ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
++ DEVICE_FLG(0x1397, 0x0508, /* Behringer UMC204HD */
++ QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
++ DEVICE_FLG(0x1397, 0x0509, /* Behringer UMC404HD */
++ QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+ DEVICE_FLG(0x13e5, 0x0001, /* Serato Phono */
+ QUIRK_FLAG_IGNORE_CTL_ERROR),
+ DEVICE_FLG(0x154e, 0x1002, /* Denon DCD-1500RE */
+diff --git a/tools/testing/selftests/bpf/prog_tests/timer_crash.c b/tools/testing/selftests/bpf/prog_tests/timer_crash.c
+deleted file mode 100644
+index f74b82305da8c..0000000000000
+--- a/tools/testing/selftests/bpf/prog_tests/timer_crash.c
++++ /dev/null
+@@ -1,32 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-#include <test_progs.h>
+-#include "timer_crash.skel.h"
+-
+-enum {
+- MODE_ARRAY,
+- MODE_HASH,
+-};
+-
+-static void test_timer_crash_mode(int mode)
+-{
+- struct timer_crash *skel;
+-
+- skel = timer_crash__open_and_load();
+- if (!ASSERT_OK_PTR(skel, "timer_crash__open_and_load"))
+- return;
+- skel->bss->pid = getpid();
+- skel->bss->crash_map = mode;
+- if (!ASSERT_OK(timer_crash__attach(skel), "timer_crash__attach"))
+- goto end;
+- usleep(1);
+-end:
+- timer_crash__destroy(skel);
+-}
+-
+-void test_timer_crash(void)
+-{
+- if (test__start_subtest("array"))
+- test_timer_crash_mode(MODE_ARRAY);
+- if (test__start_subtest("hash"))
+- test_timer_crash_mode(MODE_HASH);
+-}
+diff --git a/tools/testing/selftests/bpf/progs/timer_crash.c b/tools/testing/selftests/bpf/progs/timer_crash.c
+deleted file mode 100644
+index f8f7944e70dae..0000000000000
+--- a/tools/testing/selftests/bpf/progs/timer_crash.c
++++ /dev/null
+@@ -1,54 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-
+-#include <vmlinux.h>
+-#include <bpf/bpf_tracing.h>
+-#include <bpf/bpf_helpers.h>
+-
+-struct map_elem {
+- struct bpf_timer timer;
+- struct bpf_spin_lock lock;
+-};
+-
+-struct {
+- __uint(type, BPF_MAP_TYPE_ARRAY);
+- __uint(max_entries, 1);
+- __type(key, int);
+- __type(value, struct map_elem);
+-} amap SEC(".maps");
+-
+-struct {
+- __uint(type, BPF_MAP_TYPE_HASH);
+- __uint(max_entries, 1);
+- __type(key, int);
+- __type(value, struct map_elem);
+-} hmap SEC(".maps");
+-
+-int pid = 0;
+-int crash_map = 0; /* 0 for amap, 1 for hmap */
+-
+-SEC("fentry/do_nanosleep")
+-int sys_enter(void *ctx)
+-{
+- struct map_elem *e, value = {};
+- void *map = crash_map ? (void *)&hmap : (void *)&amap;
+-
+- if (bpf_get_current_task_btf()->tgid != pid)
+- return 0;
+-
+- *(void **)&value = (void *)0xdeadcaf3;
+-
+- bpf_map_update_elem(map, &(int){0}, &value, 0);
+- /* For array map, doing bpf_map_update_elem will do a
+- * check_and_free_timer_in_array, which will trigger the crash if timer
+- * pointer was overwritten, for hmap we need to use bpf_timer_cancel.
+- */
+- if (crash_map == 1) {
+- e = bpf_map_lookup_elem(map, &(int){0});
+- if (!e)
+- return 0;
+- bpf_timer_cancel(&e->timer);
+- }
+- return 0;
+-}
+-
+-char _license[] SEC("license") = "GPL";
+diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh
+index 92087d423bcf1..c9507df9c05bc 100644
+--- a/tools/testing/selftests/net/forwarding/lib.sh
++++ b/tools/testing/selftests/net/forwarding/lib.sh
+@@ -1149,6 +1149,7 @@ learning_test()
+ # FDB entry was installed.
+ bridge link set dev $br_port1 flood off
+
++ ip link set $host1_if promisc on
+ tc qdisc add dev $host1_if ingress
+ tc filter add dev $host1_if ingress protocol ip pref 1 handle 101 \
+ flower dst_mac $mac action drop
+@@ -1159,7 +1160,7 @@ learning_test()
+ tc -j -s filter show dev $host1_if ingress \
+ | jq -e ".[] | select(.options.handle == 101) \
+ | select(.options.actions[0].stats.packets == 1)" &> /dev/null
+- check_fail $? "Packet reached second host when should not"
++ check_fail $? "Packet reached first host when should not"
+
+ $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
+ sleep 1
+@@ -1198,6 +1199,7 @@ learning_test()
+
+ tc filter del dev $host1_if ingress protocol ip pref 1 handle 101 flower
+ tc qdisc del dev $host1_if ingress
++ ip link set $host1_if promisc off
+
+ bridge link set dev $br_port1 flood on
+
+@@ -1215,6 +1217,7 @@ flood_test_do()
+
+ # Add an ACL on `host2_if` which will tell us whether the packet
+ # was flooded to it or not.
++ ip link set $host2_if promisc on
+ tc qdisc add dev $host2_if ingress
+ tc filter add dev $host2_if ingress protocol ip pref 1 handle 101 \
+ flower dst_mac $mac action drop
+@@ -1232,6 +1235,7 @@ flood_test_do()
+
+ tc filter del dev $host2_if ingress protocol ip pref 1 handle 101 flower
+ tc qdisc del dev $host2_if ingress
++ ip link set $host2_if promisc off
+
+ return $err
+ }
+diff --git a/tools/testing/selftests/net/udpgro.sh b/tools/testing/selftests/net/udpgro.sh
+index f8a19f548ae9d..ebbd0b2824327 100755
+--- a/tools/testing/selftests/net/udpgro.sh
++++ b/tools/testing/selftests/net/udpgro.sh
+@@ -34,7 +34,7 @@ cfg_veth() {
+ ip -netns "${PEER_NS}" addr add dev veth1 192.168.1.1/24
+ ip -netns "${PEER_NS}" addr add dev veth1 2001:db8::1/64 nodad
+ ip -netns "${PEER_NS}" link set dev veth1 up
+- ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp_dummy
++ ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp
+ }
+
+ run_one() {
+diff --git a/tools/testing/selftests/net/udpgro_bench.sh b/tools/testing/selftests/net/udpgro_bench.sh
+index 820bc50f6b687..fad2d1a71cac3 100755
+--- a/tools/testing/selftests/net/udpgro_bench.sh
++++ b/tools/testing/selftests/net/udpgro_bench.sh
+@@ -34,7 +34,7 @@ run_one() {
+ ip -netns "${PEER_NS}" addr add dev veth1 2001:db8::1/64 nodad
+ ip -netns "${PEER_NS}" link set dev veth1 up
+
+- ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp_dummy
++ ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp
+ ip netns exec "${PEER_NS}" ./udpgso_bench_rx ${rx_args} -r &
+ ip netns exec "${PEER_NS}" ./udpgso_bench_rx -t ${rx_args} -r &
+
+diff --git a/tools/testing/selftests/net/udpgro_fwd.sh b/tools/testing/selftests/net/udpgro_fwd.sh
+index 6f05e06f67613..1bcd82e1f662e 100755
+--- a/tools/testing/selftests/net/udpgro_fwd.sh
++++ b/tools/testing/selftests/net/udpgro_fwd.sh
+@@ -46,7 +46,7 @@ create_ns() {
+ ip -n $BASE$ns addr add dev veth$ns $BM_NET_V4$ns/24
+ ip -n $BASE$ns addr add dev veth$ns $BM_NET_V6$ns/64 nodad
+ done
+- ip -n $NS_DST link set veth$DST xdp object ../bpf/xdp_dummy.o section xdp_dummy 2>/dev/null
++ ip -n $NS_DST link set veth$DST xdp object ../bpf/xdp_dummy.o section xdp 2>/dev/null
+ }
+
+ create_vxlan_endpoint() {
+diff --git a/tools/testing/selftests/net/veth.sh b/tools/testing/selftests/net/veth.sh
+index 19eac3e44c065..430895d1a2b63 100755
+--- a/tools/testing/selftests/net/veth.sh
++++ b/tools/testing/selftests/net/veth.sh
+@@ -289,14 +289,14 @@ if [ $CPUS -gt 1 ]; then
+ ip netns exec $NS_SRC ethtool -L veth$SRC rx 1 tx 2 2>/dev/null
+ printf "%-60s" "bad setting: XDP with RX nr less than TX"
+ ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o \
+- section xdp_dummy 2>/dev/null &&\
++ section xdp 2>/dev/null &&\
+ echo "fail - set operation successful ?!?" || echo " ok "
+
+ # the following tests will run with multiple channels active
+ ip netns exec $NS_SRC ethtool -L veth$SRC rx 2
+ ip netns exec $NS_DST ethtool -L veth$DST rx 2
+ ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o \
+- section xdp_dummy 2>/dev/null
++ section xdp 2>/dev/null
+ printf "%-60s" "bad setting: reducing RX nr below peer TX with XDP set"
+ ip netns exec $NS_DST ethtool -L veth$DST rx 1 2>/dev/null &&\
+ echo "fail - set operation successful ?!?" || echo " ok "
+@@ -311,7 +311,7 @@ if [ $CPUS -gt 2 ]; then
+ chk_channels "setting invalid channels nr" $DST 2 2
+ fi
+
+-ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o section xdp_dummy 2>/dev/null
++ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o section xdp 2>/dev/null
+ chk_gro_flag "with xdp attached - gro flag" $DST on
+ chk_gro_flag " - peer gro flag" $SRC off
+ chk_tso_flag " - tso flag" $SRC off
+diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
+index fefdf3a6dae35..9eac68ae291e3 100644
+--- a/virt/kvm/kvm_main.c
++++ b/virt/kvm/kvm_main.c
+@@ -911,7 +911,7 @@ static void kvm_destroy_vm_debugfs(struct kvm *kvm)
+ int kvm_debugfs_num_entries = kvm_vm_stats_header.num_desc +
+ kvm_vcpu_stats_header.num_desc;
+
+- if (!kvm->debugfs_dentry)
++ if (IS_ERR(kvm->debugfs_dentry))
+ return;
+
+ debugfs_remove_recursive(kvm->debugfs_dentry);
+@@ -1049,6 +1049,12 @@ static struct kvm *kvm_create_vm(unsigned long type)
+
+ BUILD_BUG_ON(KVM_MEM_SLOTS_NUM > SHRT_MAX);
+
++ /*
++ * Force subsequent debugfs file creations to fail if the VM directory
++ * is not created (by kvm_create_vm_debugfs()).
++ */
++ kvm->debugfs_dentry = ERR_PTR(-ENOENT);
++
+ if (init_srcu_struct(&kvm->srcu))
+ goto out_err_no_srcu;
+ if (init_srcu_struct(&kvm->irq_srcu))
+@@ -1255,9 +1261,9 @@ static int kvm_vm_release(struct inode *inode, struct file *filp)
+ */
+ static int kvm_alloc_dirty_bitmap(struct kvm_memory_slot *memslot)
+ {
+- unsigned long dirty_bytes = 2 * kvm_dirty_bitmap_bytes(memslot);
++ unsigned long dirty_bytes = kvm_dirty_bitmap_bytes(memslot);
+
+- memslot->dirty_bitmap = kvzalloc(dirty_bytes, GFP_KERNEL_ACCOUNT);
++ memslot->dirty_bitmap = __vcalloc(2, dirty_bytes, GFP_KERNEL_ACCOUNT);
+ if (!memslot->dirty_bitmap)
+ return -ENOMEM;
+
+@@ -5373,7 +5379,7 @@ static void kvm_uevent_notify_change(unsigned int type, struct kvm *kvm)
+ }
+ add_uevent_var(env, "PID=%d", kvm->userspace_pid);
+
+- if (kvm->debugfs_dentry) {
++ if (!IS_ERR(kvm->debugfs_dentry)) {
+ char *tmp, *p = kmalloc(PATH_MAX, GFP_KERNEL_ACCOUNT);
+
+ if (p) {