From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 1343B158041 for ; Wed, 27 Mar 2024 11:22:30 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 15D38E2A39; Wed, 27 Mar 2024 11:22:29 +0000 (UTC) Received: from smtp.gentoo.org (mail.gentoo.org [IPv6:2001:470:ea4a:1:5054:ff:fec7:86e4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 651E0E2A39 for ; Wed, 27 Mar 2024 11:22:28 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 5919E33BE3B for ; Wed, 27 Mar 2024 11:22:25 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id B7A39B29 for ; Wed, 27 Mar 2024 11:22:23 +0000 (UTC) From: "Mike Pagano" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Mike Pagano" Message-ID: <1711538486.3aa27a23fc901db82a7d02bc717bf1699abca15d.mpagano@gentoo> Subject: [gentoo-commits] proj/linux-patches:6.8 commit in: / X-VCS-Repository: proj/linux-patches X-VCS-Files: 0000_README 1001_linux-6.8.2.patch X-VCS-Directories: / X-VCS-Committer: mpagano X-VCS-Committer-Name: Mike Pagano X-VCS-Revision: 3aa27a23fc901db82a7d02bc717bf1699abca15d X-VCS-Branch: 6.8 Date: Wed, 27 Mar 2024 11:22:23 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: c2272ed3-82e7-4b66-9c8e-dea4657eadc5 X-Archives-Hash: 6ee3503228f82940cd463c5f829c1e11 commit: 3aa27a23fc901db82a7d02bc717bf1699abca15d Author: Mike Pagano gentoo org> AuthorDate: Wed Mar 27 11:21:26 2024 +0000 Commit: Mike Pagano gentoo org> CommitDate: Wed Mar 27 11:21:26 2024 +0000 URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=3aa27a23 Linux patch 6.8.2 Signed-off-by: Mike Pagano gentoo.org> 0000_README | 4 + 1001_linux-6.8.2.patch | 33522 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 33526 insertions(+) diff --git a/0000_README b/0000_README index 5fe89b7e..5b18c2c3 100644 --- a/0000_README +++ b/0000_README @@ -47,6 +47,10 @@ Patch: 1000_linux-6.8.1.patch From: https://www.kernel.org Desc: Linux 6.8.1 +Patch: 1001_linux-6.8.2.patch +From: https://www.kernel.org +Desc: Linux 6.8.2 + Patch: 1510_fs-enable-link-security-restrictions-by-default.patch From: http://sources.debian.net/src/linux/3.16.7-ckt4-3/debian/patches/debian/fs-enable-link-security-restrictions-by-default.patch/ Desc: Enable link security restrictions by default. diff --git a/1001_linux-6.8.2.patch b/1001_linux-6.8.2.patch new file mode 100644 index 00000000..7e16c762 --- /dev/null +++ b/1001_linux-6.8.2.patch @@ -0,0 +1,33522 @@ +diff --git a/Documentation/devicetree/bindings/display/msm/qcom,mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,mdss.yaml +index 0999ea07f47bb..e4576546bf0db 100644 +--- a/Documentation/devicetree/bindings/display/msm/qcom,mdss.yaml ++++ b/Documentation/devicetree/bindings/display/msm/qcom,mdss.yaml +@@ -127,6 +127,7 @@ patternProperties: + - qcom,dsi-phy-20nm + - qcom,dsi-phy-28nm-8226 + - qcom,dsi-phy-28nm-hpm ++ - qcom,dsi-phy-28nm-hpm-fam-b + - qcom,dsi-phy-28nm-lp + - qcom,hdmi-phy-8084 + - qcom,hdmi-phy-8660 +diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml +index a4042ae247702..38c48131e6e7b 100644 +--- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml ++++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml +@@ -484,7 +484,12 @@ allOf: + - if: + properties: + compatible: +- const: qcom,sm8450-smmu-500 ++ items: ++ - const: qcom,sm8450-smmu-500 ++ - const: qcom,adreno-smmu ++ - const: qcom,smmu-500 ++ - const: arm,mmu-500 ++ + then: + properties: + clock-names: +@@ -508,7 +513,11 @@ allOf: + - if: + properties: + compatible: +- const: qcom,sm8550-smmu-500 ++ items: ++ - const: qcom,sm8550-smmu-500 ++ - const: qcom,adreno-smmu ++ - const: qcom,smmu-500 ++ - const: arm,mmu-500 + then: + properties: + clock-names: +diff --git a/Documentation/devicetree/bindings/media/i2c/techwell,tw9900.yaml b/Documentation/devicetree/bindings/media/i2c/techwell,tw9900.yaml +index e37317f810722..c9673391afdbd 100644 +--- a/Documentation/devicetree/bindings/media/i2c/techwell,tw9900.yaml ++++ b/Documentation/devicetree/bindings/media/i2c/techwell,tw9900.yaml +@@ -36,7 +36,7 @@ properties: + + properties: + port@0: +- $ref: /schemas/graph.yaml#/$defs/port-base ++ $ref: /schemas/graph.yaml#/properties/port + description: Analog input port + + properties: +diff --git a/Documentation/driver-api/soundwire/stream.rst b/Documentation/driver-api/soundwire/stream.rst +index b432a2de45d37..2a794484f62c9 100644 +--- a/Documentation/driver-api/soundwire/stream.rst ++++ b/Documentation/driver-api/soundwire/stream.rst +@@ -324,12 +324,12 @@ framework, this stream state is linked to .hw_params() operation. + + int sdw_stream_add_master(struct sdw_bus * bus, + struct sdw_stream_config * stream_config, +- struct sdw_ports_config * ports_config, ++ const struct sdw_ports_config * ports_config, + struct sdw_stream_runtime * stream); + + int sdw_stream_add_slave(struct sdw_slave * slave, + struct sdw_stream_config * stream_config, +- struct sdw_ports_config * ports_config, ++ const struct sdw_ports_config * ports_config, + struct sdw_stream_runtime * stream); + + +diff --git a/Documentation/netlink/specs/devlink.yaml b/Documentation/netlink/specs/devlink.yaml +index cf6eaa0da821b..09fbb4c03fc8d 100644 +--- a/Documentation/netlink/specs/devlink.yaml ++++ b/Documentation/netlink/specs/devlink.yaml +@@ -290,7 +290,7 @@ attribute-sets: + enum: eswitch-mode + - + name: eswitch-inline-mode +- type: u16 ++ type: u8 + enum: eswitch-inline-mode + - + name: dpipe-tables +diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml +index 3dcc9ece272aa..d0c821c202036 100644 +--- a/Documentation/netlink/specs/dpll.yaml ++++ b/Documentation/netlink/specs/dpll.yaml +@@ -274,6 +274,7 @@ attribute-sets: + - + name: capabilities + type: u32 ++ enum: pin-capabilities + - + name: parent-device + type: nest +diff --git a/Documentation/networking/net_cachelines/net_device.rst b/Documentation/networking/net_cachelines/net_device.rst +index dceb49d56a911..70c4fb9d4e5ce 100644 +--- a/Documentation/networking/net_cachelines/net_device.rst ++++ b/Documentation/networking/net_cachelines/net_device.rst +@@ -13,7 +13,7 @@ struct_dev_ifalias* ifalias + unsigned_long mem_end + unsigned_long mem_start + unsigned_long base_addr +-unsigned_long state ++unsigned_long state read_mostly read_mostly netif_running(dev) + struct_list_head dev_list + struct_list_head napi_list + struct_list_head unreg_list +diff --git a/Makefile b/Makefile +index 95b320ada47c4..33d8e822f6f11 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 8 +-SUBLEVEL = 1 ++SUBLEVEL = 2 + EXTRAVERSION = + NAME = Hurr durr I'ma ninja sloth + +diff --git a/arch/arm/boot/dts/arm/arm-realview-pb1176.dts b/arch/arm/boot/dts/arm/arm-realview-pb1176.dts +index efed325af88d2..d99bac02232b3 100644 +--- a/arch/arm/boot/dts/arm/arm-realview-pb1176.dts ++++ b/arch/arm/boot/dts/arm/arm-realview-pb1176.dts +@@ -451,7 +451,7 @@ pb1176_serial3: serial@1010f000 { + + /* Direct-mapped development chip ROM */ + pb1176_rom@10200000 { +- compatible = "direct-mapped"; ++ compatible = "mtd-rom"; + reg = <0x10200000 0x4000>; + bank-width = <1>; + }; +diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-yapp4-common.dtsi b/arch/arm/boot/dts/nxp/imx/imx6dl-yapp4-common.dtsi +index 3be38a3c4bb11..c32ea040fecdd 100644 +--- a/arch/arm/boot/dts/nxp/imx/imx6dl-yapp4-common.dtsi ++++ b/arch/arm/boot/dts/nxp/imx/imx6dl-yapp4-common.dtsi +@@ -117,17 +117,9 @@ mdio { + #address-cells = <1>; + #size-cells = <0>; + +- phy_port2: phy@1 { +- reg = <1>; +- }; +- +- phy_port3: phy@2 { +- reg = <2>; +- }; +- + switch@10 { + compatible = "qca,qca8334"; +- reg = <10>; ++ reg = <0x10>; + reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>; + + switch_ports: ports { +@@ -149,15 +141,30 @@ fixed-link { + eth2: port@2 { + reg = <2>; + label = "eth2"; ++ phy-mode = "internal"; + phy-handle = <&phy_port2>; + }; + + eth1: port@3 { + reg = <3>; + label = "eth1"; ++ phy-mode = "internal"; + phy-handle = <&phy_port3>; + }; + }; ++ ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ phy_port2: ethernet-phy@1 { ++ reg = <1>; ++ }; ++ ++ phy_port3: ethernet-phy@2 { ++ reg = <2>; ++ }; ++ }; + }; + }; + }; +diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi +index b1413983787c2..083ab780ab7e4 100644 +--- a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi ++++ b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi +@@ -1234,7 +1234,7 @@ restart@fc4ab000 { + + qfprom: qfprom@fc4bc000 { + compatible = "qcom,msm8974-qfprom", "qcom,qfprom"; +- reg = <0xfc4bc000 0x1000>; ++ reg = <0xfc4bc000 0x2100>; + #address-cells = <1>; + #size-cells = <1>; + +diff --git a/arch/arm/boot/dts/renesas/r8a73a4-ape6evm.dts b/arch/arm/boot/dts/renesas/r8a73a4-ape6evm.dts +index ed75c01dbee10..3d02f065f71c2 100644 +--- a/arch/arm/boot/dts/renesas/r8a73a4-ape6evm.dts ++++ b/arch/arm/boot/dts/renesas/r8a73a4-ape6evm.dts +@@ -209,6 +209,18 @@ &cmt1 { + status = "okay"; + }; + ++&extal1_clk { ++ clock-frequency = <26000000>; ++}; ++ ++&extal2_clk { ++ clock-frequency = <48000000>; ++}; ++ ++&extalr_clk { ++ clock-frequency = <32768>; ++}; ++ + &pfc { + scifa0_pins: scifa0 { + groups = "scifa0_data"; +diff --git a/arch/arm/boot/dts/renesas/r8a73a4.dtsi b/arch/arm/boot/dts/renesas/r8a73a4.dtsi +index c39066967053f..d1f4cbd099efb 100644 +--- a/arch/arm/boot/dts/renesas/r8a73a4.dtsi ++++ b/arch/arm/boot/dts/renesas/r8a73a4.dtsi +@@ -450,17 +450,20 @@ clocks { + extalr_clk: extalr { + compatible = "fixed-clock"; + #clock-cells = <0>; +- clock-frequency = <32768>; ++ /* This value must be overridden by the board. */ ++ clock-frequency = <0>; + }; + extal1_clk: extal1 { + compatible = "fixed-clock"; + #clock-cells = <0>; +- clock-frequency = <25000000>; ++ /* This value must be overridden by the board. */ ++ clock-frequency = <0>; + }; + extal2_clk: extal2 { + compatible = "fixed-clock"; + #clock-cells = <0>; +- clock-frequency = <48000000>; ++ /* This value must be overridden by the board. */ ++ clock-frequency = <0>; + }; + fsiack_clk: fsiack { + compatible = "fixed-clock"; +diff --git a/arch/arm/crypto/sha256_glue.c b/arch/arm/crypto/sha256_glue.c +index 433ee4ddce6c8..f85933fdec75f 100644 +--- a/arch/arm/crypto/sha256_glue.c ++++ b/arch/arm/crypto/sha256_glue.c +@@ -24,8 +24,8 @@ + + #include "sha256_glue.h" + +-asmlinkage void sha256_block_data_order(u32 *digest, const void *data, +- unsigned int num_blks); ++asmlinkage void sha256_block_data_order(struct sha256_state *state, ++ const u8 *data, int num_blks); + + int crypto_sha256_arm_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +@@ -33,23 +33,20 @@ int crypto_sha256_arm_update(struct shash_desc *desc, const u8 *data, + /* make sure casting to sha256_block_fn() is safe */ + BUILD_BUG_ON(offsetof(struct sha256_state, state) != 0); + +- return sha256_base_do_update(desc, data, len, +- (sha256_block_fn *)sha256_block_data_order); ++ return sha256_base_do_update(desc, data, len, sha256_block_data_order); + } + EXPORT_SYMBOL(crypto_sha256_arm_update); + + static int crypto_sha256_arm_final(struct shash_desc *desc, u8 *out) + { +- sha256_base_do_finalize(desc, +- (sha256_block_fn *)sha256_block_data_order); ++ sha256_base_do_finalize(desc, sha256_block_data_order); + return sha256_base_finish(desc, out); + } + + int crypto_sha256_arm_finup(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) + { +- sha256_base_do_update(desc, data, len, +- (sha256_block_fn *)sha256_block_data_order); ++ sha256_base_do_update(desc, data, len, sha256_block_data_order); + return crypto_sha256_arm_final(desc, out); + } + EXPORT_SYMBOL(crypto_sha256_arm_finup); +diff --git a/arch/arm/crypto/sha512-glue.c b/arch/arm/crypto/sha512-glue.c +index 0635a65aa488b..1be5bd498af36 100644 +--- a/arch/arm/crypto/sha512-glue.c ++++ b/arch/arm/crypto/sha512-glue.c +@@ -25,27 +25,25 @@ MODULE_ALIAS_CRYPTO("sha512"); + MODULE_ALIAS_CRYPTO("sha384-arm"); + MODULE_ALIAS_CRYPTO("sha512-arm"); + +-asmlinkage void sha512_block_data_order(u64 *state, u8 const *src, int blocks); ++asmlinkage void sha512_block_data_order(struct sha512_state *state, ++ u8 const *src, int blocks); + + int sha512_arm_update(struct shash_desc *desc, const u8 *data, + unsigned int len) + { +- return sha512_base_do_update(desc, data, len, +- (sha512_block_fn *)sha512_block_data_order); ++ return sha512_base_do_update(desc, data, len, sha512_block_data_order); + } + + static int sha512_arm_final(struct shash_desc *desc, u8 *out) + { +- sha512_base_do_finalize(desc, +- (sha512_block_fn *)sha512_block_data_order); ++ sha512_base_do_finalize(desc, sha512_block_data_order); + return sha512_base_finish(desc, out); + } + + int sha512_arm_finup(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) + { +- sha512_base_do_update(desc, data, len, +- (sha512_block_fn *)sha512_block_data_order); ++ sha512_base_do_update(desc, data, len, sha512_block_data_order); + return sha512_arm_final(desc, out); + } + +diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig +index aa7c1d4351396..6b96d75a3a3d8 100644 +--- a/arch/arm64/Kconfig ++++ b/arch/arm64/Kconfig +@@ -198,7 +198,7 @@ config ARM64 + if DYNAMIC_FTRACE_WITH_ARGS && DYNAMIC_FTRACE_WITH_CALL_OPS + select HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS \ + if (DYNAMIC_FTRACE_WITH_ARGS && !CFI_CLANG && \ +- !CC_OPTIMIZE_FOR_SIZE) ++ (CC_IS_CLANG || !CC_OPTIMIZE_FOR_SIZE)) + select FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY \ + if DYNAMIC_FTRACE_WITH_ARGS + select HAVE_SAMPLE_FTRACE_DIRECT +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts +index 9ec49ac2f6fd5..381d58cea092d 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts +@@ -291,6 +291,8 @@ sw { + }; + + &spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spdif_tx_pin>; + status = "okay"; + }; + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi +index 4903d6358112d..855b7d43bc503 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi +@@ -166,6 +166,8 @@ &r_ir { + }; + + &spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spdif_tx_pin>; + status = "okay"; + }; + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +index ca1d287a0a01d..d11e5041bae9a 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +@@ -406,6 +406,7 @@ spi1_cs_pin: spi1-cs-pin { + function = "spi1"; + }; + ++ /omit-if-no-ref/ + spdif_tx_pin: spdif-tx-pin { + pins = "PH7"; + function = "spdif"; +@@ -655,10 +656,8 @@ spdif: spdif@5093000 { + clocks = <&ccu CLK_BUS_SPDIF>, <&ccu CLK_SPDIF>; + clock-names = "apb", "spdif"; + resets = <&ccu RST_BUS_SPDIF>; +- dmas = <&dma 2>; +- dma-names = "tx"; +- pinctrl-names = "default"; +- pinctrl-0 = <&spdif_tx_pin>; ++ dmas = <&dma 2>, <&dma 2>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +diff --git a/arch/arm64/boot/dts/broadcom/bcmbca/bcm4908.dtsi b/arch/arm64/boot/dts/broadcom/bcmbca/bcm4908.dtsi +index 2f124b027bbf0..aadfa0ae05252 100644 +--- a/arch/arm64/boot/dts/broadcom/bcmbca/bcm4908.dtsi ++++ b/arch/arm64/boot/dts/broadcom/bcmbca/bcm4908.dtsi +@@ -227,9 +227,6 @@ ethernet-switch@0 { + brcm,num-gphy = <5>; + brcm,num-rgmii-ports = <2>; + +- #address-cells = <1>; +- #size-cells = <0>; +- + ports: ports { + #address-cells = <1>; + #size-cells = <0>; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl-osm-s.dts b/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl-osm-s.dts +index 8b16bd68576c0..d9fa0deea7002 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl-osm-s.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl-osm-s.dts +@@ -294,8 +294,8 @@ MX8MM_IOMUXC_SAI3_MCLK_GPIO5_IO2 0x19 + + pinctrl_i2c4: i2c4grp { + fsl,pins = < +- MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL 0x400001c3 +- MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA 0x400001c3 ++ MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL 0x40000083 ++ MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA 0x40000083 + >; + }; + +@@ -313,19 +313,19 @@ MX8MM_IOMUXC_SAI5_MCLK_GPIO3_IO25 0x19 + + pinctrl_uart1: uart1grp { + fsl,pins = < +- MX8MM_IOMUXC_SAI2_RXC_UART1_DCE_RX 0x140 +- MX8MM_IOMUXC_SAI2_RXFS_UART1_DCE_TX 0x140 +- MX8MM_IOMUXC_SAI2_RXD0_UART1_DCE_RTS_B 0x140 +- MX8MM_IOMUXC_SAI2_TXFS_UART1_DCE_CTS_B 0x140 ++ MX8MM_IOMUXC_SAI2_RXC_UART1_DCE_RX 0x0 ++ MX8MM_IOMUXC_SAI2_RXFS_UART1_DCE_TX 0x0 ++ MX8MM_IOMUXC_SAI2_RXD0_UART1_DCE_RTS_B 0x0 ++ MX8MM_IOMUXC_SAI2_TXFS_UART1_DCE_CTS_B 0x0 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < +- MX8MM_IOMUXC_SAI3_TXFS_UART2_DCE_RX 0x140 +- MX8MM_IOMUXC_SAI3_TXC_UART2_DCE_TX 0x140 +- MX8MM_IOMUXC_SAI3_RXD_UART2_DCE_RTS_B 0x140 +- MX8MM_IOMUXC_SAI3_RXC_UART2_DCE_CTS_B 0x140 ++ MX8MM_IOMUXC_SAI3_TXFS_UART2_DCE_RX 0x0 ++ MX8MM_IOMUXC_SAI3_TXC_UART2_DCE_TX 0x0 ++ MX8MM_IOMUXC_SAI3_RXD_UART2_DCE_RTS_B 0x0 ++ MX8MM_IOMUXC_SAI3_RXC_UART2_DCE_CTS_B 0x0 + >; + }; + +@@ -337,40 +337,40 @@ MX8MM_IOMUXC_NAND_CE1_B_GPIO3_IO2 0x19 + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < +- MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x190 ++ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x90 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d0 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d0 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d0 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d0 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d0 +- MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x019 +- MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0 ++ MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x19 ++ MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xd0 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + fsl,pins = < +- MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x194 ++ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x94 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d4 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d4 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d4 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d4 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d4 +- MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x019 +- MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0 ++ MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x19 ++ MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xd0 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + fsl,pins = < +- MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x196 ++ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x96 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d6 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d6 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d6 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d6 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d6 +- MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x019 +- MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0 ++ MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x19 ++ MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xd0 + >; + }; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl.dts b/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl.dts +index dcec57c20399e..aab8e24216501 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl.dts +@@ -279,8 +279,8 @@ MX8MM_IOMUXC_SAI3_MCLK_GPIO5_IO2 0x19 + + pinctrl_i2c4: i2c4grp { + fsl,pins = < +- MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL 0x400001c3 +- MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA 0x400001c3 ++ MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL 0x40000083 ++ MX8MM_IOMUXC_I2C4_SDA_I2C4_SDA 0x40000083 + >; + }; + +@@ -292,19 +292,19 @@ MX8MM_IOMUXC_SPDIF_RX_PWM2_OUT 0x19 + + pinctrl_uart1: uart1grp { + fsl,pins = < +- MX8MM_IOMUXC_SAI2_RXC_UART1_DCE_RX 0x140 +- MX8MM_IOMUXC_SAI2_RXFS_UART1_DCE_TX 0x140 +- MX8MM_IOMUXC_SAI2_RXD0_UART1_DCE_RTS_B 0x140 +- MX8MM_IOMUXC_SAI2_TXFS_UART1_DCE_CTS_B 0x140 ++ MX8MM_IOMUXC_SAI2_RXC_UART1_DCE_RX 0x0 ++ MX8MM_IOMUXC_SAI2_RXFS_UART1_DCE_TX 0x0 ++ MX8MM_IOMUXC_SAI2_RXD0_UART1_DCE_RTS_B 0x0 ++ MX8MM_IOMUXC_SAI2_TXFS_UART1_DCE_CTS_B 0x0 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < +- MX8MM_IOMUXC_SAI3_TXFS_UART2_DCE_RX 0x140 +- MX8MM_IOMUXC_SAI3_TXC_UART2_DCE_TX 0x140 +- MX8MM_IOMUXC_SAI3_RXD_UART2_DCE_RTS_B 0x140 +- MX8MM_IOMUXC_SAI3_RXC_UART2_DCE_CTS_B 0x140 ++ MX8MM_IOMUXC_SAI3_TXFS_UART2_DCE_RX 0x0 ++ MX8MM_IOMUXC_SAI3_TXC_UART2_DCE_TX 0x0 ++ MX8MM_IOMUXC_SAI3_RXD_UART2_DCE_RTS_B 0x0 ++ MX8MM_IOMUXC_SAI3_RXC_UART2_DCE_CTS_B 0x0 + >; + }; + +@@ -316,40 +316,40 @@ MX8MM_IOMUXC_NAND_CE1_B_GPIO3_IO2 0x19 + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < +- MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x190 ++ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x90 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d0 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d0 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d0 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d0 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d0 +- MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x019 +- MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0 ++ MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x19 ++ MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xd0 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + fsl,pins = < +- MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x194 ++ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x94 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d4 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d4 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d4 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d4 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d4 +- MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x019 +- MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0 ++ MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x19 ++ MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xd0 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + fsl,pins = < +- MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x196 ++ MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x96 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d6 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d6 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d6 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d6 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d6 +- MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x019 +- MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x1d0 ++ MX8MM_IOMUXC_SD2_CD_B_GPIO2_IO12 0x19 ++ MX8MM_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xd0 + >; + }; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-kontron-osm-s.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-kontron-osm-s.dtsi +index 6e75ab879bf59..60abcb636cedf 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-kontron-osm-s.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-kontron-osm-s.dtsi +@@ -210,7 +210,7 @@ rv3028: rtc@52 { + reg = <0x52>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rtc>; +- interrupts-extended = <&gpio4 1 IRQ_TYPE_LEVEL_HIGH>; ++ interrupts-extended = <&gpio4 1 IRQ_TYPE_LEVEL_LOW>; + trickle-diode-disable; + }; + }; +@@ -252,8 +252,8 @@ MX8MM_IOMUXC_ECSPI1_SS0_GPIO5_IO9 0x19 + + pinctrl_i2c1: i2c1grp { + fsl,pins = < +- MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL 0x400001c3 +- MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA 0x400001c3 ++ MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL 0x40000083 ++ MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA 0x40000083 + >; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-kontron-sl.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-kontron-sl.dtsi +index 1f8326613ee9e..2076148e08627 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-kontron-sl.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-kontron-sl.dtsi +@@ -237,8 +237,8 @@ MX8MM_IOMUXC_ECSPI1_SS0_GPIO5_IO9 0x19 + + pinctrl_i2c1: i2c1grp { + fsl,pins = < +- MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL 0x400001c3 +- MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA 0x400001c3 ++ MX8MM_IOMUXC_I2C1_SCL_I2C1_SCL 0x40000083 ++ MX8MM_IOMUXC_I2C1_SDA_I2C1_SDA 0x40000083 + >; + }; + +diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi +index 6425773f68e0a..bbbaf2165ea28 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi +@@ -47,17 +47,6 @@ pps { + gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; +- +- reg_usb_otg1_vbus: regulator-usb-otg1 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_reg_usb1_en>; +- compatible = "regulator-fixed"; +- regulator-name = "usb_otg1_vbus"; +- gpio = <&gpio1 10 GPIO_ACTIVE_HIGH>; +- enable-active-high; +- regulator-min-microvolt = <5000000>; +- regulator-max-microvolt = <5000000>; +- }; + }; + + /* off-board header */ +@@ -144,9 +133,10 @@ &uart3 { + }; + + &usbotg1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg1>; + dr_mode = "otg"; + over-current-active-low; +- vbus-supply = <®_usb_otg1_vbus>; + status = "okay"; + }; + +@@ -204,14 +194,6 @@ MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15 0x41 + >; + }; + +- pinctrl_reg_usb1_en: regusb1grp { +- fsl,pins = < +- MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10 0x41 +- MX8MM_IOMUXC_GPIO1_IO12_GPIO1_IO12 0x141 +- MX8MM_IOMUXC_GPIO1_IO13_USB1_OTG_OC 0x41 +- >; +- }; +- + pinctrl_spi2: spi2grp { + fsl,pins = < + MX8MM_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK 0xd6 +@@ -234,4 +216,11 @@ MX8MM_IOMUXC_UART3_RXD_UART3_DCE_RX 0x140 + MX8MM_IOMUXC_UART3_TXD_UART3_DCE_TX 0x140 + >; + }; ++ ++ pinctrl_usbotg1: usbotg1grp { ++ fsl,pins = < ++ MX8MM_IOMUXC_GPIO1_IO12_GPIO1_IO12 0x141 ++ MX8MM_IOMUXC_GPIO1_IO13_USB1_OTG_OC 0x41 ++ >; ++ }; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts +index 5828c9d7821de..b5ce7b14b5434 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-data-modul-edm-sbc.dts +@@ -121,7 +121,7 @@ &ecspi1 { + flash@0 { /* W25Q128JVEI */ + compatible = "jedec,spi-nor"; + reg = <0>; +- spi-max-frequency = <100000000>; /* Up to 133 MHz */ ++ spi-max-frequency = <40000000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +index f87fa5a948ccc..9beba8d6a0dfe 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +@@ -23,7 +23,7 @@ hdmi-connector { + + port { + hdmi_connector_in: endpoint { +- remote-endpoint = <&adv7533_out>; ++ remote-endpoint = <&adv7535_out>; + }; + }; + }; +@@ -107,6 +107,13 @@ reg_usdhc2_vmmc: regulator-usdhc2 { + enable-active-high; + }; + ++ reg_vext_3v3: regulator-vext-3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VEXT_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "wm8960-audio"; +@@ -364,7 +371,7 @@ BUCK4 { + regulator-always-on; + }; + +- BUCK5 { ++ reg_buck5: BUCK5 { + regulator-name = "BUCK5"; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <1950000>; +@@ -415,14 +422,16 @@ &i2c2 { + + hdmi@3d { + compatible = "adi,adv7535"; +- reg = <0x3d>, <0x3c>, <0x3e>, <0x3f>; +- reg-names = "main", "cec", "edid", "packet"; ++ reg = <0x3d>; ++ interrupt-parent = <&gpio1>; ++ interrupts = <9 IRQ_TYPE_EDGE_FALLING>; + adi,dsi-lanes = <4>; +- adi,input-depth = <8>; +- adi,input-colorspace = "rgb"; +- adi,input-clock = "1x"; +- adi,input-style = <1>; +- adi,input-justification = "evenly"; ++ avdd-supply = <®_buck5>; ++ dvdd-supply = <®_buck5>; ++ pvdd-supply = <®_buck5>; ++ a2vdd-supply = <®_buck5>; ++ v3p3-supply = <®_vext_3v3>; ++ v1p2-supply = <®_buck5>; + + ports { + #address-cells = <1>; +@@ -431,7 +440,7 @@ ports { + port@0 { + reg = <0>; + +- adv7533_in: endpoint { ++ adv7535_in: endpoint { + remote-endpoint = <&dsi_out>; + }; + }; +@@ -439,7 +448,7 @@ adv7533_in: endpoint { + port@1 { + reg = <1>; + +- adv7533_out: endpoint { ++ adv7535_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; +@@ -524,7 +533,7 @@ port@1 { + reg = <1>; + + dsi_out: endpoint { +- remote-endpoint = <&adv7533_in>; ++ remote-endpoint = <&adv7535_in>; + data-lanes = <1 2 3 4>; + }; + }; +diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi +index 69cb8676732ea..cafc1383115ab 100644 +--- a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi +@@ -96,15 +96,30 @@ &edma2 { + status = "okay"; + }; + ++/* It is eDMA1 in 8QM RM, but 8QXP it is eDMA3 */ + &edma3 { ++ reg = <0x5a9f0000 0x210000>; ++ dma-channels = <10>; ++ interrupts = , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ ; + power-domains = <&pd IMX_SC_R_DMA_1_CH0>, +- <&pd IMX_SC_R_DMA_1_CH1>, +- <&pd IMX_SC_R_DMA_1_CH2>, +- <&pd IMX_SC_R_DMA_1_CH3>, +- <&pd IMX_SC_R_DMA_1_CH4>, +- <&pd IMX_SC_R_DMA_1_CH5>, +- <&pd IMX_SC_R_DMA_1_CH6>, +- <&pd IMX_SC_R_DMA_1_CH7>; ++ <&pd IMX_SC_R_DMA_1_CH1>, ++ <&pd IMX_SC_R_DMA_1_CH2>, ++ <&pd IMX_SC_R_DMA_1_CH3>, ++ <&pd IMX_SC_R_DMA_1_CH4>, ++ <&pd IMX_SC_R_DMA_1_CH5>, ++ <&pd IMX_SC_R_DMA_1_CH6>, ++ <&pd IMX_SC_R_DMA_1_CH7>, ++ <&pd IMX_SC_R_DMA_1_CH8>, ++ <&pd IMX_SC_R_DMA_1_CH9>; + }; + + &flexcan1 { +diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +index e300145ad1a6f..1cc3fa1c354de 100644 +--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +@@ -431,14 +431,14 @@ xor11 { + crypto: crypto@90000 { + compatible = "inside-secure,safexcel-eip97ies"; + reg = <0x90000 0x20000>; +- interrupts = , +- , ++ interrupts = , + , + , + , +- ; +- interrupt-names = "mem", "ring0", "ring1", +- "ring2", "ring3", "eip"; ++ , ++ ; ++ interrupt-names = "ring0", "ring1", "ring2", ++ "ring3", "eip", "mem"; + clocks = <&nb_periph_clk 15>; + }; + +diff --git a/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi b/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi +index 4ec1aae0a3a9c..7e595ac80043a 100644 +--- a/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-cp11x.dtsi +@@ -511,14 +511,14 @@ CP11X_LABEL(sdhci0): mmc@780000 { + CP11X_LABEL(crypto): crypto@800000 { + compatible = "inside-secure,safexcel-eip197b"; + reg = <0x800000 0x200000>; +- interrupts = <87 IRQ_TYPE_LEVEL_HIGH>, +- <88 IRQ_TYPE_LEVEL_HIGH>, ++ interrupts = <88 IRQ_TYPE_LEVEL_HIGH>, + <89 IRQ_TYPE_LEVEL_HIGH>, + <90 IRQ_TYPE_LEVEL_HIGH>, + <91 IRQ_TYPE_LEVEL_HIGH>, +- <92 IRQ_TYPE_LEVEL_HIGH>; +- interrupt-names = "mem", "ring0", "ring1", +- "ring2", "ring3", "eip"; ++ <92 IRQ_TYPE_LEVEL_HIGH>, ++ <87 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "ring0", "ring1", "ring2", "ring3", ++ "eip", "mem"; + clock-names = "core", "reg"; + clocks = <&CP11X_LABEL(clk) 1 26>, + <&CP11X_LABEL(clk) 1 17>; +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +index a1f42048dcc70..850b3e2773680 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +@@ -75,6 +75,7 @@ led-1 { + + memory@40000000 { + reg = <0 0x40000000 0 0x40000000>; ++ device_type = "memory"; + }; + + reg_1p8v: regulator-1p8v { +diff --git a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +index 2dc1bdc74e212..5c26021fc4cf1 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +@@ -57,6 +57,7 @@ key-wps { + + memory@40000000 { + reg = <0 0x40000000 0 0x20000000>; ++ device_type = "memory"; + }; + + reg_1p8v: regulator-1p8v { +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts +index d06d4af43cbff..e04b1c0c0ebbf 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts +@@ -43,7 +43,7 @@ fan: pwm-fan { + #cooling-cells = <2>; + /* cooling level (0, 1, 2) - pwm inverted */ + cooling-levels = <255 96 0>; +- pwms = <&pwm 0 10000 0>; ++ pwms = <&pwm 0 10000>; + status = "okay"; + }; + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts +index 3ef371ca254e8..2f884c24f1eb4 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dts +@@ -237,12 +237,13 @@ &spi0 { + pinctrl-0 = <&spi_flash_pins>; + cs-gpios = <0>, <0>; + status = "okay"; +- spi_nand: spi_nand@0 { ++ ++ spi_nand: flash@0 { + compatible = "spi-nand"; + reg = <0>; + spi-max-frequency = <10000000>; +- spi-tx-buswidth = <4>; +- spi-rx-buswidth = <4>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; + }; + }; + +diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +index fc751e049953c..d974739eae1c9 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +@@ -153,6 +153,7 @@ infracfg: infracfg@10001000 { + compatible = "mediatek,mt7986-infracfg", "syscon"; + reg = <0 0x10001000 0 0x1000>; + #clock-cells = <1>; ++ #reset-cells = <1>; + }; + + wed_pcie: wed-pcie@10003000 { +@@ -234,7 +235,6 @@ crypto: crypto@10320000 { + ; + interrupt-names = "ring0", "ring1", "ring2", "ring3"; + clocks = <&infracfg CLK_INFRA_EIP97_CK>; +- clock-names = "infra_eip97_ck"; + assigned-clocks = <&topckgen CLK_TOP_EIP_B_SEL>; + assigned-clock-parents = <&apmixedsys CLK_APMIXED_NET2PLL>; + status = "disabled"; +@@ -243,7 +243,6 @@ crypto: crypto@10320000 { + pwm: pwm@10048000 { + compatible = "mediatek,mt7986-pwm"; + reg = <0 0x10048000 0 0x1000>; +- #clock-cells = <1>; + #pwm-cells = <2>; + interrupts = ; + clocks = <&topckgen CLK_TOP_PWM_SEL>, +diff --git a/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts b/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts +index dde190442e386..57dcaeef31d7f 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7986b-rfb.dts +@@ -152,12 +152,13 @@ &spi0 { + pinctrl-0 = <&spi_flash_pins>; + cs-gpios = <0>, <0>; + status = "okay"; +- spi_nand: spi_nand@0 { ++ ++ spi_nand: flash@0 { + compatible = "spi-nand"; + reg = <0>; + spi-max-frequency = <10000000>; +- spi-tx-buswidth = <4>; +- spi-rx-buswidth = <4>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; + }; + }; + +diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi +index b6a9830af2696..bfb9e42c8acaa 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi +@@ -360,6 +360,10 @@ pen_eject { + }; + + &cros_ec { ++ cbas { ++ compatible = "google,cros-cbas"; ++ }; ++ + keyboard-controller { + compatible = "google,cros-ec-keyb-switches"; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi +index 306c95166f3fe..5c1bf6a1e4758 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi +@@ -339,6 +339,10 @@ touch_pin_reset: pin_reset { + }; + + &cros_ec { ++ cbas { ++ compatible = "google,cros-cbas"; ++ }; ++ + keyboard-controller { + compatible = "google,cros-ec-keyb-switches"; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi +index 382e4c6d7191c..0f5fa893a7742 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi +@@ -343,6 +343,10 @@ rst_pin { + }; + + &cros_ec { ++ cbas { ++ compatible = "google,cros-cbas"; ++ }; ++ + keyboard-controller { + compatible = "google,cros-ec-keyb-switches"; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi +index 1b3396b1cee39..90c5ad917a9ba 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi +@@ -937,10 +937,6 @@ usbc_extcon: extcon0 { + google,usb-port-id = <0>; + }; + +- cbas { +- compatible = "google,cros-cbas"; +- }; +- + typec { + compatible = "google,cros-ec-typec"; + #address-cells = <1>; +diff --git a/arch/arm64/boot/dts/mediatek/mt8186.dtsi b/arch/arm64/boot/dts/mediatek/mt8186.dtsi +index 2fec6fd1c1a71..84ec6c1aa12b9 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8186.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8186.dtsi +@@ -931,11 +931,17 @@ power-domain@MT8186_POWER_DOMAIN_CSIRX_TOP { + + power-domain@MT8186_POWER_DOMAIN_SSUSB { + reg = ; ++ clocks = <&topckgen CLK_TOP_USB_TOP>, ++ <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_REF>; ++ clock-names = "sys_ck", "ref_ck"; + #power-domain-cells = <0>; + }; + + power-domain@MT8186_POWER_DOMAIN_SSUSB_P1 { + reg = ; ++ clocks = <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_SYS>, ++ <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_REF>; ++ clock-names = "sys_ck", "ref_ck"; + #power-domain-cells = <0>; + }; + +@@ -1061,7 +1067,7 @@ power-domain@MT8186_POWER_DOMAIN_VENC { + reg = ; + clocks = <&topckgen CLK_TOP_VENC>, + <&vencsys CLK_VENC_CKE1_VENC>; +- clock-names = "venc0", "larb"; ++ clock-names = "venc0", "subsys-larb"; + mediatek,infracfg = <&infracfg_ao>; + #power-domain-cells = <0>; + }; +@@ -1530,8 +1536,9 @@ ssusb0: usb@11201000 { + clocks = <&topckgen CLK_TOP_USB_TOP>, + <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_REF>, + <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_HCLK>, +- <&infracfg_ao CLK_INFRA_AO_ICUSB>; +- clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck"; ++ <&infracfg_ao CLK_INFRA_AO_ICUSB>, ++ <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_XHCI>; ++ clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck"; + interrupts = ; + phys = <&u2port0 PHY_TYPE_USB2>; + power-domains = <&spm MT8186_POWER_DOMAIN_SSUSB>; +@@ -1595,8 +1602,9 @@ ssusb1: usb@11281000 { + clocks = <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_SYS>, + <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_REF>, + <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_HCLK>, +- <&clk26m>; +- clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck"; ++ <&clk26m>, ++ <&infracfg_ao CLK_INFRA_AO_SSUSB_TOP_P1_XHCI>; ++ clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck"; + interrupts = ; + phys = <&u2port1 PHY_TYPE_USB2>, <&u3port1 PHY_TYPE_USB3>; + power-domains = <&spm MT8186_POWER_DOMAIN_SSUSB_P1>; +diff --git a/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi b/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi +index d87aab8d7a79e..d4dd5e8b2e1d3 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi +@@ -1336,10 +1336,6 @@ cros_ec: ec@0 { + #address-cells = <1>; + #size-cells = <0>; + +- base_detection: cbas { +- compatible = "google,cros-cbas"; +- }; +- + cros_ec_pwm: pwm { + compatible = "google,cros-ec-pwm"; + #pwm-cells = <1>; +diff --git a/arch/arm64/boot/dts/mediatek/mt8192.dtsi b/arch/arm64/boot/dts/mediatek/mt8192.dtsi +index 6dd32dbfb832e..0e432636b8c23 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8192.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8192.dtsi +@@ -1814,7 +1814,7 @@ vcodec_enc: vcodec@17020000 { + mediatek,scp = <&scp>; + power-domains = <&spm MT8192_POWER_DOMAIN_VENC>; + clocks = <&vencsys CLK_VENC_SET1_VENC>; +- clock-names = "venc-set1"; ++ clock-names = "venc_sel"; + assigned-clocks = <&topckgen CLK_TOP_VENC_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D4>; + }; +diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r1.dts b/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r1.dts +index 2d5e8f371b6de..a82d716f10d44 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r1.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r1.dts +@@ -23,3 +23,7 @@ &sound { + &ts_10 { + status = "okay"; + }; ++ ++&watchdog { ++ /delete-property/ mediatek,disable-extrst; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r2.dts b/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r2.dts +index 2586c32ce6e6f..2fe20e0dad836 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r2.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r2.dts +@@ -43,3 +43,7 @@ &sound { + &ts_10 { + status = "okay"; + }; ++ ++&watchdog { ++ /delete-property/ mediatek,disable-extrst; ++}; +diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r3.dts b/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r3.dts +index f54f9477b99da..dd294ca98194c 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r3.dts ++++ b/arch/arm64/boot/dts/mediatek/mt8195-cherry-tomato-r3.dts +@@ -44,3 +44,7 @@ &sound { + &ts_10 { + status = "okay"; + }; ++ ++&watchdog { ++ /delete-property/ mediatek,disable-extrst; ++}; +diff --git a/arch/arm64/boot/dts/qcom/pm2250.dtsi b/arch/arm64/boot/dts/qcom/pm2250.dtsi +deleted file mode 100644 +index 5f1d15db5c993..0000000000000 +--- a/arch/arm64/boot/dts/qcom/pm2250.dtsi ++++ /dev/null +@@ -1,63 +0,0 @@ +-// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +-/* +- * Copyright (c) 2023, Linaro Ltd +- */ +- +-#include +-#include +-#include +-#include +- +-&spmi_bus { +- pmic@0 { +- compatible = "qcom,pm2250", "qcom,spmi-pmic"; +- reg = <0x0 SPMI_USID>; +- #address-cells = <1>; +- #size-cells = <0>; +- +- pon@800 { +- compatible = "qcom,pm8916-pon"; +- reg = <0x800>; +- +- pm2250_pwrkey: pwrkey { +- compatible = "qcom,pm8941-pwrkey"; +- interrupts-extended = <&spmi_bus 0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; +- linux,code = ; +- debounce = <15625>; +- bias-pull-up; +- }; +- +- pm2250_resin: resin { +- compatible = "qcom,pm8941-resin"; +- interrupts-extended = <&spmi_bus 0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>; +- debounce = <15625>; +- bias-pull-up; +- status = "disabled"; +- }; +- }; +- +- rtc@6000 { +- compatible = "qcom,pm8941-rtc"; +- reg = <0x6000>, <0x6100>; +- reg-names = "rtc", "alarm"; +- interrupts-extended = <&spmi_bus 0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; +- }; +- +- pm2250_gpios: gpio@c000 { +- compatible = "qcom,pm2250-gpio", "qcom,spmi-gpio"; +- reg = <0xc000>; +- gpio-controller; +- gpio-ranges = <&pm2250_gpios 0 0 10>; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- }; +- }; +- +- pmic@1 { +- compatible = "qcom,pm2250", "qcom,spmi-pmic"; +- reg = <0x1 SPMI_USID>; +- #address-cells = <1>; +- #size-cells = <0>; +- }; +-}; +diff --git a/arch/arm64/boot/dts/qcom/pm4125.dtsi b/arch/arm64/boot/dts/qcom/pm4125.dtsi +new file mode 100644 +index 0000000000000..d886a9e4b0918 +--- /dev/null ++++ b/arch/arm64/boot/dts/qcom/pm4125.dtsi +@@ -0,0 +1,63 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (c) 2023, Linaro Ltd ++ */ ++ ++#include ++#include ++#include ++#include ++ ++&spmi_bus { ++ pmic@0 { ++ compatible = "qcom,pm2250", "qcom,spmi-pmic"; ++ reg = <0x0 SPMI_USID>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pon@800 { ++ compatible = "qcom,pm8916-pon"; ++ reg = <0x800>; ++ ++ pm4125_pwrkey: pwrkey { ++ compatible = "qcom,pm8941-pwrkey"; ++ interrupts-extended = <&spmi_bus 0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; ++ linux,code = ; ++ debounce = <15625>; ++ bias-pull-up; ++ }; ++ ++ pm4125_resin: resin { ++ compatible = "qcom,pm8941-resin"; ++ interrupts-extended = <&spmi_bus 0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>; ++ debounce = <15625>; ++ bias-pull-up; ++ status = "disabled"; ++ }; ++ }; ++ ++ rtc@6000 { ++ compatible = "qcom,pm8941-rtc"; ++ reg = <0x6000>, <0x6100>; ++ reg-names = "rtc", "alarm"; ++ interrupts-extended = <&spmi_bus 0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; ++ }; ++ ++ pm4125_gpios: gpio@c000 { ++ compatible = "qcom,pm2250-gpio", "qcom,spmi-gpio"; ++ reg = <0xc000>; ++ gpio-controller; ++ gpio-ranges = <&pm4125_gpios 0 0 10>; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ }; ++ ++ pmic@1 { ++ compatible = "qcom,pm2250", "qcom,spmi-pmic"; ++ reg = <0x1 SPMI_USID>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/qcom/qcm2290.dtsi b/arch/arm64/boot/dts/qcom/qcm2290.dtsi +index 0911fb08ed632..89beac833d435 100644 +--- a/arch/arm64/boot/dts/qcom/qcm2290.dtsi ++++ b/arch/arm64/boot/dts/qcom/qcm2290.dtsi +@@ -442,6 +442,11 @@ tcsr_mutex: hwlock@340000 { + #hwlock-cells = <1>; + }; + ++ tcsr_regs: syscon@3c0000 { ++ compatible = "qcom,qcm2290-tcsr", "syscon"; ++ reg = <0x0 0x003c0000 0x0 0x40000>; ++ }; ++ + tlmm: pinctrl@500000 { + compatible = "qcom,qcm2290-tlmm"; + reg = <0x0 0x00500000 0x0 0x300000>; +@@ -690,6 +695,8 @@ usb_qmpphy: phy@1615000 { + + #phy-cells = <0>; + ++ qcom,tcsr-reg = <&tcsr_regs 0xb244>; ++ + status = "disabled"; + }; + +diff --git a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts +index 176898c9dbbd7..1e85c43a6fd14 100644 +--- a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts ++++ b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts +@@ -82,6 +82,11 @@ cdsp_mem: cdsp@88f00000 { + no-map; + }; + ++ removed_mem: removed@c0000000 { ++ reg = <0x0 0xc0000000 0x0 0x5100000>; ++ no-map; ++ }; ++ + rmtfs_mem: memory@f8500000 { + compatible = "qcom,rmtfs-mem"; + reg = <0x0 0xf8500000 0x0 0x600000>; +diff --git a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts +index 03e97e27d16d4..74f5a43d53db9 100644 +--- a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts ++++ b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts +@@ -123,8 +123,8 @@ debug_vm_mem: debug-vm@d0600000 { + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; +- regulator-min-microvolt = <2500000>; +- regulator-max-microvolt = <4350000>; ++ regulator-min-microvolt = <3700000>; ++ regulator-max-microvolt = <3700000>; + }; + }; + +diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts +index 8bb7d13d85f66..ae1632182d7c1 100644 +--- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts ++++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts +@@ -124,8 +124,8 @@ debug_vm_mem: debug-vm@d0600000 { + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; +- regulator-min-microvolt = <2500000>; +- regulator-max-microvolt = <4350000>; ++ regulator-min-microvolt = <3700000>; ++ regulator-max-microvolt = <3700000>; + }; + }; + +diff --git a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts +index aa53b6af6d9cb..64b2ab2862793 100644 +--- a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts ++++ b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts +@@ -7,7 +7,7 @@ + + #include + #include "qcm2290.dtsi" +-#include "pm2250.dtsi" ++#include "pm4125.dtsi" + + / { + model = "Qualcomm Technologies, Inc. Robotics RB1"; +@@ -226,7 +226,7 @@ &mdss { + }; + + &mdss_dsi0 { +- vdda-supply = <&pm2250_l5>; ++ vdda-supply = <&pm4125_l5>; + status = "okay"; + }; + +@@ -239,7 +239,7 @@ &mdss_dsi0_phy { + status = "okay"; + }; + +-&pm2250_resin { ++&pm4125_resin { + linux,code = ; + status = "okay"; + }; +@@ -263,23 +263,23 @@ regulators { + compatible = "qcom,rpm-pm2250-regulators"; + vdd_s3-supply = <&vph_pwr>; + vdd_s4-supply = <&vph_pwr>; +- vdd_l1_l2_l3_l5_l6_l7_l8_l9_l10_l11_l12-supply = <&pm2250_s3>; ++ vdd_l1_l2_l3_l5_l6_l7_l8_l9_l10_l11_l12-supply = <&pm4125_s3>; + vdd_l4_l17_l18_l19_l20_l21_l22-supply = <&vph_pwr>; +- vdd_l13_l14_l15_l16-supply = <&pm2250_s4>; ++ vdd_l13_l14_l15_l16-supply = <&pm4125_s4>; + + /* + * S1 - VDD_APC + * S2 - VDD_CX + */ + +- pm2250_s3: s3 { ++ pm4125_s3: s3 { + /* 0.4V-1.6625V -> 1.3V (Power tree requirements) */ + regulator-min-microvolt = <1352000>; + regulator-max-microvolt = <1352000>; + regulator-boot-on; + }; + +- pm2250_s4: s4 { ++ pm4125_s4: s4 { + /* 1.2V-2.35V -> 2.05V (Power tree requirements) */ + regulator-min-microvolt = <2072000>; + regulator-max-microvolt = <2072000>; +@@ -288,7 +288,7 @@ pm2250_s4: s4 { + + /* L1 - VDD_MX */ + +- pm2250_l2: l2 { ++ pm4125_l2: l2 { + /* LPDDR4X VDD2 */ + regulator-min-microvolt = <1136000>; + regulator-max-microvolt = <1136000>; +@@ -296,7 +296,7 @@ pm2250_l2: l2 { + regulator-boot-on; + }; + +- pm2250_l3: l3 { ++ pm4125_l3: l3 { + /* LPDDR4X VDDQ */ + regulator-min-microvolt = <616000>; + regulator-max-microvolt = <616000>; +@@ -304,14 +304,14 @@ pm2250_l3: l3 { + regulator-boot-on; + }; + +- pm2250_l4: l4 { ++ pm4125_l4: l4 { + /* max = 3.05V -> max = 2.7 to disable 3V signaling (SDHCI2) */ + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2700000>; + regulator-allow-set-load; + }; + +- pm2250_l5: l5 { ++ pm4125_l5: l5 { + /* CSI/DSI */ + regulator-min-microvolt = <1232000>; + regulator-max-microvolt = <1232000>; +@@ -319,7 +319,7 @@ pm2250_l5: l5 { + regulator-boot-on; + }; + +- pm2250_l6: l6 { ++ pm4125_l6: l6 { + /* DRAM PLL */ + regulator-min-microvolt = <928000>; + regulator-max-microvolt = <928000>; +@@ -327,7 +327,7 @@ pm2250_l6: l6 { + regulator-boot-on; + }; + +- pm2250_l7: l7 { ++ pm4125_l7: l7 { + /* Wi-Fi CX/MX */ + regulator-min-microvolt = <664000>; + regulator-max-microvolt = <664000>; +@@ -338,20 +338,20 @@ pm2250_l7: l7 { + * L9 - VDD_LPI_MX + */ + +- pm2250_l10: l10 { ++ pm4125_l10: l10 { + /* Wi-Fi RFA */ + regulator-min-microvolt = <1304000>; + regulator-max-microvolt = <1304000>; + }; + +- pm2250_l11: l11 { ++ pm4125_l11: l11 { + /* GPS RF1 */ + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-boot-on; + }; + +- pm2250_l12: l12 { ++ pm4125_l12: l12 { + /* USB PHYs */ + regulator-min-microvolt = <928000>; + regulator-max-microvolt = <928000>; +@@ -359,7 +359,7 @@ pm2250_l12: l12 { + regulator-boot-on; + }; + +- pm2250_l13: l13 { ++ pm4125_l13: l13 { + /* USB/QFPROM/PLLs */ + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; +@@ -367,7 +367,7 @@ pm2250_l13: l13 { + regulator-boot-on; + }; + +- pm2250_l14: l14 { ++ pm4125_l14: l14 { + /* SDHCI1 VQMMC */ + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; +@@ -376,7 +376,7 @@ pm2250_l14: l14 { + regulator-always-on; + }; + +- pm2250_l15: l15 { ++ pm4125_l15: l15 { + /* WCD/DSI/BT VDDIO */ + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; +@@ -385,38 +385,38 @@ pm2250_l15: l15 { + regulator-boot-on; + }; + +- pm2250_l16: l16 { ++ pm4125_l16: l16 { + /* GPS RF2 */ + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + }; + +- pm2250_l17: l17 { ++ pm4125_l17: l17 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + +- pm2250_l18: l18 { ++ pm4125_l18: l18 { + /* VDD_PXn */ + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + +- pm2250_l19: l19 { ++ pm4125_l19: l19 { + /* VDD_PXn */ + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + +- pm2250_l20: l20 { ++ pm4125_l20: l20 { + /* SDHCI1 VMMC */ + regulator-min-microvolt = <2400000>; + regulator-max-microvolt = <3600000>; + regulator-allow-set-load; + }; + +- pm2250_l21: l21 { ++ pm4125_l21: l21 { + /* SDHCI2 VMMC */ + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <3300000>; +@@ -424,7 +424,7 @@ pm2250_l21: l21 { + regulator-boot-on; + }; + +- pm2250_l22: l22 { ++ pm4125_l22: l22 { + /* Wi-Fi */ + regulator-min-microvolt = <3312000>; + regulator-max-microvolt = <3312000>; +@@ -433,8 +433,8 @@ pm2250_l22: l22 { + }; + + &sdhc_1 { +- vmmc-supply = <&pm2250_l20>; +- vqmmc-supply = <&pm2250_l14>; ++ vmmc-supply = <&pm4125_l20>; ++ vqmmc-supply = <&pm4125_l14>; + pinctrl-0 = <&sdc1_state_on>; + pinctrl-1 = <&sdc1_state_off>; + pinctrl-names = "default", "sleep"; +@@ -446,8 +446,8 @@ &sdhc_1 { + }; + + &sdhc_2 { +- vmmc-supply = <&pm2250_l21>; +- vqmmc-supply = <&pm2250_l4>; ++ vmmc-supply = <&pm4125_l21>; ++ vqmmc-supply = <&pm4125_l4>; + cd-gpios = <&tlmm 88 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&sdc2_state_on &sd_det_in_on>; + pinctrl-1 = <&sdc2_state_off &sd_det_in_off>; +@@ -518,8 +518,8 @@ &usb { + }; + + &usb_qmpphy { +- vdda-phy-supply = <&pm2250_l12>; +- vdda-pll-supply = <&pm2250_l13>; ++ vdda-phy-supply = <&pm4125_l12>; ++ vdda-pll-supply = <&pm4125_l13>; + status = "okay"; + }; + +@@ -528,17 +528,17 @@ &usb_dwc3 { + }; + + &usb_hsphy { +- vdd-supply = <&pm2250_l12>; +- vdda-pll-supply = <&pm2250_l13>; +- vdda-phy-dpdm-supply = <&pm2250_l21>; ++ vdd-supply = <&pm4125_l12>; ++ vdda-pll-supply = <&pm4125_l13>; ++ vdda-phy-dpdm-supply = <&pm4125_l21>; + status = "okay"; + }; + + &wifi { +- vdd-0.8-cx-mx-supply = <&pm2250_l7>; +- vdd-1.8-xo-supply = <&pm2250_l13>; +- vdd-1.3-rfa-supply = <&pm2250_l10>; +- vdd-3.3-ch0-supply = <&pm2250_l22>; ++ vdd-0.8-cx-mx-supply = <&pm4125_l7>; ++ vdd-1.8-xo-supply = <&pm4125_l13>; ++ vdd-1.3-rfa-supply = <&pm4125_l10>; ++ vdd-3.3-ch0-supply = <&pm4125_l22>; + qcom,ath10k-calibration-variant = "Thundercomm_RB1"; + status = "okay"; + }; +diff --git a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts +index 7c19f874fa716..52f31f3166c2f 100644 +--- a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts ++++ b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts +@@ -607,10 +607,6 @@ &usb { + status = "okay"; + }; + +-&usb_dwc3 { +- maximum-speed = "super-speed"; +-}; +- + &usb_hsphy { + vdd-supply = <&vreg_l4a_0p9>; + vdda-pll-supply = <&vreg_l12a_1p8>; +diff --git a/arch/arm64/boot/dts/qcom/sa8540p.dtsi b/arch/arm64/boot/dts/qcom/sa8540p.dtsi +index 96b2c59ad02b4..23888029cc117 100644 +--- a/arch/arm64/boot/dts/qcom/sa8540p.dtsi ++++ b/arch/arm64/boot/dts/qcom/sa8540p.dtsi +@@ -168,6 +168,9 @@ opp-2592000000 { + }; + + &gpucc { ++ /* SA8295P and SA8540P doesn't provide gfx.lvl */ ++ /delete-property/ power-domains; ++ + status = "disabled"; + }; + +diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi +index 83b5b76ba1794..ce0d24ee7eedb 100644 +--- a/arch/arm64/boot/dts/qcom/sc7280.dtsi ++++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi +@@ -2345,6 +2345,8 @@ cryptobam: dma-controller@1dc4000 { + <&apps_smmu 0x4e6 0x0011>; + qcom,ee = <0>; + qcom,controlled-remotely; ++ num-channels = <16>; ++ qcom,num-ees = <4>; + }; + + crypto: crypto@1dfa000 { +diff --git a/arch/arm64/boot/dts/qcom/sc8180x.dtsi b/arch/arm64/boot/dts/qcom/sc8180x.dtsi +index 0430d99091e30..c0dd44f146748 100644 +--- a/arch/arm64/boot/dts/qcom/sc8180x.dtsi ++++ b/arch/arm64/boot/dts/qcom/sc8180x.dtsi +@@ -290,7 +290,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x40000004>; +- entry-latency-us = <241>; ++ entry-latency-us = <2411>; + exit-latency-us = <1461>; + min-residency-us = <4488>; + local-timer-stop; +@@ -298,7 +298,15 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + }; + + domain-idle-states { +- CLUSTER_SLEEP_0: cluster-sleep-0 { ++ CLUSTER_SLEEP_APSS_OFF: cluster-sleep-0 { ++ compatible = "domain-idle-state"; ++ arm,psci-suspend-param = <0x41000044>; ++ entry-latency-us = <3300>; ++ exit-latency-us = <3300>; ++ min-residency-us = <6000>; ++ }; ++ ++ CLUSTER_SLEEP_AOSS_SLEEP: cluster-sleep-1 { + compatible = "domain-idle-state"; + arm,psci-suspend-param = <0x4100a344>; + entry-latency-us = <3263>; +@@ -582,7 +590,7 @@ CPU_PD7: power-domain-cpu7 { + + CLUSTER_PD: power-domain-cpu-cluster0 { + #power-domain-cells = <0>; +- domain-idle-states = <&CLUSTER_SLEEP_0>; ++ domain-idle-states = <&CLUSTER_SLEEP_APSS_OFF &CLUSTER_SLEEP_AOSS_SLEEP>; + }; + }; + +@@ -782,6 +790,7 @@ gcc: clock-controller@100000 { + clock-names = "bi_tcxo", + "bi_tcxo_ao", + "sleep_clk"; ++ power-domains = <&rpmhpd SC8180X_CX>; + }; + + qupv3_id_0: geniqup@8c0000 { +@@ -2692,9 +2701,15 @@ mdss: mdss@ae00000 { + interrupt-controller; + #interrupt-cells = <1>; + +- interconnects = <&mmss_noc MASTER_MDP_PORT0 0 &mc_virt SLAVE_EBI_CH0 0>, +- <&mmss_noc MASTER_MDP_PORT1 0 &mc_virt SLAVE_EBI_CH0 0>; +- interconnect-names = "mdp0-mem", "mdp1-mem"; ++ interconnects = <&mmss_noc MASTER_MDP_PORT0 QCOM_ICC_TAG_ALWAYS ++ &mc_virt SLAVE_EBI_CH0 QCOM_ICC_TAG_ALWAYS>, ++ <&mmss_noc MASTER_MDP_PORT1 QCOM_ICC_TAG_ALWAYS ++ &mc_virt SLAVE_EBI_CH0 QCOM_ICC_TAG_ALWAYS>, ++ <&gem_noc MASTER_AMPSS_M0 QCOM_ICC_TAG_ALWAYS ++ &config_noc SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ALWAYS>; ++ interconnect-names = "mdp0-mem", ++ "mdp1-mem", ++ "cpu-cfg"; + + iommus = <&apps_smmu 0x800 0x420>; + +@@ -2723,10 +2738,8 @@ mdss_mdp: mdp@ae01000 { + "rot", + "lut"; + +- assigned-clocks = <&dispcc DISP_CC_MDSS_MDP_CLK>, +- <&dispcc DISP_CC_MDSS_VSYNC_CLK>; +- assigned-clock-rates = <460000000>, +- <19200000>; ++ assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>; ++ assigned-clock-rates = <19200000>; + + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmhpd SC8180X_MMCX>; +@@ -3184,7 +3197,7 @@ edp_phy: phy@aec2a00 { + <&dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "aux", "cfg_ahb"; + +- power-domains = <&dispcc MDSS_GDSC>; ++ power-domains = <&rpmhpd SC8180X_MX>; + + #clock-cells = <1>; + #phy-cells = <0>; +@@ -3210,6 +3223,7 @@ dispcc: clock-controller@af00000 { + "edp_phy_pll_link_clk", + "edp_phy_pll_vco_div_clk"; + power-domains = <&rpmhpd SC8180X_MMCX>; ++ required-opps = <&rpmhpd_opp_low_svs>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; +@@ -3248,7 +3262,7 @@ tsens1: thermal-sensor@c265000 { + + aoss_qmp: power-controller@c300000 { + compatible = "qcom,sc8180x-aoss-qmp", "qcom,aoss-qmp"; +- reg = <0x0 0x0c300000 0x0 0x100000>; ++ reg = <0x0 0x0c300000 0x0 0x400>; + interrupts = ; + mboxes = <&apss_shared 0>; + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +index ab6220456513c..1f517328199b9 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts ++++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +@@ -580,7 +580,7 @@ &mss_pil { + &pcie0 { + status = "okay"; + perst-gpios = <&tlmm 35 GPIO_ACTIVE_LOW>; +- enable-gpio = <&tlmm 134 GPIO_ACTIVE_HIGH>; ++ wake-gpios = <&tlmm 134 GPIO_ACTIVE_HIGH>; + + vddpe-3v3-supply = <&pcie0_3p3v_dual>; + +diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +index e821103d49c0a..46e25c53829ad 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +@@ -508,13 +508,13 @@ led-1 { + }; + + &q6afedai { +- qi2s@22 { +- reg = <22>; ++ dai@22 { ++ reg = ; + qcom,sd-lines = <1>; + }; + +- qi2s@23 { +- reg = <23>; ++ dai@23 { ++ reg = ; + qcom,sd-lines = <0>; + }; + }; +diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi +index c2244824355a2..237d404861424 100644 +--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi ++++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi +@@ -3366,8 +3366,8 @@ slpi_pas: remoteproc@5c00000 { + + qcom,qmp = <&aoss_qmp>; + +- power-domains = <&rpmhpd SDM845_CX>, +- <&rpmhpd SDM845_MX>; ++ power-domains = <&rpmhpd SDM845_LCX>, ++ <&rpmhpd SDM845_LMX>; + power-domain-names = "lcx", "lmx"; + + memory-region = <&slpi_mem>; +diff --git a/arch/arm64/boot/dts/qcom/sm6115.dtsi b/arch/arm64/boot/dts/qcom/sm6115.dtsi +index f9849b8befbf2..d33763d092659 100644 +--- a/arch/arm64/boot/dts/qcom/sm6115.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm6115.dtsi +@@ -614,6 +614,11 @@ tcsr_mutex: hwlock@340000 { + #hwlock-cells = <1>; + }; + ++ tcsr_regs: syscon@3c0000 { ++ compatible = "qcom,sm6115-tcsr", "syscon"; ++ reg = <0x0 0x003c0000 0x0 0x40000>; ++ }; ++ + tlmm: pinctrl@500000 { + compatible = "qcom,sm6115-tlmm"; + reg = <0x0 0x00500000 0x0 0x400000>, +@@ -879,6 +884,8 @@ usb_qmpphy: phy@1615000 { + + #phy-cells = <0>; + ++ qcom,tcsr-reg = <&tcsr_regs 0xb244>; ++ + status = "disabled"; + }; + +@@ -1603,7 +1610,6 @@ &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>, + interconnect-names = "usb-ddr", + "apps-usb"; + +- qcom,select-utmi-as-pipe-clk; + status = "disabled"; + + usb_dwc3: usb@4e00000 { +diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi +index 761a6757dc26f..2abd4c87a3ca9 100644 +--- a/arch/arm64/boot/dts/qcom/sm8150.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi +@@ -1879,7 +1879,7 @@ pcie0: pcie@1c00000 { + phy-names = "pciephy"; + + perst-gpios = <&tlmm 35 GPIO_ACTIVE_HIGH>; +- enable-gpio = <&tlmm 37 GPIO_ACTIVE_HIGH>; ++ wake-gpios = <&tlmm 37 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie0_default_state>; +diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi +index 01e4dfc4babd2..06f183ef8c78f 100644 +--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi +@@ -1028,6 +1028,12 @@ uart20: serial@894000 { + pinctrl-names = "default"; + pinctrl-0 = <&qup_uart20_default>; + interrupts = ; ++ interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS ++ &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, ++ <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS ++ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; ++ interconnect-names = "qup-core", ++ "qup-config"; + status = "disabled"; + }; + +@@ -1420,6 +1426,12 @@ uart7: serial@99c000 { + pinctrl-names = "default"; + pinctrl-0 = <&qup_uart7_tx>, <&qup_uart7_rx>; + interrupts = ; ++ interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS ++ &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, ++ <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS ++ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; ++ interconnect-names = "qup-core", ++ "qup-config"; + status = "disabled"; + }; + }; +diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi +index ee1ba5a8c8fc2..90acdf16b8307 100644 +--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi +@@ -3248,7 +3248,7 @@ sram@c3f0000 { + spmi_bus: spmi@c400000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0 0x0c400000 0 0x3000>, +- <0 0x0c500000 0 0x4000000>, ++ <0 0x0c500000 0 0x400000>, + <0 0x0c440000 0 0x80000>, + <0 0x0c4c0000 0 0x20000>, + <0 0x0c42d000 0 0x4000>; +diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi +index 2df77123a8c7b..0e4bd83b2c68a 100644 +--- a/arch/arm64/boot/dts/qcom/sm8650.dtsi ++++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi +@@ -2448,10 +2448,12 @@ ufs_mem_phy: phy@1d80000 { + compatible = "qcom,sm8650-qmp-ufs-phy"; + reg = <0 0x01d80000 0 0x2000>; + +- clocks = <&tcsr TCSR_UFS_CLKREF_EN>, +- <&gcc GCC_UFS_PHY_PHY_AUX_CLK>; ++ clocks = <&rpmhcc RPMH_CXO_CLK>, ++ <&gcc GCC_UFS_PHY_PHY_AUX_CLK>, ++ <&tcsr TCSR_UFS_CLKREF_EN>; + clock-names = "ref", +- "ref_aux"; ++ "ref_aux", ++ "qref"; + + resets = <&ufs_mem_hc 0>; + reset-names = "ufsphy"; +@@ -3703,7 +3705,7 @@ sram@c3f0000 { + spmi_bus: spmi@c400000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0 0x0c400000 0 0x3000>, +- <0 0x0c500000 0 0x4000000>, ++ <0 0x0c500000 0 0x400000>, + <0 0x0c440000 0 0x80000>, + <0 0x0c4c0000 0 0x20000>, + <0 0x0c42d000 0 0x4000>; +diff --git a/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts b/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts +index a37ad9475c90d..3112487d2a168 100644 +--- a/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts ++++ b/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts +@@ -243,7 +243,7 @@ regulators-3 { + qcom,pmic-id = "e"; + + vdd-l2-supply = <&vreg_s1f_0p7>; +- vdd-l3-supply = <&vph_pwr>; ++ vdd-l3-supply = <&vreg_s5j_1p2>; + + vreg_l2e_0p8: ldo2 { + regulator-name = "vreg_l2e_0p8"; +@@ -349,7 +349,7 @@ regulators-7 { + qcom,pmic-id = "j"; + + vdd-l1-supply = <&vreg_s1f_0p7>; +- vdd-l2-supply = <&vph_pwr>; ++ vdd-l2-supply = <&vreg_s5j_1p2>; + vdd-l3-supply = <&vreg_s1f_0p7>; + vdd-s5-supply = <&vph_pwr>; + +diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi +index 6f75fc342ceb3..be1285d9919e0 100644 +--- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi ++++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi +@@ -3315,7 +3315,6 @@ apps_rsc: rsc@17500000 { + <0 0x17510000 0 0x10000>, + <0 0x17520000 0 0x10000>; + reg-names = "drv-0", "drv-1", "drv-2"; +- qcom,drv-count = <3>; + + interrupts = , + , +diff --git a/arch/arm64/boot/dts/renesas/r8a779a0.dtsi b/arch/arm64/boot/dts/renesas/r8a779a0.dtsi +index 4e67a03564971..504ac8c93faf5 100644 +--- a/arch/arm64/boot/dts/renesas/r8a779a0.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a779a0.dtsi +@@ -658,7 +658,7 @@ channel7 { + avb0: ethernet@e6800000 { + compatible = "renesas,etheravb-r8a779a0", + "renesas,etheravb-rcar-gen4"; +- reg = <0 0xe6800000 0 0x800>; ++ reg = <0 0xe6800000 0 0x1000>; + interrupts = , + , + , +@@ -706,7 +706,7 @@ avb0: ethernet@e6800000 { + avb1: ethernet@e6810000 { + compatible = "renesas,etheravb-r8a779a0", + "renesas,etheravb-rcar-gen4"; +- reg = <0 0xe6810000 0 0x800>; ++ reg = <0 0xe6810000 0 0x1000>; + interrupts = , + , + , +diff --git a/arch/arm64/boot/dts/renesas/r8a779g0.dtsi b/arch/arm64/boot/dts/renesas/r8a779g0.dtsi +index d3d25e077c5d5..d7677595204dc 100644 +--- a/arch/arm64/boot/dts/renesas/r8a779g0.dtsi ++++ b/arch/arm64/boot/dts/renesas/r8a779g0.dtsi +@@ -161,11 +161,6 @@ L3_CA76_1: cache-controller-1 { + }; + }; + +- psci { +- compatible = "arm,psci-1.0", "arm,psci-0.2"; +- method = "smc"; +- }; +- + extal_clk: extal { + compatible = "fixed-clock"; + #clock-cells = <0>; +@@ -185,13 +180,24 @@ pmu_a76 { + interrupts-extended = <&gic GIC_PPI 7 IRQ_TYPE_LEVEL_LOW>; + }; + +- /* External SCIF clock - to be overridden by boards that provide it */ ++ psci { ++ compatible = "arm,psci-1.0", "arm,psci-0.2"; ++ method = "smc"; ++ }; ++ ++ /* External SCIF clocks - to be overridden by boards that provide them */ + scif_clk: scif { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; + ++ scif_clk2: scif2 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <0>; ++ }; ++ + soc: soc { + compatible = "simple-bus"; + interrupt-parent = <&gic>; +@@ -681,7 +687,7 @@ hscif2: serial@e6560000 { + interrupts = ; + clocks = <&cpg CPG_MOD 516>, + <&cpg CPG_CORE R8A779G0_CLK_SASYNCPERD1>, +- <&scif_clk>; ++ <&scif_clk2>; + clock-names = "fck", "brg_int", "scif_clk"; + dmas = <&dmac0 0x35>, <&dmac0 0x34>, + <&dmac1 0x35>, <&dmac1 0x34>; +@@ -761,7 +767,7 @@ channel7 { + avb0: ethernet@e6800000 { + compatible = "renesas,etheravb-r8a779g0", + "renesas,etheravb-rcar-gen4"; +- reg = <0 0xe6800000 0 0x800>; ++ reg = <0 0xe6800000 0 0x1000>; + interrupts = , + , + , +@@ -808,7 +814,7 @@ avb0: ethernet@e6800000 { + avb1: ethernet@e6810000 { + compatible = "renesas,etheravb-r8a779g0", + "renesas,etheravb-rcar-gen4"; +- reg = <0 0xe6810000 0 0x800>; ++ reg = <0 0xe6810000 0 0x1000>; + interrupts = , + , + , +@@ -1057,7 +1063,7 @@ scif4: serial@e6c40000 { + interrupts = ; + clocks = <&cpg CPG_MOD 705>, + <&cpg CPG_CORE R8A779G0_CLK_SASYNCPERD1>, +- <&scif_clk>; ++ <&scif_clk2>; + clock-names = "fck", "brg_int", "scif_clk"; + dmas = <&dmac0 0x59>, <&dmac0 0x58>, + <&dmac1 0x59>, <&dmac1 0x58>; +@@ -1777,6 +1783,37 @@ ssi0: ssi-0 { + }; + }; + ++ mmc0: mmc@ee140000 { ++ compatible = "renesas,sdhi-r8a779g0", ++ "renesas,rcar-gen4-sdhi"; ++ reg = <0 0xee140000 0 0x2000>; ++ interrupts = ; ++ clocks = <&cpg CPG_MOD 706>, ++ <&cpg CPG_CORE R8A779G0_CLK_SD0H>; ++ clock-names = "core", "clkh"; ++ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>; ++ resets = <&cpg 706>; ++ max-frequency = <200000000>; ++ iommus = <&ipmmu_ds0 32>; ++ status = "disabled"; ++ }; ++ ++ rpc: spi@ee200000 { ++ compatible = "renesas,r8a779g0-rpc-if", ++ "renesas,rcar-gen4-rpc-if"; ++ reg = <0 0xee200000 0 0x200>, ++ <0 0x08000000 0 0x04000000>, ++ <0 0xee208000 0 0x100>; ++ reg-names = "regs", "dirmap", "wbuf"; ++ interrupts = ; ++ clocks = <&cpg CPG_MOD 629>; ++ power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>; ++ resets = <&cpg 629>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ + ipmmu_rt0: iommu@ee480000 { + compatible = "renesas,ipmmu-r8a779g0", + "renesas,rcar-gen4-ipmmu-vmsa"; +@@ -1886,37 +1923,6 @@ ipmmu_mm: iommu@eefc0000 { + #iommu-cells = <1>; + }; + +- mmc0: mmc@ee140000 { +- compatible = "renesas,sdhi-r8a779g0", +- "renesas,rcar-gen4-sdhi"; +- reg = <0 0xee140000 0 0x2000>; +- interrupts = ; +- clocks = <&cpg CPG_MOD 706>, +- <&cpg CPG_CORE R8A779G0_CLK_SD0H>; +- clock-names = "core", "clkh"; +- power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>; +- resets = <&cpg 706>; +- max-frequency = <200000000>; +- iommus = <&ipmmu_ds0 32>; +- status = "disabled"; +- }; +- +- rpc: spi@ee200000 { +- compatible = "renesas,r8a779g0-rpc-if", +- "renesas,rcar-gen4-rpc-if"; +- reg = <0 0xee200000 0 0x200>, +- <0 0x08000000 0 0x04000000>, +- <0 0xee208000 0 0x100>; +- reg-names = "regs", "dirmap", "wbuf"; +- interrupts = ; +- clocks = <&cpg CPG_MOD 629>; +- power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>; +- resets = <&cpg 629>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; +- + gic: interrupt-controller@f1000000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; +diff --git a/arch/arm64/boot/dts/renesas/r9a07g043u.dtsi b/arch/arm64/boot/dts/renesas/r9a07g043u.dtsi +index 2ab231572d95f..b3f83d0ebcbb5 100644 +--- a/arch/arm64/boot/dts/renesas/r9a07g043u.dtsi ++++ b/arch/arm64/boot/dts/renesas/r9a07g043u.dtsi +@@ -109,7 +109,13 @@ irqc: interrupt-controller@110a0000 { + , + , + , +- ; ++ , ++ , ++ , ++ , ++ , ++ , ++ ; + interrupt-names = "nmi", + "irq0", "irq1", "irq2", "irq3", + "irq4", "irq5", "irq6", "irq7", +@@ -121,7 +127,9 @@ irqc: interrupt-controller@110a0000 { + "tint20", "tint21", "tint22", "tint23", + "tint24", "tint25", "tint26", "tint27", + "tint28", "tint29", "tint30", "tint31", +- "bus-err"; ++ "bus-err", "ec7tie1-0", "ec7tie2-0", ++ "ec7tiovf-0", "ec7tie1-1", "ec7tie2-1", ++ "ec7tiovf-1"; + clocks = <&cpg CPG_MOD R9A07G043_IA55_CLK>, + <&cpg CPG_MOD R9A07G043_IA55_PCLK>; + clock-names = "clk", "pclk"; +diff --git a/arch/arm64/boot/dts/renesas/r9a07g044.dtsi b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi +index 66f68fc2b2411..081d8f49db879 100644 +--- a/arch/arm64/boot/dts/renesas/r9a07g044.dtsi ++++ b/arch/arm64/boot/dts/renesas/r9a07g044.dtsi +@@ -905,7 +905,27 @@ irqc: interrupt-controller@110a0000 { + , + , + , +- ; ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ ; ++ interrupt-names = "nmi", "irq0", "irq1", "irq2", "irq3", ++ "irq4", "irq5", "irq6", "irq7", ++ "tint0", "tint1", "tint2", "tint3", ++ "tint4", "tint5", "tint6", "tint7", ++ "tint8", "tint9", "tint10", "tint11", ++ "tint12", "tint13", "tint14", "tint15", ++ "tint16", "tint17", "tint18", "tint19", ++ "tint20", "tint21", "tint22", "tint23", ++ "tint24", "tint25", "tint26", "tint27", ++ "tint28", "tint29", "tint30", "tint31", ++ "bus-err", "ec7tie1-0", "ec7tie2-0", ++ "ec7tiovf-0", "ec7tie1-1", "ec7tie2-1", ++ "ec7tiovf-1"; + clocks = <&cpg CPG_MOD R9A07G044_IA55_CLK>, + <&cpg CPG_MOD R9A07G044_IA55_PCLK>; + clock-names = "clk", "pclk"; +diff --git a/arch/arm64/boot/dts/renesas/r9a07g054.dtsi b/arch/arm64/boot/dts/renesas/r9a07g054.dtsi +index 1f1d481dc7830..0d327464d2baf 100644 +--- a/arch/arm64/boot/dts/renesas/r9a07g054.dtsi ++++ b/arch/arm64/boot/dts/renesas/r9a07g054.dtsi +@@ -912,7 +912,27 @@ irqc: interrupt-controller@110a0000 { + , + , + , +- ; ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ ; ++ interrupt-names = "nmi", "irq0", "irq1", "irq2", "irq3", ++ "irq4", "irq5", "irq6", "irq7", ++ "tint0", "tint1", "tint2", "tint3", ++ "tint4", "tint5", "tint6", "tint7", ++ "tint8", "tint9", "tint10", "tint11", ++ "tint12", "tint13", "tint14", "tint15", ++ "tint16", "tint17", "tint18", "tint19", ++ "tint20", "tint21", "tint22", "tint23", ++ "tint24", "tint25", "tint26", "tint27", ++ "tint28", "tint29", "tint30", "tint31", ++ "bus-err", "ec7tie1-0", "ec7tie2-0", ++ "ec7tiovf-0", "ec7tie1-1", "ec7tie2-1", ++ "ec7tiovf-1"; + clocks = <&cpg CPG_MOD R9A07G054_IA55_CLK>, + <&cpg CPG_MOD R9A07G054_IA55_PCLK>; + clock-names = "clk", "pclk"; +diff --git a/arch/arm64/boot/dts/renesas/r9a08g045.dtsi b/arch/arm64/boot/dts/renesas/r9a08g045.dtsi +index 5facfad961583..6315ffa6c1bb9 100644 +--- a/arch/arm64/boot/dts/renesas/r9a08g045.dtsi ++++ b/arch/arm64/boot/dts/renesas/r9a08g045.dtsi +@@ -152,7 +152,10 @@ irqc: interrupt-controller@11050000 { + , + , + , +- ; ++ , ++ , ++ , ++ ; + interrupt-names = "nmi", + "irq0", "irq1", "irq2", "irq3", + "irq4", "irq5", "irq6", "irq7", +@@ -164,7 +167,8 @@ irqc: interrupt-controller@11050000 { + "tint20", "tint21", "tint22", "tint23", + "tint24", "tint25", "tint26", "tint27", + "tint28", "tint29", "tint30", "tint31", +- "bus-err"; ++ "bus-err", "ec7tie1-0", "ec7tie2-0", ++ "ec7tiovf-0"; + clocks = <&cpg CPG_MOD R9A08G045_IA55_CLK>, + <&cpg CPG_MOD R9A08G045_IA55_PCLK>; + clock-names = "clk", "pclk"; +diff --git a/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi b/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi +index f062d4ad78b79..d33ab4c887878 100644 +--- a/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi ++++ b/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi +@@ -193,12 +193,14 @@ &sdhi2 { + #endif + + &pinctrl { ++#if SW_CONFIG3 == SW_ON + eth0-phy-irq-hog { + gpio-hog; + gpios = ; + input; + line-name = "eth0-phy-irq"; + }; ++#endif + + eth0_pins: eth0 { + txc { +@@ -234,12 +236,14 @@ mux { + }; + }; + ++#if SW_CONFIG3 == SW_ON + eth1-phy-irq-hog { + gpio-hog; + gpios = ; + input; + line-name = "eth1-phy-irq"; + }; ++#endif + + eth1_pins: eth1 { + txc { +diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi +index c19c0f1b3778f..92f96ec01385d 100644 +--- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi +@@ -597,6 +597,7 @@ vpu: video-codec@fdea0400 { + compatible = "rockchip,rk3568-vpu"; + reg = <0x0 0xfdea0000 0x0 0x800>; + interrupts = ; ++ interrupt-names = "vdpu"; + clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; + clock-names = "aclk", "hclk"; + iommus = <&vdpu_mmu>; +@@ -1123,7 +1124,7 @@ i2s2_2ch: i2s@fe420000 { + dmas = <&dmac1 4>, <&dmac1 5>; + dma-names = "tx", "rx"; + resets = <&cru SRST_M_I2S2_2CH>; +- reset-names = "m"; ++ reset-names = "tx-m"; + rockchip,grf = <&grf>; + pinctrl-names = "default"; + pinctrl-0 = <&i2s2m0_sclktx +diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi +index 36b1b7acfe6a1..82350ddb262f2 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi +@@ -1704,7 +1704,6 @@ i2s2_2ch: i2s@fe490000 { + dmas = <&dmac1 0>, <&dmac1 1>; + dma-names = "tx", "rx"; + power-domains = <&power RK3588_PD_AUDIO>; +- rockchip,trcm-sync-tx-only; + pinctrl-names = "default"; + pinctrl-0 = <&i2s2m1_lrck + &i2s2m1_sclk +@@ -1725,7 +1724,6 @@ i2s3_2ch: i2s@fe4a0000 { + dmas = <&dmac1 2>, <&dmac1 3>; + dma-names = "tx", "rx"; + power-domains = <&power RK3588_PD_AUDIO>; +- rockchip,trcm-sync-tx-only; + pinctrl-names = "default"; + pinctrl-0 = <&i2s3_lrck + &i2s3_sclk +diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile +index 52c1dc9103087..08ce34d21d5d0 100644 +--- a/arch/arm64/boot/dts/ti/Makefile ++++ b/arch/arm64/boot/dts/ti/Makefile +@@ -57,6 +57,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-am654-base-board.dtb + dtb-$(CONFIG_ARCH_K3) += k3-am654-gp-evm.dtb + dtb-$(CONFIG_ARCH_K3) += k3-am654-evm.dtb + dtb-$(CONFIG_ARCH_K3) += k3-am654-idk.dtb ++dtb-$(CONFIG_ARCH_K3) += k3-am654-base-board-rocktech-rk101-panel.dtbo + + # Boards with J7200 SoC + k3-j7200-evm-dtbs := k3-j7200-common-proc-board.dtb k3-j7200-evm-quad-port-eth-exp.dtbo +diff --git a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi +index 464b7565d085d..6d07b65a3614e 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi +@@ -640,6 +640,8 @@ usb0: usb@31000000 { + interrupt-names = "host", "peripheral"; + maximum-speed = "high-speed"; + dr_mode = "otg"; ++ snps,usb2-gadget-lpm-disable; ++ snps,usb2-lpm-disable; + }; + }; + +@@ -663,6 +665,8 @@ usb1: usb@31100000 { + interrupt-names = "host", "peripheral"; + maximum-speed = "high-speed"; + dr_mode = "otg"; ++ snps,usb2-gadget-lpm-disable; ++ snps,usb2-lpm-disable; + }; + }; + +@@ -779,9 +783,10 @@ dss: dss@30200000 { + <0x00 0x30207000 0x00 0x1000>, /* ovr1 */ + <0x00 0x30208000 0x00 0x1000>, /* ovr2 */ + <0x00 0x3020a000 0x00 0x1000>, /* vp1: Used for OLDI */ +- <0x00 0x3020b000 0x00 0x1000>; /* vp2: Used as DPI Out */ ++ <0x00 0x3020b000 0x00 0x1000>, /* vp2: Used as DPI Out */ ++ <0x00 0x30201000 0x00 0x1000>; /* common1 */ + reg-names = "common", "vidl1", "vid", +- "ovr1", "ovr2", "vp1", "vp2"; ++ "ovr1", "ovr2", "vp1", "vp2", "common1"; + power-domains = <&k3_pds 186 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 186 6>, + <&dss_vp1_clk>, +diff --git a/arch/arm64/boot/dts/ti/k3-am62p-mcu.dtsi b/arch/arm64/boot/dts/ti/k3-am62p-mcu.dtsi +index c4b0b91d70cf3..14eb9ba836d32 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62p-mcu.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am62p-mcu.dtsi +@@ -187,6 +187,8 @@ mcu_r5fss0: r5fss@79000000 { + ranges = <0x79000000 0x00 0x79000000 0x8000>, + <0x79020000 0x00 0x79020000 0x8000>; + power-domains = <&k3_pds 7 TI_SCI_PD_EXCLUSIVE>; ++ status = "disabled"; ++ + mcu_r5fss0_core0: r5f@79000000 { + compatible = "ti,am62-r5f"; + reg = <0x79000000 0x00008000>, +diff --git a/arch/arm64/boot/dts/ti/k3-am62p-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-am62p-wakeup.dtsi +index 19f42b39394ee..10a7059b2d9b5 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62p-wakeup.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am62p-wakeup.dtsi +@@ -78,6 +78,7 @@ wkup_r5fss0: r5fss@78000000 { + ranges = <0x78000000 0x00 0x78000000 0x8000>, + <0x78100000 0x00 0x78100000 0x8000>; + power-domains = <&k3_pds 119 TI_SCI_PD_EXCLUSIVE>; ++ status = "disabled"; + + wkup_r5fss0_core0: r5f@78000000 { + compatible = "ti,am62-r5f"; +diff --git a/arch/arm64/boot/dts/ti/k3-am62p.dtsi b/arch/arm64/boot/dts/ti/k3-am62p.dtsi +index 84ffe7b9dcaf3..4f22b5d9fb9f0 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62p.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am62p.dtsi +@@ -71,7 +71,7 @@ cbass_main: bus@f0000 { + <0x00 0x43600000 0x00 0x43600000 0x00 0x00010000>, /* SA3 sproxy data */ + <0x00 0x44043000 0x00 0x44043000 0x00 0x00000fe0>, /* TI SCI DEBUG */ + <0x00 0x44860000 0x00 0x44860000 0x00 0x00040000>, /* SA3 sproxy config */ +- <0x00 0x48000000 0x00 0x48000000 0x00 0x06400000>, /* DMSS */ ++ <0x00 0x48000000 0x00 0x48000000 0x00 0x06408000>, /* DMSS */ + <0x00 0x60000000 0x00 0x60000000 0x00 0x08000000>, /* FSS0 DAT1 */ + <0x00 0x70000000 0x00 0x70000000 0x00 0x00010000>, /* OCSRAM */ + <0x01 0x00000000 0x01 0x00000000 0x00 0x00310000>, /* A53 PERIPHBASE */ +diff --git a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts +index 1773c05f752cd..60868862e3b43 100644 +--- a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts ++++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts +@@ -445,6 +445,10 @@ &cpsw_port2 { + }; + + &cpsw3g_mdio { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&main_mdio1_pins_default>; ++ status = "okay"; ++ + cpsw3g_phy0: ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = ; +diff --git a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi +index e348114f42e01..ba624ef72f5b4 100644 +--- a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi +@@ -633,6 +633,9 @@ sdhci0: mmc@fa10000 { + ti,otap-del-sel-mmc-hs = <0x0>; + ti,otap-del-sel-ddr52 = <0x6>; + ti,otap-del-sel-hs200 = <0x7>; ++ ti,itap-del-sel-legacy = <0x10>; ++ ti,itap-del-sel-mmc-hs = <0xa>; ++ ti,itap-del-sel-ddr52 = <0x3>; + status = "disabled"; + }; + +@@ -645,12 +648,16 @@ sdhci1: mmc@fa00000 { + clock-names = "clk_ahb", "clk_xin"; + ti,trm-icp = <0x2>; + ti,otap-del-sel-legacy = <0x0>; +- ti,otap-del-sel-sd-hs = <0xf>; ++ ti,otap-del-sel-sd-hs = <0x0>; + ti,otap-del-sel-sdr12 = <0xf>; + ti,otap-del-sel-sdr25 = <0xf>; + ti,otap-del-sel-sdr50 = <0xc>; + ti,otap-del-sel-sdr104 = <0x6>; + ti,otap-del-sel-ddr50 = <0x9>; ++ ti,itap-del-sel-legacy = <0x0>; ++ ti,itap-del-sel-sd-hs = <0x0>; ++ ti,itap-del-sel-sdr12 = <0x0>; ++ ti,itap-del-sel-sdr25 = <0x0>; + ti,clkbuf-sel = <0x7>; + status = "disabled"; + }; +diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +index fcea544656360..5b2d4365b9111 100644 +--- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +@@ -1019,9 +1019,10 @@ dss: dss@4a00000 { + <0x0 0x04a07000 0x0 0x1000>, /* ovr1 */ + <0x0 0x04a08000 0x0 0x1000>, /* ovr2 */ + <0x0 0x04a0a000 0x0 0x1000>, /* vp1 */ +- <0x0 0x04a0b000 0x0 0x1000>; /* vp2 */ ++ <0x0 0x04a0b000 0x0 0x1000>, /* vp2 */ ++ <0x0 0x04a01000 0x0 0x1000>; /* common1 */ + reg-names = "common", "vidl1", "vid", +- "ovr1", "ovr2", "vp1", "vp2"; ++ "ovr1", "ovr2", "vp1", "vp2", "common1"; + + ti,am65x-oldi-io-ctrl = <&dss_oldi_io_ctrl>; + +diff --git a/arch/arm64/boot/dts/ti/k3-am69-sk.dts b/arch/arm64/boot/dts/ti/k3-am69-sk.dts +index 8da5915798688..c8fb9dfb89723 100644 +--- a/arch/arm64/boot/dts/ti/k3-am69-sk.dts ++++ b/arch/arm64/boot/dts/ti/k3-am69-sk.dts +@@ -646,7 +646,7 @@ tps659413: pmic@48 { + pinctrl-names = "default"; + pinctrl-0 = <&pmic_irq_pins_default>; + interrupt-parent = <&wkup_gpio0>; +- interrupts = <39 IRQ_TYPE_EDGE_FALLING>; ++ interrupts = <83 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + ti,primary-pmic; +@@ -918,13 +918,9 @@ &dss { + pinctrl-names = "default"; + pinctrl-0 = <&dss_vout0_pins_default>; + assigned-clocks = <&k3_clks 218 2>, +- <&k3_clks 218 5>, +- <&k3_clks 218 14>, +- <&k3_clks 218 18>; ++ <&k3_clks 218 5>; + assigned-clock-parents = <&k3_clks 218 3>, +- <&k3_clks 218 7>, +- <&k3_clks 218 16>, +- <&k3_clks 218 22>; ++ <&k3_clks 218 7>; + }; + + &serdes_wiz4 { +diff --git a/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts +index cee2b4b0eb87d..7a0c599f2b1c3 100644 +--- a/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts ++++ b/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts +@@ -91,24 +91,25 @@ vdd_sd_dv: gpio-regulator-TLV71033 { + }; + + &wkup_pmx0 { ++}; ++ ++&wkup_pmx2 { + mcu_uart0_pins_default: mcu-uart0-default-pins { + pinctrl-single,pins = < +- J721E_WKUP_IOPAD(0xf4, PIN_INPUT, 0) /* (D20) MCU_UART0_RXD */ +- J721E_WKUP_IOPAD(0xf0, PIN_OUTPUT, 0) /* (D19) MCU_UART0_TXD */ +- J721E_WKUP_IOPAD(0xf8, PIN_INPUT, 0) /* (E20) MCU_UART0_CTSn */ +- J721E_WKUP_IOPAD(0xfc, PIN_OUTPUT, 0) /* (E21) MCU_UART0_RTSn */ ++ J721E_WKUP_IOPAD(0x90, PIN_INPUT, 0) /* (E20) MCU_UART0_CTSn */ ++ J721E_WKUP_IOPAD(0x94, PIN_OUTPUT, 0) /* (E21) MCU_UART0_RTSn */ ++ J721E_WKUP_IOPAD(0x8c, PIN_INPUT, 0) /* (D20) MCU_UART0_RXD */ ++ J721E_WKUP_IOPAD(0x88, PIN_OUTPUT, 0) /* (D19) MCU_UART0_TXD */ + >; + }; + + wkup_uart0_pins_default: wkup-uart0-default-pins { + pinctrl-single,pins = < +- J721E_WKUP_IOPAD(0xb0, PIN_INPUT, 0) /* (B14) WKUP_UART0_RXD */ +- J721E_WKUP_IOPAD(0xb4, PIN_OUTPUT, 0) /* (A14) WKUP_UART0_TXD */ ++ J721E_WKUP_IOPAD(0x48, PIN_INPUT, 0) /* (B14) WKUP_UART0_RXD */ ++ J721E_WKUP_IOPAD(0x4c, PIN_OUTPUT, 0) /* (A14) WKUP_UART0_TXD */ + >; + }; +-}; + +-&wkup_pmx2 { + mcu_cpsw_pins_default: mcu-cpsw-default-pins { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x0000, PIN_OUTPUT, 0) /* MCU_RGMII1_TX_CTL */ +@@ -210,7 +211,6 @@ &mcu_uart0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_uart0_pins_default>; +- clock-frequency = <96000000>; + }; + + &main_uart0 { +diff --git a/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi +index a74912d9e4daf..c463e23ced04e 100644 +--- a/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi +@@ -353,9 +353,9 @@ fss: bus@47000000 { + + hbmc_mux: mux-controller@47000004 { + compatible = "reg-mux"; +- reg = <0x00 0x47000004 0x00 0x2>; ++ reg = <0x00 0x47000004 0x00 0x4>; + #mux-control-cells = <1>; +- mux-reg-masks = <0x4 0x2>; /* HBMC select */ ++ mux-reg-masks = <0x0 0x2>; /* HBMC select */ + }; + + hbmc: hyperbus@47034000 { +diff --git a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts +index 188dfe291a32b..658764f7d5443 100644 +--- a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts ++++ b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts +@@ -574,7 +574,7 @@ tps659413: pmic@48 { + pinctrl-names = "default"; + pinctrl-0 = <&pmic_irq_pins_default>; + interrupt-parent = <&wkup_gpio0>; +- interrupts = <9 IRQ_TYPE_EDGE_FALLING>; ++ interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + ti,primary-pmic; +@@ -651,7 +651,7 @@ tps659411: pmic@4c { + reg = <0x4c>; + system-power-controller; + interrupt-parent = <&wkup_gpio0>; +- interrupts = <9 IRQ_TYPE_EDGE_FALLING>; ++ interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + buck1234-supply = <&vsys_3v3>; +diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts +index c6b85bbf9a179..1ba1f53c72d03 100644 +--- a/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts ++++ b/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts +@@ -190,8 +190,6 @@ J721S2_IOPAD(0x038, PIN_OUTPUT, 0) /* (AB28) MCASP0_ACLKX.MCAN5_TX */ + &wkup_pmx2 { + wkup_uart0_pins_default: wkup-uart0-default-pins { + pinctrl-single,pins = < +- J721S2_WKUP_IOPAD(0x070, PIN_INPUT, 0) /* (E25) WKUP_GPIO0_6.WKUP_UART0_CTSn */ +- J721S2_WKUP_IOPAD(0x074, PIN_OUTPUT, 0) /* (F28) WKUP_GPIO0_7.WKUP_UART0_RTSn */ + J721S2_WKUP_IOPAD(0x048, PIN_INPUT, 0) /* (D28) WKUP_UART0_RXD */ + J721S2_WKUP_IOPAD(0x04c, PIN_OUTPUT, 0) /* (D27) WKUP_UART0_TXD */ + >; +diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi +index 80aa33c58a452..a47cb557dd956 100644 +--- a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi +@@ -663,7 +663,7 @@ wkup_vtm0: temperature-sensor@42040000 { + compatible = "ti,j7200-vtm"; + reg = <0x00 0x42040000 0x0 0x350>, + <0x00 0x42050000 0x0 0x350>; +- power-domains = <&k3_pds 154 TI_SCI_PD_SHARED>; ++ power-domains = <&k3_pds 180 TI_SCI_PD_SHARED>; + #thermal-sensor-cells = <1>; + }; + +diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts b/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts +index f34b92acc56d8..33795a0bc69cf 100644 +--- a/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts ++++ b/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts +@@ -335,8 +335,6 @@ &wkup_pmx2 { + wkup_uart0_pins_default: wkup-uart0-default-pins { + bootph-all; + pinctrl-single,pins = < +- J721S2_WKUP_IOPAD(0x070, PIN_INPUT, 0) /* (L37) WKUP_GPIO0_6.WKUP_UART0_CTSn */ +- J721S2_WKUP_IOPAD(0x074, PIN_INPUT, 0) /* (L36) WKUP_GPIO0_7.WKUP_UART0_RTSn */ + J721S2_WKUP_IOPAD(0x048, PIN_INPUT, 0) /* (K35) WKUP_UART0_RXD */ + J721S2_WKUP_IOPAD(0x04c, PIN_INPUT, 0) /* (K34) WKUP_UART0_TXD */ + >; +diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +index f2b720ed1e4f2..56c8eaad6324b 100644 +--- a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +@@ -52,12 +52,12 @@ serdes_ln_ctrl: mux-controller@4080 { + compatible = "reg-mux"; + reg = <0x00004080 0x30>; + #mux-control-cells = <1>; +- mux-reg-masks = <0x4080 0x3>, <0x4084 0x3>, /* SERDES0 lane0/1 select */ +- <0x4088 0x3>, <0x408c 0x3>, /* SERDES0 lane2/3 select */ +- <0x4090 0x3>, <0x4094 0x3>, /* SERDES1 lane0/1 select */ +- <0x4098 0x3>, <0x409c 0x3>, /* SERDES1 lane2/3 select */ +- <0x40a0 0x3>, <0x40a4 0x3>, /* SERDES2 lane0/1 select */ +- <0x40a8 0x3>, <0x40ac 0x3>; /* SERDES2 lane2/3 select */ ++ mux-reg-masks = <0x0 0x3>, <0x4 0x3>, /* SERDES0 lane0/1 select */ ++ <0x8 0x3>, <0xc 0x3>, /* SERDES0 lane2/3 select */ ++ <0x10 0x3>, <0x14 0x3>, /* SERDES1 lane0/1 select */ ++ <0x18 0x3>, <0x1c 0x3>, /* SERDES1 lane2/3 select */ ++ <0x20 0x3>, <0x24 0x3>, /* SERDES2 lane0/1 select */ ++ <0x28 0x3>, <0x2c 0x3>; /* SERDES2 lane2/3 select */ + idle-states = , + , + , +diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi +index 3902a921d7e58..337122c3f4020 100644 +--- a/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi ++++ b/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi +@@ -628,7 +628,7 @@ wkup_vtm0: temperature-sensor@42040000 { + compatible = "ti,j7200-vtm"; + reg = <0x00 0x42040000 0x00 0x350>, + <0x00 0x42050000 0x00 0x350>; +- power-domains = <&k3_pds 154 TI_SCI_PD_SHARED>; ++ power-domains = <&k3_pds 243 TI_SCI_PD_SHARED>; + #thermal-sensor-cells = <1>; + }; + +diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h +index 23c67c0871b17..6cc79296c8ef2 100644 +--- a/arch/mips/include/asm/mips-cm.h ++++ b/arch/mips/include/asm/mips-cm.h +@@ -33,6 +33,19 @@ extern void __iomem *mips_cm_l2sync_base; + */ + extern phys_addr_t __mips_cm_phys_base(void); + ++/** ++ * mips_cm_l2sync_phys_base - retrieve the physical base address of the CM ++ * L2-sync region ++ * ++ * This function returns the physical base address of the Coherence Manager ++ * L2-cache only region. It provides a default implementation which reads the ++ * CMGCRL2OnlySyncBase register where available or returns a 4K region just ++ * behind the CM GCR base address. It may be overridden by platforms which ++ * determine this address in a different way by defining a function with the ++ * same prototype. ++ */ ++extern phys_addr_t mips_cm_l2sync_phys_base(void); ++ + /* + * mips_cm_is64 - determine CM register width + * +diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c +index 84b3affb9de88..268ac0b811e35 100644 +--- a/arch/mips/kernel/mips-cm.c ++++ b/arch/mips/kernel/mips-cm.c +@@ -201,7 +201,7 @@ phys_addr_t __mips_cm_phys_base(void) + phys_addr_t mips_cm_phys_base(void) + __attribute__((weak, alias("__mips_cm_phys_base"))); + +-static phys_addr_t __mips_cm_l2sync_phys_base(void) ++phys_addr_t __weak mips_cm_l2sync_phys_base(void) + { + u32 base_reg; + +@@ -217,9 +217,6 @@ static phys_addr_t __mips_cm_l2sync_phys_base(void) + return mips_cm_phys_base() + MIPS_CM_GCR_SIZE; + } + +-phys_addr_t mips_cm_l2sync_phys_base(void) +- __attribute__((weak, alias("__mips_cm_l2sync_phys_base"))); +- + static void mips_cm_probe_l2sync(void) + { + unsigned major_rev; +diff --git a/arch/powerpc/include/asm/vmalloc.h b/arch/powerpc/include/asm/vmalloc.h +index 4c69ece52a31e..59ed89890c902 100644 +--- a/arch/powerpc/include/asm/vmalloc.h ++++ b/arch/powerpc/include/asm/vmalloc.h +@@ -7,14 +7,14 @@ + #ifdef CONFIG_HAVE_ARCH_HUGE_VMAP + + #define arch_vmap_pud_supported arch_vmap_pud_supported +-static inline bool arch_vmap_pud_supported(pgprot_t prot) ++static __always_inline bool arch_vmap_pud_supported(pgprot_t prot) + { + /* HPT does not cope with large pages in the vmalloc area */ + return radix_enabled(); + } + + #define arch_vmap_pmd_supported arch_vmap_pmd_supported +-static inline bool arch_vmap_pmd_supported(pgprot_t prot) ++static __always_inline bool arch_vmap_pmd_supported(pgprot_t prot) + { + return radix_enabled(); + } +diff --git a/arch/powerpc/perf/hv-gpci.c b/arch/powerpc/perf/hv-gpci.c +index 27f18119fda17..241551d1282f8 100644 +--- a/arch/powerpc/perf/hv-gpci.c ++++ b/arch/powerpc/perf/hv-gpci.c +@@ -695,6 +695,20 @@ static unsigned long single_gpci_request(u32 req, u32 starting_index, + + ret = plpar_hcall_norets(H_GET_PERF_COUNTER_INFO, + virt_to_phys(arg), HGPCI_REQ_BUFFER_SIZE); ++ ++ /* ++ * ret value as 'H_PARAMETER' with detail_rc as 'GEN_BUF_TOO_SMALL', ++ * specifies that the current buffer size cannot accommodate ++ * all the information and a partial buffer returned. ++ * Since in this function we are only accessing data for a given starting index, ++ * we don't need to accommodate whole data and can get required count by ++ * accessing first entry data. ++ * Hence hcall fails only incase the ret value is other than H_SUCCESS or ++ * H_PARAMETER with detail_rc value as GEN_BUF_TOO_SMALL(0x1B). ++ */ ++ if (ret == H_PARAMETER && be32_to_cpu(arg->params.detail_rc) == 0x1B) ++ ret = 0; ++ + if (ret) { + pr_devel("hcall failed: 0x%lx\n", ret); + goto out; +@@ -759,6 +773,7 @@ static int h_gpci_event_init(struct perf_event *event) + { + u64 count; + u8 length; ++ unsigned long ret; + + /* Not our event */ + if (event->attr.type != event->pmu->type) +@@ -789,13 +804,23 @@ static int h_gpci_event_init(struct perf_event *event) + } + + /* check if the request works... */ +- if (single_gpci_request(event_get_request(event), ++ ret = single_gpci_request(event_get_request(event), + event_get_starting_index(event), + event_get_secondary_index(event), + event_get_counter_info_version(event), + event_get_offset(event), + length, +- &count)) { ++ &count); ++ ++ /* ++ * ret value as H_AUTHORITY implies that partition is not permitted to retrieve ++ * performance information, and required to set ++ * "Enable Performance Information Collection" option. ++ */ ++ if (ret == H_AUTHORITY) ++ return -EPERM; ++ ++ if (ret) { + pr_devel("gpci hcall failed\n"); + return -EINVAL; + } +diff --git a/arch/powerpc/platforms/44x/warp.c b/arch/powerpc/platforms/44x/warp.c +index bf0188dcb9184..a5001d32f978d 100644 +--- a/arch/powerpc/platforms/44x/warp.c ++++ b/arch/powerpc/platforms/44x/warp.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c +index 9c10aac40c7b1..e265f026eee2a 100644 +--- a/arch/powerpc/platforms/embedded6xx/linkstation.c ++++ b/arch/powerpc/platforms/embedded6xx/linkstation.c +@@ -99,9 +99,6 @@ static void __init linkstation_init_IRQ(void) + mpic_init(mpic); + } + +-extern void avr_uart_configure(void); +-extern void avr_uart_send(const char); +- + static void __noreturn linkstation_restart(char *cmd) + { + local_irq_disable(); +diff --git a/arch/powerpc/platforms/embedded6xx/mpc10x.h b/arch/powerpc/platforms/embedded6xx/mpc10x.h +index 5ad12023e5628..ebc258fa4858d 100644 +--- a/arch/powerpc/platforms/embedded6xx/mpc10x.h ++++ b/arch/powerpc/platforms/embedded6xx/mpc10x.h +@@ -156,4 +156,7 @@ int mpc10x_disable_store_gathering(struct pci_controller *hose); + /* For MPC107 boards that use the built-in openpic */ + void mpc10x_set_openpic(void); + ++void avr_uart_configure(void); ++void avr_uart_send(const char c); ++ + #endif /* __PPC_KERNEL_MPC10X_H */ +diff --git a/arch/powerpc/platforms/powermac/Kconfig b/arch/powerpc/platforms/powermac/Kconfig +index 8bdae0caf21e5..84f101ec53a96 100644 +--- a/arch/powerpc/platforms/powermac/Kconfig ++++ b/arch/powerpc/platforms/powermac/Kconfig +@@ -2,7 +2,7 @@ + config PPC_PMAC + bool "Apple PowerMac based machines" + depends on PPC_BOOK3S && CPU_BIG_ENDIAN +- select ADB_CUDA if POWER_RESET && PPC32 ++ select ADB_CUDA if POWER_RESET && ADB + select MPIC + select FORCE_PCI + select PPC_INDIRECT_PCI if PPC32 +diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig +index e9c1087dd42ec..706194e5f0b46 100644 +--- a/arch/powerpc/platforms/ps3/Kconfig ++++ b/arch/powerpc/platforms/ps3/Kconfig +@@ -67,6 +67,7 @@ config PS3_VUART + config PS3_PS3AV + depends on PPC_PS3 + tristate "PS3 AV settings driver" if PS3_ADVANCED ++ select VIDEO + select PS3_VUART + default y + help +diff --git a/arch/powerpc/platforms/pseries/papr_platform_attributes.c b/arch/powerpc/platforms/pseries/papr_platform_attributes.c +index 526c621b098be..eea2041b270b5 100644 +--- a/arch/powerpc/platforms/pseries/papr_platform_attributes.c ++++ b/arch/powerpc/platforms/pseries/papr_platform_attributes.c +@@ -101,10 +101,12 @@ static int papr_get_attr(u64 id, struct energy_scale_attribute *esi) + esi_buf_size = ESI_HDR_SIZE + (CURR_MAX_ESI_ATTRS * max_esi_attrs); + + temp_buf = krealloc(buf, esi_buf_size, GFP_KERNEL); +- if (temp_buf) ++ if (temp_buf) { + buf = temp_buf; +- else +- return -ENOMEM; ++ } else { ++ ret = -ENOMEM; ++ goto out_buf; ++ } + + goto retry; + } +diff --git a/arch/riscv/boot/dts/starfive/jh7100.dtsi b/arch/riscv/boot/dts/starfive/jh7100.dtsi +index 8bcf36d07f3f7..5d499d8aa8044 100644 +--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi ++++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi +@@ -116,6 +116,7 @@ cpu-crit { + osc_sys: osc-sys { + compatible = "fixed-clock"; + #clock-cells = <0>; ++ clock-output-names = "osc_sys"; + /* This value must be overridden by the board */ + clock-frequency = <0>; + }; +@@ -123,6 +124,7 @@ osc_sys: osc-sys { + osc_aud: osc-aud { + compatible = "fixed-clock"; + #clock-cells = <0>; ++ clock-output-names = "osc_aud"; + /* This value must be overridden by the board */ + clock-frequency = <0>; + }; +@@ -130,6 +132,7 @@ osc_aud: osc-aud { + gmac_rmii_ref: gmac-rmii-ref { + compatible = "fixed-clock"; + #clock-cells = <0>; ++ clock-output-names = "gmac_rmii_ref"; + /* Should be overridden by the board when needed */ + clock-frequency = <0>; + }; +@@ -137,6 +140,7 @@ gmac_rmii_ref: gmac-rmii-ref { + gmac_gr_mii_rxclk: gmac-gr-mii-rxclk { + compatible = "fixed-clock"; + #clock-cells = <0>; ++ clock-output-names = "gmac_gr_mii_rxclk"; + /* Should be overridden by the board when needed */ + clock-frequency = <0>; + }; +diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h +index 6066822e7396f..3422ced8a07fd 100644 +--- a/arch/riscv/include/asm/pgtable.h ++++ b/arch/riscv/include/asm/pgtable.h +@@ -439,9 +439,11 @@ static inline pte_t pte_mkhuge(pte_t pte) + return pte; + } + ++#ifdef CONFIG_RISCV_ISA_SVNAPOT + #define pte_leaf_size(pte) (pte_napot(pte) ? \ + napot_cont_size(napot_cont_order(pte)) :\ + PAGE_SIZE) ++#endif + + #ifdef CONFIG_NUMA_BALANCING + /* +diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c +index 8ded225e8c5b1..c2ed4e689bf96 100644 +--- a/arch/riscv/kernel/traps_misaligned.c ++++ b/arch/riscv/kernel/traps_misaligned.c +@@ -632,7 +632,7 @@ void unaligned_emulation_finish(void) + * accesses emulated since tasks requesting such control can run on any + * CPU. + */ +- for_each_present_cpu(cpu) { ++ for_each_online_cpu(cpu) { + if (per_cpu(misaligned_access_speed, cpu) != + RISCV_HWPROBE_MISALIGNED_EMULATED) { + return; +diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c +index 7a6abed41bc17..ee7215f4071f5 100644 +--- a/arch/riscv/kvm/vcpu_insn.c ++++ b/arch/riscv/kvm/vcpu_insn.c +@@ -7,6 +7,8 @@ + #include + #include + ++#include ++ + #define INSN_OPCODE_MASK 0x007c + #define INSN_OPCODE_SHIFT 2 + #define INSN_OPCODE_SYSTEM 28 +@@ -213,9 +215,20 @@ struct csr_func { + unsigned long wr_mask); + }; + ++static int seed_csr_rmw(struct kvm_vcpu *vcpu, unsigned int csr_num, ++ unsigned long *val, unsigned long new_val, ++ unsigned long wr_mask) ++{ ++ if (!riscv_isa_extension_available(vcpu->arch.isa, ZKR)) ++ return KVM_INSN_ILLEGAL_TRAP; ++ ++ return KVM_INSN_EXIT_TO_USER_SPACE; ++} ++ + static const struct csr_func csr_funcs[] = { + KVM_RISCV_VCPU_AIA_CSR_FUNCS + KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS ++ { .base = CSR_SEED, .count = 1, .func = seed_csr_rmw }, + }; + + /** +diff --git a/arch/s390/kernel/cache.c b/arch/s390/kernel/cache.c +index 56254fa06f990..4f26690302209 100644 +--- a/arch/s390/kernel/cache.c ++++ b/arch/s390/kernel/cache.c +@@ -166,5 +166,6 @@ int populate_cache_leaves(unsigned int cpu) + ci_leaf_init(this_leaf++, pvt, ctype, level, cpu); + } + } ++ this_cpu_ci->cpu_map_populated = true; + return 0; + } +diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c +index bf8a672b15a41..522a5ea0a9f49 100644 +--- a/arch/s390/kernel/perf_pai_crypto.c ++++ b/arch/s390/kernel/perf_pai_crypto.c +@@ -721,7 +721,7 @@ static int __init attr_event_init(void) + for (i = 0; i < ARRAY_SIZE(paicrypt_ctrnames); i++) { + ret = attr_event_init_one(attrs, i); + if (ret) { +- attr_event_free(attrs, i - 1); ++ attr_event_free(attrs, i); + return ret; + } + } +diff --git a/arch/s390/kernel/perf_pai_ext.c b/arch/s390/kernel/perf_pai_ext.c +index af7f2b538c8fd..95d1a890640a3 100644 +--- a/arch/s390/kernel/perf_pai_ext.c ++++ b/arch/s390/kernel/perf_pai_ext.c +@@ -611,7 +611,7 @@ static int __init attr_event_init(void) + for (i = 0; i < ARRAY_SIZE(paiext_ctrnames); i++) { + ret = attr_event_init_one(attrs, i); + if (ret) { +- attr_event_free(attrs, i - 1); ++ attr_event_free(attrs, i); + return ret; + } + } +diff --git a/arch/s390/kernel/vdso32/Makefile b/arch/s390/kernel/vdso32/Makefile +index caec7db6f9668..b12a274cbb473 100644 +--- a/arch/s390/kernel/vdso32/Makefile ++++ b/arch/s390/kernel/vdso32/Makefile +@@ -22,7 +22,7 @@ KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS)) + KBUILD_CFLAGS_32 := $(filter-out -mno-pic-data-is-text-relative,$(KBUILD_CFLAGS_32)) + KBUILD_CFLAGS_32 += -m31 -fPIC -shared -fno-common -fno-builtin + +-LDFLAGS_vdso32.so.dbg += -fPIC -shared -soname=linux-vdso32.so.1 \ ++LDFLAGS_vdso32.so.dbg += -shared -soname=linux-vdso32.so.1 \ + --hash-style=both --build-id=sha1 -melf_s390 -T + + $(targets:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_32) +diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile +index e3c9085f8fa72..caa4ebff8a193 100644 +--- a/arch/s390/kernel/vdso64/Makefile ++++ b/arch/s390/kernel/vdso64/Makefile +@@ -26,7 +26,7 @@ KBUILD_AFLAGS_64 += -m64 + KBUILD_CFLAGS_64 := $(filter-out -m64,$(KBUILD_CFLAGS)) + KBUILD_CFLAGS_64 := $(filter-out -mno-pic-data-is-text-relative,$(KBUILD_CFLAGS_64)) + KBUILD_CFLAGS_64 += -m64 -fPIC -fno-common -fno-builtin +-ldflags-y := -fPIC -shared -soname=linux-vdso64.so.1 \ ++ldflags-y := -shared -soname=linux-vdso64.so.1 \ + --hash-style=both --build-id=sha1 -T + + $(targets:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_64) +diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c +index e0a88dcaf5cb7..24a18e5ef6e8e 100644 +--- a/arch/s390/kernel/vtime.c ++++ b/arch/s390/kernel/vtime.c +@@ -210,13 +210,13 @@ void vtime_flush(struct task_struct *tsk) + virt_timer_expire(); + + steal = S390_lowcore.steal_timer; +- avg_steal = S390_lowcore.avg_steal_timer / 2; ++ avg_steal = S390_lowcore.avg_steal_timer; + if ((s64) steal > 0) { + S390_lowcore.steal_timer = 0; + account_steal_time(cputime_to_nsecs(steal)); + avg_steal += steal; + } +- S390_lowcore.avg_steal_timer = avg_steal; ++ S390_lowcore.avg_steal_timer = avg_steal / 2; + } + + static u64 vtime_delta(void) +diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig +index 204c43cb3d435..37a1cfecd9c73 100644 +--- a/arch/sparc/Kconfig ++++ b/arch/sparc/Kconfig +@@ -57,6 +57,8 @@ config SPARC32 + select CLZ_TAB + select DMA_DIRECT_REMAP + select GENERIC_ATOMIC64 ++ select GENERIC_LIB_CMPDI2 ++ select GENERIC_LIB_UCMPDI2 + select HAVE_UID16 + select LOCK_MM_AND_FIND_VMA + select OLD_SIGACTION +@@ -140,10 +142,6 @@ config HIGHMEM + default y if SPARC32 + select KMAP_LOCAL + +-config GENERIC_ISA_DMA +- bool +- default y if SPARC32 +- + config PGTABLE_LEVELS + default 4 if 64BIT + default 3 +diff --git a/arch/sparc/kernel/leon_pci_grpci1.c b/arch/sparc/kernel/leon_pci_grpci1.c +index 8700a0e3b0df7..b2b639bee0684 100644 +--- a/arch/sparc/kernel/leon_pci_grpci1.c ++++ b/arch/sparc/kernel/leon_pci_grpci1.c +@@ -697,7 +697,7 @@ static int grpci1_of_probe(struct platform_device *ofdev) + return err; + } + +-static const struct of_device_id grpci1_of_match[] __initconst = { ++static const struct of_device_id grpci1_of_match[] = { + { + .name = "GAISLER_PCIFBRG", + }, +diff --git a/arch/sparc/kernel/leon_pci_grpci2.c b/arch/sparc/kernel/leon_pci_grpci2.c +index 60b6bdf7761fb..ac2acd62a24ec 100644 +--- a/arch/sparc/kernel/leon_pci_grpci2.c ++++ b/arch/sparc/kernel/leon_pci_grpci2.c +@@ -889,7 +889,7 @@ static int grpci2_of_probe(struct platform_device *ofdev) + return err; + } + +-static const struct of_device_id grpci2_of_match[] __initconst = { ++static const struct of_device_id grpci2_of_match[] = { + { + .name = "GAISLER_GRPCI2", + }, +diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile +index 59669ebddd4e1..ee5091dd67ed7 100644 +--- a/arch/sparc/lib/Makefile ++++ b/arch/sparc/lib/Makefile +@@ -14,7 +14,7 @@ lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o + lib-$(CONFIG_SPARC32) += copy_user.o locks.o + lib-$(CONFIG_SPARC64) += atomic_64.o + lib-$(CONFIG_SPARC32) += lshrdi3.o ashldi3.o +-lib-$(CONFIG_SPARC32) += muldi3.o bitext.o cmpdi2.o ++lib-$(CONFIG_SPARC32) += muldi3.o bitext.o + lib-$(CONFIG_SPARC64) += multi3.o + lib-$(CONFIG_SPARC64) += fls.o + lib-$(CONFIG_SPARC64) += fls64.o +@@ -51,5 +51,5 @@ lib-$(CONFIG_SPARC64) += copy_in_user.o memmove.o + lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o hweight.o ffs.o + + obj-$(CONFIG_SPARC64) += iomap.o +-obj-$(CONFIG_SPARC32) += atomic32.o ucmpdi2.o ++obj-$(CONFIG_SPARC32) += atomic32.o + obj-$(CONFIG_SPARC64) += PeeCeeI.o +diff --git a/arch/sparc/lib/cmpdi2.c b/arch/sparc/lib/cmpdi2.c +deleted file mode 100644 +index 333367fe73533..0000000000000 +--- a/arch/sparc/lib/cmpdi2.c ++++ /dev/null +@@ -1,28 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-#include +- +-#include "libgcc.h" +- +-word_type __cmpdi2(long long a, long long b) +-{ +- const DWunion au = { +- .ll = a +- }; +- const DWunion bu = { +- .ll = b +- }; +- +- if (au.s.high < bu.s.high) +- return 0; +- else if (au.s.high > bu.s.high) +- return 2; +- +- if ((unsigned int) au.s.low < (unsigned int) bu.s.low) +- return 0; +- else if ((unsigned int) au.s.low > (unsigned int) bu.s.low) +- return 2; +- +- return 1; +-} +- +-EXPORT_SYMBOL(__cmpdi2); +diff --git a/arch/sparc/lib/ucmpdi2.c b/arch/sparc/lib/ucmpdi2.c +deleted file mode 100644 +index 82c1cccb12644..0000000000000 +--- a/arch/sparc/lib/ucmpdi2.c ++++ /dev/null +@@ -1,20 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-#include +-#include "libgcc.h" +- +-word_type __ucmpdi2(unsigned long long a, unsigned long long b) +-{ +- const DWunion au = {.ll = a}; +- const DWunion bu = {.ll = b}; +- +- if ((unsigned int) au.s.high < (unsigned int) bu.s.high) +- return 0; +- else if ((unsigned int) au.s.high > (unsigned int) bu.s.high) +- return 2; +- if ((unsigned int) au.s.low < (unsigned int) bu.s.low) +- return 0; +- else if ((unsigned int) au.s.low > (unsigned int) bu.s.low) +- return 2; +- return 1; +-} +-EXPORT_SYMBOL(__ucmpdi2); +diff --git a/arch/x86/events/amd/core.c b/arch/x86/events/amd/core.c +index 81f6d8275b6bf..1f114d4bfe303 100644 +--- a/arch/x86/events/amd/core.c ++++ b/arch/x86/events/amd/core.c +@@ -604,7 +604,6 @@ static void amd_pmu_cpu_dead(int cpu) + + kfree(cpuhw->lbr_sel); + cpuhw->lbr_sel = NULL; +- amd_pmu_cpu_reset(cpu); + + if (!x86_pmu.amd_nb_constraints) + return; +diff --git a/arch/x86/hyperv/hv_vtl.c b/arch/x86/hyperv/hv_vtl.c +index cf1b78cb2d043..c8062975a5316 100644 +--- a/arch/x86/hyperv/hv_vtl.c ++++ b/arch/x86/hyperv/hv_vtl.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include <../kernel/smpboot.h> + + extern struct boot_params boot_params; + static struct real_mode_header hv_vtl_real_mode_header; +@@ -64,7 +65,7 @@ static void hv_vtl_ap_entry(void) + ((secondary_startup_64_fn)secondary_startup_64)(&boot_params, &boot_params); + } + +-static int hv_vtl_bringup_vcpu(u32 target_vp_index, u64 eip_ignored) ++static int hv_vtl_bringup_vcpu(u32 target_vp_index, int cpu, u64 eip_ignored) + { + u64 status; + int ret = 0; +@@ -78,7 +79,9 @@ static int hv_vtl_bringup_vcpu(u32 target_vp_index, u64 eip_ignored) + struct ldttss_desc *ldt; + struct desc_struct *gdt; + +- u64 rsp = current->thread.sp; ++ struct task_struct *idle = idle_thread_get(cpu); ++ u64 rsp = (unsigned long)idle->thread.sp; ++ + u64 rip = (u64)&hv_vtl_ap_entry; + + native_store_gdt(&gdt_ptr); +@@ -205,7 +208,15 @@ static int hv_vtl_apicid_to_vp_id(u32 apic_id) + + static int hv_vtl_wakeup_secondary_cpu(u32 apicid, unsigned long start_eip) + { +- int vp_id; ++ int vp_id, cpu; ++ ++ /* Find the logical CPU for the APIC ID */ ++ for_each_present_cpu(cpu) { ++ if (arch_match_cpu_phys_id(cpu, apicid)) ++ break; ++ } ++ if (cpu >= nr_cpu_ids) ++ return -EINVAL; + + pr_debug("Bringing up CPU with APIC ID %d in VTL2...\n", apicid); + vp_id = hv_vtl_apicid_to_vp_id(apicid); +@@ -219,7 +230,7 @@ static int hv_vtl_wakeup_secondary_cpu(u32 apicid, unsigned long start_eip) + return -EINVAL; + } + +- return hv_vtl_bringup_vcpu(vp_id, start_eip); ++ return hv_vtl_bringup_vcpu(vp_id, cpu, start_eip); + } + + int __init hv_vtl_early_init(void) +diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h +index 3814a9263d64e..294cd2a408181 100644 +--- a/arch/x86/include/asm/io.h ++++ b/arch/x86/include/asm/io.h +@@ -379,7 +379,7 @@ static inline void iosubmit_cmds512(void __iomem *dst, const void *src, + const u8 *end = from + count * 64; + + while (from < end) { +- movdir64b(dst, from); ++ movdir64b_io(dst, from); + from += 64; + } + } +diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h +index d18e5c332cb9f..1b93ff80b43bc 100644 +--- a/arch/x86/include/asm/page.h ++++ b/arch/x86/include/asm/page.h +@@ -66,10 +66,14 @@ static inline void copy_user_page(void *to, void *from, unsigned long vaddr, + * virt_addr_valid(kaddr) returns true. + */ + #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) +-#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) + extern bool __virt_addr_valid(unsigned long kaddr); + #define virt_addr_valid(kaddr) __virt_addr_valid((unsigned long) (kaddr)) + ++static __always_inline void *pfn_to_kaddr(unsigned long pfn) ++{ ++ return __va(pfn << PAGE_SHIFT); ++} ++ + static __always_inline u64 __canonical_address(u64 vaddr, u8 vaddr_bits) + { + return ((s64)vaddr << (64 - vaddr_bits)) >> (64 - vaddr_bits); +diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h +index 48f8dd47cf688..09a5461d72439 100644 +--- a/arch/x86/include/asm/special_insns.h ++++ b/arch/x86/include/asm/special_insns.h +@@ -224,10 +224,10 @@ static inline void serialize(void) + } + + /* The dst parameter must be 64-bytes aligned */ +-static inline void movdir64b(void __iomem *dst, const void *src) ++static inline void movdir64b(void *dst, const void *src) + { + const struct { char _[64]; } *__src = src; +- struct { char _[64]; } __iomem *__dst = dst; ++ struct { char _[64]; } *__dst = dst; + + /* + * MOVDIR64B %(rdx), rax. +@@ -245,6 +245,11 @@ static inline void movdir64b(void __iomem *dst, const void *src) + : "m" (*__src), "a" (__dst), "d" (__src)); + } + ++static inline void movdir64b_io(void __iomem *dst, const void *src) ++{ ++ movdir64b((void __force *)dst, src); ++} ++ + /** + * enqcmds - Enqueue a command in supervisor (CPL0) mode + * @dst: destination, in MMIO space (must be 512-bit aligned) +diff --git a/arch/x86/kernel/acpi/cppc.c b/arch/x86/kernel/acpi/cppc.c +index 8d8752b44f113..ff8f25faca3dd 100644 +--- a/arch/x86/kernel/acpi/cppc.c ++++ b/arch/x86/kernel/acpi/cppc.c +@@ -20,7 +20,7 @@ bool cpc_supported_by_cpu(void) + (boot_cpu_data.x86_model >= 0x20 && boot_cpu_data.x86_model <= 0x2f))) + return true; + else if (boot_cpu_data.x86 == 0x17 && +- boot_cpu_data.x86_model >= 0x70 && boot_cpu_data.x86_model <= 0x7f) ++ boot_cpu_data.x86_model >= 0x30 && boot_cpu_data.x86_model <= 0x7f) + return true; + return boot_cpu_has(X86_FEATURE_CPPC); + } +diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c +index 19e0681f04356..d04371e851b4c 100644 +--- a/arch/x86/kernel/cpu/resctrl/core.c ++++ b/arch/x86/kernel/cpu/resctrl/core.c +@@ -231,9 +231,7 @@ static bool __get_mem_config_intel(struct rdt_resource *r) + static bool __rdt_get_mem_config_amd(struct rdt_resource *r) + { + struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); +- union cpuid_0x10_3_eax eax; +- union cpuid_0x10_x_edx edx; +- u32 ebx, ecx, subleaf; ++ u32 eax, ebx, ecx, edx, subleaf; + + /* + * Query CPUID_Fn80000020_EDX_x01 for MBA and +@@ -241,9 +239,9 @@ static bool __rdt_get_mem_config_amd(struct rdt_resource *r) + */ + subleaf = (r->rid == RDT_RESOURCE_SMBA) ? 2 : 1; + +- cpuid_count(0x80000020, subleaf, &eax.full, &ebx, &ecx, &edx.full); +- hw_res->num_closid = edx.split.cos_max + 1; +- r->default_ctrl = MAX_MBA_BW_AMD; ++ cpuid_count(0x80000020, subleaf, &eax, &ebx, &ecx, &edx); ++ hw_res->num_closid = edx + 1; ++ r->default_ctrl = 1 << eax; + + /* AMD does not use delay */ + r->membw.delay_linear = false; +diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h +index a4f1aa15f0a2a..52e7e7deee106 100644 +--- a/arch/x86/kernel/cpu/resctrl/internal.h ++++ b/arch/x86/kernel/cpu/resctrl/internal.h +@@ -18,7 +18,6 @@ + #define MBM_OVERFLOW_INTERVAL 1000 + #define MAX_MBA_BW 100u + #define MBA_IS_LINEAR 0x4 +-#define MAX_MBA_BW_AMD 0x800 + #define MBM_CNTR_WIDTH_OFFSET_AMD 20 + + #define RMID_VAL_ERROR BIT_ULL(63) +@@ -296,14 +295,10 @@ struct rftype { + * struct mbm_state - status for each MBM counter in each domain + * @prev_bw_bytes: Previous bytes value read for bandwidth calculation + * @prev_bw: The most recent bandwidth in MBps +- * @delta_bw: Difference between the current and previous bandwidth +- * @delta_comp: Indicates whether to compute the delta_bw + */ + struct mbm_state { + u64 prev_bw_bytes; + u32 prev_bw; +- u32 delta_bw; +- bool delta_comp; + }; + + /** +@@ -395,6 +390,8 @@ struct rdt_parse_data { + * @msr_update: Function pointer to update QOS MSRs + * @mon_scale: cqm counter * mon_scale = occupancy in bytes + * @mbm_width: Monitor width, to detect and correct for overflow. ++ * @mbm_cfg_mask: Bandwidth sources that can be tracked when Bandwidth ++ * Monitoring Event Configuration (BMEC) is supported. + * @cdp_enabled: CDP state of this resource + * + * Members of this structure are either private to the architecture +@@ -409,6 +406,7 @@ struct rdt_hw_resource { + struct rdt_resource *r); + unsigned int mon_scale; + unsigned int mbm_width; ++ unsigned int mbm_cfg_mask; + bool cdp_enabled; + }; + +diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c +index f136ac046851c..3a6c069614eb8 100644 +--- a/arch/x86/kernel/cpu/resctrl/monitor.c ++++ b/arch/x86/kernel/cpu/resctrl/monitor.c +@@ -440,9 +440,6 @@ static void mbm_bw_count(u32 rmid, struct rmid_read *rr) + + cur_bw = bytes / SZ_1M; + +- if (m->delta_comp) +- m->delta_bw = abs(cur_bw - m->prev_bw); +- m->delta_comp = false; + m->prev_bw = cur_bw; + } + +@@ -520,11 +517,11 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) + { + u32 closid, rmid, cur_msr_val, new_msr_val; + struct mbm_state *pmbm_data, *cmbm_data; +- u32 cur_bw, delta_bw, user_bw; + struct rdt_resource *r_mba; + struct rdt_domain *dom_mba; + struct list_head *head; + struct rdtgroup *entry; ++ u32 cur_bw, user_bw; + + if (!is_mbm_local_enabled()) + return; +@@ -543,7 +540,6 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) + + cur_bw = pmbm_data->prev_bw; + user_bw = dom_mba->mbps_val[closid]; +- delta_bw = pmbm_data->delta_bw; + + /* MBA resource doesn't support CDP */ + cur_msr_val = resctrl_arch_get_config(r_mba, dom_mba, closid, CDP_NONE); +@@ -555,49 +551,31 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm) + list_for_each_entry(entry, head, mon.crdtgrp_list) { + cmbm_data = &dom_mbm->mbm_local[entry->mon.rmid]; + cur_bw += cmbm_data->prev_bw; +- delta_bw += cmbm_data->delta_bw; + } + + /* + * Scale up/down the bandwidth linearly for the ctrl group. The + * bandwidth step is the bandwidth granularity specified by the + * hardware. +- * +- * The delta_bw is used when increasing the bandwidth so that we +- * dont alternately increase and decrease the control values +- * continuously. +- * +- * For ex: consider cur_bw = 90MBps, user_bw = 100MBps and if +- * bandwidth step is 20MBps(> user_bw - cur_bw), we would keep +- * switching between 90 and 110 continuously if we only check +- * cur_bw < user_bw. ++ * Always increase throttling if current bandwidth is above the ++ * target set by user. ++ * But avoid thrashing up and down on every poll by checking ++ * whether a decrease in throttling is likely to push the group ++ * back over target. E.g. if currently throttling to 30% of bandwidth ++ * on a system with 10% granularity steps, check whether moving to ++ * 40% would go past the limit by multiplying current bandwidth by ++ * "(30 + 10) / 30". + */ + if (cur_msr_val > r_mba->membw.min_bw && user_bw < cur_bw) { + new_msr_val = cur_msr_val - r_mba->membw.bw_gran; + } else if (cur_msr_val < MAX_MBA_BW && +- (user_bw > (cur_bw + delta_bw))) { ++ (user_bw > (cur_bw * (cur_msr_val + r_mba->membw.min_bw) / cur_msr_val))) { + new_msr_val = cur_msr_val + r_mba->membw.bw_gran; + } else { + return; + } + + resctrl_arch_update_one(r_mba, dom_mba, closid, CDP_NONE, new_msr_val); +- +- /* +- * Delta values are updated dynamically package wise for each +- * rdtgrp every time the throttle MSR changes value. +- * +- * This is because (1)the increase in bandwidth is not perfectly +- * linear and only "approximately" linear even when the hardware +- * says it is linear.(2)Also since MBA is a core specific +- * mechanism, the delta values vary based on number of cores used +- * by the rdtgrp. +- */ +- pmbm_data->delta_comp = true; +- list_for_each_entry(entry, head, mon.crdtgrp_list) { +- cmbm_data = &dom_mbm->mbm_local[entry->mon.rmid]; +- cmbm_data->delta_comp = true; +- } + } + + static void mbm_update(struct rdt_resource *r, struct rdt_domain *d, int rmid) +@@ -813,6 +791,12 @@ int __init rdt_get_mon_l3_config(struct rdt_resource *r) + return ret; + + if (rdt_cpu_has(X86_FEATURE_BMEC)) { ++ u32 eax, ebx, ecx, edx; ++ ++ /* Detect list of bandwidth sources that can be tracked */ ++ cpuid_count(0x80000020, 3, &eax, &ebx, &ecx, &edx); ++ hw_res->mbm_cfg_mask = ecx & MAX_EVT_CONFIG_BITS; ++ + if (rdt_cpu_has(X86_FEATURE_CQM_MBM_TOTAL)) { + mbm_total_event.configurable = true; + mbm_config_rftype_init("mbm_total_bytes_config"); +diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c +index 69a1de92384ab..2b69e560b05f1 100644 +--- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c ++++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c +@@ -1620,12 +1620,6 @@ static int mbm_config_write_domain(struct rdt_resource *r, + struct mon_config_info mon_info = {0}; + int ret = 0; + +- /* mon_config cannot be more than the supported set of events */ +- if (val > MAX_EVT_CONFIG_BITS) { +- rdt_last_cmd_puts("Invalid event configuration\n"); +- return -EINVAL; +- } +- + /* + * Read the current config value first. If both are the same then + * no need to write it again. +@@ -1663,6 +1657,7 @@ static int mbm_config_write_domain(struct rdt_resource *r, + + static int mon_config_write(struct rdt_resource *r, char *tok, u32 evtid) + { ++ struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); + char *dom_str = NULL, *id_str; + unsigned long dom_id, val; + struct rdt_domain *d; +@@ -1686,6 +1681,13 @@ static int mon_config_write(struct rdt_resource *r, char *tok, u32 evtid) + return -EINVAL; + } + ++ /* Value from user cannot be more than the supported set of events */ ++ if ((val & hw_res->mbm_cfg_mask) != val) { ++ rdt_last_cmd_printf("Invalid event configuration: max valid mask is 0x%02x\n", ++ hw_res->mbm_cfg_mask); ++ return -EINVAL; ++ } ++ + list_for_each_entry(d, &r->domains, list) { + if (d->id == dom_id) { + ret = mbm_config_write_domain(r, d, evtid, val); +diff --git a/arch/x86/mm/mem_encrypt_identity.c b/arch/x86/mm/mem_encrypt_identity.c +index d73aeb16417fc..7f72472a34d6d 100644 +--- a/arch/x86/mm/mem_encrypt_identity.c ++++ b/arch/x86/mm/mem_encrypt_identity.c +@@ -507,7 +507,6 @@ void __init sme_enable(struct boot_params *bp) + const char *cmdline_ptr, *cmdline_arg, *cmdline_on, *cmdline_off; + unsigned int eax, ebx, ecx, edx; + unsigned long feature_mask; +- bool active_by_default; + unsigned long me_mask; + char buffer[16]; + bool snp; +@@ -593,22 +592,19 @@ void __init sme_enable(struct boot_params *bp) + : "p" (sme_cmdline_off)); + + if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT)) +- active_by_default = true; +- else +- active_by_default = false; ++ sme_me_mask = me_mask; + + cmdline_ptr = (const char *)((u64)bp->hdr.cmd_line_ptr | + ((u64)bp->ext_cmd_line_ptr << 32)); + + if (cmdline_find_option(cmdline_ptr, cmdline_arg, buffer, sizeof(buffer)) < 0) +- return; ++ goto out; + + if (!strncmp(buffer, cmdline_on, sizeof(buffer))) + sme_me_mask = me_mask; + else if (!strncmp(buffer, cmdline_off, sizeof(buffer))) + sme_me_mask = 0; +- else +- sme_me_mask = active_by_default ? me_mask : 0; ++ + out: + if (sme_me_mask) { + physical_mask &= ~sme_me_mask; +diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c +index a3bae2b24626b..b029fb81ebeee 100644 +--- a/arch/x86/tools/relocs.c ++++ b/arch/x86/tools/relocs.c +@@ -653,6 +653,14 @@ static void print_absolute_relocs(void) + if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) { + continue; + } ++ /* ++ * Do not perform relocations in .notes section; any ++ * values there are meant for pre-boot consumption (e.g. ++ * startup_xen). ++ */ ++ if (sec_applies->shdr.sh_type == SHT_NOTE) { ++ continue; ++ } + sh_symtab = sec_symtab->symtab; + sym_strtab = sec_symtab->link->strtab; + for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) { +diff --git a/block/holder.c b/block/holder.c +index 37d18c13d9581..791091a7eac23 100644 +--- a/block/holder.c ++++ b/block/holder.c +@@ -8,6 +8,8 @@ struct bd_holder_disk { + int refcnt; + }; + ++static DEFINE_MUTEX(blk_holder_mutex); ++ + static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev, + struct gendisk *disk) + { +@@ -80,7 +82,7 @@ int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk) + kobject_get(bdev->bd_holder_dir); + mutex_unlock(&bdev->bd_disk->open_mutex); + +- mutex_lock(&disk->open_mutex); ++ mutex_lock(&blk_holder_mutex); + WARN_ON_ONCE(!bdev->bd_holder); + + holder = bd_find_holder_disk(bdev, disk); +@@ -108,7 +110,7 @@ int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk) + goto out_del_symlink; + list_add(&holder->list, &disk->slave_bdevs); + +- mutex_unlock(&disk->open_mutex); ++ mutex_unlock(&blk_holder_mutex); + return 0; + + out_del_symlink: +@@ -116,7 +118,7 @@ int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk) + out_free_holder: + kfree(holder); + out_unlock: +- mutex_unlock(&disk->open_mutex); ++ mutex_unlock(&blk_holder_mutex); + if (ret) + kobject_put(bdev->bd_holder_dir); + return ret; +@@ -140,7 +142,7 @@ void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk) + if (WARN_ON_ONCE(!disk->slave_dir)) + return; + +- mutex_lock(&disk->open_mutex); ++ mutex_lock(&blk_holder_mutex); + holder = bd_find_holder_disk(bdev, disk); + if (!WARN_ON_ONCE(holder == NULL) && !--holder->refcnt) { + del_symlink(disk->slave_dir, bdev_kobj(bdev)); +@@ -149,6 +151,6 @@ void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk) + list_del_init(&holder->list); + kfree(holder); + } +- mutex_unlock(&disk->open_mutex); ++ mutex_unlock(&blk_holder_mutex); + } + EXPORT_SYMBOL_GPL(bd_unlink_disk_holder); +diff --git a/crypto/Kconfig b/crypto/Kconfig +index 7d156c75f15f2..44661c2e30ca5 100644 +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -1269,10 +1269,11 @@ config CRYPTO_JITTERENTROPY + + A non-physical non-deterministic ("true") RNG (e.g., an entropy source + compliant with NIST SP800-90B) intended to provide a seed to a +- deterministic RNG (e.g. per NIST SP800-90C). ++ deterministic RNG (e.g., per NIST SP800-90C). + This RNG does not perform any cryptographic whitening of the generated ++ random numbers. + +- See https://www.chronox.de/jent.html ++ See https://www.chronox.de/jent/ + + if CRYPTO_JITTERENTROPY + if CRYPTO_FIPS && EXPERT +diff --git a/drivers/acpi/numa/hmat.c b/drivers/acpi/numa/hmat.c +index d6b85f0f6082f..a26e7793ec4ef 100644 +--- a/drivers/acpi/numa/hmat.c ++++ b/drivers/acpi/numa/hmat.c +@@ -770,12 +770,12 @@ static void __hmat_register_target_initiators(struct memory_target *target, + } + } + +-static void hmat_register_generic_target_initiators(struct memory_target *target) ++static void hmat_update_generic_target(struct memory_target *target) + { + static DECLARE_BITMAP(p_nodes, MAX_NUMNODES); + +- __hmat_register_target_initiators(target, p_nodes, +- NODE_ACCESS_CLASS_GENPORT_SINK); ++ hmat_update_target_attrs(target, p_nodes, ++ NODE_ACCESS_CLASS_GENPORT_SINK); + } + + static void hmat_register_target_initiators(struct memory_target *target) +@@ -835,7 +835,7 @@ static void hmat_register_target(struct memory_target *target) + */ + mutex_lock(&target_lock); + if (*(u16 *)target->gen_port_device_handle) { +- hmat_register_generic_target_initiators(target); ++ hmat_update_generic_target(target); + target->registered = true; + } + mutex_unlock(&target_lock); +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index 55437f5e0c3ae..bd6a7857ce058 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -1430,6 +1430,8 @@ int acpi_processor_power_exit(struct acpi_processor *pr) + acpi_processor_registered--; + if (acpi_processor_registered == 0) + cpuidle_unregister_driver(&acpi_idle_driver); ++ ++ kfree(dev); + } + + pr->flags.power_setup_done = 0; +diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c +index dacad1d846c0d..c843feb02e980 100644 +--- a/drivers/acpi/resource.c ++++ b/drivers/acpi/resource.c +@@ -588,6 +588,27 @@ static const struct dmi_system_id irq1_edge_low_force_override[] = { + DMI_MATCH(DMI_BOARD_NAME, "GM5RGEE0016COM"), + }, + }, ++ { ++ /* Lunnen Ground 15 / AMD Ryzen 5 5500U */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Lunnen"), ++ DMI_MATCH(DMI_BOARD_NAME, "LLL5DAW"), ++ }, ++ }, ++ { ++ /* Lunnen Ground 16 / AMD Ryzen 7 5800U */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Lunnen"), ++ DMI_MATCH(DMI_BOARD_NAME, "LL6FA"), ++ }, ++ }, ++ { ++ /* MAIBENBEN X577 */ ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "MAIBENBEN"), ++ DMI_MATCH(DMI_BOARD_NAME, "X577"), ++ }, ++ }, + { } + }; + +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index e6ed1ba91e5c9..617f3e0e963d5 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -314,18 +314,14 @@ static int acpi_scan_device_check(struct acpi_device *adev) + * again). + */ + if (adev->handler) { +- dev_warn(&adev->dev, "Already enumerated\n"); +- return -EALREADY; ++ dev_dbg(&adev->dev, "Already enumerated\n"); ++ return 0; + } + error = acpi_bus_scan(adev->handle); + if (error) { + dev_warn(&adev->dev, "Namespace scan failure\n"); + return error; + } +- if (!adev->handler) { +- dev_warn(&adev->dev, "Enumeration failure\n"); +- error = -ENODEV; +- } + } else { + error = acpi_scan_device_not_enumerated(adev); + } +diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c +index d7317425be510..cc9077b588d7e 100644 +--- a/drivers/block/aoe/aoecmd.c ++++ b/drivers/block/aoe/aoecmd.c +@@ -419,13 +419,16 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff_head *qu + rcu_read_lock(); + for_each_netdev_rcu(&init_net, ifp) { + dev_hold(ifp); +- if (!is_aoe_netif(ifp)) +- goto cont; ++ if (!is_aoe_netif(ifp)) { ++ dev_put(ifp); ++ continue; ++ } + + skb = new_skb(sizeof *h + sizeof *ch); + if (skb == NULL) { + printk(KERN_INFO "aoe: skb alloc failure\n"); +- goto cont; ++ dev_put(ifp); ++ continue; + } + skb_put(skb, sizeof *h + sizeof *ch); + skb->dev = ifp; +@@ -440,9 +443,6 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff_head *qu + h->major = cpu_to_be16(aoemajor); + h->minor = aoeminor; + h->cmd = AOECMD_CFG; +- +-cont: +- dev_put(ifp); + } + rcu_read_unlock(); + } +diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c +index c51ea95bc2ce4..923a134fd7665 100644 +--- a/drivers/block/aoe/aoenet.c ++++ b/drivers/block/aoe/aoenet.c +@@ -63,6 +63,7 @@ tx(int id) __must_hold(&txlock) + pr_warn("aoe: packet could not be sent on %s. %s\n", + ifp ? ifp->name : "netif", + "consider increasing tx_queue_len"); ++ dev_put(ifp); + spin_lock_irq(&txlock); + } + return 0; +diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c +index 33a8f37bb6a1f..b7c332528ed7a 100644 +--- a/drivers/block/nbd.c ++++ b/drivers/block/nbd.c +@@ -2433,6 +2433,12 @@ static int nbd_genl_status(struct sk_buff *skb, struct genl_info *info) + } + + dev_list = nla_nest_start_noflag(reply, NBD_ATTR_DEVICE_LIST); ++ if (!dev_list) { ++ nlmsg_free(reply); ++ ret = -EMSGSIZE; ++ goto out; ++ } ++ + if (index == -1) { + ret = idr_for_each(&nbd_index_idr, &status_cb, reply); + if (ret) { +diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c +index aaabb732082cd..285418dbb43f5 100644 +--- a/drivers/bluetooth/btmtk.c ++++ b/drivers/bluetooth/btmtk.c +@@ -372,8 +372,10 @@ int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb) + struct btmediatek_data *data = hci_get_priv(hdev); + int err; + +- if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) ++ if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) { ++ kfree_skb(skb); + return 0; ++ } + + switch (data->cd_info.state) { + case HCI_DEVCOREDUMP_IDLE: +diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c +index d31edad7a0560..6cb87d47ad7d5 100644 +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -3273,7 +3273,6 @@ static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb) + { + struct btusb_data *data = hci_get_drvdata(hdev); + u16 handle = le16_to_cpu(hci_acl_hdr(skb)->handle); +- struct sk_buff *skb_cd; + + switch (handle) { + case 0xfc6f: /* Firmware dump from device */ +@@ -3286,9 +3285,12 @@ static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb) + * for backward compatibility, so we have to clone the packet + * extraly for the in-kernel coredump support. + */ +- skb_cd = skb_clone(skb, GFP_ATOMIC); +- if (skb_cd) +- btmtk_process_coredump(hdev, skb_cd); ++ if (IS_ENABLED(CONFIG_DEV_COREDUMP)) { ++ struct sk_buff *skb_cd = skb_clone(skb, GFP_ATOMIC); ++ ++ if (skb_cd) ++ btmtk_process_coredump(hdev, skb_cd); ++ } + + fallthrough; + case 0x05ff: /* Firmware debug logging 1 */ +diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c +index 71e748a9477e4..c0436881a533c 100644 +--- a/drivers/bluetooth/hci_h5.c ++++ b/drivers/bluetooth/hci_h5.c +@@ -113,6 +113,7 @@ struct h5_vnd { + int (*suspend)(struct h5 *h5); + int (*resume)(struct h5 *h5); + const struct acpi_gpio_mapping *acpi_gpio_map; ++ int sizeof_priv; + }; + + struct h5_device_data { +@@ -863,7 +864,8 @@ static int h5_serdev_probe(struct serdev_device *serdev) + if (IS_ERR(h5->device_wake_gpio)) + return PTR_ERR(h5->device_wake_gpio); + +- return hci_uart_register_device(&h5->serdev_hu, &h5p); ++ return hci_uart_register_device_priv(&h5->serdev_hu, &h5p, ++ h5->vnd->sizeof_priv); + } + + static void h5_serdev_remove(struct serdev_device *serdev) +@@ -1070,6 +1072,7 @@ static struct h5_vnd rtl_vnd = { + .suspend = h5_btrtl_suspend, + .resume = h5_btrtl_resume, + .acpi_gpio_map = acpi_btrtl_gpios, ++ .sizeof_priv = sizeof(struct btrealtek_data), + }; + + static const struct h5_device_data h5_data_rtl8822cs = { +diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c +index edd2a81b4d5ed..8a60ad7acd705 100644 +--- a/drivers/bluetooth/hci_qca.c ++++ b/drivers/bluetooth/hci_qca.c +@@ -2326,7 +2326,7 @@ static int qca_serdev_probe(struct serdev_device *serdev) + + qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable", + GPIOD_OUT_LOW); +- if (IS_ERR_OR_NULL(qcadev->bt_en) && ++ if (IS_ERR(qcadev->bt_en) && + (data->soc_type == QCA_WCN6750 || + data->soc_type == QCA_WCN6855)) { + dev_err(&serdev->dev, "failed to acquire BT_EN gpio\n"); +@@ -2335,7 +2335,7 @@ static int qca_serdev_probe(struct serdev_device *serdev) + + qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl", + GPIOD_IN); +- if (IS_ERR_OR_NULL(qcadev->sw_ctrl) && ++ if (IS_ERR(qcadev->sw_ctrl) && + (data->soc_type == QCA_WCN6750 || + data->soc_type == QCA_WCN6855 || + data->soc_type == QCA_WCN7850)) +@@ -2357,7 +2357,7 @@ static int qca_serdev_probe(struct serdev_device *serdev) + default: + qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable", + GPIOD_OUT_LOW); +- if (IS_ERR_OR_NULL(qcadev->bt_en)) { ++ if (IS_ERR(qcadev->bt_en)) { + dev_warn(&serdev->dev, "failed to acquire enable gpio\n"); + power_ctrl_enabled = false; + } +diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c +index 39c8b567da3c0..214fff876eae5 100644 +--- a/drivers/bluetooth/hci_serdev.c ++++ b/drivers/bluetooth/hci_serdev.c +@@ -300,8 +300,9 @@ static const struct serdev_device_ops hci_serdev_client_ops = { + .write_wakeup = hci_uart_write_wakeup, + }; + +-int hci_uart_register_device(struct hci_uart *hu, +- const struct hci_uart_proto *p) ++int hci_uart_register_device_priv(struct hci_uart *hu, ++ const struct hci_uart_proto *p, ++ int sizeof_priv) + { + int err; + struct hci_dev *hdev; +@@ -325,7 +326,7 @@ int hci_uart_register_device(struct hci_uart *hu, + set_bit(HCI_UART_PROTO_READY, &hu->flags); + + /* Initialize and register HCI device */ +- hdev = hci_alloc_dev(); ++ hdev = hci_alloc_dev_priv(sizeof_priv); + if (!hdev) { + BT_ERR("Can't allocate HCI device"); + err = -ENOMEM; +@@ -394,7 +395,7 @@ int hci_uart_register_device(struct hci_uart *hu, + percpu_free_rwsem(&hu->proto_lock); + return err; + } +-EXPORT_SYMBOL_GPL(hci_uart_register_device); ++EXPORT_SYMBOL_GPL(hci_uart_register_device_priv); + + void hci_uart_unregister_device(struct hci_uart *hu) + { +diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h +index fb4a2d0d8cc80..68c8c7e95d64d 100644 +--- a/drivers/bluetooth/hci_uart.h ++++ b/drivers/bluetooth/hci_uart.h +@@ -97,7 +97,17 @@ struct hci_uart { + + int hci_uart_register_proto(const struct hci_uart_proto *p); + int hci_uart_unregister_proto(const struct hci_uart_proto *p); +-int hci_uart_register_device(struct hci_uart *hu, const struct hci_uart_proto *p); ++ ++int hci_uart_register_device_priv(struct hci_uart *hu, ++ const struct hci_uart_proto *p, ++ int sizeof_priv); ++ ++static inline int hci_uart_register_device(struct hci_uart *hu, ++ const struct hci_uart_proto *p) ++{ ++ return hci_uart_register_device_priv(hu, p, 0); ++} ++ + void hci_uart_unregister_device(struct hci_uart *hu); + + int hci_uart_tx_wakeup(struct hci_uart *hu); +diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig +index e6742998f372c..d5e7fa9173a16 100644 +--- a/drivers/bus/Kconfig ++++ b/drivers/bus/Kconfig +@@ -186,11 +186,12 @@ config SUNXI_RSB + + config TEGRA_ACONNECT + tristate "Tegra ACONNECT Bus Driver" +- depends on ARCH_TEGRA_210_SOC ++ depends on ARCH_TEGRA + depends on OF && PM + help + Driver for the Tegra ACONNECT bus which is used to interface with +- the devices inside the Audio Processing Engine (APE) for Tegra210. ++ the devices inside the Audio Processing Engine (APE) for ++ Tegra210 and later. + + config TEGRA_GMI + tristate "Tegra Generic Memory Interface bus driver" +diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c +index 65fc1d738bec2..65f1f6b9b5df3 100644 +--- a/drivers/bus/mhi/ep/main.c ++++ b/drivers/bus/mhi/ep/main.c +@@ -1496,7 +1496,7 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl, + mhi_cntrl->ring_item_cache = kmem_cache_create("mhi_ep_ring_item", + sizeof(struct mhi_ep_ring_item), 0, + 0, NULL); +- if (!mhi_cntrl->ev_ring_el_cache) { ++ if (!mhi_cntrl->ring_item_cache) { + ret = -ENOMEM; + goto err_destroy_tre_buf_cache; + } +diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c +index 019cf6079cecd..6d2eadefd9dc9 100644 +--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c ++++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c +@@ -639,8 +639,8 @@ static int hwicap_setup(struct platform_device *pdev, int id, + dev_set_drvdata(dev, (void *)drvdata); + + drvdata->base_address = devm_platform_ioremap_resource(pdev, 0); +- if (!drvdata->base_address) { +- retval = -ENODEV; ++ if (IS_ERR(drvdata->base_address)) { ++ retval = PTR_ERR(drvdata->base_address); + goto failed; + } + +diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c +index 2253c154a8248..20c4b28fed061 100644 +--- a/drivers/clk/clk.c ++++ b/drivers/clk/clk.c +@@ -418,6 +418,9 @@ static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index) + if (IS_ERR(hw)) + return ERR_CAST(hw); + ++ if (!hw) ++ return NULL; ++ + return hw->core; + } + +diff --git a/drivers/clk/hisilicon/clk-hi3519.c b/drivers/clk/hisilicon/clk-hi3519.c +index b871872d9960d..141b727ff60d6 100644 +--- a/drivers/clk/hisilicon/clk-hi3519.c ++++ b/drivers/clk/hisilicon/clk-hi3519.c +@@ -130,7 +130,7 @@ static void hi3519_clk_unregister(struct platform_device *pdev) + of_clk_del_provider(pdev->dev.of_node); + + hisi_clk_unregister_gate(hi3519_gate_clks, +- ARRAY_SIZE(hi3519_mux_clks), ++ ARRAY_SIZE(hi3519_gate_clks), + crg->clk_data); + hisi_clk_unregister_mux(hi3519_mux_clks, + ARRAY_SIZE(hi3519_mux_clks), +diff --git a/drivers/clk/hisilicon/clk-hi3559a.c b/drivers/clk/hisilicon/clk-hi3559a.c +index ff4ca0edce06a..4623befafaec4 100644 +--- a/drivers/clk/hisilicon/clk-hi3559a.c ++++ b/drivers/clk/hisilicon/clk-hi3559a.c +@@ -491,7 +491,6 @@ static void hisi_clk_register_pll(struct hi3559av100_pll_clock *clks, + + clk = clk_register(NULL, &p_clk->hw); + if (IS_ERR(clk)) { +- devm_kfree(dev, p_clk); + dev_err(dev, "%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; +diff --git a/drivers/clk/imx/clk-imx8mp-audiomix.c b/drivers/clk/imx/clk-imx8mp-audiomix.c +index e4300df88f1ac..55ed211a5e0b1 100644 +--- a/drivers/clk/imx/clk-imx8mp-audiomix.c ++++ b/drivers/clk/imx/clk-imx8mp-audiomix.c +@@ -18,7 +18,12 @@ + + #define CLKEN0 0x000 + #define CLKEN1 0x004 +-#define SAI_MCLK_SEL(n) (0x300 + 4 * (n)) /* n in 0..5 */ ++#define SAI1_MCLK_SEL 0x300 ++#define SAI2_MCLK_SEL 0x304 ++#define SAI3_MCLK_SEL 0x308 ++#define SAI5_MCLK_SEL 0x30C ++#define SAI6_MCLK_SEL 0x310 ++#define SAI7_MCLK_SEL 0x314 + #define PDM_SEL 0x318 + #define SAI_PLL_GNRL_CTL 0x400 + +@@ -95,13 +100,13 @@ static const struct clk_parent_data clk_imx8mp_audiomix_pll_bypass_sels[] = { + IMX8MP_CLK_AUDIOMIX_SAI##n##_MCLK1_SEL, {}, \ + clk_imx8mp_audiomix_sai##n##_mclk1_parents, \ + ARRAY_SIZE(clk_imx8mp_audiomix_sai##n##_mclk1_parents), \ +- SAI_MCLK_SEL(n), 1, 0 \ ++ SAI##n##_MCLK_SEL, 1, 0 \ + }, { \ + "sai"__stringify(n)"_mclk2_sel", \ + IMX8MP_CLK_AUDIOMIX_SAI##n##_MCLK2_SEL, {}, \ + clk_imx8mp_audiomix_sai_mclk2_parents, \ + ARRAY_SIZE(clk_imx8mp_audiomix_sai_mclk2_parents), \ +- SAI_MCLK_SEL(n), 4, 1 \ ++ SAI##n##_MCLK_SEL, 4, 1 \ + }, { \ + "sai"__stringify(n)"_ipg_cg", \ + IMX8MP_CLK_AUDIOMIX_SAI##n##_IPG, \ +diff --git a/drivers/clk/mediatek/clk-mt7622-apmixedsys.c b/drivers/clk/mediatek/clk-mt7622-apmixedsys.c +index 9cffd278e9a43..1b8f859b6b6cc 100644 +--- a/drivers/clk/mediatek/clk-mt7622-apmixedsys.c ++++ b/drivers/clk/mediatek/clk-mt7622-apmixedsys.c +@@ -127,7 +127,6 @@ static void clk_mt7622_apmixed_remove(struct platform_device *pdev) + of_clk_del_provider(node); + mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); +- mtk_free_clk_data(clk_data); + } + + static const struct of_device_id of_match_clk_mt7622_apmixed[] = { +diff --git a/drivers/clk/mediatek/clk-mt7981-topckgen.c b/drivers/clk/mediatek/clk-mt7981-topckgen.c +index 682f4ca9e89ad..493aa11d3a175 100644 +--- a/drivers/clk/mediatek/clk-mt7981-topckgen.c ++++ b/drivers/clk/mediatek/clk-mt7981-topckgen.c +@@ -357,8 +357,9 @@ static const struct mtk_mux top_muxes[] = { + MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_325M_SEL, "sgm_325m_sel", + sgm_325m_parents, 0x050, 0x054, 0x058, 8, 1, 15, + 0x1C0, 21), +- MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_REG_SEL, "sgm_reg_sel", sgm_reg_parents, +- 0x050, 0x054, 0x058, 16, 1, 23, 0x1C0, 22), ++ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SGM_REG_SEL, "sgm_reg_sel", sgm_reg_parents, ++ 0x050, 0x054, 0x058, 16, 1, 23, 0x1C0, 22, ++ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT), + MUX_GATE_CLR_SET_UPD(CLK_TOP_EIP97B_SEL, "eip97b_sel", eip97b_parents, + 0x050, 0x054, 0x058, 24, 3, 31, 0x1C0, 23), + /* CLK_CFG_6 */ +diff --git a/drivers/clk/mediatek/clk-mt8135-apmixedsys.c b/drivers/clk/mediatek/clk-mt8135-apmixedsys.c +index d1239b4b3db74..41bb2d2e2ea74 100644 +--- a/drivers/clk/mediatek/clk-mt8135-apmixedsys.c ++++ b/drivers/clk/mediatek/clk-mt8135-apmixedsys.c +@@ -59,7 +59,7 @@ static int clk_mt8135_apmixed_probe(struct platform_device *pdev) + + ret = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + if (ret) +- return ret; ++ goto free_clk_data; + + ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + if (ret) +@@ -69,6 +69,8 @@ static int clk_mt8135_apmixed_probe(struct platform_device *pdev) + + unregister_plls: + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); ++free_clk_data: ++ mtk_free_clk_data(clk_data); + + return ret; + } +diff --git a/drivers/clk/mediatek/clk-mt8183.c b/drivers/clk/mediatek/clk-mt8183.c +index 6e23461a04559..934d5a15acfc5 100644 +--- a/drivers/clk/mediatek/clk-mt8183.c ++++ b/drivers/clk/mediatek/clk-mt8183.c +@@ -790,7 +790,7 @@ static const struct mtk_gate infra_clks[] = { + /* infra_sspm_26m_self is main clock in co-processor, should not be closed in Linux. */ + GATE_INFRA3_FLAGS(CLK_INFRA_SSPM_26M_SELF, "infra_sspm_26m_self", "f_f26m_ck", 3, CLK_IS_CRITICAL), + /* infra_sspm_32k_self is main clock in co-processor, should not be closed in Linux. */ +- GATE_INFRA3_FLAGS(CLK_INFRA_SSPM_32K_SELF, "infra_sspm_32k_self", "f_f26m_ck", 4, CLK_IS_CRITICAL), ++ GATE_INFRA3_FLAGS(CLK_INFRA_SSPM_32K_SELF, "infra_sspm_32k_self", "clk32k", 4, CLK_IS_CRITICAL), + GATE_INFRA3(CLK_INFRA_UFS_AXI, "infra_ufs_axi", "axi_sel", 5), + GATE_INFRA3(CLK_INFRA_I2C6, "infra_i2c6", "i2c_sel", 6), + GATE_INFRA3(CLK_INFRA_AP_MSDC0, "infra_ap_msdc0", "msdc50_hclk_sel", 7), +diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c +index c12f81dfa6745..5f60f2bcca592 100644 +--- a/drivers/clk/meson/axg.c ++++ b/drivers/clk/meson/axg.c +@@ -2142,7 +2142,9 @@ static struct clk_regmap *const axg_clk_regmaps[] = { + &axg_vclk_input, + &axg_vclk2_input, + &axg_vclk_div, ++ &axg_vclk_div1, + &axg_vclk2_div, ++ &axg_vclk2_div1, + &axg_vclk_div2_en, + &axg_vclk_div4_en, + &axg_vclk_div6_en, +diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c +index 735adfefc3798..e792e0b130d33 100644 +--- a/drivers/clk/qcom/dispcc-sdm845.c ++++ b/drivers/clk/qcom/dispcc-sdm845.c +@@ -759,6 +759,8 @@ static struct clk_branch disp_cc_mdss_vsync_clk = { + + static struct gdsc mdss_gdsc = { + .gdscr = 0x3000, ++ .en_few_wait_val = 0x6, ++ .en_rest_wait_val = 0x5, + .pd = { + .name = "mdss_gdsc", + }, +diff --git a/drivers/clk/qcom/gcc-ipq5018.c b/drivers/clk/qcom/gcc-ipq5018.c +index 4aba47e8700d2..e2bd54826a4ce 100644 +--- a/drivers/clk/qcom/gcc-ipq5018.c ++++ b/drivers/clk/qcom/gcc-ipq5018.c +@@ -1754,7 +1754,7 @@ static struct clk_branch gcc_gmac0_sys_clk = { + .halt_check = BRANCH_HALT_DELAY, + .halt_bit = 31, + .clkr = { +- .enable_reg = 0x683190, ++ .enable_reg = 0x68190, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) { + .name = "gcc_gmac0_sys_clk", +@@ -2180,7 +2180,7 @@ static struct clk_branch gcc_pcie1_axi_s_clk = { + }; + + static struct clk_branch gcc_pcie1_pipe_clk = { +- .halt_reg = 8, ++ .halt_reg = 0x76018, + .halt_check = BRANCH_HALT_DELAY, + .halt_bit = 31, + .clkr = { +@@ -3632,7 +3632,7 @@ static const struct qcom_reset_map gcc_ipq5018_resets[] = { + [GCC_SYSTEM_NOC_BCR] = { 0x26000, 0 }, + [GCC_TCSR_BCR] = { 0x28000, 0 }, + [GCC_TLMM_BCR] = { 0x34000, 0 }, +- [GCC_UBI0_AXI_ARES] = { 0x680}, ++ [GCC_UBI0_AXI_ARES] = { 0x68010, 0 }, + [GCC_UBI0_AHB_ARES] = { 0x68010, 1 }, + [GCC_UBI0_NC_AXI_ARES] = { 0x68010, 2 }, + [GCC_UBI0_DBG_ARES] = { 0x68010, 3 }, +diff --git a/drivers/clk/qcom/reset.c b/drivers/clk/qcom/reset.c +index e45e32804d2c7..d96c96a9089f4 100644 +--- a/drivers/clk/qcom/reset.c ++++ b/drivers/clk/qcom/reset.c +@@ -22,8 +22,8 @@ static int qcom_reset(struct reset_controller_dev *rcdev, unsigned long id) + return 0; + } + +-static int +-qcom_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) ++static int qcom_reset_set_assert(struct reset_controller_dev *rcdev, ++ unsigned long id, bool assert) + { + struct qcom_reset_controller *rst; + const struct qcom_reset_map *map; +@@ -33,21 +33,22 @@ qcom_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) + map = &rst->reset_map[id]; + mask = map->bitmask ? map->bitmask : BIT(map->bit); + +- return regmap_update_bits(rst->regmap, map->reg, mask, mask); ++ regmap_update_bits(rst->regmap, map->reg, mask, assert ? mask : 0); ++ ++ /* Read back the register to ensure write completion, ignore the value */ ++ regmap_read(rst->regmap, map->reg, &mask); ++ ++ return 0; + } + +-static int +-qcom_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) ++static int qcom_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) + { +- struct qcom_reset_controller *rst; +- const struct qcom_reset_map *map; +- u32 mask; +- +- rst = to_qcom_reset_controller(rcdev); +- map = &rst->reset_map[id]; +- mask = map->bitmask ? map->bitmask : BIT(map->bit); ++ return qcom_reset_set_assert(rcdev, id, true); ++} + +- return regmap_update_bits(rst->regmap, map->reg, mask, 0); ++static int qcom_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) ++{ ++ return qcom_reset_set_assert(rcdev, id, false); + } + + const struct reset_control_ops qcom_reset_ops = { +diff --git a/drivers/clk/renesas/r8a779f0-cpg-mssr.c b/drivers/clk/renesas/r8a779f0-cpg-mssr.c +index f721835c7e212..cc06127406ab5 100644 +--- a/drivers/clk/renesas/r8a779f0-cpg-mssr.c ++++ b/drivers/clk/renesas/r8a779f0-cpg-mssr.c +@@ -161,7 +161,7 @@ static const struct mssr_mod_clk r8a779f0_mod_clks[] __initconst = { + DEF_MOD("cmt1", 911, R8A779F0_CLK_R), + DEF_MOD("cmt2", 912, R8A779F0_CLK_R), + DEF_MOD("cmt3", 913, R8A779F0_CLK_R), +- DEF_MOD("pfc0", 915, R8A779F0_CLK_CL16M), ++ DEF_MOD("pfc0", 915, R8A779F0_CLK_CPEX), + DEF_MOD("tsc", 919, R8A779F0_CLK_CL16M), + DEF_MOD("rswitch2", 1505, R8A779F0_CLK_RSW2), + DEF_MOD("ether-serdes", 1506, R8A779F0_CLK_S0D2_HSC), +diff --git a/drivers/clk/renesas/r8a779g0-cpg-mssr.c b/drivers/clk/renesas/r8a779g0-cpg-mssr.c +index 5974adcef3eda..c4b1938db76b3 100644 +--- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c ++++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c +@@ -22,7 +22,7 @@ + + enum clk_ids { + /* Core Clock Outputs exported to DT */ +- LAST_DT_CORE_CLK = R8A779G0_CLK_R, ++ LAST_DT_CORE_CLK = R8A779G0_CLK_CP, + + /* External Input Clocks */ + CLK_EXTAL, +@@ -141,6 +141,7 @@ static const struct cpg_core_clk r8a779g0_core_clks[] __initconst = { + DEF_FIXED("svd2_vip", R8A779G0_CLK_SVD2_VIP, CLK_SV_VIP, 2, 1), + DEF_FIXED("cbfusa", R8A779G0_CLK_CBFUSA, CLK_EXTAL, 2, 1), + DEF_FIXED("cpex", R8A779G0_CLK_CPEX, CLK_EXTAL, 2, 1), ++ DEF_FIXED("cp", R8A779G0_CLK_CP, CLK_EXTAL, 2, 1), + DEF_FIXED("viobus", R8A779G0_CLK_VIOBUS, CLK_VIO, 1, 1), + DEF_FIXED("viobusd2", R8A779G0_CLK_VIOBUSD2, CLK_VIO, 2, 1), + DEF_FIXED("vcbus", R8A779G0_CLK_VCBUS, CLK_VC, 1, 1), +@@ -193,7 +194,7 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = { + DEF_MOD("msi4", 622, R8A779G0_CLK_MSO), + DEF_MOD("msi5", 623, R8A779G0_CLK_MSO), + DEF_MOD("pciec0", 624, R8A779G0_CLK_S0D2_HSC), +- DEF_MOD("pscie1", 625, R8A779G0_CLK_S0D2_HSC), ++ DEF_MOD("pciec1", 625, R8A779G0_CLK_S0D2_HSC), + DEF_MOD("pwm", 628, R8A779G0_CLK_SASYNCPERD4), + DEF_MOD("rpc-if", 629, R8A779G0_CLK_RPCD2), + DEF_MOD("scif0", 702, R8A779G0_CLK_SASYNCPERD4), +@@ -232,10 +233,10 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = { + DEF_MOD("cmt1", 911, R8A779G0_CLK_R), + DEF_MOD("cmt2", 912, R8A779G0_CLK_R), + DEF_MOD("cmt3", 913, R8A779G0_CLK_R), +- DEF_MOD("pfc0", 915, R8A779G0_CLK_CL16M), +- DEF_MOD("pfc1", 916, R8A779G0_CLK_CL16M), +- DEF_MOD("pfc2", 917, R8A779G0_CLK_CL16M), +- DEF_MOD("pfc3", 918, R8A779G0_CLK_CL16M), ++ DEF_MOD("pfc0", 915, R8A779G0_CLK_CP), ++ DEF_MOD("pfc1", 916, R8A779G0_CLK_CP), ++ DEF_MOD("pfc2", 917, R8A779G0_CLK_CP), ++ DEF_MOD("pfc3", 918, R8A779G0_CLK_CP), + DEF_MOD("tsc", 919, R8A779G0_CLK_CL16M), + DEF_MOD("tsn", 2723, R8A779G0_CLK_S0D4_HSC), + DEF_MOD("ssiu", 2926, R8A779G0_CLK_S0D6_PER), +diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c +index b70bb378ab469..075ade0925d45 100644 +--- a/drivers/clk/renesas/r9a07g043-cpg.c ++++ b/drivers/clk/renesas/r9a07g043-cpg.c +@@ -138,7 +138,7 @@ static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { + DEF_FIXED("SPI1", R9A07G043_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4), + DEF_SD_MUX("SD0", R9A07G043_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_shdi, + mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), +- DEF_SD_MUX("SD1", R9A07G043_CLK_SD1, SEL_SDHI1, SEL_SDHI0_STS, sel_shdi, ++ DEF_SD_MUX("SD1", R9A07G043_CLK_SD1, SEL_SDHI1, SEL_SDHI1_STS, sel_shdi, + mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), + DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G043_CLK_SD0, 1, 4), + DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G043_CLK_SD1, 1, 4), +diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c +index 1047278c9079a..bc822b9fd7ce6 100644 +--- a/drivers/clk/renesas/r9a07g044-cpg.c ++++ b/drivers/clk/renesas/r9a07g044-cpg.c +@@ -178,7 +178,7 @@ static const struct { + DEF_FIXED("SPI1", R9A07G044_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4), + DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_shdi, + mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), +- DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, SEL_SDHI0_STS, sel_shdi, ++ DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, SEL_SDHI1_STS, sel_shdi, + mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), + DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G044_CLK_SD0, 1, 4), + DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G044_CLK_SD1, 1, 4), +diff --git a/drivers/clk/samsung/clk-exynos850.c b/drivers/clk/samsung/clk-exynos850.c +index bdc1eef7d6e54..c7b0b9751307b 100644 +--- a/drivers/clk/samsung/clk-exynos850.c ++++ b/drivers/clk/samsung/clk-exynos850.c +@@ -605,7 +605,7 @@ static const struct samsung_div_clock apm_div_clks[] __initconst = { + + static const struct samsung_gate_clock apm_gate_clks[] __initconst = { + GATE(CLK_GOUT_CLKCMU_CMGP_BUS, "gout_clkcmu_cmgp_bus", "dout_apm_bus", +- CLK_CON_GAT_CLKCMU_CMGP_BUS, 21, 0, 0), ++ CLK_CON_GAT_CLKCMU_CMGP_BUS, 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_CLKCMU_CHUB_BUS, "gout_clkcmu_chub_bus", + "mout_clkcmu_chub_bus", + CLK_CON_GAT_GATE_CLKCMU_CHUB_BUS, 21, 0, 0), +@@ -974,19 +974,19 @@ static const struct samsung_fixed_rate_clock cmgp_fixed_clks[] __initconst = { + static const struct samsung_mux_clock cmgp_mux_clks[] __initconst = { + MUX(CLK_MOUT_CMGP_ADC, "mout_cmgp_adc", mout_cmgp_adc_p, + CLK_CON_MUX_CLK_CMGP_ADC, 0, 1), +- MUX(CLK_MOUT_CMGP_USI0, "mout_cmgp_usi0", mout_cmgp_usi0_p, +- CLK_CON_MUX_MUX_CLK_CMGP_USI_CMGP0, 0, 1), +- MUX(CLK_MOUT_CMGP_USI1, "mout_cmgp_usi1", mout_cmgp_usi1_p, +- CLK_CON_MUX_MUX_CLK_CMGP_USI_CMGP1, 0, 1), ++ MUX_F(CLK_MOUT_CMGP_USI0, "mout_cmgp_usi0", mout_cmgp_usi0_p, ++ CLK_CON_MUX_MUX_CLK_CMGP_USI_CMGP0, 0, 1, CLK_SET_RATE_PARENT, 0), ++ MUX_F(CLK_MOUT_CMGP_USI1, "mout_cmgp_usi1", mout_cmgp_usi1_p, ++ CLK_CON_MUX_MUX_CLK_CMGP_USI_CMGP1, 0, 1, CLK_SET_RATE_PARENT, 0), + }; + + static const struct samsung_div_clock cmgp_div_clks[] __initconst = { + DIV(CLK_DOUT_CMGP_ADC, "dout_cmgp_adc", "gout_clkcmu_cmgp_bus", + CLK_CON_DIV_DIV_CLK_CMGP_ADC, 0, 4), +- DIV(CLK_DOUT_CMGP_USI0, "dout_cmgp_usi0", "mout_cmgp_usi0", +- CLK_CON_DIV_DIV_CLK_CMGP_USI_CMGP0, 0, 5), +- DIV(CLK_DOUT_CMGP_USI1, "dout_cmgp_usi1", "mout_cmgp_usi1", +- CLK_CON_DIV_DIV_CLK_CMGP_USI_CMGP1, 0, 5), ++ DIV_F(CLK_DOUT_CMGP_USI0, "dout_cmgp_usi0", "mout_cmgp_usi0", ++ CLK_CON_DIV_DIV_CLK_CMGP_USI_CMGP0, 0, 5, CLK_SET_RATE_PARENT, 0), ++ DIV_F(CLK_DOUT_CMGP_USI1, "dout_cmgp_usi1", "mout_cmgp_usi1", ++ CLK_CON_DIV_DIV_CLK_CMGP_USI_CMGP1, 0, 5, CLK_SET_RATE_PARENT, 0), + }; + + static const struct samsung_gate_clock cmgp_gate_clks[] __initconst = { +@@ -1001,12 +1001,12 @@ static const struct samsung_gate_clock cmgp_gate_clks[] __initconst = { + "gout_clkcmu_cmgp_bus", + CLK_CON_GAT_GOUT_CMGP_GPIO_PCLK, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_CMGP_USI0_IPCLK, "gout_cmgp_usi0_ipclk", "dout_cmgp_usi0", +- CLK_CON_GAT_GOUT_CMGP_USI_CMGP0_IPCLK, 21, 0, 0), ++ CLK_CON_GAT_GOUT_CMGP_USI_CMGP0_IPCLK, 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_CMGP_USI0_PCLK, "gout_cmgp_usi0_pclk", + "gout_clkcmu_cmgp_bus", + CLK_CON_GAT_GOUT_CMGP_USI_CMGP0_PCLK, 21, 0, 0), + GATE(CLK_GOUT_CMGP_USI1_IPCLK, "gout_cmgp_usi1_ipclk", "dout_cmgp_usi1", +- CLK_CON_GAT_GOUT_CMGP_USI_CMGP1_IPCLK, 21, 0, 0), ++ CLK_CON_GAT_GOUT_CMGP_USI_CMGP1_IPCLK, 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_CMGP_USI1_PCLK, "gout_cmgp_usi1_pclk", + "gout_clkcmu_cmgp_bus", + CLK_CON_GAT_GOUT_CMGP_USI_CMGP1_PCLK, 21, 0, 0), +@@ -1557,8 +1557,9 @@ static const struct samsung_mux_clock peri_mux_clks[] __initconst = { + mout_peri_uart_user_p, PLL_CON0_MUX_CLKCMU_PERI_UART_USER, 4, 1), + MUX(CLK_MOUT_PERI_HSI2C_USER, "mout_peri_hsi2c_user", + mout_peri_hsi2c_user_p, PLL_CON0_MUX_CLKCMU_PERI_HSI2C_USER, 4, 1), +- MUX(CLK_MOUT_PERI_SPI_USER, "mout_peri_spi_user", mout_peri_spi_user_p, +- PLL_CON0_MUX_CLKCMU_PERI_SPI_USER, 4, 1), ++ MUX_F(CLK_MOUT_PERI_SPI_USER, "mout_peri_spi_user", ++ mout_peri_spi_user_p, PLL_CON0_MUX_CLKCMU_PERI_SPI_USER, 4, 1, ++ CLK_SET_RATE_PARENT, 0), + }; + + static const struct samsung_div_clock peri_div_clks[] __initconst = { +@@ -1568,8 +1569,8 @@ static const struct samsung_div_clock peri_div_clks[] __initconst = { + CLK_CON_DIV_DIV_CLK_PERI_HSI2C_1, 0, 5), + DIV(CLK_DOUT_PERI_HSI2C2, "dout_peri_hsi2c2", "gout_peri_hsi2c2", + CLK_CON_DIV_DIV_CLK_PERI_HSI2C_2, 0, 5), +- DIV(CLK_DOUT_PERI_SPI0, "dout_peri_spi0", "mout_peri_spi_user", +- CLK_CON_DIV_DIV_CLK_PERI_SPI_0, 0, 5), ++ DIV_F(CLK_DOUT_PERI_SPI0, "dout_peri_spi0", "mout_peri_spi_user", ++ CLK_CON_DIV_DIV_CLK_PERI_SPI_0, 0, 5, CLK_SET_RATE_PARENT, 0), + }; + + static const struct samsung_gate_clock peri_gate_clks[] __initconst = { +@@ -1611,7 +1612,7 @@ static const struct samsung_gate_clock peri_gate_clks[] __initconst = { + "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_PWM_MOTOR_PCLK, 21, 0, 0), + GATE(CLK_GOUT_SPI0_IPCLK, "gout_spi0_ipclk", "dout_peri_spi0", +- CLK_CON_GAT_GOUT_PERI_SPI_0_IPCLK, 21, 0, 0), ++ CLK_CON_GAT_GOUT_PERI_SPI_0_IPCLK, 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_SPI0_PCLK, "gout_spi0_pclk", "mout_peri_bus_user", + CLK_CON_GAT_GOUT_PERI_SPI_0_PCLK, 21, 0, 0), + GATE(CLK_GOUT_SYSREG_PERI_PCLK, "gout_sysreg_peri_pclk", +diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c +index 7bdeaff2bfd68..c28d3dacf0fb2 100644 +--- a/drivers/clk/zynq/clkc.c ++++ b/drivers/clk/zynq/clkc.c +@@ -42,6 +42,7 @@ static void __iomem *zynq_clkc_base; + #define SLCR_SWDT_CLK_SEL (zynq_clkc_base + 0x204) + + #define NUM_MIO_PINS 54 ++#define CLK_NAME_LEN 16 + + #define DBG_CLK_CTRL_CLKACT_TRC BIT(0) + #define DBG_CLK_CTRL_CPU_1XCLKACT BIT(1) +@@ -215,7 +216,7 @@ static void __init zynq_clk_setup(struct device_node *np) + int i; + u32 tmp; + int ret; +- char *clk_name; ++ char clk_name[CLK_NAME_LEN]; + unsigned int fclk_enable = 0; + const char *clk_output_name[clk_max]; + const char *cpu_parents[4]; +@@ -426,12 +427,10 @@ static void __init zynq_clk_setup(struct device_node *np) + "gem1_emio_mux", CLK_SET_RATE_PARENT, + SLCR_GEM1_CLK_CTRL, 0, 0, &gem1clk_lock); + +- tmp = strlen("mio_clk_00x"); +- clk_name = kmalloc(tmp, GFP_KERNEL); + for (i = 0; i < NUM_MIO_PINS; i++) { + int idx; + +- snprintf(clk_name, tmp, "mio_clk_%2.2d", i); ++ snprintf(clk_name, CLK_NAME_LEN, "mio_clk_%2.2d", i); + idx = of_property_match_string(np, "clock-names", clk_name); + if (idx >= 0) + can_mio_mux_parents[i] = of_clk_get_parent_name(np, +@@ -439,7 +438,6 @@ static void __init zynq_clk_setup(struct device_node *np) + else + can_mio_mux_parents[i] = dummy_nm; + } +- kfree(clk_name); + clk_register_mux(NULL, "can_mux", periph_parents, 4, + CLK_SET_RATE_NO_REPARENT, SLCR_CAN_CLK_CTRL, 4, 2, 0, + &canclk_lock); +diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm +index f911606897b8d..a0ebad77666e3 100644 +--- a/drivers/cpufreq/Kconfig.arm ++++ b/drivers/cpufreq/Kconfig.arm +@@ -173,6 +173,7 @@ config ARM_QCOM_CPUFREQ_NVMEM + config ARM_QCOM_CPUFREQ_HW + tristate "QCOM CPUFreq HW driver" + depends on ARCH_QCOM || COMPILE_TEST ++ depends on COMMON_CLK + help + Support for the CPUFreq HW driver. + Some QCOM chipsets have a HW engine to offload the steps +diff --git a/drivers/cpufreq/brcmstb-avs-cpufreq.c b/drivers/cpufreq/brcmstb-avs-cpufreq.c +index 35fb3a559ea97..1a1857b0a6f48 100644 +--- a/drivers/cpufreq/brcmstb-avs-cpufreq.c ++++ b/drivers/cpufreq/brcmstb-avs-cpufreq.c +@@ -481,6 +481,8 @@ static bool brcm_avs_is_firmware_loaded(struct private_data *priv) + static unsigned int brcm_avs_cpufreq_get(unsigned int cpu) + { + struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); ++ if (!policy) ++ return 0; + struct private_data *priv = policy->driver_data; + + cpufreq_cpu_put(policy); +diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c +index 44db4f59c4cc6..7d570b44777ac 100644 +--- a/drivers/cpufreq/cpufreq.c ++++ b/drivers/cpufreq/cpufreq.c +@@ -644,14 +644,16 @@ static ssize_t store_local_boost(struct cpufreq_policy *policy, + if (policy->boost_enabled == enable) + return count; + ++ policy->boost_enabled = enable; ++ + cpus_read_lock(); + ret = cpufreq_driver->set_boost(policy, enable); + cpus_read_unlock(); + +- if (ret) ++ if (ret) { ++ policy->boost_enabled = !policy->boost_enabled; + return ret; +- +- policy->boost_enabled = enable; ++ } + + return count; + } +@@ -1419,6 +1421,9 @@ static int cpufreq_online(unsigned int cpu) + goto out_free_policy; + } + ++ /* Let the per-policy boost flag mirror the cpufreq_driver boost during init */ ++ policy->boost_enabled = cpufreq_boost_enabled() && policy_has_boost_freq(policy); ++ + /* + * The initialization has succeeded and the policy is online. + * If there is a problem with its frequency table, take it +@@ -2755,11 +2760,12 @@ int cpufreq_boost_trigger_state(int state) + + cpus_read_lock(); + for_each_active_policy(policy) { ++ policy->boost_enabled = state; + ret = cpufreq_driver->set_boost(policy, state); +- if (ret) ++ if (ret) { ++ policy->boost_enabled = !policy->boost_enabled; + goto err_reset_state; +- +- policy->boost_enabled = state; ++ } + } + cpus_read_unlock(); + +diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c +index c4d4643b6ca65..c17dc51a5a022 100644 +--- a/drivers/cpufreq/freq_table.c ++++ b/drivers/cpufreq/freq_table.c +@@ -40,7 +40,7 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, + cpufreq_for_each_valid_entry(pos, table) { + freq = pos->frequency; + +- if (!cpufreq_boost_enabled() ++ if ((!cpufreq_boost_enabled() || !policy->boost_enabled) + && (pos->flags & CPUFREQ_BOOST_FREQ)) + continue; + +diff --git a/drivers/cpufreq/mediatek-cpufreq-hw.c b/drivers/cpufreq/mediatek-cpufreq-hw.c +index d46afb3c00923..8d097dcddda47 100644 +--- a/drivers/cpufreq/mediatek-cpufreq-hw.c ++++ b/drivers/cpufreq/mediatek-cpufreq-hw.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + + #define LUT_MAX_ENTRIES 32U +@@ -300,7 +301,23 @@ static struct cpufreq_driver cpufreq_mtk_hw_driver = { + static int mtk_cpufreq_hw_driver_probe(struct platform_device *pdev) + { + const void *data; +- int ret; ++ int ret, cpu; ++ struct device *cpu_dev; ++ struct regulator *cpu_reg; ++ ++ /* Make sure that all CPU supplies are available before proceeding. */ ++ for_each_possible_cpu(cpu) { ++ cpu_dev = get_cpu_device(cpu); ++ if (!cpu_dev) ++ return dev_err_probe(&pdev->dev, -EPROBE_DEFER, ++ "Failed to get cpu%d device\n", cpu); ++ ++ cpu_reg = devm_regulator_get(cpu_dev, "cpu"); ++ if (IS_ERR(cpu_reg)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(cpu_reg), ++ "CPU%d regulator get failed\n", cpu); ++ } ++ + + data = of_device_get_match_data(&pdev->dev); + if (!data) +diff --git a/drivers/crypto/ccp/platform-access.c b/drivers/crypto/ccp/platform-access.c +index 94367bc49e35b..1b8ed33897332 100644 +--- a/drivers/crypto/ccp/platform-access.c ++++ b/drivers/crypto/ccp/platform-access.c +@@ -118,9 +118,16 @@ int psp_send_platform_access_msg(enum psp_platform_access_msg msg, + goto unlock; + } + +- /* Store the status in request header for caller to investigate */ ++ /* ++ * Read status from PSP. If status is non-zero, it indicates an error ++ * occurred during "processing" of the command. ++ * If status is zero, it indicates the command was "processed" ++ * successfully, but the result of the command is in the payload. ++ * Return both cases to the caller as -EIO to investigate. ++ */ + cmd_reg = ioread32(cmd); +- req->header.status = FIELD_GET(PSP_CMDRESP_STS, cmd_reg); ++ if (FIELD_GET(PSP_CMDRESP_STS, cmd_reg)) ++ req->header.status = FIELD_GET(PSP_CMDRESP_STS, cmd_reg); + if (req->header.status) { + ret = -EIO; + goto unlock; +diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c +index a87d29ae724fe..7909b51e97c30 100644 +--- a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c ++++ b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c +@@ -372,6 +372,13 @@ static u16 get_ring_to_svc_map(struct adf_accel_dev *accel_dev) + if (!fw_config) + return 0; + ++ /* If dcc, all rings handle compression requests */ ++ if (adf_get_service_enabled(accel_dev) == SVC_DCC) { ++ for (i = 0; i < RP_GROUP_COUNT; i++) ++ rps[i] = COMP; ++ goto set_mask; ++ } ++ + for (i = 0; i < RP_GROUP_COUNT; i++) { + switch (fw_config[i].ae_mask) { + case ADF_AE_GROUP_0: +@@ -400,6 +407,7 @@ static u16 get_ring_to_svc_map(struct adf_accel_dev *accel_dev) + } + } + ++set_mask: + ring_to_svc_map = rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_0_SHIFT | + rps[RP_GROUP_1] << ADF_CFG_SERV_RING_PAIR_1_SHIFT | + rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_2_SHIFT | +diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c +index 94a0ebb03d8c9..e171cddf6f025 100644 +--- a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c ++++ b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c +@@ -331,6 +331,13 @@ static u16 get_ring_to_svc_map(struct adf_accel_dev *accel_dev) + if (!fw_config) + return 0; + ++ /* If dcc, all rings handle compression requests */ ++ if (adf_get_service_enabled(accel_dev) == SVC_DCC) { ++ for (i = 0; i < RP_GROUP_COUNT; i++) ++ rps[i] = COMP; ++ goto set_mask; ++ } ++ + for (i = 0; i < RP_GROUP_COUNT; i++) { + switch (fw_config[i].ae_mask) { + case ADF_AE_GROUP_0: +@@ -359,6 +366,7 @@ static u16 get_ring_to_svc_map(struct adf_accel_dev *accel_dev) + } + } + ++set_mask: + ring_to_svc_map = rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_0_SHIFT | + rps[RP_GROUP_1] << ADF_CFG_SERV_RING_PAIR_1_SHIFT | + rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_2_SHIFT | +diff --git a/drivers/crypto/intel/qat/qat_common/adf_clock.c b/drivers/crypto/intel/qat/qat_common/adf_clock.c +index 01e0a389e462b..cf89f57de2a70 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_clock.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_clock.c +@@ -83,6 +83,9 @@ static int measure_clock(struct adf_accel_dev *accel_dev, u32 *frequency) + } + + delta_us = timespec_to_us(&ts3) - timespec_to_us(&ts1); ++ if (!delta_us) ++ return -EINVAL; ++ + temp = (timestamp2 - timestamp1) * ME_CLK_DIVIDER * 10; + temp = DIV_ROUND_CLOSEST_ULL(temp, delta_us); + /* +diff --git a/drivers/crypto/intel/qat/qat_common/adf_cnv_dbgfs.c b/drivers/crypto/intel/qat/qat_common/adf_cnv_dbgfs.c +index 07119c487da01..627953a72d478 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_cnv_dbgfs.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_cnv_dbgfs.c +@@ -16,7 +16,6 @@ + + #define CNV_ERR_INFO_MASK GENMASK(11, 0) + #define CNV_ERR_TYPE_MASK GENMASK(15, 12) +-#define CNV_SLICE_ERR_MASK GENMASK(7, 0) + #define CNV_SLICE_ERR_SIGN_BIT_INDEX 7 + #define CNV_DELTA_ERR_SIGN_BIT_INDEX 11 + +diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c b/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c +index 9985683056d5f..f752653ccb47e 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c +@@ -398,6 +398,9 @@ int adf_gen4_init_thd2arb_map(struct adf_accel_dev *accel_dev) + ADF_GEN4_ADMIN_ACCELENGINES; + + if (srv_id == SVC_DCC) { ++ if (ae_cnt > ICP_QAT_HW_AE_DELIMITER) ++ return -EINVAL; ++ + memcpy(thd2arb_map, thrd_to_arb_map_dcc, + array_size(sizeof(*thd2arb_map), ae_cnt)); + return 0; +diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_ras.c b/drivers/crypto/intel/qat/qat_common/adf_gen4_ras.c +index 048c246079390..2dd3772bf58a6 100644 +--- a/drivers/crypto/intel/qat/qat_common/adf_gen4_ras.c ++++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_ras.c +@@ -1007,8 +1007,7 @@ static bool adf_handle_spppar_err(struct adf_accel_dev *accel_dev, + static bool adf_handle_ssmcpppar_err(struct adf_accel_dev *accel_dev, + void __iomem *csr, u32 iastatssm) + { +- u32 reg = ADF_CSR_RD(csr, ADF_GEN4_SSMCPPERR); +- u32 bits_num = BITS_PER_REG(reg); ++ u32 reg, bits_num = BITS_PER_REG(reg); + bool reset_required = false; + unsigned long errs_bits; + u32 bit_iterator; +@@ -1106,8 +1105,7 @@ static bool adf_handle_rf_parr_err(struct adf_accel_dev *accel_dev, + static bool adf_handle_ser_err_ssmsh(struct adf_accel_dev *accel_dev, + void __iomem *csr, u32 iastatssm) + { +- u32 reg = ADF_CSR_RD(csr, ADF_GEN4_SER_ERR_SSMSH); +- u32 bits_num = BITS_PER_REG(reg); ++ u32 reg, bits_num = BITS_PER_REG(reg); + bool reset_required = false; + unsigned long errs_bits; + u32 bit_iterator; +diff --git a/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c b/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c +index bf8c0ee629175..2ba4aa22e0927 100644 +--- a/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c ++++ b/drivers/crypto/intel/qat/qat_common/qat_comp_algs.c +@@ -13,15 +13,6 @@ + #include "qat_compression.h" + #include "qat_algs_send.h" + +-#define QAT_RFC_1950_HDR_SIZE 2 +-#define QAT_RFC_1950_FOOTER_SIZE 4 +-#define QAT_RFC_1950_CM_DEFLATE 8 +-#define QAT_RFC_1950_CM_DEFLATE_CINFO_32K 7 +-#define QAT_RFC_1950_CM_MASK 0x0f +-#define QAT_RFC_1950_CM_OFFSET 4 +-#define QAT_RFC_1950_DICT_MASK 0x20 +-#define QAT_RFC_1950_COMP_HDR 0x785e +- + static DEFINE_MUTEX(algs_lock); + static unsigned int active_devs; + +diff --git a/drivers/crypto/xilinx/zynqmp-aes-gcm.c b/drivers/crypto/xilinx/zynqmp-aes-gcm.c +index 3c205324b22b6..e614057188409 100644 +--- a/drivers/crypto/xilinx/zynqmp-aes-gcm.c ++++ b/drivers/crypto/xilinx/zynqmp-aes-gcm.c +@@ -231,7 +231,10 @@ static int zynqmp_handle_aes_req(struct crypto_engine *engine, + err = zynqmp_aes_aead_cipher(areq); + } + ++ local_bh_disable(); + crypto_finalize_aead_request(engine, areq, err); ++ local_bh_enable(); ++ + return 0; + } + +diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c +index 08fd0baea7a0e..0363ca434ef45 100644 +--- a/drivers/cxl/core/cdat.c ++++ b/drivers/cxl/core/cdat.c +@@ -389,36 +389,38 @@ EXPORT_SYMBOL_NS_GPL(cxl_endpoint_parse_cdat, CXL); + static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg, + const unsigned long end) + { ++ struct acpi_cdat_sslbis_table { ++ struct acpi_cdat_header header; ++ struct acpi_cdat_sslbis sslbis_header; ++ struct acpi_cdat_sslbe entries[]; ++ } *tbl = (struct acpi_cdat_sslbis_table *)header; ++ int size = sizeof(header->cdat) + sizeof(tbl->sslbis_header); + struct acpi_cdat_sslbis *sslbis; +- int size = sizeof(header->cdat) + sizeof(*sslbis); + struct cxl_port *port = arg; + struct device *dev = &port->dev; +- struct acpi_cdat_sslbe *entry; + int remain, entries, i; + u16 len; + + len = le16_to_cpu((__force __le16)header->cdat.length); + remain = len - size; +- if (!remain || remain % sizeof(*entry) || ++ if (!remain || remain % sizeof(tbl->entries[0]) || + (unsigned long)header + len > end) { + dev_warn(dev, "Malformed SSLBIS table length: (%u)\n", len); + return -EINVAL; + } + +- /* Skip common header */ +- sslbis = (struct acpi_cdat_sslbis *)((unsigned long)header + +- sizeof(header->cdat)); +- ++ sslbis = &tbl->sslbis_header; + /* Unrecognized data type, we can skip */ + if (sslbis->data_type > ACPI_HMAT_WRITE_BANDWIDTH) + return 0; + +- entries = remain / sizeof(*entry); +- entry = (struct acpi_cdat_sslbe *)((unsigned long)header + sizeof(*sslbis)); ++ entries = remain / sizeof(tbl->entries[0]); ++ if (struct_size(tbl, entries, entries) != len) ++ return -EINVAL; + + for (i = 0; i < entries; i++) { +- u16 x = le16_to_cpu((__force __le16)entry->portx_id); +- u16 y = le16_to_cpu((__force __le16)entry->porty_id); ++ u16 x = le16_to_cpu((__force __le16)tbl->entries[i].portx_id); ++ u16 y = le16_to_cpu((__force __le16)tbl->entries[i].porty_id); + __le64 le_base; + __le16 le_val; + struct cxl_dport *dport; +@@ -448,8 +450,8 @@ static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg, + break; + } + +- le_base = (__force __le64)sslbis->entry_base_unit; +- le_val = (__force __le16)entry->latency_or_bandwidth; ++ le_base = (__force __le64)tbl->sslbis_header.entry_base_unit; ++ le_val = (__force __le16)tbl->entries[i].latency_or_bandwidth; + + if (check_mul_overflow(le64_to_cpu(le_base), + le16_to_cpu(le_val), &val)) +@@ -462,8 +464,6 @@ static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg, + sslbis->data_type, + val); + } +- +- entry++; + } + + return 0; +diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig +index e928f2ca0f1e9..002a5ec806207 100644 +--- a/drivers/dma/Kconfig ++++ b/drivers/dma/Kconfig +@@ -643,16 +643,16 @@ config TEGRA20_APB_DMA + + config TEGRA210_ADMA + tristate "NVIDIA Tegra210 ADMA support" +- depends on (ARCH_TEGRA_210_SOC || COMPILE_TEST) ++ depends on (ARCH_TEGRA || COMPILE_TEST) + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help +- Support for the NVIDIA Tegra210 ADMA controller driver. The +- DMA controller has multiple DMA channels and is used to service +- various audio clients in the Tegra210 audio processing engine +- (APE). This DMA controller transfers data from memory to +- peripheral and vice versa. It does not support memory to +- memory data transfer. ++ Support for the NVIDIA Tegra210/Tegra186/Tegra194/Tegra234 ADMA ++ controller driver. The DMA controller has multiple DMA channels ++ and is used to service various audio clients in the Tegra210 ++ audio processing engine (APE). This DMA controller transfers ++ data from memory to peripheral and vice versa. It does not ++ support memory to memory data transfer. + + config TIMB_DMA + tristate "Timberdale FPGA DMA support" +diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c +index 7f686d179fc93..c751a87c7a8e6 100644 +--- a/drivers/dpll/dpll_core.c ++++ b/drivers/dpll/dpll_core.c +@@ -129,9 +129,9 @@ static int dpll_xa_ref_pin_del(struct xarray *xa_pins, struct dpll_pin *pin, + reg = dpll_pin_registration_find(ref, ops, priv); + if (WARN_ON(!reg)) + return -EINVAL; ++ list_del(®->list); ++ kfree(reg); + if (refcount_dec_and_test(&ref->refcount)) { +- list_del(®->list); +- kfree(reg); + xa_erase(xa_pins, i); + WARN_ON(!list_empty(&ref->registration_list)); + kfree(ref); +@@ -209,9 +209,9 @@ dpll_xa_ref_dpll_del(struct xarray *xa_dplls, struct dpll_device *dpll, + reg = dpll_pin_registration_find(ref, ops, priv); + if (WARN_ON(!reg)) + return; ++ list_del(®->list); ++ kfree(reg); + if (refcount_dec_and_test(&ref->refcount)) { +- list_del(®->list); +- kfree(reg); + xa_erase(xa_dplls, i); + WARN_ON(!list_empty(&ref->registration_list)); + kfree(ref); +diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c +index 7611e9665038d..39936e1dd30e9 100644 +--- a/drivers/firmware/arm_scmi/smc.c ++++ b/drivers/firmware/arm_scmi/smc.c +@@ -214,6 +214,13 @@ static int smc_chan_free(int id, void *p, void *data) + struct scmi_chan_info *cinfo = p; + struct scmi_smc *scmi_info = cinfo->transport_info; + ++ /* ++ * Different protocols might share the same chan info, so a previous ++ * smc_chan_free call might have already freed the structure. ++ */ ++ if (!scmi_info) ++ return 0; ++ + /* Ignore any possible further reception on the IRQ path */ + if (scmi_info->irq > 0) + free_irq(scmi_info->irq, scmi_info); +diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c +index 99429bc4b0c7e..c9857ee3880c2 100644 +--- a/drivers/firmware/efi/libstub/x86-stub.c ++++ b/drivers/firmware/efi/libstub/x86-stub.c +@@ -21,6 +21,8 @@ + #include "efistub.h" + #include "x86-stub.h" + ++extern char _bss[], _ebss[]; ++ + const efi_system_table_t *efi_system_table; + const efi_dxe_services_table_t *efi_dxe_table; + static efi_loaded_image_t *image = NULL; +@@ -465,6 +467,9 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, + efi_status_t status; + char *cmdline_ptr; + ++ if (efi_is_native()) ++ memset(_bss, 0, _ebss - _bss); ++ + efi_system_table = sys_table_arg; + + /* Check if we were booted by the EFI firmware */ +@@ -958,8 +963,6 @@ void __noreturn efi_stub_entry(efi_handle_t handle, + void efi_handover_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg, + struct boot_params *boot_params) + { +- extern char _bss[], _ebss[]; +- + memset(_bss, 0, _ebss - _bss); + efi_stub_entry(handle, sys_table_arg, boot_params); + } +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig +index 1301cec94f128..353af1a4d0ace 100644 +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -711,7 +711,8 @@ config GPIO_UNIPHIER + Say yes here to support UniPhier GPIOs. + + config GPIO_VF610 +- def_bool y ++ bool "VF610 GPIO support" ++ default y if SOC_VF610 + depends on ARCH_MXC + select GPIOLIB_IRQCHIP + help +diff --git a/drivers/gpio/gpiolib-devres.c b/drivers/gpio/gpiolib-devres.c +index fe9ce6b19f15c..4987e62dcb3d1 100644 +--- a/drivers/gpio/gpiolib-devres.c ++++ b/drivers/gpio/gpiolib-devres.c +@@ -158,7 +158,7 @@ struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, + if (!dr) + return ERR_PTR(-ENOMEM); + +- desc = fwnode_gpiod_get_index(fwnode, con_id, index, flags, label); ++ desc = gpiod_find_and_request(dev, fwnode, con_id, index, flags, label, false); + if (IS_ERR(desc)) { + devres_free(dr); + return desc; +diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c +index 75be4a3ca7f84..3ad09d2193330 100644 +--- a/drivers/gpio/gpiolib.c ++++ b/drivers/gpio/gpiolib.c +@@ -4138,13 +4138,13 @@ static struct gpio_desc *gpiod_find_by_fwnode(struct fwnode_handle *fwnode, + return desc; + } + +-static struct gpio_desc *gpiod_find_and_request(struct device *consumer, +- struct fwnode_handle *fwnode, +- const char *con_id, +- unsigned int idx, +- enum gpiod_flags flags, +- const char *label, +- bool platform_lookup_allowed) ++struct gpio_desc *gpiod_find_and_request(struct device *consumer, ++ struct fwnode_handle *fwnode, ++ const char *con_id, ++ unsigned int idx, ++ enum gpiod_flags flags, ++ const char *label, ++ bool platform_lookup_allowed) + { + unsigned long lookupflags = GPIO_LOOKUP_FLAGS_DEFAULT; + struct gpio_desc *desc; +diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h +index a4a2520b5f31c..c6e5fb9aa2122 100644 +--- a/drivers/gpio/gpiolib.h ++++ b/drivers/gpio/gpiolib.h +@@ -202,6 +202,14 @@ static inline int gpiod_request_user(struct gpio_desc *desc, const char *label) + return ret; + } + ++struct gpio_desc *gpiod_find_and_request(struct device *consumer, ++ struct fwnode_handle *fwnode, ++ const char *con_id, ++ unsigned int idx, ++ enum gpiod_flags flags, ++ const char *label, ++ bool platform_lookup_allowed); ++ + int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, + unsigned long lflags, enum gpiod_flags dflags); + int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +index c7d60dd0fb975..4f9900779ef9e 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +@@ -1278,11 +1278,10 @@ static int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev) + * 0b10 : encode is disabled + * 0b01 : decode is disabled + */ +- adev->vcn.vcn_config[adev->vcn.num_vcn_inst] = +- ip->revision & 0xc0; +- ip->revision &= ~0xc0; + if (adev->vcn.num_vcn_inst < + AMDGPU_MAX_VCN_INSTANCES) { ++ adev->vcn.vcn_config[adev->vcn.num_vcn_inst] = ++ ip->revision & 0xc0; + adev->vcn.num_vcn_inst++; + adev->vcn.inst_mask |= + (1U << ip->instance_number); +@@ -1293,6 +1292,7 @@ static int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev) + adev->vcn.num_vcn_inst + 1, + AMDGPU_MAX_VCN_INSTANCES); + } ++ ip->revision &= ~0xc0; + } + if (le16_to_cpu(ip->hw_id) == SDMA0_HWID || + le16_to_cpu(ip->hw_id) == SDMA1_HWID || +diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/amdgpu/atom.c +index a33e890c70d90..ac51d19b518ca 100644 +--- a/drivers/gpu/drm/amd/amdgpu/atom.c ++++ b/drivers/gpu/drm/amd/amdgpu/atom.c +@@ -313,7 +313,7 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, + DEBUG("IMM 0x%02X\n", val); + return val; + } +- return 0; ++ break; + case ATOM_ARG_PLL: + idx = U8(*ptr); + (*ptr)++; +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +index c9c653cfc765b..3f1692194b7ad 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +@@ -570,6 +570,7 @@ static void gmc_v11_0_set_mmhub_funcs(struct amdgpu_device *adev) + adev->mmhub.funcs = &mmhub_v3_0_2_funcs; + break; + case IP_VERSION(3, 3, 0): ++ case IP_VERSION(3, 3, 1): + adev->mmhub.funcs = &mmhub_v3_3_funcs; + break; + default: +diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_3.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_3.c +index dc4812ecc98d6..238ea40c24500 100644 +--- a/drivers/gpu/drm/amd/amdgpu/mmhub_v3_3.c ++++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v3_3.c +@@ -98,16 +98,16 @@ mmhub_v3_3_print_l2_protection_fault_status(struct amdgpu_device *adev, + + switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) { + case IP_VERSION(3, 3, 0): +- mmhub_cid = mmhub_client_ids_v3_3[cid][rw]; ++ case IP_VERSION(3, 3, 1): ++ mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_v3_3) ? ++ mmhub_client_ids_v3_3[cid][rw] : ++ cid == 0x140 ? "UMSCH" : NULL; + break; + default: + mmhub_cid = NULL; + break; + } + +- if (!mmhub_cid && cid == 0x140) +- mmhub_cid = "UMSCH"; +- + dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n", + mmhub_cid ? mmhub_cid : "unknown", cid); + dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n", +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +index 2d688dca26bed..45a67a77455ee 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +@@ -429,16 +429,11 @@ static void sdma_v4_4_2_inst_gfx_stop(struct amdgpu_device *adev, + struct amdgpu_ring *sdma[AMDGPU_MAX_SDMA_INSTANCES]; + u32 doorbell_offset, doorbell; + u32 rb_cntl, ib_cntl; +- int i, unset = 0; ++ int i; + + for_each_inst(i, inst_mask) { + sdma[i] = &adev->sdma.instance[i].ring; + +- if ((adev->mman.buffer_funcs_ring == sdma[i]) && unset != 1) { +- amdgpu_ttm_set_buffer_funcs_status(adev, false); +- unset = 1; +- } +- + rb_cntl = RREG32_SDMA(i, regSDMA_GFX_RB_CNTL); + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA_GFX_RB_CNTL, RB_ENABLE, 0); + WREG32_SDMA(i, regSDMA_GFX_RB_CNTL, rb_cntl); +@@ -485,20 +480,10 @@ static void sdma_v4_4_2_inst_rlc_stop(struct amdgpu_device *adev, + static void sdma_v4_4_2_inst_page_stop(struct amdgpu_device *adev, + uint32_t inst_mask) + { +- struct amdgpu_ring *sdma[AMDGPU_MAX_SDMA_INSTANCES]; + u32 rb_cntl, ib_cntl; + int i; +- bool unset = false; + + for_each_inst(i, inst_mask) { +- sdma[i] = &adev->sdma.instance[i].page; +- +- if ((adev->mman.buffer_funcs_ring == sdma[i]) && +- (!unset)) { +- amdgpu_ttm_set_buffer_funcs_status(adev, false); +- unset = true; +- } +- + rb_cntl = RREG32_SDMA(i, regSDMA_PAGE_RB_CNTL); + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA_PAGE_RB_CNTL, + RB_ENABLE, 0); +@@ -948,13 +933,7 @@ static int sdma_v4_4_2_inst_start(struct amdgpu_device *adev, + r = amdgpu_ring_test_helper(page); + if (r) + return r; +- +- if (adev->mman.buffer_funcs_ring == page) +- amdgpu_ttm_set_buffer_funcs_status(adev, true); + } +- +- if (adev->mman.buffer_funcs_ring == ring) +- amdgpu_ttm_set_buffer_funcs_status(adev, true); + } + + return r; +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +index 1a9bbb04bd5e2..8083e7156afcf 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -1929,17 +1929,15 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev) + adev->dm.hdcp_workqueue = NULL; + } + +- if (adev->dm.dc) ++ if (adev->dm.dc) { + dc_deinit_callbacks(adev->dm.dc); +- +- if (adev->dm.dc) + dc_dmub_srv_destroy(&adev->dm.dc->ctx->dmub_srv); +- +- if (dc_enable_dmub_notifications(adev->dm.dc)) { +- kfree(adev->dm.dmub_notify); +- adev->dm.dmub_notify = NULL; +- destroy_workqueue(adev->dm.delayed_hpd_wq); +- adev->dm.delayed_hpd_wq = NULL; ++ if (dc_enable_dmub_notifications(adev->dm.dc)) { ++ kfree(adev->dm.dmub_notify); ++ adev->dm.dmub_notify = NULL; ++ destroy_workqueue(adev->dm.delayed_hpd_wq); ++ adev->dm.delayed_hpd_wq = NULL; ++ } + } + + if (adev->dm.dmub_bo) +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +index 68a8463239127..85fc6181303bb 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +@@ -1483,7 +1483,7 @@ static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf, + const uint32_t rd_buf_size = 10; + struct pipe_ctx *pipe_ctx; + ssize_t result = 0; +- int i, r, str_len = 30; ++ int i, r, str_len = 10; + + rd_buf = kcalloc(rd_buf_size, sizeof(char), GFP_KERNEL); + +diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c +index 6dd479e8a3485..f614bc2806d86 100644 +--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c ++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c +@@ -1840,6 +1840,9 @@ bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + { + struct dpp *dpp = pipe_ctx->plane_res.dpp; + ++ if (!stream) ++ return false; ++ + if (dpp == NULL) + return false; + +@@ -1862,8 +1865,8 @@ bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx, + } else + dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_BYPASS); + +- if (stream != NULL && stream->ctx != NULL && +- stream->out_transfer_func != NULL) { ++ if (stream->ctx && ++ stream->out_transfer_func) { + log_tf(stream->ctx, + stream->out_transfer_func, + dpp->regamma_params.hw_points_num); +diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +index 046d3e2054153..f1489f4a40c12 100644 +--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c ++++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +@@ -892,7 +892,8 @@ bool edp_set_replay_allow_active(struct dc_link *link, const bool *allow_active, + + /* Set power optimization flag */ + if (power_opts && link->replay_settings.replay_power_opt_active != *power_opts) { +- if (link->replay_settings.replay_feature_enabled && replay->funcs->replay_set_power_opt) { ++ if (replay != NULL && link->replay_settings.replay_feature_enabled && ++ replay->funcs->replay_set_power_opt) { + replay->funcs->replay_set_power_opt(replay, *power_opts, panel_inst); + link->replay_settings.replay_power_opt_active = *power_opts; + } +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +index bcad42534da46..1d96eb274d72d 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +@@ -2272,8 +2272,8 @@ static uint16_t arcturus_get_current_pcie_link_speed(struct smu_context *smu) + + /* TODO: confirm this on real target */ + esm_ctrl = RREG32_PCIE(smnPCIE_ESM_CTRL); +- if ((esm_ctrl >> 15) & 0x1FFFF) +- return (uint16_t)(((esm_ctrl >> 8) & 0x3F) + 128); ++ if ((esm_ctrl >> 15) & 0x1) ++ return (uint16_t)(((esm_ctrl >> 8) & 0x7F) + 128); + + return smu_v11_0_get_current_pcie_link_speed(smu); + } +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +index dd9bcbd630a1f..ca0d5a5b204ad 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +@@ -1682,8 +1682,8 @@ static int aldebaran_get_current_pcie_link_speed(struct smu_context *smu) + + /* TODO: confirm this on real target */ + esm_ctrl = RREG32_PCIE(smnPCIE_ESM_CTRL); +- if ((esm_ctrl >> 15) & 0x1FFFF) +- return (((esm_ctrl >> 8) & 0x3F) + 128); ++ if ((esm_ctrl >> 15) & 0x1) ++ return (((esm_ctrl >> 8) & 0x7F) + 128); + + return smu_v13_0_get_current_pcie_link_speed(smu); + } +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +index 7e1941cf17964..78491b04df108 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +@@ -2060,8 +2060,8 @@ static int smu_v13_0_6_get_current_pcie_link_speed(struct smu_context *smu) + + /* TODO: confirm this on real target */ + esm_ctrl = RREG32_PCIE(smnPCIE_ESM_CTRL); +- if ((esm_ctrl >> 15) & 0x1FFFF) +- return (((esm_ctrl >> 8) & 0x3F) + 128); ++ if ((esm_ctrl >> 15) & 0x1) ++ return (((esm_ctrl >> 8) & 0x7F) + 128); + + speed_level = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) & + PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) +diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +index 8be235144f6d9..6fc292393c674 100644 +--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c ++++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +@@ -1277,17 +1277,6 @@ static int adv7511_probe(struct i2c_client *i2c) + + INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work); + +- if (i2c->irq) { +- init_waitqueue_head(&adv7511->wq); +- +- ret = devm_request_threaded_irq(dev, i2c->irq, NULL, +- adv7511_irq_handler, +- IRQF_ONESHOT, dev_name(dev), +- adv7511); +- if (ret) +- goto err_unregister_cec; +- } +- + adv7511_power_off(adv7511); + + i2c_set_clientdata(i2c, adv7511); +@@ -1311,6 +1300,17 @@ static int adv7511_probe(struct i2c_client *i2c) + + adv7511_audio_init(dev, adv7511); + ++ if (i2c->irq) { ++ init_waitqueue_head(&adv7511->wq); ++ ++ ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ++ adv7511_irq_handler, ++ IRQF_ONESHOT, dev_name(dev), ++ adv7511); ++ if (ret) ++ goto err_unregister_audio; ++ } ++ + if (adv7511->info->has_dsi) { + ret = adv7533_attach_dsi(adv7511); + if (ret) +diff --git a/drivers/gpu/drm/ci/test.yml b/drivers/gpu/drm/ci/test.yml +index 2c9a1838e7284..5e1c727640c40 100644 +--- a/drivers/gpu/drm/ci/test.yml ++++ b/drivers/gpu/drm/ci/test.yml +@@ -104,7 +104,10 @@ msm:apq8016: + DRIVER_NAME: msm + BM_DTB: https://${PIPELINE_ARTIFACTS_BASE}/arm64/apq8016-sbc-usb-host.dtb + GPU_VERSION: apq8016 +- BM_CMDLINE: "ip=dhcp console=ttyMSM0,115200n8 $BM_KERNEL_EXTRA_ARGS root=/dev/nfs rw nfsrootdebug nfsroot=,tcp,nfsvers=4.2 init=/init $BM_KERNELARGS" ++ # disabling unused clocks congests with the MDSS runtime PM trying to ++ # disable those clocks and causes boot to fail. ++ # Reproducer: DRM_MSM=y, DRM_I2C_ADV7511=m ++ BM_KERNEL_EXTRA_ARGS: clk_ignore_unused + RUNNER_TAG: google-freedreno-db410c + script: + - ./install/bare-metal/fastboot.sh +diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c +index 4f9736e5f929b..7ea244d876ca6 100644 +--- a/drivers/gpu/drm/lima/lima_gem.c ++++ b/drivers/gpu/drm/lima/lima_gem.c +@@ -75,29 +75,34 @@ int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm) + } else { + bo->base.sgt = kmalloc(sizeof(*bo->base.sgt), GFP_KERNEL); + if (!bo->base.sgt) { +- sg_free_table(&sgt); +- return -ENOMEM; ++ ret = -ENOMEM; ++ goto err_out0; + } + } + + ret = dma_map_sgtable(dev, &sgt, DMA_BIDIRECTIONAL, 0); +- if (ret) { +- sg_free_table(&sgt); +- kfree(bo->base.sgt); +- bo->base.sgt = NULL; +- return ret; +- } ++ if (ret) ++ goto err_out1; + + *bo->base.sgt = sgt; + + if (vm) { + ret = lima_vm_map_bo(vm, bo, old_size >> PAGE_SHIFT); + if (ret) +- return ret; ++ goto err_out2; + } + + bo->heap_size = new_size; + return 0; ++ ++err_out2: ++ dma_unmap_sgtable(dev, &sgt, DMA_BIDIRECTIONAL, 0); ++err_out1: ++ kfree(bo->base.sgt); ++ bo->base.sgt = NULL; ++err_out0: ++ sg_free_table(&sgt); ++ return ret; + } + + int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file, +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +index c729af3b98224..3d17de34d72bd 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +@@ -95,11 +95,13 @@ static void mtk_drm_crtc_finish_page_flip(struct mtk_drm_crtc *mtk_crtc) + struct drm_crtc *crtc = &mtk_crtc->base; + unsigned long flags; + +- spin_lock_irqsave(&crtc->dev->event_lock, flags); +- drm_crtc_send_vblank_event(crtc, mtk_crtc->event); +- drm_crtc_vblank_put(crtc); +- mtk_crtc->event = NULL; +- spin_unlock_irqrestore(&crtc->dev->event_lock, flags); ++ if (mtk_crtc->event) { ++ spin_lock_irqsave(&crtc->dev->event_lock, flags); ++ drm_crtc_send_vblank_event(crtc, mtk_crtc->event); ++ drm_crtc_vblank_put(crtc); ++ mtk_crtc->event = NULL; ++ spin_unlock_irqrestore(&crtc->dev->event_lock, flags); ++ } + } + + static void mtk_drm_finish_page_flip(struct mtk_drm_crtc *mtk_crtc) +diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c +index a2fdfc8ddb153..cd19885ee017f 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dsi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dsi.c +@@ -71,8 +71,8 @@ + #define DSI_PS_WC 0x3fff + #define DSI_PS_SEL (3 << 16) + #define PACKED_PS_16BIT_RGB565 (0 << 16) +-#define LOOSELY_PS_18BIT_RGB666 (1 << 16) +-#define PACKED_PS_18BIT_RGB666 (2 << 16) ++#define PACKED_PS_18BIT_RGB666 (1 << 16) ++#define LOOSELY_PS_24BIT_RGB666 (2 << 16) + #define PACKED_PS_24BIT_RGB888 (3 << 16) + + #define DSI_VSA_NL 0x20 +@@ -369,10 +369,10 @@ static void mtk_dsi_ps_control_vact(struct mtk_dsi *dsi) + ps_bpp_mode |= PACKED_PS_24BIT_RGB888; + break; + case MIPI_DSI_FMT_RGB666: +- ps_bpp_mode |= PACKED_PS_18BIT_RGB666; ++ ps_bpp_mode |= LOOSELY_PS_24BIT_RGB666; + break; + case MIPI_DSI_FMT_RGB666_PACKED: +- ps_bpp_mode |= LOOSELY_PS_18BIT_RGB666; ++ ps_bpp_mode |= PACKED_PS_18BIT_RGB666; + break; + case MIPI_DSI_FMT_RGB565: + ps_bpp_mode |= PACKED_PS_16BIT_RGB565; +@@ -426,7 +426,7 @@ static void mtk_dsi_ps_control(struct mtk_dsi *dsi) + dsi_tmp_buf_bpp = 3; + break; + case MIPI_DSI_FMT_RGB666: +- tmp_reg = LOOSELY_PS_18BIT_RGB666; ++ tmp_reg = LOOSELY_PS_24BIT_RGB666; + dsi_tmp_buf_bpp = 3; + break; + case MIPI_DSI_FMT_RGB666_PACKED: +diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +index c9c55e2ea5849..fd60e49b8ec4d 100644 +--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c ++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +@@ -1292,9 +1292,8 @@ static void a6xx_calc_ubwc_config(struct adreno_gpu *gpu) + gpu->ubwc_config.ubwc_mode = 1; + } + +- /* a618 is using the hw default values */ + if (adreno_is_a618(gpu)) +- return; ++ gpu->ubwc_config.highest_bank_bit = 14; + + if (adreno_is_a619_holi(gpu)) + gpu->ubwc_config.highest_bank_bit = 13; +@@ -2427,7 +2426,7 @@ static int a6xx_gmu_pm_resume(struct msm_gpu *gpu) + + msm_devfreq_resume(gpu); + +- adreno_is_a7xx(adreno_gpu) ? a7xx_llc_activate : a6xx_llc_activate(a6xx_gpu); ++ adreno_is_a7xx(adreno_gpu) ? a7xx_llc_activate(a6xx_gpu) : a6xx_llc_activate(a6xx_gpu); + + return ret; + } +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +index 6a4b489d44e51..aca689314ccea 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +@@ -226,6 +226,13 @@ bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc) + return dpu_enc->wide_bus_en; + } + ++bool dpu_encoder_is_dsc_enabled(const struct drm_encoder *drm_enc) ++{ ++ const struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); ++ ++ return dpu_enc->dsc ? true : false; ++} ++ + int dpu_encoder_get_crc_values_cnt(const struct drm_encoder *drm_enc) + { + struct dpu_encoder_virt *dpu_enc; +@@ -1853,7 +1860,9 @@ static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc, + dsc_common_mode = 0; + pic_width = dsc->pic_width; + +- dsc_common_mode = DSC_MODE_MULTIPLEX | DSC_MODE_SPLIT_PANEL; ++ dsc_common_mode = DSC_MODE_SPLIT_PANEL; ++ if (dpu_encoder_use_dsc_merge(enc_master->parent)) ++ dsc_common_mode |= DSC_MODE_MULTIPLEX; + if (enc_master->intf_mode == INTF_MODE_VIDEO) + dsc_common_mode |= DSC_MODE_VIDEO; + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +index 4c05fd5e9ed18..fe6b1d312a742 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +@@ -158,6 +158,13 @@ int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc); + + bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc); + ++/** ++ * dpu_encoder_is_dsc_enabled - indicate whether dsc is enabled ++ * for the encoder. ++ * @drm_enc: Pointer to previously created drm encoder structure ++ */ ++bool dpu_encoder_is_dsc_enabled(const struct drm_encoder *drm_enc); ++ + /** + * dpu_encoder_get_crc_values_cnt - get number of physical encoders contained + * in virtual encoder that can collect CRC values +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +index d0f56c5c4cce9..f02411b062c4c 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +@@ -102,6 +102,7 @@ static void drm_mode_to_intf_timing_params( + } + + timing->wide_bus_en = dpu_encoder_is_widebus_enabled(phys_enc->parent); ++ timing->compression_en = dpu_encoder_is_dsc_enabled(phys_enc->parent); + + /* + * for DP, divide the horizonal parameters by 2 when +@@ -259,12 +260,14 @@ static void dpu_encoder_phys_vid_setup_timing_engine( + mode.htotal >>= 1; + mode.hsync_start >>= 1; + mode.hsync_end >>= 1; ++ mode.hskew >>= 1; + + DPU_DEBUG_VIDENC(phys_enc, +- "split_role %d, halve horizontal %d %d %d %d\n", ++ "split_role %d, halve horizontal %d %d %d %d %d\n", + phys_enc->split_role, + mode.hdisplay, mode.htotal, +- mode.hsync_start, mode.hsync_end); ++ mode.hsync_start, mode.hsync_end, ++ mode.hskew); + } + + drm_mode_to_intf_timing_params(phys_enc, &mode, &timing_params); +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c +index e9cdc7934a499..9016b3ade6bc3 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c +@@ -186,7 +186,7 @@ static int dpu_hw_cdm_enable(struct dpu_hw_cdm *ctx, struct dpu_hw_cdm_cfg *cdm) + dpu_hw_cdm_setup_cdwn(ctx, cdm); + + if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) { +- if (fmt->chroma_sample != DPU_CHROMA_H1V2) ++ if (fmt->chroma_sample == DPU_CHROMA_H1V2) + return -EINVAL; /*unsupported format */ + opmode = CDM_HDMI_PACK_OP_MODE_EN; + opmode |= (fmt->chroma_sample << 1); +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +index 6bba531d6dc41..965692ef7892c 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +@@ -163,13 +163,8 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx, + hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width; + display_hctl = (hsync_end_x << 16) | hsync_start_x; + +- /* +- * DATA_HCTL_EN controls data timing which can be different from +- * video timing. It is recommended to enable it for all cases, except +- * if compression is enabled in 1 pixel per clock mode +- */ + if (p->wide_bus_en) +- intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN | INTF_CFG2_DATA_HCTL_EN; ++ intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN; + + data_width = p->width; + +@@ -229,6 +224,14 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx, + DPU_REG_WRITE(c, INTF_CONFIG, intf_cfg); + DPU_REG_WRITE(c, INTF_PANEL_FORMAT, panel_format); + if (ctx->cap->features & BIT(DPU_DATA_HCTL_EN)) { ++ /* ++ * DATA_HCTL_EN controls data timing which can be different from ++ * video timing. It is recommended to enable it for all cases, except ++ * if compression is enabled in 1 pixel per clock mode ++ */ ++ if (!(p->compression_en && !p->wide_bus_en)) ++ intf_cfg2 |= INTF_CFG2_DATA_HCTL_EN; ++ + DPU_REG_WRITE(c, INTF_CONFIG2, intf_cfg2); + DPU_REG_WRITE(c, INTF_DISPLAY_DATA_HCTL, display_data_hctl); + DPU_REG_WRITE(c, INTF_ACTIVE_DATA_HCTL, active_data_hctl); +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +index 0bd57a32144a6..6f4c87244f944 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +@@ -33,6 +33,7 @@ struct dpu_hw_intf_timing_params { + u32 hsync_skew; + + bool wide_bus_en; ++ bool compression_en; + }; + + struct dpu_hw_intf_prog_fetch { +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +index 723cc1d821431..2330eb2a4e9c8 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +@@ -374,6 +374,12 @@ static int dpu_kms_global_obj_init(struct dpu_kms *dpu_kms) + return 0; + } + ++static void dpu_kms_global_obj_fini(struct dpu_kms *dpu_kms) ++{ ++ drm_atomic_private_obj_fini(&dpu_kms->global_state); ++ drm_modeset_lock_fini(&dpu_kms->global_state_lock); ++} ++ + static int dpu_kms_parse_data_bus_icc_path(struct dpu_kms *dpu_kms) + { + struct icc_path *path0; +@@ -801,6 +807,8 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) + dpu_kms->hw_vbif[i] = NULL; + } + ++ dpu_kms_global_obj_fini(dpu_kms); ++ + dpu_kms->catalog = NULL; + + dpu_kms->hw_mdp = NULL; +diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c +index 00cc7d1abaa39..5d8ee17295424 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_bo.c ++++ b/drivers/gpu/drm/nouveau/nouveau_bo.c +@@ -1264,6 +1264,8 @@ nouveau_ttm_io_mem_reserve(struct ttm_device *bdev, struct ttm_resource *reg) + drm_vma_node_unmap(&nvbo->bo.base.vma_node, + bdev->dev_mapping); + nouveau_ttm_io_mem_free_locked(drm, nvbo->bo.resource); ++ nvbo->bo.resource->bus.offset = 0; ++ nvbo->bo.resource->bus.addr = NULL; + goto retry; + } + +diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/r535.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/r535.c +index 666eb93b1742c..11b4c9c274a1a 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/r535.c ++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/r535.c +@@ -41,7 +41,6 @@ r535_devinit_new(const struct nvkm_devinit_func *hw, + + rm->dtor = r535_devinit_dtor; + rm->post = hw->post; +- rm->disable = hw->disable; + + ret = nv50_devinit_new_(rm, device, type, inst, pdevinit); + if (ret) +diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c +index 4945a1e787eb3..0ffe8f8c01de8 100644 +--- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c ++++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c +@@ -1871,6 +1871,8 @@ static int boe_panel_add(struct boe_panel *boe) + + gpiod_set_value(boe->enable_gpio, 0); + ++ boe->base.prepare_prev_first = true; ++ + drm_panel_init(&boe->base, dev, &boe_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + err = of_drm_get_panel_orientation(dev->of_node, &boe->orientation); +diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c +index a0b6f69b916f9..e5e3f0b9ca61d 100644 +--- a/drivers/gpu/drm/panel/panel-edp.c ++++ b/drivers/gpu/drm/panel/panel-edp.c +@@ -413,8 +413,7 @@ static int panel_edp_unprepare(struct drm_panel *panel) + if (!p->prepared) + return 0; + +- pm_runtime_mark_last_busy(panel->dev); +- ret = pm_runtime_put_autosuspend(panel->dev); ++ ret = pm_runtime_put_sync_suspend(panel->dev); + if (ret < 0) + return ret; + p->prepared = false; +diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c +index 927e5f42e97d0..3e48cbb522a1c 100644 +--- a/drivers/gpu/drm/radeon/ni.c ++++ b/drivers/gpu/drm/radeon/ni.c +@@ -813,7 +813,7 @@ int ni_init_microcode(struct radeon_device *rdev) + err = 0; + } else if (rdev->smc_fw->size != smc_req_size) { + pr_err("ni_mc: Bogus length %zu in firmware \"%s\"\n", +- rdev->mc_fw->size, fw_name); ++ rdev->smc_fw->size, fw_name); + err = -EINVAL; + } + } +diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c +index e6fbe040ccf6a..b66c1ef5838fd 100644 +--- a/drivers/gpu/drm/rockchip/inno_hdmi.c ++++ b/drivers/gpu/drm/rockchip/inno_hdmi.c +@@ -411,7 +411,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF); + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF); + +- value = mode->hsync_start - mode->hdisplay; ++ value = mode->htotal - mode->hsync_start; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF); + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF); + +@@ -426,7 +426,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, + value = mode->vtotal - mode->vdisplay; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF); + +- value = mode->vsync_start - mode->vdisplay; ++ value = mode->vtotal - mode->vsync_start; + hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF); + + value = mode->vsync_end - mode->vsync_start; +diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c +index 59341654ec32b..77b76cff1adb9 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c ++++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c +@@ -576,8 +576,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, + ret = -EINVAL; + goto err_put_port; + } else if (ret) { +- DRM_DEV_ERROR(dev, "failed to find panel and bridge node\n"); +- ret = -EPROBE_DEFER; ++ dev_err_probe(dev, ret, "failed to find panel and bridge node\n"); + goto err_put_port; + } + if (lvds->panel) +diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c +index ef02d530f78d7..ae12d001a04bf 100644 +--- a/drivers/gpu/drm/tegra/dpaux.c ++++ b/drivers/gpu/drm/tegra/dpaux.c +@@ -522,7 +522,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev) + if (err < 0) { + dev_err(dpaux->dev, "failed to request IRQ#%u: %d\n", + dpaux->irq, err); +- return err; ++ goto err_pm_disable; + } + + disable_irq(dpaux->irq); +@@ -542,7 +542,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev) + */ + err = tegra_dpaux_pad_config(dpaux, DPAUX_PADCTL_FUNC_I2C); + if (err < 0) +- return err; ++ goto err_pm_disable; + + #ifdef CONFIG_GENERIC_PINCONF + dpaux->desc.name = dev_name(&pdev->dev); +@@ -555,7 +555,8 @@ static int tegra_dpaux_probe(struct platform_device *pdev) + dpaux->pinctrl = devm_pinctrl_register(&pdev->dev, &dpaux->desc, dpaux); + if (IS_ERR(dpaux->pinctrl)) { + dev_err(&pdev->dev, "failed to register pincontrol\n"); +- return PTR_ERR(dpaux->pinctrl); ++ err = PTR_ERR(dpaux->pinctrl); ++ goto err_pm_disable; + } + #endif + /* enable and clear all interrupts */ +@@ -571,10 +572,15 @@ static int tegra_dpaux_probe(struct platform_device *pdev) + err = devm_of_dp_aux_populate_ep_devices(&dpaux->aux); + if (err < 0) { + dev_err(dpaux->dev, "failed to populate AUX bus: %d\n", err); +- return err; ++ goto err_pm_disable; + } + + return 0; ++ ++err_pm_disable: ++ pm_runtime_put_sync(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ return err; + } + + static void tegra_dpaux_remove(struct platform_device *pdev) +diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c +index fbfe92a816d4b..db606e151afc8 100644 +--- a/drivers/gpu/drm/tegra/dsi.c ++++ b/drivers/gpu/drm/tegra/dsi.c +@@ -1544,9 +1544,11 @@ static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi) + np = of_parse_phandle(dsi->dev->of_node, "nvidia,ganged-mode", 0); + if (np) { + struct platform_device *gangster = of_find_device_by_node(np); ++ of_node_put(np); ++ if (!gangster) ++ return -EPROBE_DEFER; + + dsi->slave = platform_get_drvdata(gangster); +- of_node_put(np); + + if (!dsi->slave) { + put_device(&gangster->dev); +@@ -1594,44 +1596,58 @@ static int tegra_dsi_probe(struct platform_device *pdev) + + if (!pdev->dev.pm_domain) { + dsi->rst = devm_reset_control_get(&pdev->dev, "dsi"); +- if (IS_ERR(dsi->rst)) +- return PTR_ERR(dsi->rst); ++ if (IS_ERR(dsi->rst)) { ++ err = PTR_ERR(dsi->rst); ++ goto remove; ++ } + } + + dsi->clk = devm_clk_get(&pdev->dev, NULL); +- if (IS_ERR(dsi->clk)) +- return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk), +- "cannot get DSI clock\n"); ++ if (IS_ERR(dsi->clk)) { ++ err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk), ++ "cannot get DSI clock\n"); ++ goto remove; ++ } + + dsi->clk_lp = devm_clk_get(&pdev->dev, "lp"); +- if (IS_ERR(dsi->clk_lp)) +- return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_lp), +- "cannot get low-power clock\n"); ++ if (IS_ERR(dsi->clk_lp)) { ++ err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_lp), ++ "cannot get low-power clock\n"); ++ goto remove; ++ } + + dsi->clk_parent = devm_clk_get(&pdev->dev, "parent"); +- if (IS_ERR(dsi->clk_parent)) +- return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_parent), +- "cannot get parent clock\n"); ++ if (IS_ERR(dsi->clk_parent)) { ++ err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_parent), ++ "cannot get parent clock\n"); ++ goto remove; ++ } + + dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi"); +- if (IS_ERR(dsi->vdd)) +- return dev_err_probe(&pdev->dev, PTR_ERR(dsi->vdd), +- "cannot get VDD supply\n"); ++ if (IS_ERR(dsi->vdd)) { ++ err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->vdd), ++ "cannot get VDD supply\n"); ++ goto remove; ++ } + + err = tegra_dsi_setup_clocks(dsi); + if (err < 0) { + dev_err(&pdev->dev, "cannot setup clocks\n"); +- return err; ++ goto remove; + } + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dsi->regs = devm_ioremap_resource(&pdev->dev, regs); +- if (IS_ERR(dsi->regs)) +- return PTR_ERR(dsi->regs); ++ if (IS_ERR(dsi->regs)) { ++ err = PTR_ERR(dsi->regs); ++ goto remove; ++ } + + dsi->mipi = tegra_mipi_request(&pdev->dev, pdev->dev.of_node); +- if (IS_ERR(dsi->mipi)) +- return PTR_ERR(dsi->mipi); ++ if (IS_ERR(dsi->mipi)) { ++ err = PTR_ERR(dsi->mipi); ++ goto remove; ++ } + + dsi->host.ops = &tegra_dsi_host_ops; + dsi->host.dev = &pdev->dev; +@@ -1659,9 +1675,12 @@ static int tegra_dsi_probe(struct platform_device *pdev) + return 0; + + unregister: ++ pm_runtime_disable(&pdev->dev); + mipi_dsi_host_unregister(&dsi->host); + mipi_free: + tegra_mipi_free(dsi->mipi); ++remove: ++ tegra_output_remove(&dsi->output); + return err; + } + +diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c +index a719af1dc9a57..46170753699dc 100644 +--- a/drivers/gpu/drm/tegra/fb.c ++++ b/drivers/gpu/drm/tegra/fb.c +@@ -159,6 +159,7 @@ struct drm_framebuffer *tegra_fb_create(struct drm_device *drm, + + if (gem->size < size) { + err = -EINVAL; ++ drm_gem_object_put(gem); + goto unreference; + } + +diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c +index a1fcee665023b..417fb884240a6 100644 +--- a/drivers/gpu/drm/tegra/hdmi.c ++++ b/drivers/gpu/drm/tegra/hdmi.c +@@ -1856,12 +1856,14 @@ static int tegra_hdmi_probe(struct platform_device *pdev) + return err; + + hdmi->regs = devm_platform_ioremap_resource(pdev, 0); +- if (IS_ERR(hdmi->regs)) +- return PTR_ERR(hdmi->regs); ++ if (IS_ERR(hdmi->regs)) { ++ err = PTR_ERR(hdmi->regs); ++ goto remove; ++ } + + err = platform_get_irq(pdev, 0); + if (err < 0) +- return err; ++ goto remove; + + hdmi->irq = err; + +@@ -1870,18 +1872,18 @@ static int tegra_hdmi_probe(struct platform_device *pdev) + if (err < 0) { + dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", + hdmi->irq, err); +- return err; ++ goto remove; + } + + platform_set_drvdata(pdev, hdmi); + + err = devm_pm_runtime_enable(&pdev->dev); + if (err) +- return err; ++ goto remove; + + err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev); + if (err) +- return err; ++ goto remove; + + INIT_LIST_HEAD(&hdmi->client.list); + hdmi->client.ops = &hdmi_client_ops; +@@ -1891,10 +1893,14 @@ static int tegra_hdmi_probe(struct platform_device *pdev) + if (err < 0) { + dev_err(&pdev->dev, "failed to register host1x client: %d\n", + err); +- return err; ++ goto remove; + } + + return 0; ++ ++remove: ++ tegra_output_remove(&hdmi->output); ++ return err; + } + + static void tegra_hdmi_remove(struct platform_device *pdev) +diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c +index dc2dcb5ca1c89..d7d2389ac2f5a 100644 +--- a/drivers/gpu/drm/tegra/output.c ++++ b/drivers/gpu/drm/tegra/output.c +@@ -142,8 +142,10 @@ int tegra_output_probe(struct tegra_output *output) + GPIOD_IN, + "HDMI hotplug detect"); + if (IS_ERR(output->hpd_gpio)) { +- if (PTR_ERR(output->hpd_gpio) != -ENOENT) +- return PTR_ERR(output->hpd_gpio); ++ if (PTR_ERR(output->hpd_gpio) != -ENOENT) { ++ err = PTR_ERR(output->hpd_gpio); ++ goto put_i2c; ++ } + + output->hpd_gpio = NULL; + } +@@ -152,7 +154,7 @@ int tegra_output_probe(struct tegra_output *output) + err = gpiod_to_irq(output->hpd_gpio); + if (err < 0) { + dev_err(output->dev, "gpiod_to_irq(): %d\n", err); +- return err; ++ goto put_i2c; + } + + output->hpd_irq = err; +@@ -165,7 +167,7 @@ int tegra_output_probe(struct tegra_output *output) + if (err < 0) { + dev_err(output->dev, "failed to request IRQ#%u: %d\n", + output->hpd_irq, err); +- return err; ++ goto put_i2c; + } + + output->connector.polled = DRM_CONNECTOR_POLL_HPD; +@@ -179,6 +181,12 @@ int tegra_output_probe(struct tegra_output *output) + } + + return 0; ++ ++put_i2c: ++ if (output->ddc) ++ i2c_put_adapter(output->ddc); ++ ++ return err; + } + + void tegra_output_remove(struct tegra_output *output) +diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c +index fc66bbd913b24..1e8ec50b759e4 100644 +--- a/drivers/gpu/drm/tegra/rgb.c ++++ b/drivers/gpu/drm/tegra/rgb.c +@@ -225,26 +225,28 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc) + rgb->clk = devm_clk_get(dc->dev, NULL); + if (IS_ERR(rgb->clk)) { + dev_err(dc->dev, "failed to get clock\n"); +- return PTR_ERR(rgb->clk); ++ err = PTR_ERR(rgb->clk); ++ goto remove; + } + + rgb->clk_parent = devm_clk_get(dc->dev, "parent"); + if (IS_ERR(rgb->clk_parent)) { + dev_err(dc->dev, "failed to get parent clock\n"); +- return PTR_ERR(rgb->clk_parent); ++ err = PTR_ERR(rgb->clk_parent); ++ goto remove; + } + + err = clk_set_parent(rgb->clk, rgb->clk_parent); + if (err < 0) { + dev_err(dc->dev, "failed to set parent clock: %d\n", err); +- return err; ++ goto remove; + } + + rgb->pll_d_out0 = clk_get_sys(NULL, "pll_d_out0"); + if (IS_ERR(rgb->pll_d_out0)) { + err = PTR_ERR(rgb->pll_d_out0); + dev_err(dc->dev, "failed to get pll_d_out0: %d\n", err); +- return err; ++ goto remove; + } + + if (dc->soc->has_pll_d2_out0) { +@@ -252,13 +254,19 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc) + if (IS_ERR(rgb->pll_d2_out0)) { + err = PTR_ERR(rgb->pll_d2_out0); + dev_err(dc->dev, "failed to get pll_d2_out0: %d\n", err); +- return err; ++ goto put_pll; + } + } + + dc->rgb = &rgb->output; + + return 0; ++ ++put_pll: ++ clk_put(rgb->pll_d_out0); ++remove: ++ tegra_output_remove(&rgb->output); ++ return err; + } + + void tegra_dc_rgb_remove(struct tegra_dc *dc) +diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c b/drivers/gpu/drm/tests/drm_buddy_test.c +index 484360c7e1f65..e48863a445564 100644 +--- a/drivers/gpu/drm/tests/drm_buddy_test.c ++++ b/drivers/gpu/drm/tests/drm_buddy_test.c +@@ -260,30 +260,30 @@ static void drm_test_buddy_alloc_contiguous(struct kunit *test) + KUNIT_ASSERT_FALSE_MSG(test, + drm_buddy_alloc_blocks(&mm, 0, mm_size, + ps, ps, list, 0), +- "buddy_alloc hit an error size=%u\n", ++ "buddy_alloc hit an error size=%lu\n", + ps); + } while (++i < n_pages); + + KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + 3 * ps, ps, &allocated, + DRM_BUDDY_CONTIGUOUS_ALLOCATION), +- "buddy_alloc didn't error size=%u\n", 3 * ps); ++ "buddy_alloc didn't error size=%lu\n", 3 * ps); + + drm_buddy_free_list(&mm, &middle); + KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + 3 * ps, ps, &allocated, + DRM_BUDDY_CONTIGUOUS_ALLOCATION), +- "buddy_alloc didn't error size=%u\n", 3 * ps); ++ "buddy_alloc didn't error size=%lu\n", 3 * ps); + KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + 2 * ps, ps, &allocated, + DRM_BUDDY_CONTIGUOUS_ALLOCATION), +- "buddy_alloc didn't error size=%u\n", 2 * ps); ++ "buddy_alloc didn't error size=%lu\n", 2 * ps); + + drm_buddy_free_list(&mm, &right); + KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + 3 * ps, ps, &allocated, + DRM_BUDDY_CONTIGUOUS_ALLOCATION), +- "buddy_alloc didn't error size=%u\n", 3 * ps); ++ "buddy_alloc didn't error size=%lu\n", 3 * ps); + /* + * At this point we should have enough contiguous space for 2 blocks, + * however they are never buddies (since we freed middle and right) so +@@ -292,13 +292,13 @@ static void drm_test_buddy_alloc_contiguous(struct kunit *test) + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + 2 * ps, ps, &allocated, + DRM_BUDDY_CONTIGUOUS_ALLOCATION), +- "buddy_alloc hit an error size=%u\n", 2 * ps); ++ "buddy_alloc hit an error size=%lu\n", 2 * ps); + + drm_buddy_free_list(&mm, &left); + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + 3 * ps, ps, &allocated, + DRM_BUDDY_CONTIGUOUS_ALLOCATION), +- "buddy_alloc hit an error size=%u\n", 3 * ps); ++ "buddy_alloc hit an error size=%lu\n", 3 * ps); + + total = 0; + list_for_each_entry(block, &allocated, link) +diff --git a/drivers/gpu/drm/tests/drm_mm_test.c b/drivers/gpu/drm/tests/drm_mm_test.c +index 1eb0c304f9607..f37c0d7658656 100644 +--- a/drivers/gpu/drm/tests/drm_mm_test.c ++++ b/drivers/gpu/drm/tests/drm_mm_test.c +@@ -157,7 +157,7 @@ static void drm_test_mm_init(struct kunit *test) + + /* After creation, it should all be one massive hole */ + if (!assert_one_hole(test, &mm, 0, size)) { +- KUNIT_FAIL(test, ""); ++ KUNIT_FAIL(test, "mm not one hole on creation"); + goto out; + } + +@@ -171,14 +171,14 @@ static void drm_test_mm_init(struct kunit *test) + + /* After filling the range entirely, there should be no holes */ + if (!assert_no_holes(test, &mm)) { +- KUNIT_FAIL(test, ""); ++ KUNIT_FAIL(test, "mm has holes when filled"); + goto out; + } + + /* And then after emptying it again, the massive hole should be back */ + drm_mm_remove_node(&tmp); + if (!assert_one_hole(test, &mm, 0, size)) { +- KUNIT_FAIL(test, ""); ++ KUNIT_FAIL(test, "mm does not have single hole after emptying"); + goto out; + } + +diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c +index 5f838980c7a11..94f8e3178df58 100644 +--- a/drivers/gpu/drm/tidss/tidss_crtc.c ++++ b/drivers/gpu/drm/tidss/tidss_crtc.c +@@ -265,6 +265,16 @@ static void tidss_crtc_atomic_disable(struct drm_crtc *crtc, + + reinit_completion(&tcrtc->framedone_completion); + ++ /* ++ * If a layer is left enabled when the videoport is disabled, and the ++ * vid pipeline that was used for the layer is taken into use on ++ * another videoport, the DSS will report sync lost issues. Disable all ++ * the layers here as a work-around. ++ */ ++ for (u32 layer = 0; layer < tidss->feat->num_planes; layer++) ++ dispc_ovr_enable_layer(tidss->dispc, tcrtc->hw_videoport, layer, ++ false); ++ + dispc_vp_disable(tidss->dispc, tcrtc->hw_videoport); + + if (!wait_for_completion_timeout(&tcrtc->framedone_completion, +diff --git a/drivers/gpu/drm/tidss/tidss_plane.c b/drivers/gpu/drm/tidss/tidss_plane.c +index e1c0ef0c3894c..68fed531f6a7f 100644 +--- a/drivers/gpu/drm/tidss/tidss_plane.c ++++ b/drivers/gpu/drm/tidss/tidss_plane.c +@@ -213,7 +213,7 @@ struct tidss_plane *tidss_plane_create(struct tidss_device *tidss, + + drm_plane_helper_add(&tplane->plane, &tidss_plane_helper_funcs); + +- drm_plane_create_zpos_property(&tplane->plane, hw_plane_id, 0, ++ drm_plane_create_zpos_property(&tplane->plane, tidss->num_planes, 0, + num_planes - 1); + + ret = drm_plane_create_color_properties(&tplane->plane, +diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c +index 3c99fb8b54e2d..e7441b227b3ce 100644 +--- a/drivers/gpu/drm/vkms/vkms_composer.c ++++ b/drivers/gpu/drm/vkms/vkms_composer.c +@@ -123,6 +123,8 @@ static u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 chan + enum lut_channel channel) + { + s64 lut_index = get_lut_index(lut, channel_value); ++ u16 *floor_lut_value, *ceil_lut_value; ++ u16 floor_channel_value, ceil_channel_value; + + /* + * This checks if `struct drm_color_lut` has any gap added by the compiler +@@ -130,11 +132,15 @@ static u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 chan + */ + static_assert(sizeof(struct drm_color_lut) == sizeof(__u16) * 4); + +- u16 *floor_lut_value = (__u16 *)&lut->base[drm_fixp2int(lut_index)]; +- u16 *ceil_lut_value = (__u16 *)&lut->base[drm_fixp2int_ceil(lut_index)]; ++ floor_lut_value = (__u16 *)&lut->base[drm_fixp2int(lut_index)]; ++ if (drm_fixp2int(lut_index) == (lut->lut_length - 1)) ++ /* We're at the end of the LUT array, use same value for ceil and floor */ ++ ceil_lut_value = floor_lut_value; ++ else ++ ceil_lut_value = (__u16 *)&lut->base[drm_fixp2int_ceil(lut_index)]; + +- u16 floor_channel_value = floor_lut_value[channel]; +- u16 ceil_channel_value = ceil_lut_value[channel]; ++ floor_channel_value = floor_lut_value[channel]; ++ ceil_channel_value = ceil_lut_value[channel]; + + return lerp_u16(floor_channel_value, ceil_channel_value, + lut_index & DRM_FIXED_DECIMAL_MASK); +diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c +index ceb4d3d3b965a..a0b47c9b33f55 100644 +--- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c ++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c +@@ -64,8 +64,11 @@ static int vmw_gmrid_man_get_node(struct ttm_resource_manager *man, + ttm_resource_init(bo, place, *res); + + id = ida_alloc_max(&gman->gmr_ida, gman->max_gmr_ids - 1, GFP_KERNEL); +- if (id < 0) ++ if (id < 0) { ++ ttm_resource_fini(man, *res); ++ kfree(*res); + return id; ++ } + + spin_lock(&gman->lock); + +diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +index 5fd0ccaa0b41b..b6f40781b907a 100644 +--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c ++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +@@ -272,6 +272,7 @@ static int vmw_du_get_cursor_mob(struct vmw_cursor_plane *vcp, + u32 size = vmw_du_cursor_mob_size(vps->base.crtc_w, vps->base.crtc_h); + u32 i; + u32 cursor_max_dim, mob_max_size; ++ struct vmw_fence_obj *fence = NULL; + int ret; + + if (!dev_priv->has_mob || +@@ -313,7 +314,15 @@ static int vmw_du_get_cursor_mob(struct vmw_cursor_plane *vcp, + if (ret != 0) + goto teardown; + +- vmw_bo_fence_single(&vps->cursor.bo->tbo, NULL); ++ ret = vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); ++ if (ret != 0) { ++ ttm_bo_unreserve(&vps->cursor.bo->tbo); ++ goto teardown; ++ } ++ ++ dma_fence_wait(&fence->base, false); ++ dma_fence_put(&fence->base); ++ + ttm_bo_unreserve(&vps->cursor.bo->tbo); + return 0; + +diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile +index efcf0ab7a1a69..802c807c782cc 100644 +--- a/drivers/gpu/drm/xe/Makefile ++++ b/drivers/gpu/drm/xe/Makefile +@@ -42,7 +42,8 @@ generated_oob := $(obj)/generated/xe_wa_oob.c $(obj)/generated/xe_wa_oob.h + quiet_cmd_wa_oob = GEN $(notdir $(generated_oob)) + cmd_wa_oob = mkdir -p $(@D); $^ $(generated_oob) + +-$(generated_oob) &: $(obj)/xe_gen_wa_oob $(srctree)/$(src)/xe_wa_oob.rules ++$(obj)/generated/%_wa_oob.c $(obj)/generated/%_wa_oob.h: $(obj)/xe_gen_wa_oob \ ++ $(srctree)/$(src)/xe_wa_oob.rules + $(call cmd,wa_oob) + + uses_generated_oob := \ +diff --git a/drivers/gpu/drm/xe/tests/xe_migrate.c b/drivers/gpu/drm/xe/tests/xe_migrate.c +index a6523df0f1d39..c347e2c29f81f 100644 +--- a/drivers/gpu/drm/xe/tests/xe_migrate.c ++++ b/drivers/gpu/drm/xe/tests/xe_migrate.c +@@ -114,21 +114,21 @@ static void test_copy(struct xe_migrate *m, struct xe_bo *bo, + region | + XE_BO_NEEDS_CPU_ACCESS); + if (IS_ERR(remote)) { +- KUNIT_FAIL(test, "Failed to allocate remote bo for %s: %li\n", +- str, PTR_ERR(remote)); ++ KUNIT_FAIL(test, "Failed to allocate remote bo for %s: %pe\n", ++ str, remote); + return; + } + + err = xe_bo_validate(remote, NULL, false); + if (err) { +- KUNIT_FAIL(test, "Failed to validate system bo for %s: %li\n", ++ KUNIT_FAIL(test, "Failed to validate system bo for %s: %i\n", + str, err); + goto out_unlock; + } + + err = xe_bo_vmap(remote); + if (err) { +- KUNIT_FAIL(test, "Failed to vmap system bo for %s: %li\n", ++ KUNIT_FAIL(test, "Failed to vmap system bo for %s: %i\n", + str, err); + goto out_unlock; + } +diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c +index 17f26952e6656..222209b0d6904 100644 +--- a/drivers/gpu/drm/xe/xe_exec.c ++++ b/drivers/gpu/drm/xe/xe_exec.c +@@ -196,6 +196,29 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) + goto err_unlock_list; + } + ++ if (!args->num_batch_buffer) { ++ err = xe_vm_lock(vm, true); ++ if (err) ++ goto err_unlock_list; ++ ++ if (!xe_vm_in_lr_mode(vm)) { ++ struct dma_fence *fence; ++ ++ fence = xe_sync_in_fence_get(syncs, num_syncs, q, vm); ++ if (IS_ERR(fence)) { ++ err = PTR_ERR(fence); ++ goto err_unlock_list; ++ } ++ for (i = 0; i < num_syncs; i++) ++ xe_sync_entry_signal(&syncs[i], NULL, fence); ++ xe_exec_queue_last_fence_set(q, vm, fence); ++ dma_fence_put(fence); ++ } ++ ++ xe_vm_unlock(vm); ++ goto err_unlock_list; ++ } ++ + vm_exec.vm = &vm->gpuvm; + vm_exec.num_fences = 1 + vm->xe->info.tile_count; + vm_exec.flags = DRM_EXEC_INTERRUPTIBLE_WAIT; +@@ -216,24 +239,6 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) + goto err_exec; + } + +- if (!args->num_batch_buffer) { +- if (!xe_vm_in_lr_mode(vm)) { +- struct dma_fence *fence; +- +- fence = xe_sync_in_fence_get(syncs, num_syncs, q, vm); +- if (IS_ERR(fence)) { +- err = PTR_ERR(fence); +- goto err_exec; +- } +- for (i = 0; i < num_syncs; i++) +- xe_sync_entry_signal(&syncs[i], NULL, fence); +- xe_exec_queue_last_fence_set(q, vm, fence); +- dma_fence_put(fence); +- } +- +- goto err_exec; +- } +- + if (xe_exec_queue_is_lr(q) && xe_exec_queue_ring_full(q)) { + err = -EWOULDBLOCK; /* Aliased to -EAGAIN */ + skip_retry = true; +diff --git a/drivers/gpu/drm/xe/xe_gt_pagefault.c b/drivers/gpu/drm/xe/xe_gt_pagefault.c +index 73f08f1924df2..ab8536c4fd580 100644 +--- a/drivers/gpu/drm/xe/xe_gt_pagefault.c ++++ b/drivers/gpu/drm/xe/xe_gt_pagefault.c +@@ -69,7 +69,7 @@ static bool access_is_atomic(enum access_type access_type) + static bool vma_is_valid(struct xe_tile *tile, struct xe_vma *vma) + { + return BIT(tile->id) & vma->tile_present && +- !(BIT(tile->id) & vma->usm.tile_invalidated); ++ !(BIT(tile->id) & vma->tile_invalidated); + } + + static bool vma_matches(struct xe_vma *vma, u64 page_addr) +@@ -146,10 +146,12 @@ static int handle_pagefault(struct xe_gt *gt, struct pagefault *pf) + /* ASID to VM */ + mutex_lock(&xe->usm.lock); + vm = xa_load(&xe->usm.asid_to_vm, pf->asid); +- if (vm) ++ if (vm && xe_vm_in_fault_mode(vm)) + xe_vm_get(vm); ++ else ++ vm = NULL; + mutex_unlock(&xe->usm.lock); +- if (!vm || !xe_vm_in_fault_mode(vm)) ++ if (!vm) + return -EINVAL; + + retry_userptr: +@@ -224,7 +226,7 @@ static int handle_pagefault(struct xe_gt *gt, struct pagefault *pf) + + if (xe_vma_is_userptr(vma)) + ret = xe_vma_userptr_check_repin(to_userptr_vma(vma)); +- vma->usm.tile_invalidated &= ~BIT(tile->id); ++ vma->tile_invalidated &= ~BIT(tile->id); + + unlock_dma_resv: + drm_exec_fini(&exec); +diff --git a/drivers/gpu/drm/xe/xe_trace.h b/drivers/gpu/drm/xe/xe_trace.h +index 4ddc55527f9ab..846f14507d5ff 100644 +--- a/drivers/gpu/drm/xe/xe_trace.h ++++ b/drivers/gpu/drm/xe/xe_trace.h +@@ -468,7 +468,7 @@ DEFINE_EVENT(xe_vma, xe_vma_userptr_invalidate, + TP_ARGS(vma) + ); + +-DEFINE_EVENT(xe_vma, xe_vma_usm_invalidate, ++DEFINE_EVENT(xe_vma, xe_vma_invalidate, + TP_PROTO(struct xe_vma *vma), + TP_ARGS(vma) + ); +diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c +index 3b21afe5b4883..a2397f232efc6 100644 +--- a/drivers/gpu/drm/xe/xe_vm.c ++++ b/drivers/gpu/drm/xe/xe_vm.c +@@ -706,6 +706,7 @@ int xe_vm_userptr_pin(struct xe_vm *vm) + int err = 0; + LIST_HEAD(tmp_evict); + ++ xe_assert(vm->xe, !xe_vm_in_fault_mode(vm)); + lockdep_assert_held_write(&vm->lock); + + /* Collect invalidated userptrs */ +@@ -722,11 +723,27 @@ int xe_vm_userptr_pin(struct xe_vm *vm) + list_for_each_entry_safe(uvma, next, &vm->userptr.repin_list, + userptr.repin_link) { + err = xe_vma_userptr_pin_pages(uvma); +- if (err < 0) +- return err; ++ if (err == -EFAULT) { ++ list_del_init(&uvma->userptr.repin_link); + +- list_del_init(&uvma->userptr.repin_link); +- list_move_tail(&uvma->vma.combined_links.rebind, &vm->rebind_list); ++ /* Wait for pending binds */ ++ xe_vm_lock(vm, false); ++ dma_resv_wait_timeout(xe_vm_resv(vm), ++ DMA_RESV_USAGE_BOOKKEEP, ++ false, MAX_SCHEDULE_TIMEOUT); ++ ++ err = xe_vm_invalidate_vma(&uvma->vma); ++ xe_vm_unlock(vm); ++ if (err) ++ return err; ++ } else { ++ if (err < 0) ++ return err; ++ ++ list_del_init(&uvma->userptr.repin_link); ++ list_move_tail(&uvma->vma.combined_links.rebind, ++ &vm->rebind_list); ++ } + } + + return 0; +@@ -2010,7 +2027,7 @@ static int xe_vm_prefetch(struct xe_vm *vm, struct xe_vma *vma, + return err; + } + +- if (vma->tile_mask != (vma->tile_present & ~vma->usm.tile_invalidated)) { ++ if (vma->tile_mask != (vma->tile_present & ~vma->tile_invalidated)) { + return xe_vm_bind(vm, vma, q, xe_vma_bo(vma), syncs, num_syncs, + true, first_op, last_op); + } else { +@@ -3184,9 +3201,8 @@ int xe_vm_invalidate_vma(struct xe_vma *vma) + u8 id; + int ret; + +- xe_assert(xe, xe_vm_in_fault_mode(xe_vma_vm(vma))); + xe_assert(xe, !xe_vma_is_null(vma)); +- trace_xe_vma_usm_invalidate(vma); ++ trace_xe_vma_invalidate(vma); + + /* Check that we don't race with page-table updates */ + if (IS_ENABLED(CONFIG_PROVE_LOCKING)) { +@@ -3224,7 +3240,7 @@ int xe_vm_invalidate_vma(struct xe_vma *vma) + } + } + +- vma->usm.tile_invalidated = vma->tile_mask; ++ vma->tile_invalidated = vma->tile_mask; + + return 0; + } +diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h +index 7300eea5394ba..5b96549479504 100644 +--- a/drivers/gpu/drm/xe/xe_vm_types.h ++++ b/drivers/gpu/drm/xe/xe_vm_types.h +@@ -83,11 +83,8 @@ struct xe_vma { + struct work_struct destroy_work; + }; + +- /** @usm: unified shared memory state */ +- struct { +- /** @tile_invalidated: VMA has been invalidated */ +- u8 tile_invalidated; +- } usm; ++ /** @tile_invalidated: VMA has been invalidated */ ++ u8 tile_invalidated; + + /** @tile_mask: Tile mask of where to create binding for this VMA */ + u8 tile_mask; +diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +index 2530fa98b568b..ce449da08e9ba 100644 +--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c ++++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +@@ -35,6 +35,8 @@ static int sensor_mask_override = -1; + module_param_named(sensor_mask, sensor_mask_override, int, 0444); + MODULE_PARM_DESC(sensor_mask, "override the detected sensors mask"); + ++static bool intr_disable = true; ++ + static int amd_sfh_wait_response_v2(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts) + { + union cmd_response cmd_resp; +@@ -55,7 +57,7 @@ static void amd_start_sensor_v2(struct amd_mp2_dev *privdata, struct amd_mp2_sen + + cmd_base.ul = 0; + cmd_base.cmd_v2.cmd_id = ENABLE_SENSOR; +- cmd_base.cmd_v2.intr_disable = 1; ++ cmd_base.cmd_v2.intr_disable = intr_disable; + cmd_base.cmd_v2.period = info.period; + cmd_base.cmd_v2.sensor_id = info.sensor_idx; + cmd_base.cmd_v2.length = 16; +@@ -73,7 +75,7 @@ static void amd_stop_sensor_v2(struct amd_mp2_dev *privdata, u16 sensor_idx) + + cmd_base.ul = 0; + cmd_base.cmd_v2.cmd_id = DISABLE_SENSOR; +- cmd_base.cmd_v2.intr_disable = 1; ++ cmd_base.cmd_v2.intr_disable = intr_disable; + cmd_base.cmd_v2.period = 0; + cmd_base.cmd_v2.sensor_id = sensor_idx; + cmd_base.cmd_v2.length = 16; +@@ -87,7 +89,7 @@ static void amd_stop_all_sensor_v2(struct amd_mp2_dev *privdata) + union sfh_cmd_base cmd_base; + + cmd_base.cmd_v2.cmd_id = STOP_ALL_SENSORS; +- cmd_base.cmd_v2.intr_disable = 1; ++ cmd_base.cmd_v2.intr_disable = intr_disable; + cmd_base.cmd_v2.period = 0; + cmd_base.cmd_v2.sensor_id = 0; + +@@ -292,6 +294,26 @@ int amd_sfh_irq_init(struct amd_mp2_dev *privdata) + return 0; + } + ++static int mp2_disable_intr(const struct dmi_system_id *id) ++{ ++ intr_disable = false; ++ return 0; ++} ++ ++static const struct dmi_system_id dmi_sfh_table[] = { ++ { ++ /* ++ * https://bugzilla.kernel.org/show_bug.cgi?id=218104 ++ */ ++ .callback = mp2_disable_intr, ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "HP"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook x360 435 G7"), ++ }, ++ }, ++ {} ++}; ++ + static const struct dmi_system_id dmi_nodevs[] = { + { + /* +@@ -315,6 +337,8 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i + if (dmi_first_match(dmi_nodevs)) + return -ENODEV; + ++ dmi_check_system(dmi_sfh_table); ++ + privdata = devm_kzalloc(&pdev->dev, sizeof(*privdata), GFP_KERNEL); + if (!privdata) + return -ENOMEM; +diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h +index 70add75fc5066..05e400a4a83e4 100644 +--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h ++++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h +@@ -90,10 +90,10 @@ enum mem_use_type { + struct hpd_status { + union { + struct { +- u32 human_presence_report : 4; +- u32 human_presence_actual : 4; +- u32 probablity : 8; + u32 object_distance : 16; ++ u32 probablity : 8; ++ u32 human_presence_actual : 4; ++ u32 human_presence_report : 4; + } shpd; + u32 val; + }; +diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c +index 149a3c74346b4..f86c1ea83a037 100644 +--- a/drivers/hid/hid-lenovo.c ++++ b/drivers/hid/hid-lenovo.c +@@ -54,10 +54,10 @@ struct lenovo_drvdata { + /* 0: Up + * 1: Down (undecided) + * 2: Scrolling +- * 3: Patched firmware, disable workaround + */ + u8 middlebutton_state; + bool fn_lock; ++ bool middleclick_workaround_cptkbd; + }; + + #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) +@@ -621,6 +621,36 @@ static ssize_t attr_sensitivity_store_cptkbd(struct device *dev, + return count; + } + ++static ssize_t attr_middleclick_workaround_show_cptkbd(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct hid_device *hdev = to_hid_device(dev); ++ struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev); ++ ++ return snprintf(buf, PAGE_SIZE, "%u\n", ++ cptkbd_data->middleclick_workaround_cptkbd); ++} ++ ++static ssize_t attr_middleclick_workaround_store_cptkbd(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, ++ size_t count) ++{ ++ struct hid_device *hdev = to_hid_device(dev); ++ struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev); ++ int value; ++ ++ if (kstrtoint(buf, 10, &value)) ++ return -EINVAL; ++ if (value < 0 || value > 1) ++ return -EINVAL; ++ ++ cptkbd_data->middleclick_workaround_cptkbd = !!value; ++ ++ return count; ++} ++ + + static struct device_attribute dev_attr_fn_lock = + __ATTR(fn_lock, S_IWUSR | S_IRUGO, +@@ -632,10 +662,16 @@ static struct device_attribute dev_attr_sensitivity_cptkbd = + attr_sensitivity_show_cptkbd, + attr_sensitivity_store_cptkbd); + ++static struct device_attribute dev_attr_middleclick_workaround_cptkbd = ++ __ATTR(middleclick_workaround, S_IWUSR | S_IRUGO, ++ attr_middleclick_workaround_show_cptkbd, ++ attr_middleclick_workaround_store_cptkbd); ++ + + static struct attribute *lenovo_attributes_cptkbd[] = { + &dev_attr_fn_lock.attr, + &dev_attr_sensitivity_cptkbd.attr, ++ &dev_attr_middleclick_workaround_cptkbd.attr, + NULL + }; + +@@ -686,23 +722,7 @@ static int lenovo_event_cptkbd(struct hid_device *hdev, + { + struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev); + +- if (cptkbd_data->middlebutton_state != 3) { +- /* REL_X and REL_Y events during middle button pressed +- * are only possible on patched, bug-free firmware +- * so set middlebutton_state to 3 +- * to never apply workaround anymore +- */ +- if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD && +- cptkbd_data->middlebutton_state == 1 && +- usage->type == EV_REL && +- (usage->code == REL_X || usage->code == REL_Y)) { +- cptkbd_data->middlebutton_state = 3; +- /* send middle button press which was hold before */ +- input_event(field->hidinput->input, +- EV_KEY, BTN_MIDDLE, 1); +- input_sync(field->hidinput->input); +- } +- ++ if (cptkbd_data->middleclick_workaround_cptkbd) { + /* "wheel" scroll events */ + if (usage->type == EV_REL && (usage->code == REL_WHEEL || + usage->code == REL_HWHEEL)) { +@@ -1166,6 +1186,7 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev) + cptkbd_data->middlebutton_state = 0; + cptkbd_data->fn_lock = true; + cptkbd_data->sensitivity = 0x05; ++ cptkbd_data->middleclick_workaround_cptkbd = true; + lenovo_features_set_cptkbd(hdev); + + ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_cptkbd); +diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig +index 00242107d62e0..862c47b191afe 100644 +--- a/drivers/hv/Kconfig ++++ b/drivers/hv/Kconfig +@@ -16,6 +16,7 @@ config HYPERV + config HYPERV_VTL_MODE + bool "Enable Linux to boot in VTL context" + depends on X86_64 && HYPERV ++ depends on SMP + default n + help + Virtual Secure Mode (VSM) is a set of hypervisor capabilities and +diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c +index d7f0e231feb99..965bb6d4e1bf4 100644 +--- a/drivers/hwtracing/coresight/coresight-core.c ++++ b/drivers/hwtracing/coresight/coresight-core.c +@@ -441,8 +441,26 @@ static void coresight_disable_helpers(struct coresight_device *csdev) + } + } + ++/* ++ * Helper function to call source_ops(csdev)->disable and also disable the ++ * helpers. ++ * ++ * There is an imbalance between coresight_enable_path() and ++ * coresight_disable_path(). Enabling also enables the source's helpers as part ++ * of the path, but disabling always skips the first item in the path (which is ++ * the source), so sources and their helpers don't get disabled as part of that ++ * function and we need the extra step here. ++ */ ++void coresight_disable_source(struct coresight_device *csdev, void *data) ++{ ++ if (source_ops(csdev)->disable) ++ source_ops(csdev)->disable(csdev, data); ++ coresight_disable_helpers(csdev); ++} ++EXPORT_SYMBOL_GPL(coresight_disable_source); ++ + /** +- * coresight_disable_source - Drop the reference count by 1 and disable ++ * coresight_disable_source_sysfs - Drop the reference count by 1 and disable + * the device if there are no users left. + * + * @csdev: The coresight device to disable +@@ -451,17 +469,15 @@ static void coresight_disable_helpers(struct coresight_device *csdev) + * + * Returns true if the device has been disabled. + */ +-bool coresight_disable_source(struct coresight_device *csdev, void *data) ++static bool coresight_disable_source_sysfs(struct coresight_device *csdev, ++ void *data) + { + if (atomic_dec_return(&csdev->refcnt) == 0) { +- if (source_ops(csdev)->disable) +- source_ops(csdev)->disable(csdev, data); +- coresight_disable_helpers(csdev); ++ coresight_disable_source(csdev, data); + csdev->enable = false; + } + return !csdev->enable; + } +-EXPORT_SYMBOL_GPL(coresight_disable_source); + + /* + * coresight_disable_path_from : Disable components in the given path beyond +@@ -1204,7 +1220,7 @@ void coresight_disable(struct coresight_device *csdev) + if (ret) + goto out; + +- if (!csdev->enable || !coresight_disable_source(csdev, NULL)) ++ if (!csdev->enable || !coresight_disable_source_sysfs(csdev, NULL)) + goto out; + + switch (csdev->subtype.source_subtype) { +diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c +index a52cfcce25d6d..c0c60e6a1703e 100644 +--- a/drivers/hwtracing/coresight/coresight-etm-perf.c ++++ b/drivers/hwtracing/coresight/coresight-etm-perf.c +@@ -589,7 +589,7 @@ static void etm_event_stop(struct perf_event *event, int mode) + return; + + /* stop tracer */ +- source_ops(csdev)->disable(csdev, event); ++ coresight_disable_source(csdev, event); + + /* tell the core */ + event->hw.state = PERF_HES_STOPPED; +diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c +index ce1995a2827f0..2e2cabc5f50ab 100644 +--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c ++++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c +@@ -1200,6 +1200,7 @@ static void etm4_init_arch_data(void *info) + struct etm4_init_arg *init_arg = info; + struct etmv4_drvdata *drvdata; + struct csdev_access *csa; ++ struct device *dev = init_arg->dev; + int i; + + drvdata = dev_get_drvdata(init_arg->dev); +@@ -1213,6 +1214,10 @@ static void etm4_init_arch_data(void *info) + if (!etm4_init_csdev_access(drvdata, csa)) + return; + ++ if (!csa->io_mem || ++ fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up")) ++ drvdata->skip_power_up = true; ++ + /* Detect the support for OS Lock before we actually use it */ + etm_detect_os_lock(drvdata, csa); + +@@ -2040,11 +2045,6 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg) + if (!drvdata->arch) + return -EINVAL; + +- /* TRCPDCR is not accessible with system instructions. */ +- if (!desc.access.io_mem || +- fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up")) +- drvdata->skip_power_up = true; +- + major = ETM_ARCH_MAJOR_VERSION(drvdata->arch); + minor = ETM_ARCH_MINOR_VERSION(drvdata->arch); + +diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h +index 767076e079701..30c051055e54b 100644 +--- a/drivers/hwtracing/coresight/coresight-priv.h ++++ b/drivers/hwtracing/coresight/coresight-priv.h +@@ -233,6 +233,6 @@ void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev); + struct coresight_device *coresight_get_percpu_sink(int cpu); + int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode, + void *data); +-bool coresight_disable_source(struct coresight_device *csdev, void *data); ++void coresight_disable_source(struct coresight_device *csdev, void *data); + + #endif +diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c +index c1b5fd2b89741..4bf04a9778407 100644 +--- a/drivers/hwtracing/ptt/hisi_ptt.c ++++ b/drivers/hwtracing/ptt/hisi_ptt.c +@@ -998,6 +998,9 @@ static int hisi_ptt_pmu_event_init(struct perf_event *event) + int ret; + u32 val; + ++ if (event->attr.type != hisi_ptt->hisi_ptt_pmu.type) ++ return -ENOENT; ++ + if (event->cpu < 0) { + dev_dbg(event->pmu->dev, "Per-task mode not supported\n"); + return -EOPNOTSUPP; +@@ -1006,9 +1009,6 @@ static int hisi_ptt_pmu_event_init(struct perf_event *event) + if (event->attach_state & PERF_ATTACH_TASK) + return -EOPNOTSUPP; + +- if (event->attr.type != hisi_ptt->hisi_ptt_pmu.type) +- return -ENOENT; +- + ret = hisi_ptt_trace_valid_filter(hisi_ptt, event->attr.config); + if (ret < 0) + return ret; +diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c +index ef5751e91cc9e..276153e10f5a4 100644 +--- a/drivers/i3c/master/dw-i3c-master.c ++++ b/drivers/i3c/master/dw-i3c-master.c +@@ -1163,8 +1163,10 @@ static void dw_i3c_master_set_sir_enabled(struct dw_i3c_master *master, + global = reg == 0xffffffff; + reg &= ~BIT(idx); + } else { +- global = reg == 0; ++ bool hj_rejected = !!(readl(master->regs + DEVICE_CTRL) & DEV_CTRL_HOT_JOIN_NACK); ++ + reg |= BIT(idx); ++ global = (reg == 0xffffffff) && hj_rejected; + } + writel(reg, master->regs + IBI_SIR_REQ_REJECT); + +diff --git a/drivers/iio/industrialio-gts-helper.c b/drivers/iio/industrialio-gts-helper.c +index 7653261d2dc2b..b51eb6cb766f3 100644 +--- a/drivers/iio/industrialio-gts-helper.c ++++ b/drivers/iio/industrialio-gts-helper.c +@@ -34,24 +34,11 @@ + static int iio_gts_get_gain(const u64 max, const u64 scale) + { + u64 full = max; +- int tmp = 1; + + if (scale > full || !scale) + return -EINVAL; + +- if (U64_MAX - full < scale) { +- /* Risk of overflow */ +- if (full - scale < scale) +- return 1; +- +- full -= scale; +- tmp++; +- } +- +- while (full > scale * (u64)tmp) +- tmp++; +- +- return tmp; ++ return div64_u64(full, scale); + } + + /** +diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c +index 30fb2de368210..e3f0de020a40c 100644 +--- a/drivers/iio/pressure/mprls0025pa.c ++++ b/drivers/iio/pressure/mprls0025pa.c +@@ -323,6 +323,7 @@ static int mpr_probe(struct i2c_client *client) + struct iio_dev *indio_dev; + struct device *dev = &client->dev; + s64 scale, offset; ++ u32 func; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE)) + return dev_err_probe(dev, -EOPNOTSUPP, +@@ -362,10 +363,11 @@ static int mpr_probe(struct i2c_client *client) + return dev_err_probe(dev, ret, + "honeywell,pmax-pascal could not be read\n"); + ret = device_property_read_u32(dev, +- "honeywell,transfer-function", &data->function); ++ "honeywell,transfer-function", &func); + if (ret) + return dev_err_probe(dev, ret, + "honeywell,transfer-function could not be read\n"); ++ data->function = func - 1; + if (data->function > MPR_FUNCTION_C) + return dev_err_probe(dev, -EINVAL, + "honeywell,transfer-function %d invalid\n", +diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c +index 67bcea7a153c6..07cb6c5ffda00 100644 +--- a/drivers/infiniband/core/device.c ++++ b/drivers/infiniband/core/device.c +@@ -1730,7 +1730,7 @@ static int assign_client_id(struct ib_client *client) + { + int ret; + +- down_write(&clients_rwsem); ++ lockdep_assert_held(&clients_rwsem); + /* + * The add/remove callbacks must be called in FIFO/LIFO order. To + * achieve this we assign client_ids so they are sorted in +@@ -1739,14 +1739,11 @@ static int assign_client_id(struct ib_client *client) + client->client_id = highest_client_id; + ret = xa_insert(&clients, client->client_id, client, GFP_KERNEL); + if (ret) +- goto out; ++ return ret; + + highest_client_id++; + xa_set_mark(&clients, client->client_id, CLIENT_REGISTERED); +- +-out: +- up_write(&clients_rwsem); +- return ret; ++ return 0; + } + + static void remove_client_id(struct ib_client *client) +@@ -1776,25 +1773,35 @@ int ib_register_client(struct ib_client *client) + { + struct ib_device *device; + unsigned long index; ++ bool need_unreg = false; + int ret; + + refcount_set(&client->uses, 1); + init_completion(&client->uses_zero); ++ ++ /* ++ * The devices_rwsem is held in write mode to ensure that a racing ++ * ib_register_device() sees a consisent view of clients and devices. ++ */ ++ down_write(&devices_rwsem); ++ down_write(&clients_rwsem); + ret = assign_client_id(client); + if (ret) +- return ret; ++ goto out; + +- down_read(&devices_rwsem); ++ need_unreg = true; + xa_for_each_marked (&devices, index, device, DEVICE_REGISTERED) { + ret = add_client_context(device, client); +- if (ret) { +- up_read(&devices_rwsem); +- ib_unregister_client(client); +- return ret; +- } ++ if (ret) ++ goto out; + } +- up_read(&devices_rwsem); +- return 0; ++ ret = 0; ++out: ++ up_write(&clients_rwsem); ++ up_write(&devices_rwsem); ++ if (need_unreg && ret) ++ ib_unregister_client(client); ++ return ret; + } + EXPORT_SYMBOL(ib_register_client); + +diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h +index b1fce5ddf6316..46f8a631093ba 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_device.h ++++ b/drivers/infiniband/hw/hns/hns_roce_device.h +@@ -585,6 +585,13 @@ struct hns_roce_work { + u32 queue_num; + }; + ++enum hns_roce_cong_type { ++ CONG_TYPE_DCQCN, ++ CONG_TYPE_LDCP, ++ CONG_TYPE_HC3, ++ CONG_TYPE_DIP, ++}; ++ + struct hns_roce_qp { + struct ib_qp ibqp; + struct hns_roce_wq rq; +@@ -628,6 +635,7 @@ struct hns_roce_qp { + struct list_head sq_node; /* all send qps are on a list */ + struct hns_user_mmap_entry *dwqe_mmap_entry; + u32 config; ++ enum hns_roce_cong_type cong_type; + }; + + struct hns_roce_ib_iboe { +@@ -699,13 +707,6 @@ struct hns_roce_eq_table { + struct hns_roce_eq *eq; + }; + +-enum cong_type { +- CONG_TYPE_DCQCN, +- CONG_TYPE_LDCP, +- CONG_TYPE_HC3, +- CONG_TYPE_DIP, +-}; +- + struct hns_roce_caps { + u64 fw_ver; + u8 num_ports; +@@ -835,7 +836,7 @@ struct hns_roce_caps { + u16 default_aeq_period; + u16 default_aeq_arm_st; + u16 default_ceq_arm_st; +- enum cong_type cong_type; ++ enum hns_roce_cong_type cong_type; + }; + + enum hns_roce_device_state { +diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +index 8206daea6767d..34e58e09b15d8 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c ++++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +@@ -4745,12 +4745,15 @@ static int check_cong_type(struct ib_qp *ibqp, + struct hns_roce_congestion_algorithm *cong_alg) + { + struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device); ++ struct hns_roce_qp *hr_qp = to_hr_qp(ibqp); + +- if (ibqp->qp_type == IB_QPT_UD) +- hr_dev->caps.cong_type = CONG_TYPE_DCQCN; ++ if (ibqp->qp_type == IB_QPT_UD || ibqp->qp_type == IB_QPT_GSI) ++ hr_qp->cong_type = CONG_TYPE_DCQCN; ++ else ++ hr_qp->cong_type = hr_dev->caps.cong_type; + + /* different congestion types match different configurations */ +- switch (hr_dev->caps.cong_type) { ++ switch (hr_qp->cong_type) { + case CONG_TYPE_DCQCN: + cong_alg->alg_sel = CONG_DCQCN; + cong_alg->alg_sub_sel = UNSUPPORT_CONG_LEVEL; +@@ -4778,8 +4781,8 @@ static int check_cong_type(struct ib_qp *ibqp, + default: + ibdev_warn(&hr_dev->ib_dev, + "invalid type(%u) for congestion selection.\n", +- hr_dev->caps.cong_type); +- hr_dev->caps.cong_type = CONG_TYPE_DCQCN; ++ hr_qp->cong_type); ++ hr_qp->cong_type = CONG_TYPE_DCQCN; + cong_alg->alg_sel = CONG_DCQCN; + cong_alg->alg_sub_sel = UNSUPPORT_CONG_LEVEL; + cong_alg->dip_vld = DIP_INVALID; +@@ -4798,6 +4801,7 @@ static int fill_cong_field(struct ib_qp *ibqp, const struct ib_qp_attr *attr, + struct hns_roce_congestion_algorithm cong_field; + struct ib_device *ibdev = ibqp->device; + struct hns_roce_dev *hr_dev = to_hr_dev(ibdev); ++ struct hns_roce_qp *hr_qp = to_hr_qp(ibqp); + u32 dip_idx = 0; + int ret; + +@@ -4810,7 +4814,7 @@ static int fill_cong_field(struct ib_qp *ibqp, const struct ib_qp_attr *attr, + return ret; + + hr_reg_write(context, QPC_CONG_ALGO_TMPL_ID, hr_dev->cong_algo_tmpl_id + +- hr_dev->caps.cong_type * HNS_ROCE_CONG_SIZE); ++ hr_qp->cong_type * HNS_ROCE_CONG_SIZE); + hr_reg_clear(qpc_mask, QPC_CONG_ALGO_TMPL_ID); + hr_reg_write(&context->ext, QPCEX_CONG_ALG_SEL, cong_field.alg_sel); + hr_reg_clear(&qpc_mask->ext, QPCEX_CONG_ALG_SEL); +diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c +index 0b046c061742b..12704efb7b19a 100644 +--- a/drivers/infiniband/hw/irdma/verbs.c ++++ b/drivers/infiniband/hw/irdma/verbs.c +@@ -719,7 +719,6 @@ static int irdma_setup_kmode_qp(struct irdma_device *iwdev, + info->rq_pa + (ukinfo->rq_depth * IRDMA_QP_WQE_MIN_SIZE); + ukinfo->sq_size = ukinfo->sq_depth >> ukinfo->sq_shift; + ukinfo->rq_size = ukinfo->rq_depth >> ukinfo->rq_shift; +- ukinfo->qp_id = iwqp->ibqp.qp_num; + + iwqp->max_send_wr = (ukinfo->sq_depth - IRDMA_SQ_RSVD) >> ukinfo->sq_shift; + iwqp->max_recv_wr = (ukinfo->rq_depth - IRDMA_RQ_RSVD) >> ukinfo->rq_shift; +@@ -944,7 +943,7 @@ static int irdma_create_qp(struct ib_qp *ibqp, + iwqp->host_ctx.size = IRDMA_QP_CTX_SIZE; + + init_info.pd = &iwpd->sc_pd; +- init_info.qp_uk_init_info.qp_id = iwqp->ibqp.qp_num; ++ init_info.qp_uk_init_info.qp_id = qp_num; + if (!rdma_protocol_roce(&iwdev->ibdev, 1)) + init_info.qp_uk_init_info.first_sq_wq = 1; + iwqp->ctx_info.qp_compl_ctx = (uintptr_t)qp; +diff --git a/drivers/infiniband/hw/mana/cq.c b/drivers/infiniband/hw/mana/cq.c +index 83ebd070535ab..4a71e678d09c1 100644 +--- a/drivers/infiniband/hw/mana/cq.c ++++ b/drivers/infiniband/hw/mana/cq.c +@@ -16,7 +16,7 @@ int mana_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, + int err; + + mdev = container_of(ibdev, struct mana_ib_dev, ib_dev); +- gc = mdev->gdma_dev->gdma_context; ++ gc = mdev_to_gc(mdev); + + if (udata->inlen < sizeof(ucmd)) + return -EINVAL; +@@ -48,7 +48,7 @@ int mana_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, + return err; + } + +- err = mana_ib_gd_create_dma_region(mdev, cq->umem, &cq->gdma_region); ++ err = mana_ib_create_zero_offset_dma_region(mdev, cq->umem, &cq->gdma_region); + if (err) { + ibdev_dbg(ibdev, + "Failed to create dma region for create cq, %d\n", +@@ -57,7 +57,7 @@ int mana_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, + } + + ibdev_dbg(ibdev, +- "mana_ib_gd_create_dma_region ret %d gdma_region 0x%llx\n", ++ "create_dma_region ret %d gdma_region 0x%llx\n", + err, cq->gdma_region); + + /* +@@ -81,7 +81,7 @@ int mana_ib_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata) + int err; + + mdev = container_of(ibdev, struct mana_ib_dev, ib_dev); +- gc = mdev->gdma_dev->gdma_context; ++ gc = mdev_to_gc(mdev); + + err = mana_ib_gd_destroy_dma_region(mdev, cq->gdma_region); + if (err) { +@@ -100,10 +100,29 @@ int mana_ib_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata) + return 0; + } + +-void mana_ib_cq_handler(void *ctx, struct gdma_queue *gdma_cq) ++static void mana_ib_cq_handler(void *ctx, struct gdma_queue *gdma_cq) + { + struct mana_ib_cq *cq = ctx; + + if (cq->ibcq.comp_handler) + cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context); + } ++ ++int mana_ib_install_cq_cb(struct mana_ib_dev *mdev, struct mana_ib_cq *cq) ++{ ++ struct gdma_context *gc = mdev_to_gc(mdev); ++ struct gdma_queue *gdma_cq; ++ ++ /* Create CQ table entry */ ++ WARN_ON(gc->cq_table[cq->id]); ++ gdma_cq = kzalloc(sizeof(*gdma_cq), GFP_KERNEL); ++ if (!gdma_cq) ++ return -ENOMEM; ++ ++ gdma_cq->cq.context = cq; ++ gdma_cq->type = GDMA_CQ; ++ gdma_cq->cq.callback = mana_ib_cq_handler; ++ gdma_cq->id = cq->id; ++ gc->cq_table[cq->id] = gdma_cq; ++ return 0; ++} +diff --git a/drivers/infiniband/hw/mana/main.c b/drivers/infiniband/hw/mana/main.c +index faca092456fa3..71e33feee61bb 100644 +--- a/drivers/infiniband/hw/mana/main.c ++++ b/drivers/infiniband/hw/mana/main.c +@@ -8,13 +8,10 @@ + void mana_ib_uncfg_vport(struct mana_ib_dev *dev, struct mana_ib_pd *pd, + u32 port) + { +- struct gdma_dev *gd = &dev->gdma_dev->gdma_context->mana; + struct mana_port_context *mpc; + struct net_device *ndev; +- struct mana_context *mc; + +- mc = gd->driver_data; +- ndev = mc->ports[port]; ++ ndev = mana_ib_get_netdev(&dev->ib_dev, port); + mpc = netdev_priv(ndev); + + mutex_lock(&pd->vport_mutex); +@@ -31,14 +28,11 @@ void mana_ib_uncfg_vport(struct mana_ib_dev *dev, struct mana_ib_pd *pd, + int mana_ib_cfg_vport(struct mana_ib_dev *dev, u32 port, struct mana_ib_pd *pd, + u32 doorbell_id) + { +- struct gdma_dev *mdev = &dev->gdma_dev->gdma_context->mana; + struct mana_port_context *mpc; +- struct mana_context *mc; + struct net_device *ndev; + int err; + +- mc = mdev->driver_data; +- ndev = mc->ports[port]; ++ ndev = mana_ib_get_netdev(&dev->ib_dev, port); + mpc = netdev_priv(ndev); + + mutex_lock(&pd->vport_mutex); +@@ -79,17 +73,17 @@ int mana_ib_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata) + struct gdma_create_pd_req req = {}; + enum gdma_pd_flags flags = 0; + struct mana_ib_dev *dev; +- struct gdma_dev *mdev; ++ struct gdma_context *gc; + int err; + + dev = container_of(ibdev, struct mana_ib_dev, ib_dev); +- mdev = dev->gdma_dev; ++ gc = mdev_to_gc(dev); + + mana_gd_init_req_hdr(&req.hdr, GDMA_CREATE_PD, sizeof(req), + sizeof(resp)); + + req.flags = flags; +- err = mana_gd_send_request(mdev->gdma_context, sizeof(req), &req, ++ err = mana_gd_send_request(gc, sizeof(req), &req, + sizeof(resp), &resp); + + if (err || resp.hdr.status) { +@@ -119,17 +113,17 @@ int mana_ib_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata) + struct gdma_destory_pd_resp resp = {}; + struct gdma_destroy_pd_req req = {}; + struct mana_ib_dev *dev; +- struct gdma_dev *mdev; ++ struct gdma_context *gc; + int err; + + dev = container_of(ibdev, struct mana_ib_dev, ib_dev); +- mdev = dev->gdma_dev; ++ gc = mdev_to_gc(dev); + + mana_gd_init_req_hdr(&req.hdr, GDMA_DESTROY_PD, sizeof(req), + sizeof(resp)); + + req.pd_handle = pd->pd_handle; +- err = mana_gd_send_request(mdev->gdma_context, sizeof(req), &req, ++ err = mana_gd_send_request(gc, sizeof(req), &req, + sizeof(resp), &resp); + + if (err || resp.hdr.status) { +@@ -206,13 +200,11 @@ int mana_ib_alloc_ucontext(struct ib_ucontext *ibcontext, + struct ib_device *ibdev = ibcontext->device; + struct mana_ib_dev *mdev; + struct gdma_context *gc; +- struct gdma_dev *dev; + int doorbell_page; + int ret; + + mdev = container_of(ibdev, struct mana_ib_dev, ib_dev); +- dev = mdev->gdma_dev; +- gc = dev->gdma_context; ++ gc = mdev_to_gc(mdev); + + /* Allocate a doorbell page index */ + ret = mana_gd_allocate_doorbell_page(gc, &doorbell_page); +@@ -238,7 +230,7 @@ void mana_ib_dealloc_ucontext(struct ib_ucontext *ibcontext) + int ret; + + mdev = container_of(ibdev, struct mana_ib_dev, ib_dev); +- gc = mdev->gdma_dev->gdma_context; ++ gc = mdev_to_gc(mdev); + + ret = mana_gd_destroy_doorbell_page(gc, mana_ucontext->doorbell); + if (ret) +@@ -309,8 +301,8 @@ mana_ib_gd_add_dma_region(struct mana_ib_dev *dev, struct gdma_context *gc, + return 0; + } + +-int mana_ib_gd_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem, +- mana_handle_t *gdma_region) ++static int mana_ib_gd_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem, ++ mana_handle_t *gdma_region, unsigned long page_sz) + { + struct gdma_dma_region_add_pages_req *add_req = NULL; + size_t num_pages_processed = 0, num_pages_to_handle; +@@ -322,23 +314,14 @@ int mana_ib_gd_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem, + size_t max_pgs_create_cmd; + struct gdma_context *gc; + size_t num_pages_total; +- struct gdma_dev *mdev; +- unsigned long page_sz; + unsigned int tail = 0; + u64 *page_addr_list; + void *request_buf; + int err; + +- mdev = dev->gdma_dev; +- gc = mdev->gdma_context; ++ gc = mdev_to_gc(dev); + hwc = gc->hwc.driver_data; + +- /* Hardware requires dma region to align to chosen page size */ +- page_sz = ib_umem_find_best_pgsz(umem, PAGE_SZ_BM, 0); +- if (!page_sz) { +- ibdev_dbg(&dev->ib_dev, "failed to find page size.\n"); +- return -ENOMEM; +- } + num_pages_total = ib_umem_num_dma_blocks(umem, page_sz); + + max_pgs_create_cmd = +@@ -358,7 +341,7 @@ int mana_ib_gd_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem, + sizeof(struct gdma_create_dma_region_resp)); + + create_req->length = umem->length; +- create_req->offset_in_page = umem->address & (page_sz - 1); ++ create_req->offset_in_page = ib_umem_dma_offset(umem, page_sz); + create_req->gdma_page_type = order_base_2(page_sz) - PAGE_SHIFT; + create_req->page_count = num_pages_total; + +@@ -424,12 +407,39 @@ int mana_ib_gd_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem, + return err; + } + ++int mana_ib_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem, ++ mana_handle_t *gdma_region, u64 virt) ++{ ++ unsigned long page_sz; ++ ++ page_sz = ib_umem_find_best_pgsz(umem, PAGE_SZ_BM, virt); ++ if (!page_sz) { ++ ibdev_dbg(&dev->ib_dev, "Failed to find page size.\n"); ++ return -EINVAL; ++ } ++ ++ return mana_ib_gd_create_dma_region(dev, umem, gdma_region, page_sz); ++} ++ ++int mana_ib_create_zero_offset_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem, ++ mana_handle_t *gdma_region) ++{ ++ unsigned long page_sz; ++ ++ /* Hardware requires dma region to align to chosen page size */ ++ page_sz = ib_umem_find_best_pgoff(umem, PAGE_SZ_BM, 0); ++ if (!page_sz) { ++ ibdev_dbg(&dev->ib_dev, "Failed to find page size.\n"); ++ return -EINVAL; ++ } ++ ++ return mana_ib_gd_create_dma_region(dev, umem, gdma_region, page_sz); ++} ++ + int mana_ib_gd_destroy_dma_region(struct mana_ib_dev *dev, u64 gdma_region) + { +- struct gdma_dev *mdev = dev->gdma_dev; +- struct gdma_context *gc; ++ struct gdma_context *gc = mdev_to_gc(dev); + +- gc = mdev->gdma_context; + ibdev_dbg(&dev->ib_dev, "destroy dma region 0x%llx\n", gdma_region); + + return mana_gd_destroy_dma_region(gc, gdma_region); +@@ -447,7 +457,7 @@ int mana_ib_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma) + int ret; + + mdev = container_of(ibdev, struct mana_ib_dev, ib_dev); +- gc = mdev->gdma_dev->gdma_context; ++ gc = mdev_to_gc(mdev); + + if (vma->vm_pgoff != 0) { + ibdev_dbg(ibdev, "Unexpected vm_pgoff %lu\n", vma->vm_pgoff); +@@ -531,7 +541,7 @@ int mana_ib_gd_query_adapter_caps(struct mana_ib_dev *dev) + req.hdr.resp.msg_version = GDMA_MESSAGE_V3; + req.hdr.dev_id = dev->gdma_dev->dev_id; + +- err = mana_gd_send_request(dev->gdma_dev->gdma_context, sizeof(req), ++ err = mana_gd_send_request(mdev_to_gc(dev), sizeof(req), + &req, sizeof(resp), &resp); + + if (err) { +diff --git a/drivers/infiniband/hw/mana/mana_ib.h b/drivers/infiniband/hw/mana/mana_ib.h +index 6bdc0f5498d5b..f83390eebb7d7 100644 +--- a/drivers/infiniband/hw/mana/mana_ib.h ++++ b/drivers/infiniband/hw/mana/mana_ib.h +@@ -142,8 +142,29 @@ struct mana_ib_query_adapter_caps_resp { + u32 max_inline_data_size; + }; /* HW Data */ + +-int mana_ib_gd_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem, +- mana_handle_t *gdma_region); ++static inline struct gdma_context *mdev_to_gc(struct mana_ib_dev *mdev) ++{ ++ return mdev->gdma_dev->gdma_context; ++} ++ ++static inline struct net_device *mana_ib_get_netdev(struct ib_device *ibdev, u32 port) ++{ ++ struct mana_ib_dev *mdev = container_of(ibdev, struct mana_ib_dev, ib_dev); ++ struct gdma_context *gc = mdev_to_gc(mdev); ++ struct mana_context *mc = gc->mana.driver_data; ++ ++ if (port < 1 || port > mc->num_ports) ++ return NULL; ++ return mc->ports[port - 1]; ++} ++ ++int mana_ib_install_cq_cb(struct mana_ib_dev *mdev, struct mana_ib_cq *cq); ++ ++int mana_ib_create_zero_offset_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem, ++ mana_handle_t *gdma_region); ++ ++int mana_ib_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem, ++ mana_handle_t *gdma_region, u64 virt); + + int mana_ib_gd_destroy_dma_region(struct mana_ib_dev *dev, + mana_handle_t gdma_region); +@@ -210,6 +231,4 @@ int mana_ib_query_gid(struct ib_device *ibdev, u32 port, int index, + void mana_ib_disassociate_ucontext(struct ib_ucontext *ibcontext); + + int mana_ib_gd_query_adapter_caps(struct mana_ib_dev *mdev); +- +-void mana_ib_cq_handler(void *ctx, struct gdma_queue *gdma_cq); + #endif +diff --git a/drivers/infiniband/hw/mana/mr.c b/drivers/infiniband/hw/mana/mr.c +index 351207c60eb65..b70b13484f097 100644 +--- a/drivers/infiniband/hw/mana/mr.c ++++ b/drivers/infiniband/hw/mana/mr.c +@@ -30,12 +30,9 @@ static int mana_ib_gd_create_mr(struct mana_ib_dev *dev, struct mana_ib_mr *mr, + { + struct gdma_create_mr_response resp = {}; + struct gdma_create_mr_request req = {}; +- struct gdma_dev *mdev = dev->gdma_dev; +- struct gdma_context *gc; ++ struct gdma_context *gc = mdev_to_gc(dev); + int err; + +- gc = mdev->gdma_context; +- + mana_gd_init_req_hdr(&req.hdr, GDMA_CREATE_MR, sizeof(req), + sizeof(resp)); + req.pd_handle = mr_params->pd_handle; +@@ -77,12 +74,9 @@ static int mana_ib_gd_destroy_mr(struct mana_ib_dev *dev, u64 mr_handle) + { + struct gdma_destroy_mr_response resp = {}; + struct gdma_destroy_mr_request req = {}; +- struct gdma_dev *mdev = dev->gdma_dev; +- struct gdma_context *gc; ++ struct gdma_context *gc = mdev_to_gc(dev); + int err; + +- gc = mdev->gdma_context; +- + mana_gd_init_req_hdr(&req.hdr, GDMA_DESTROY_MR, sizeof(req), + sizeof(resp)); + +@@ -133,7 +127,7 @@ struct ib_mr *mana_ib_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 length, + goto err_free; + } + +- err = mana_ib_gd_create_dma_region(dev, mr->umem, &dma_region_handle); ++ err = mana_ib_create_dma_region(dev, mr->umem, &dma_region_handle, iova); + if (err) { + ibdev_dbg(ibdev, "Failed create dma region for user-mr, %d\n", + err); +@@ -141,7 +135,7 @@ struct ib_mr *mana_ib_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 length, + } + + ibdev_dbg(ibdev, +- "mana_ib_gd_create_dma_region ret %d gdma_region %llx\n", err, ++ "create_dma_region ret %d gdma_region %llx\n", err, + dma_region_handle); + + mr_params.pd_handle = pd->pd_handle; +@@ -164,8 +158,7 @@ struct ib_mr *mana_ib_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 length, + return &mr->ibmr; + + err_dma_region: +- mana_gd_destroy_dma_region(dev->gdma_dev->gdma_context, +- dma_region_handle); ++ mana_gd_destroy_dma_region(mdev_to_gc(dev), dma_region_handle); + + err_umem: + ib_umem_release(mr->umem); +diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c +index 21ac9fcadf3f2..6e7627745c957 100644 +--- a/drivers/infiniband/hw/mana/qp.c ++++ b/drivers/infiniband/hw/mana/qp.c +@@ -17,12 +17,10 @@ static int mana_ib_cfg_vport_steering(struct mana_ib_dev *dev, + struct mana_cfg_rx_steer_resp resp = {}; + mana_handle_t *req_indir_tab; + struct gdma_context *gc; +- struct gdma_dev *mdev; + u32 req_buf_size; + int i, err; + +- gc = dev->gdma_dev->gdma_context; +- mdev = &gc->mana; ++ gc = mdev_to_gc(dev); + + req_buf_size = + sizeof(*req) + sizeof(mana_handle_t) * MANA_INDIRECT_TABLE_SIZE; +@@ -39,7 +37,7 @@ static int mana_ib_cfg_vport_steering(struct mana_ib_dev *dev, + req->rx_enable = 1; + req->update_default_rxobj = 1; + req->default_rxobj = default_rxobj; +- req->hdr.dev_id = mdev->dev_id; ++ req->hdr.dev_id = gc->mana.dev_id; + + /* If there are more than 1 entries in indirection table, enable RSS */ + if (log_ind_tbl_size) +@@ -99,20 +97,17 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd, + struct mana_ib_qp *qp = container_of(ibqp, struct mana_ib_qp, ibqp); + struct mana_ib_dev *mdev = + container_of(pd->device, struct mana_ib_dev, ib_dev); ++ struct gdma_context *gc = mdev_to_gc(mdev); + struct ib_rwq_ind_table *ind_tbl = attr->rwq_ind_tbl; + struct mana_ib_create_qp_rss_resp resp = {}; + struct mana_ib_create_qp_rss ucmd = {}; + struct gdma_queue **gdma_cq_allocated; + mana_handle_t *mana_ind_table; + struct mana_port_context *mpc; +- struct gdma_queue *gdma_cq; + unsigned int ind_tbl_size; +- struct mana_context *mc; + struct net_device *ndev; +- struct gdma_context *gc; + struct mana_ib_cq *cq; + struct mana_ib_wq *wq; +- struct gdma_dev *gd; + struct mana_eq *eq; + struct ib_cq *ibcq; + struct ib_wq *ibwq; +@@ -120,10 +115,6 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd, + u32 port; + int ret; + +- gc = mdev->gdma_dev->gdma_context; +- gd = &gc->mana; +- mc = gd->driver_data; +- + if (!udata || udata->inlen < sizeof(ucmd)) + return -EINVAL; + +@@ -166,12 +157,12 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd, + + /* IB ports start with 1, MANA start with 0 */ + port = ucmd.port; +- if (port < 1 || port > mc->num_ports) { ++ ndev = mana_ib_get_netdev(pd->device, port); ++ if (!ndev) { + ibdev_dbg(&mdev->ib_dev, "Invalid port %u in creating qp\n", + port); + return -EINVAL; + } +- ndev = mc->ports[port - 1]; + mpc = netdev_priv(ndev); + + ibdev_dbg(&mdev->ib_dev, "rx_hash_function %d port %d\n", +@@ -209,7 +200,7 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd, + cq_spec.gdma_region = cq->gdma_region; + cq_spec.queue_size = cq->cqe * COMP_ENTRY_SIZE; + cq_spec.modr_ctx_id = 0; +- eq = &mc->eqs[cq->comp_vector % gc->max_num_queues]; ++ eq = &mpc->ac->eqs[cq->comp_vector % gc->max_num_queues]; + cq_spec.attached_eq = eq->eq->id; + + ret = mana_create_wq_obj(mpc, mpc->port_handle, GDMA_RQ, +@@ -237,19 +228,11 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd, + mana_ind_table[i] = wq->rx_object; + + /* Create CQ table entry */ +- WARN_ON(gc->cq_table[cq->id]); +- gdma_cq = kzalloc(sizeof(*gdma_cq), GFP_KERNEL); +- if (!gdma_cq) { +- ret = -ENOMEM; ++ ret = mana_ib_install_cq_cb(mdev, cq); ++ if (ret) + goto fail; +- } +- gdma_cq_allocated[i] = gdma_cq; + +- gdma_cq->cq.context = cq; +- gdma_cq->type = GDMA_CQ; +- gdma_cq->cq.callback = mana_ib_cq_handler; +- gdma_cq->id = cq->id; +- gc->cq_table[cq->id] = gdma_cq; ++ gdma_cq_allocated[i] = gc->cq_table[cq->id]; + } + resp.num_entries = i; + +@@ -306,14 +289,13 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd, + struct mana_ib_ucontext *mana_ucontext = + rdma_udata_to_drv_context(udata, struct mana_ib_ucontext, + ibucontext); +- struct gdma_dev *gd = &mdev->gdma_dev->gdma_context->mana; ++ struct gdma_context *gc = mdev_to_gc(mdev); + struct mana_ib_create_qp_resp resp = {}; + struct mana_ib_create_qp ucmd = {}; + struct gdma_queue *gdma_cq = NULL; + struct mana_obj_spec wq_spec = {}; + struct mana_obj_spec cq_spec = {}; + struct mana_port_context *mpc; +- struct mana_context *mc; + struct net_device *ndev; + struct ib_umem *umem; + struct mana_eq *eq; +@@ -321,8 +303,6 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd, + u32 port; + int err; + +- mc = gd->driver_data; +- + if (!mana_ucontext || udata->inlen < sizeof(ucmd)) + return -EINVAL; + +@@ -333,11 +313,6 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd, + return err; + } + +- /* IB ports start with 1, MANA Ethernet ports start with 0 */ +- port = ucmd.port; +- if (port < 1 || port > mc->num_ports) +- return -EINVAL; +- + if (attr->cap.max_send_wr > mdev->adapter_caps.max_qp_wr) { + ibdev_dbg(&mdev->ib_dev, + "Requested max_send_wr %d exceeding limit\n", +@@ -352,11 +327,17 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd, + return -EINVAL; + } + +- ndev = mc->ports[port - 1]; ++ port = ucmd.port; ++ ndev = mana_ib_get_netdev(ibpd->device, port); ++ if (!ndev) { ++ ibdev_dbg(&mdev->ib_dev, "Invalid port %u in creating qp\n", ++ port); ++ return -EINVAL; ++ } + mpc = netdev_priv(ndev); + ibdev_dbg(&mdev->ib_dev, "port %u ndev %p mpc %p\n", port, ndev, mpc); + +- err = mana_ib_cfg_vport(mdev, port - 1, pd, mana_ucontext->doorbell); ++ err = mana_ib_cfg_vport(mdev, port, pd, mana_ucontext->doorbell); + if (err) + return -ENODEV; + +@@ -376,8 +357,8 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd, + } + qp->sq_umem = umem; + +- err = mana_ib_gd_create_dma_region(mdev, qp->sq_umem, +- &qp->sq_gdma_region); ++ err = mana_ib_create_zero_offset_dma_region(mdev, qp->sq_umem, ++ &qp->sq_gdma_region); + if (err) { + ibdev_dbg(&mdev->ib_dev, + "Failed to create dma region for create qp-raw, %d\n", +@@ -386,7 +367,7 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd, + } + + ibdev_dbg(&mdev->ib_dev, +- "mana_ib_gd_create_dma_region ret %d gdma_region 0x%llx\n", ++ "create_dma_region ret %d gdma_region 0x%llx\n", + err, qp->sq_gdma_region); + + /* Create a WQ on the same port handle used by the Ethernet */ +@@ -396,8 +377,8 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd, + cq_spec.gdma_region = send_cq->gdma_region; + cq_spec.queue_size = send_cq->cqe * COMP_ENTRY_SIZE; + cq_spec.modr_ctx_id = 0; +- eq_vec = send_cq->comp_vector % gd->gdma_context->max_num_queues; +- eq = &mc->eqs[eq_vec]; ++ eq_vec = send_cq->comp_vector % gc->max_num_queues; ++ eq = &mpc->ac->eqs[eq_vec]; + cq_spec.attached_eq = eq->eq->id; + + err = mana_create_wq_obj(mpc, mpc->port_handle, GDMA_SQ, &wq_spec, +@@ -417,18 +398,9 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd, + send_cq->id = cq_spec.queue_index; + + /* Create CQ table entry */ +- WARN_ON(gd->gdma_context->cq_table[send_cq->id]); +- gdma_cq = kzalloc(sizeof(*gdma_cq), GFP_KERNEL); +- if (!gdma_cq) { +- err = -ENOMEM; ++ err = mana_ib_install_cq_cb(mdev, send_cq); ++ if (err) + goto err_destroy_wq_obj; +- } +- +- gdma_cq->cq.context = send_cq; +- gdma_cq->type = GDMA_CQ; +- gdma_cq->cq.callback = mana_ib_cq_handler; +- gdma_cq->id = send_cq->id; +- gd->gdma_context->cq_table[send_cq->id] = gdma_cq; + + ibdev_dbg(&mdev->ib_dev, + "ret %d qp->tx_object 0x%llx sq id %llu cq id %llu\n", err, +@@ -450,7 +422,7 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd, + + err_release_gdma_cq: + kfree(gdma_cq); +- gd->gdma_context->cq_table[send_cq->id] = NULL; ++ gc->cq_table[send_cq->id] = NULL; + + err_destroy_wq_obj: + mana_destroy_wq_obj(mpc, GDMA_SQ, qp->tx_object); +@@ -462,7 +434,7 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd, + ib_umem_release(umem); + + err_free_vport: +- mana_ib_uncfg_vport(mdev, pd, port - 1); ++ mana_ib_uncfg_vport(mdev, pd, port); + + return err; + } +@@ -500,16 +472,13 @@ static int mana_ib_destroy_qp_rss(struct mana_ib_qp *qp, + { + struct mana_ib_dev *mdev = + container_of(qp->ibqp.device, struct mana_ib_dev, ib_dev); +- struct gdma_dev *gd = &mdev->gdma_dev->gdma_context->mana; + struct mana_port_context *mpc; +- struct mana_context *mc; + struct net_device *ndev; + struct mana_ib_wq *wq; + struct ib_wq *ibwq; + int i; + +- mc = gd->driver_data; +- ndev = mc->ports[qp->port - 1]; ++ ndev = mana_ib_get_netdev(qp->ibqp.device, qp->port); + mpc = netdev_priv(ndev); + + for (i = 0; i < (1 << ind_tbl->log_ind_tbl_size); i++) { +@@ -527,15 +496,12 @@ static int mana_ib_destroy_qp_raw(struct mana_ib_qp *qp, struct ib_udata *udata) + { + struct mana_ib_dev *mdev = + container_of(qp->ibqp.device, struct mana_ib_dev, ib_dev); +- struct gdma_dev *gd = &mdev->gdma_dev->gdma_context->mana; + struct ib_pd *ibpd = qp->ibqp.pd; + struct mana_port_context *mpc; +- struct mana_context *mc; + struct net_device *ndev; + struct mana_ib_pd *pd; + +- mc = gd->driver_data; +- ndev = mc->ports[qp->port - 1]; ++ ndev = mana_ib_get_netdev(qp->ibqp.device, qp->port); + mpc = netdev_priv(ndev); + pd = container_of(ibpd, struct mana_ib_pd, ibpd); + +@@ -546,7 +512,7 @@ static int mana_ib_destroy_qp_raw(struct mana_ib_qp *qp, struct ib_udata *udata) + ib_umem_release(qp->sq_umem); + } + +- mana_ib_uncfg_vport(mdev, pd, qp->port - 1); ++ mana_ib_uncfg_vport(mdev, pd, qp->port); + + return 0; + } +diff --git a/drivers/infiniband/hw/mana/wq.c b/drivers/infiniband/hw/mana/wq.c +index 372d361510e0c..7c9c699625734 100644 +--- a/drivers/infiniband/hw/mana/wq.c ++++ b/drivers/infiniband/hw/mana/wq.c +@@ -46,7 +46,7 @@ struct ib_wq *mana_ib_create_wq(struct ib_pd *pd, + wq->wq_buf_size = ucmd.wq_buf_size; + wq->rx_object = INVALID_MANA_HANDLE; + +- err = mana_ib_gd_create_dma_region(mdev, wq->umem, &wq->gdma_region); ++ err = mana_ib_create_zero_offset_dma_region(mdev, wq->umem, &wq->gdma_region); + if (err) { + ibdev_dbg(&mdev->ib_dev, + "Failed to create dma region for create wq, %d\n", +@@ -55,7 +55,7 @@ struct ib_wq *mana_ib_create_wq(struct ib_pd *pd, + } + + ibdev_dbg(&mdev->ib_dev, +- "mana_ib_gd_create_dma_region ret %d gdma_region 0x%llx\n", ++ "create_dma_region ret %d gdma_region 0x%llx\n", + err, wq->gdma_region); + + /* WQ ID is returned at wq_create time, doesn't know the value yet */ +diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt-sysfs.c b/drivers/infiniband/ulp/rtrs/rtrs-clt-sysfs.c +index d3c436ead6946..4aa80c9388f05 100644 +--- a/drivers/infiniband/ulp/rtrs/rtrs-clt-sysfs.c ++++ b/drivers/infiniband/ulp/rtrs/rtrs-clt-sysfs.c +@@ -133,7 +133,7 @@ static ssize_t mpath_policy_store(struct device *dev, + + /* distinguish "mi" and "min-latency" with length */ + len = strnlen(buf, NAME_MAX); +- if (buf[len - 1] == '\n') ++ if (len && buf[len - 1] == '\n') + len--; + + if (!strncasecmp(buf, "round-robin", 11) || +diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c +index 040234c01be4d..9632afbd727b6 100644 +--- a/drivers/infiniband/ulp/srpt/ib_srpt.c ++++ b/drivers/infiniband/ulp/srpt/ib_srpt.c +@@ -3209,7 +3209,6 @@ static int srpt_add_one(struct ib_device *device) + + INIT_IB_EVENT_HANDLER(&sdev->event_handler, sdev->device, + srpt_event_handler); +- ib_register_event_handler(&sdev->event_handler); + + for (i = 1; i <= sdev->device->phys_port_cnt; i++) { + sport = &sdev->port[i - 1]; +@@ -3232,6 +3231,7 @@ static int srpt_add_one(struct ib_device *device) + } + } + ++ ib_register_event_handler(&sdev->event_handler); + spin_lock(&srpt_dev_lock); + list_add_tail(&sdev->list, &srpt_dev_list); + spin_unlock(&srpt_dev_lock); +@@ -3242,7 +3242,6 @@ static int srpt_add_one(struct ib_device *device) + + err_port: + srpt_unregister_mad_agent(sdev, i); +- ib_unregister_event_handler(&sdev->event_handler); + err_cm: + if (sdev->cm_id) + ib_destroy_cm_id(sdev->cm_id); +diff --git a/drivers/input/misc/iqs7222.c b/drivers/input/misc/iqs7222.c +index 36aeeae776110..9ca5a743f19fe 100644 +--- a/drivers/input/misc/iqs7222.c ++++ b/drivers/input/misc/iqs7222.c +@@ -620,6 +620,118 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = { + }, + }, + }, ++ { ++ .prod_num = IQS7222_PROD_NUM_D, ++ .fw_major = 1, ++ .fw_minor = 2, ++ .touch_link = 1770, ++ .allow_offset = 9, ++ .event_offset = 10, ++ .comms_offset = 11, ++ .reg_grps = { ++ [IQS7222_REG_GRP_STAT] = { ++ .base = IQS7222_SYS_STATUS, ++ .num_row = 1, ++ .num_col = 7, ++ }, ++ [IQS7222_REG_GRP_CYCLE] = { ++ .base = 0x8000, ++ .num_row = 7, ++ .num_col = 2, ++ }, ++ [IQS7222_REG_GRP_GLBL] = { ++ .base = 0x8700, ++ .num_row = 1, ++ .num_col = 3, ++ }, ++ [IQS7222_REG_GRP_BTN] = { ++ .base = 0x9000, ++ .num_row = 14, ++ .num_col = 3, ++ }, ++ [IQS7222_REG_GRP_CHAN] = { ++ .base = 0xA000, ++ .num_row = 14, ++ .num_col = 4, ++ }, ++ [IQS7222_REG_GRP_FILT] = { ++ .base = 0xAE00, ++ .num_row = 1, ++ .num_col = 2, ++ }, ++ [IQS7222_REG_GRP_TPAD] = { ++ .base = 0xB000, ++ .num_row = 1, ++ .num_col = 24, ++ }, ++ [IQS7222_REG_GRP_GPIO] = { ++ .base = 0xC000, ++ .num_row = 3, ++ .num_col = 3, ++ }, ++ [IQS7222_REG_GRP_SYS] = { ++ .base = IQS7222_SYS_SETUP, ++ .num_row = 1, ++ .num_col = 12, ++ }, ++ }, ++ }, ++ { ++ .prod_num = IQS7222_PROD_NUM_D, ++ .fw_major = 1, ++ .fw_minor = 1, ++ .touch_link = 1774, ++ .allow_offset = 9, ++ .event_offset = 10, ++ .comms_offset = 11, ++ .reg_grps = { ++ [IQS7222_REG_GRP_STAT] = { ++ .base = IQS7222_SYS_STATUS, ++ .num_row = 1, ++ .num_col = 7, ++ }, ++ [IQS7222_REG_GRP_CYCLE] = { ++ .base = 0x8000, ++ .num_row = 7, ++ .num_col = 2, ++ }, ++ [IQS7222_REG_GRP_GLBL] = { ++ .base = 0x8700, ++ .num_row = 1, ++ .num_col = 3, ++ }, ++ [IQS7222_REG_GRP_BTN] = { ++ .base = 0x9000, ++ .num_row = 14, ++ .num_col = 3, ++ }, ++ [IQS7222_REG_GRP_CHAN] = { ++ .base = 0xA000, ++ .num_row = 14, ++ .num_col = 4, ++ }, ++ [IQS7222_REG_GRP_FILT] = { ++ .base = 0xAE00, ++ .num_row = 1, ++ .num_col = 2, ++ }, ++ [IQS7222_REG_GRP_TPAD] = { ++ .base = 0xB000, ++ .num_row = 1, ++ .num_col = 24, ++ }, ++ [IQS7222_REG_GRP_GPIO] = { ++ .base = 0xC000, ++ .num_row = 3, ++ .num_col = 3, ++ }, ++ [IQS7222_REG_GRP_SYS] = { ++ .base = IQS7222_SYS_SETUP, ++ .num_row = 1, ++ .num_col = 12, ++ }, ++ }, ++ }, + { + .prod_num = IQS7222_PROD_NUM_D, + .fw_major = 0, +diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig +index 9a29d742617e3..9dbb55e745bd9 100644 +--- a/drivers/iommu/Kconfig ++++ b/drivers/iommu/Kconfig +@@ -196,7 +196,7 @@ source "drivers/iommu/iommufd/Kconfig" + config IRQ_REMAP + bool "Support for Interrupt Remapping" + depends on X86_64 && X86_IO_APIC && PCI_MSI && ACPI +- select DMAR_TABLE ++ select DMAR_TABLE if INTEL_IOMMU + help + Supports Interrupt remapping for IO-APIC and MSI devices. + To use x2apic mode in the CPU's which support x2APIC enhancements or +diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c +index c83bd0c2a1c92..40979b0f5250f 100644 +--- a/drivers/iommu/amd/init.c ++++ b/drivers/iommu/amd/init.c +@@ -2068,6 +2068,9 @@ static int __init iommu_init_pci(struct amd_iommu *iommu) + /* Prevent binding other PCI device drivers to IOMMU devices */ + iommu->dev->match_driver = false; + ++ /* ACPI _PRT won't have an IRQ for IOMMU */ ++ iommu->dev->irq_managed = 1; ++ + pci_read_config_dword(iommu->dev, cap_ptr + MMIO_CAP_HDR_OFFSET, + &iommu->cap); + +diff --git a/drivers/iommu/intel/Makefile b/drivers/iommu/intel/Makefile +index 5dabf081a7793..5402b699a1229 100644 +--- a/drivers/iommu/intel/Makefile ++++ b/drivers/iommu/intel/Makefile +@@ -5,5 +5,7 @@ obj-$(CONFIG_DMAR_TABLE) += trace.o cap_audit.o + obj-$(CONFIG_DMAR_PERF) += perf.o + obj-$(CONFIG_INTEL_IOMMU_DEBUGFS) += debugfs.o + obj-$(CONFIG_INTEL_IOMMU_SVM) += svm.o ++ifdef CONFIG_INTEL_IOMMU + obj-$(CONFIG_IRQ_REMAP) += irq_remapping.o ++endif + obj-$(CONFIG_INTEL_IOMMU_PERF_EVENTS) += perfmon.o +diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c +index 23cb80d62a9ab..36d7427b12026 100644 +--- a/drivers/iommu/intel/dmar.c ++++ b/drivers/iommu/intel/dmar.c +@@ -1095,7 +1095,9 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd) + iommu->agaw = agaw; + iommu->msagaw = msagaw; + iommu->segment = drhd->segment; +- ++ iommu->device_rbtree = RB_ROOT; ++ spin_lock_init(&iommu->device_rbtree_lock); ++ mutex_init(&iommu->iopf_lock); + iommu->node = NUMA_NO_NODE; + + ver = readl(iommu->reg + DMAR_VER_REG); +@@ -1271,6 +1273,8 @@ static int qi_check_fault(struct intel_iommu *iommu, int index, int wait_index) + { + u32 fault; + int head, tail; ++ struct device *dev; ++ u64 iqe_err, ite_sid; + struct q_inval *qi = iommu->qi; + int shift = qi_shift(iommu); + +@@ -1315,6 +1319,13 @@ static int qi_check_fault(struct intel_iommu *iommu, int index, int wait_index) + tail = readl(iommu->reg + DMAR_IQT_REG); + tail = ((tail >> shift) - 1 + QI_LENGTH) % QI_LENGTH; + ++ /* ++ * SID field is valid only when the ITE field is Set in FSTS_REG ++ * see Intel VT-d spec r4.1, section 11.4.9.9 ++ */ ++ iqe_err = dmar_readq(iommu->reg + DMAR_IQER_REG); ++ ite_sid = DMAR_IQER_REG_ITESID(iqe_err); ++ + writel(DMA_FSTS_ITE, iommu->reg + DMAR_FSTS_REG); + pr_info("Invalidation Time-out Error (ITE) cleared\n"); + +@@ -1324,6 +1335,19 @@ static int qi_check_fault(struct intel_iommu *iommu, int index, int wait_index) + head = (head - 2 + QI_LENGTH) % QI_LENGTH; + } while (head != tail); + ++ /* ++ * If device was released or isn't present, no need to retry ++ * the ATS invalidate request anymore. ++ * ++ * 0 value of ite_sid means old VT-d device, no ite_sid value. ++ * see Intel VT-d spec r4.1, section 11.4.9.9 ++ */ ++ if (ite_sid) { ++ dev = device_rbtree_find(iommu, ite_sid); ++ if (!dev || !dev_is_pci(dev) || ++ !pci_device_is_present(to_pci_dev(dev))) ++ return -ETIMEDOUT; ++ } + if (qi->desc_status[wait_index] == QI_ABORT) + return -EAGAIN; + } +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 11652e0bcab3a..5dba58f322f03 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -97,6 +97,81 @@ static phys_addr_t root_entry_uctp(struct root_entry *re) + return re->hi & VTD_PAGE_MASK; + } + ++static int device_rid_cmp_key(const void *key, const struct rb_node *node) ++{ ++ struct device_domain_info *info = ++ rb_entry(node, struct device_domain_info, node); ++ const u16 *rid_lhs = key; ++ ++ if (*rid_lhs < PCI_DEVID(info->bus, info->devfn)) ++ return -1; ++ ++ if (*rid_lhs > PCI_DEVID(info->bus, info->devfn)) ++ return 1; ++ ++ return 0; ++} ++ ++static int device_rid_cmp(struct rb_node *lhs, const struct rb_node *rhs) ++{ ++ struct device_domain_info *info = ++ rb_entry(lhs, struct device_domain_info, node); ++ u16 key = PCI_DEVID(info->bus, info->devfn); ++ ++ return device_rid_cmp_key(&key, rhs); ++} ++ ++/* ++ * Looks up an IOMMU-probed device using its source ID. ++ * ++ * Returns the pointer to the device if there is a match. Otherwise, ++ * returns NULL. ++ * ++ * Note that this helper doesn't guarantee that the device won't be ++ * released by the iommu subsystem after being returned. The caller ++ * should use its own synchronization mechanism to avoid the device ++ * being released during its use if its possibly the case. ++ */ ++struct device *device_rbtree_find(struct intel_iommu *iommu, u16 rid) ++{ ++ struct device_domain_info *info = NULL; ++ struct rb_node *node; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&iommu->device_rbtree_lock, flags); ++ node = rb_find(&rid, &iommu->device_rbtree, device_rid_cmp_key); ++ if (node) ++ info = rb_entry(node, struct device_domain_info, node); ++ spin_unlock_irqrestore(&iommu->device_rbtree_lock, flags); ++ ++ return info ? info->dev : NULL; ++} ++ ++static int device_rbtree_insert(struct intel_iommu *iommu, ++ struct device_domain_info *info) ++{ ++ struct rb_node *curr; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&iommu->device_rbtree_lock, flags); ++ curr = rb_find_add(&info->node, &iommu->device_rbtree, device_rid_cmp); ++ spin_unlock_irqrestore(&iommu->device_rbtree_lock, flags); ++ if (WARN_ON(curr)) ++ return -EEXIST; ++ ++ return 0; ++} ++ ++static void device_rbtree_remove(struct device_domain_info *info) ++{ ++ struct intel_iommu *iommu = info->iommu; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&iommu->device_rbtree_lock, flags); ++ rb_erase(&info->node, &iommu->device_rbtree); ++ spin_unlock_irqrestore(&iommu->device_rbtree_lock, flags); ++} ++ + /* + * This domain is a statically identity mapping domain. + * 1. This domain creats a static 1:1 mapping to all usable memory. +@@ -3799,30 +3874,6 @@ static void domain_context_clear(struct device_domain_info *info) + &domain_context_clear_one_cb, info); + } + +-static void dmar_remove_one_dev_info(struct device *dev) +-{ +- struct device_domain_info *info = dev_iommu_priv_get(dev); +- struct dmar_domain *domain = info->domain; +- struct intel_iommu *iommu = info->iommu; +- unsigned long flags; +- +- if (!dev_is_real_dma_subdevice(info->dev)) { +- if (dev_is_pci(info->dev) && sm_supported(iommu)) +- intel_pasid_tear_down_entry(iommu, info->dev, +- IOMMU_NO_PASID, false); +- +- iommu_disable_pci_caps(info); +- domain_context_clear(info); +- } +- +- spin_lock_irqsave(&domain->lock, flags); +- list_del(&info->link); +- spin_unlock_irqrestore(&domain->lock, flags); +- +- domain_detach_iommu(domain, iommu); +- info->domain = NULL; +-} +- + /* + * Clear the page table pointer in context or pasid table entries so that + * all DMA requests without PASID from the device are blocked. If the page +@@ -4330,26 +4381,42 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev) + } + + dev_iommu_priv_set(dev, info); ++ ret = device_rbtree_insert(iommu, info); ++ if (ret) ++ goto free; + + if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev)) { + ret = intel_pasid_alloc_table(dev); + if (ret) { + dev_err(dev, "PASID table allocation failed\n"); +- kfree(info); +- return ERR_PTR(ret); ++ goto clear_rbtree; + } + } + + intel_iommu_debugfs_create_dev(info); + + return &iommu->iommu; ++clear_rbtree: ++ device_rbtree_remove(info); ++free: ++ kfree(info); ++ ++ return ERR_PTR(ret); + } + + static void intel_iommu_release_device(struct device *dev) + { + struct device_domain_info *info = dev_iommu_priv_get(dev); ++ struct intel_iommu *iommu = info->iommu; ++ ++ mutex_lock(&iommu->iopf_lock); ++ device_rbtree_remove(info); ++ mutex_unlock(&iommu->iopf_lock); ++ ++ if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev) && ++ !context_copied(iommu, info->bus, info->devfn)) ++ intel_pasid_teardown_sm_context(dev); + +- dmar_remove_one_dev_info(dev); + intel_pasid_free_table(dev); + intel_iommu_debugfs_remove_dev(info); + kfree(info); +@@ -4855,6 +4922,7 @@ static const struct iommu_dirty_ops intel_dirty_ops = { + + const struct iommu_ops intel_iommu_ops = { + .blocked_domain = &blocking_domain, ++ .release_domain = &blocking_domain, + .capable = intel_iommu_capable, + .hw_info = intel_iommu_hw_info, + .domain_alloc = intel_iommu_domain_alloc, +diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h +index 4145c04cb1c68..cd267ba64eda1 100644 +--- a/drivers/iommu/intel/iommu.h ++++ b/drivers/iommu/intel/iommu.h +@@ -719,9 +719,16 @@ struct intel_iommu { + #endif + struct iopf_queue *iopf_queue; + unsigned char iopfq_name[16]; ++ /* Synchronization between fault report and iommu device release. */ ++ struct mutex iopf_lock; + struct q_inval *qi; /* Queued invalidation info */ + u32 iommu_state[MAX_SR_DMAR_REGS]; /* Store iommu states between suspend and resume.*/ + ++ /* rb tree for all probed devices */ ++ struct rb_root device_rbtree; ++ /* protect the device_rbtree */ ++ spinlock_t device_rbtree_lock; ++ + #ifdef CONFIG_IRQ_REMAP + struct ir_table *ir_table; /* Interrupt remapping info */ + struct irq_domain *ir_domain; +@@ -755,6 +762,8 @@ struct device_domain_info { + struct intel_iommu *iommu; /* IOMMU used by this device */ + struct dmar_domain *domain; /* pointer to domain */ + struct pasid_table *pasid_table; /* pasid table */ ++ /* device tracking node(lookup by PCI RID) */ ++ struct rb_node node; + #ifdef CONFIG_INTEL_IOMMU_DEBUGFS + struct dentry *debugfs_dentry; /* pointer to device directory dentry */ + #endif +@@ -1081,6 +1090,7 @@ void free_pgtable_page(void *vaddr); + void iommu_flush_write_buffer(struct intel_iommu *iommu); + struct iommu_domain *intel_nested_domain_alloc(struct iommu_domain *parent, + const struct iommu_user_data *user_data); ++struct device *device_rbtree_find(struct intel_iommu *iommu, u16 rid); + + #ifdef CONFIG_INTEL_IOMMU_SVM + void intel_svm_check(struct intel_iommu *iommu); +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 108158e2b907d..a51e895d9a178 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -214,6 +214,9 @@ devtlb_invalidation_with_pasid(struct intel_iommu *iommu, + if (!info || !info->ats_enabled) + return; + ++ if (pci_dev_is_disconnected(to_pci_dev(dev))) ++ return; ++ + sid = info->bus << 8 | info->devfn; + qdep = info->ats_qdep; + pfsid = info->pfsid; +@@ -667,3 +670,67 @@ int intel_pasid_setup_nested(struct intel_iommu *iommu, struct device *dev, + + return 0; + } ++ ++/* ++ * Interfaces to setup or teardown a pasid table to the scalable-mode ++ * context table entry: ++ */ ++ ++static void device_pasid_table_teardown(struct device *dev, u8 bus, u8 devfn) ++{ ++ struct device_domain_info *info = dev_iommu_priv_get(dev); ++ struct intel_iommu *iommu = info->iommu; ++ struct context_entry *context; ++ ++ spin_lock(&iommu->lock); ++ context = iommu_context_addr(iommu, bus, devfn, false); ++ if (!context) { ++ spin_unlock(&iommu->lock); ++ return; ++ } ++ ++ context_clear_entry(context); ++ __iommu_flush_cache(iommu, context, sizeof(*context)); ++ spin_unlock(&iommu->lock); ++ ++ /* ++ * Cache invalidation for changes to a scalable-mode context table ++ * entry. ++ * ++ * Section 6.5.3.3 of the VT-d spec: ++ * - Device-selective context-cache invalidation; ++ * - Domain-selective PASID-cache invalidation to affected domains ++ * (can be skipped if all PASID entries were not-present); ++ * - Domain-selective IOTLB invalidation to affected domains; ++ * - Global Device-TLB invalidation to affected functions. ++ * ++ * The iommu has been parked in the blocking state. All domains have ++ * been detached from the device or PASID. The PASID and IOTLB caches ++ * have been invalidated during the domain detach path. ++ */ ++ iommu->flush.flush_context(iommu, 0, PCI_DEVID(bus, devfn), ++ DMA_CCMD_MASK_NOBIT, DMA_CCMD_DEVICE_INVL); ++ devtlb_invalidation_with_pasid(iommu, dev, IOMMU_NO_PASID); ++} ++ ++static int pci_pasid_table_teardown(struct pci_dev *pdev, u16 alias, void *data) ++{ ++ struct device *dev = data; ++ ++ if (dev == &pdev->dev) ++ device_pasid_table_teardown(dev, PCI_BUS_NUM(alias), alias & 0xff); ++ ++ return 0; ++} ++ ++void intel_pasid_teardown_sm_context(struct device *dev) ++{ ++ struct device_domain_info *info = dev_iommu_priv_get(dev); ++ ++ if (!dev_is_pci(dev)) { ++ device_pasid_table_teardown(dev, info->bus, info->devfn); ++ return; ++ } ++ ++ pci_for_each_dma_alias(to_pci_dev(dev), pci_pasid_table_teardown, dev); ++} +diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h +index 487ede039bdde..42fda97fd8516 100644 +--- a/drivers/iommu/intel/pasid.h ++++ b/drivers/iommu/intel/pasid.h +@@ -318,4 +318,5 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, + bool fault_ignore); + void intel_pasid_setup_page_snoop_control(struct intel_iommu *iommu, + struct device *dev, u32 pasid); ++void intel_pasid_teardown_sm_context(struct device *dev); + #endif /* __INTEL_PASID_H */ +diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c +index 40edd282903fb..ec47ec81f0ecd 100644 +--- a/drivers/iommu/intel/svm.c ++++ b/drivers/iommu/intel/svm.c +@@ -650,7 +650,7 @@ static irqreturn_t prq_event_thread(int irq, void *d) + struct intel_iommu *iommu = d; + struct page_req_dsc *req; + int head, tail, handled; +- struct pci_dev *pdev; ++ struct device *dev; + u64 address; + + /* +@@ -696,23 +696,24 @@ static irqreturn_t prq_event_thread(int irq, void *d) + if (unlikely(req->lpig && !req->rd_req && !req->wr_req)) + goto prq_advance; + +- pdev = pci_get_domain_bus_and_slot(iommu->segment, +- PCI_BUS_NUM(req->rid), +- req->rid & 0xff); + /* + * If prq is to be handled outside iommu driver via receiver of + * the fault notifiers, we skip the page response here. + */ +- if (!pdev) ++ mutex_lock(&iommu->iopf_lock); ++ dev = device_rbtree_find(iommu, req->rid); ++ if (!dev) { ++ mutex_unlock(&iommu->iopf_lock); + goto bad_req; ++ } + +- if (intel_svm_prq_report(iommu, &pdev->dev, req)) ++ if (intel_svm_prq_report(iommu, dev, req)) + handle_bad_prq_event(iommu, req, QI_RESP_INVALID); + else +- trace_prq_report(iommu, &pdev->dev, req->qw_0, req->qw_1, ++ trace_prq_report(iommu, dev, req->qw_0, req->qw_1, + req->priv_data[0], req->priv_data[1], + iommu->prq_seq_number++); +- pci_dev_put(pdev); ++ mutex_unlock(&iommu->iopf_lock); + prq_advance: + head = (head + sizeof(*req)) & PRQ_RING_MASK; + } +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index d14413916f93a..cd1210026ac53 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -463,13 +463,24 @@ static void iommu_deinit_device(struct device *dev) + + /* + * release_device() must stop using any attached domain on the device. +- * If there are still other devices in the group they are not effected ++ * If there are still other devices in the group, they are not affected + * by this callback. + * +- * The IOMMU driver must set the device to either an identity or +- * blocking translation and stop using any domain pointer, as it is +- * going to be freed. ++ * If the iommu driver provides release_domain, the core code ensures ++ * that domain is attached prior to calling release_device. Drivers can ++ * use this to enforce a translation on the idle iommu. Typically, the ++ * global static blocked_domain is a good choice. ++ * ++ * Otherwise, the iommu driver must set the device to either an identity ++ * or a blocking translation in release_device() and stop using any ++ * domain pointer, as it is going to be freed. ++ * ++ * Regardless, if a delayed attach never occurred, then the release ++ * should still avoid touching any hardware configuration either. + */ ++ if (!dev->iommu->attach_deferred && ops->release_domain) ++ ops->release_domain->ops->attach_dev(ops->release_domain, dev); ++ + if (ops->release_device) + ops->release_device(dev); + +diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c +index 83314b9d8f38b..ee59647c20501 100644 +--- a/drivers/iommu/irq_remapping.c ++++ b/drivers/iommu/irq_remapping.c +@@ -99,7 +99,8 @@ int __init irq_remapping_prepare(void) + if (disable_irq_remap) + return -ENOSYS; + +- if (intel_irq_remap_ops.prepare() == 0) ++ if (IS_ENABLED(CONFIG_INTEL_IOMMU) && ++ intel_irq_remap_ops.prepare() == 0) + remap_ops = &intel_irq_remap_ops; + else if (IS_ENABLED(CONFIG_AMD_IOMMU) && + amd_iommu_irq_ops.prepare() == 0) +diff --git a/drivers/leds/flash/leds-sgm3140.c b/drivers/leds/flash/leds-sgm3140.c +index eb648ff54b4e5..db0ac6641954e 100644 +--- a/drivers/leds/flash/leds-sgm3140.c ++++ b/drivers/leds/flash/leds-sgm3140.c +@@ -114,8 +114,11 @@ static int sgm3140_brightness_set(struct led_classdev *led_cdev, + "failed to enable regulator: %d\n", ret); + return ret; + } ++ gpiod_set_value_cansleep(priv->flash_gpio, 0); + gpiod_set_value_cansleep(priv->enable_gpio, 1); + } else { ++ del_timer_sync(&priv->powerdown_timer); ++ gpiod_set_value_cansleep(priv->flash_gpio, 0); + gpiod_set_value_cansleep(priv->enable_gpio, 0); + ret = regulator_disable(priv->vin_regulator); + if (ret) { +diff --git a/drivers/leds/leds-aw2013.c b/drivers/leds/leds-aw2013.c +index 91f44b23cb113..17235a5e576ae 100644 +--- a/drivers/leds/leds-aw2013.c ++++ b/drivers/leds/leds-aw2013.c +@@ -405,6 +405,7 @@ static int aw2013_probe(struct i2c_client *client) + chip->regulators); + + error: ++ mutex_unlock(&chip->mutex); + mutex_destroy(&chip->mutex); + return ret; + } +diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c +index 13c65b7e1ed63..f5541b8f6320c 100644 +--- a/drivers/md/dm-bufio.c ++++ b/drivers/md/dm-bufio.c +@@ -1315,7 +1315,7 @@ static void use_dmio(struct dm_buffer *b, enum req_op op, sector_t sector, + io_req.mem.ptr.vma = (char *)b->data + offset; + } + +- r = dm_io(&io_req, 1, ®ion, NULL); ++ r = dm_io(&io_req, 1, ®ion, NULL, IOPRIO_DEFAULT); + if (unlikely(r)) + b->end_io(b, errno_to_blk_status(r)); + } +@@ -2167,7 +2167,7 @@ int dm_bufio_issue_flush(struct dm_bufio_client *c) + if (WARN_ON_ONCE(dm_bufio_in_request())) + return -EINVAL; + +- return dm_io(&io_req, 1, &io_reg, NULL); ++ return dm_io(&io_req, 1, &io_reg, NULL, IOPRIO_DEFAULT); + } + EXPORT_SYMBOL_GPL(dm_bufio_issue_flush); + +@@ -2191,7 +2191,7 @@ int dm_bufio_issue_discard(struct dm_bufio_client *c, sector_t block, sector_t c + if (WARN_ON_ONCE(dm_bufio_in_request())) + return -EINVAL; /* discards are optional */ + +- return dm_io(&io_req, 1, &io_reg, NULL); ++ return dm_io(&io_req, 1, &io_reg, NULL, IOPRIO_DEFAULT); + } + EXPORT_SYMBOL_GPL(dm_bufio_issue_discard); + +diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c +index 1fc901df84eb1..47cf1ab34941f 100644 +--- a/drivers/md/dm-integrity.c ++++ b/drivers/md/dm-integrity.c +@@ -555,7 +555,7 @@ static int sync_rw_sb(struct dm_integrity_c *ic, blk_opf_t opf) + } + } + +- r = dm_io(&io_req, 1, &io_loc, NULL); ++ r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT); + if (unlikely(r)) + return r; + +@@ -1073,7 +1073,7 @@ static void rw_journal_sectors(struct dm_integrity_c *ic, blk_opf_t opf, + io_loc.sector = ic->start + SB_SECTORS + sector; + io_loc.count = n_sectors; + +- r = dm_io(&io_req, 1, &io_loc, NULL); ++ r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT); + if (unlikely(r)) { + dm_integrity_io_error(ic, (opf & REQ_OP_MASK) == REQ_OP_READ ? + "reading journal" : "writing journal", r); +@@ -1190,7 +1190,7 @@ static void copy_from_journal(struct dm_integrity_c *ic, unsigned int section, u + io_loc.sector = target; + io_loc.count = n_sectors; + +- r = dm_io(&io_req, 1, &io_loc, NULL); ++ r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT); + if (unlikely(r)) { + WARN_ONCE(1, "asynchronous dm_io failed: %d", r); + fn(-1UL, data); +@@ -1519,7 +1519,7 @@ static void dm_integrity_flush_buffers(struct dm_integrity_c *ic, bool flush_dat + fr.io_reg.count = 0, + fr.ic = ic; + init_completion(&fr.comp); +- r = dm_io(&fr.io_req, 1, &fr.io_reg, NULL); ++ r = dm_io(&fr.io_req, 1, &fr.io_reg, NULL, IOPRIO_DEFAULT); + BUG_ON(r); + } + +@@ -1699,7 +1699,6 @@ static noinline void integrity_recheck(struct dm_integrity_io *dio, char *checks + struct bio_vec bv; + sector_t sector, logical_sector, area, offset; + struct page *page; +- void *buffer; + + get_area_and_offset(ic, dio->range.logical_sector, &area, &offset); + dio->metadata_block = get_metadata_sector_and_offset(ic, area, offset, +@@ -1708,13 +1707,14 @@ static noinline void integrity_recheck(struct dm_integrity_io *dio, char *checks + logical_sector = dio->range.logical_sector; + + page = mempool_alloc(&ic->recheck_pool, GFP_NOIO); +- buffer = page_to_virt(page); + + __bio_for_each_segment(bv, bio, iter, dio->bio_details.bi_iter) { + unsigned pos = 0; + + do { ++ sector_t alignment; + char *mem; ++ char *buffer = page_to_virt(page); + int r; + struct dm_io_request io_req; + struct dm_io_region io_loc; +@@ -1727,7 +1727,15 @@ static noinline void integrity_recheck(struct dm_integrity_io *dio, char *checks + io_loc.sector = sector; + io_loc.count = ic->sectors_per_block; + +- r = dm_io(&io_req, 1, &io_loc, NULL); ++ /* Align the bio to logical block size */ ++ alignment = dio->range.logical_sector | bio_sectors(bio) | (PAGE_SIZE >> SECTOR_SHIFT); ++ alignment &= -alignment; ++ io_loc.sector = round_down(io_loc.sector, alignment); ++ io_loc.count += sector - io_loc.sector; ++ buffer += (sector - io_loc.sector) << SECTOR_SHIFT; ++ io_loc.count = round_up(io_loc.count, alignment); ++ ++ r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT); + if (unlikely(r)) { + dio->bi_status = errno_to_blk_status(r); + goto free_ret; +@@ -1848,12 +1856,12 @@ static void integrity_metadata(struct work_struct *w) + r = dm_integrity_rw_tag(ic, checksums, &dio->metadata_block, &dio->metadata_offset, + checksums_ptr - checksums, dio->op == REQ_OP_READ ? TAG_CMP : TAG_WRITE); + if (unlikely(r)) { ++ if (likely(checksums != checksums_onstack)) ++ kfree(checksums); + if (r > 0) { +- integrity_recheck(dio, checksums); ++ integrity_recheck(dio, checksums_onstack); + goto skip_io; + } +- if (likely(checksums != checksums_onstack)) +- kfree(checksums); + goto error; + } + +@@ -2806,7 +2814,7 @@ static void integrity_recalc(struct work_struct *w) + io_loc.sector = get_data_sector(ic, area, offset); + io_loc.count = n_sectors; + +- r = dm_io(&io_req, 1, &io_loc, NULL); ++ r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT); + if (unlikely(r)) { + dm_integrity_io_error(ic, "reading data", r); + goto err; +diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c +index f053ce2458147..7409490259d1d 100644 +--- a/drivers/md/dm-io.c ++++ b/drivers/md/dm-io.c +@@ -305,7 +305,7 @@ static void km_dp_init(struct dpages *dp, void *data) + */ + static void do_region(const blk_opf_t opf, unsigned int region, + struct dm_io_region *where, struct dpages *dp, +- struct io *io) ++ struct io *io, unsigned short ioprio) + { + struct bio *bio; + struct page *page; +@@ -354,6 +354,7 @@ static void do_region(const blk_opf_t opf, unsigned int region, + &io->client->bios); + bio->bi_iter.bi_sector = where->sector + (where->count - remaining); + bio->bi_end_io = endio; ++ bio->bi_ioprio = ioprio; + store_io_and_region_in_bio(bio, io, region); + + if (op == REQ_OP_DISCARD || op == REQ_OP_WRITE_ZEROES) { +@@ -383,7 +384,7 @@ static void do_region(const blk_opf_t opf, unsigned int region, + + static void dispatch_io(blk_opf_t opf, unsigned int num_regions, + struct dm_io_region *where, struct dpages *dp, +- struct io *io, int sync) ++ struct io *io, int sync, unsigned short ioprio) + { + int i; + struct dpages old_pages = *dp; +@@ -400,7 +401,7 @@ static void dispatch_io(blk_opf_t opf, unsigned int num_regions, + for (i = 0; i < num_regions; i++) { + *dp = old_pages; + if (where[i].count || (opf & REQ_PREFLUSH)) +- do_region(opf, i, where + i, dp, io); ++ do_region(opf, i, where + i, dp, io, ioprio); + } + + /* +@@ -425,7 +426,7 @@ static void sync_io_complete(unsigned long error, void *context) + + static int sync_io(struct dm_io_client *client, unsigned int num_regions, + struct dm_io_region *where, blk_opf_t opf, struct dpages *dp, +- unsigned long *error_bits) ++ unsigned long *error_bits, unsigned short ioprio) + { + struct io *io; + struct sync_io sio; +@@ -447,7 +448,7 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions, + io->vma_invalidate_address = dp->vma_invalidate_address; + io->vma_invalidate_size = dp->vma_invalidate_size; + +- dispatch_io(opf, num_regions, where, dp, io, 1); ++ dispatch_io(opf, num_regions, where, dp, io, 1, ioprio); + + wait_for_completion_io(&sio.wait); + +@@ -459,7 +460,8 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions, + + static int async_io(struct dm_io_client *client, unsigned int num_regions, + struct dm_io_region *where, blk_opf_t opf, +- struct dpages *dp, io_notify_fn fn, void *context) ++ struct dpages *dp, io_notify_fn fn, void *context, ++ unsigned short ioprio) + { + struct io *io; + +@@ -479,7 +481,7 @@ static int async_io(struct dm_io_client *client, unsigned int num_regions, + io->vma_invalidate_address = dp->vma_invalidate_address; + io->vma_invalidate_size = dp->vma_invalidate_size; + +- dispatch_io(opf, num_regions, where, dp, io, 0); ++ dispatch_io(opf, num_regions, where, dp, io, 0, ioprio); + return 0; + } + +@@ -521,7 +523,8 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp, + } + + int dm_io(struct dm_io_request *io_req, unsigned int num_regions, +- struct dm_io_region *where, unsigned long *sync_error_bits) ++ struct dm_io_region *where, unsigned long *sync_error_bits, ++ unsigned short ioprio) + { + int r; + struct dpages dp; +@@ -532,11 +535,11 @@ int dm_io(struct dm_io_request *io_req, unsigned int num_regions, + + if (!io_req->notify.fn) + return sync_io(io_req->client, num_regions, where, +- io_req->bi_opf, &dp, sync_error_bits); ++ io_req->bi_opf, &dp, sync_error_bits, ioprio); + + return async_io(io_req->client, num_regions, where, + io_req->bi_opf, &dp, io_req->notify.fn, +- io_req->notify.context); ++ io_req->notify.context, ioprio); + } + EXPORT_SYMBOL(dm_io); + +diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c +index 36bcfdccae046..6ea75436a433a 100644 +--- a/drivers/md/dm-kcopyd.c ++++ b/drivers/md/dm-kcopyd.c +@@ -578,9 +578,9 @@ static int run_io_job(struct kcopyd_job *job) + io_job_start(job->kc->throttle); + + if (job->op == REQ_OP_READ) +- r = dm_io(&io_req, 1, &job->source, NULL); ++ r = dm_io(&io_req, 1, &job->source, NULL, IOPRIO_DEFAULT); + else +- r = dm_io(&io_req, job->num_dests, job->dests, NULL); ++ r = dm_io(&io_req, job->num_dests, job->dests, NULL, IOPRIO_DEFAULT); + + return r; + } +diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c +index f9f84236dfcd7..f7f9c2100937b 100644 +--- a/drivers/md/dm-log.c ++++ b/drivers/md/dm-log.c +@@ -300,7 +300,7 @@ static int rw_header(struct log_c *lc, enum req_op op) + { + lc->io_req.bi_opf = op; + +- return dm_io(&lc->io_req, 1, &lc->header_location, NULL); ++ return dm_io(&lc->io_req, 1, &lc->header_location, NULL, IOPRIO_DEFAULT); + } + + static int flush_header(struct log_c *lc) +@@ -313,7 +313,7 @@ static int flush_header(struct log_c *lc) + + lc->io_req.bi_opf = REQ_OP_WRITE | REQ_PREFLUSH; + +- return dm_io(&lc->io_req, 1, &null_location, NULL); ++ return dm_io(&lc->io_req, 1, &null_location, NULL, IOPRIO_DEFAULT); + } + + static int read_header(struct log_c *log) +diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c +index eb009d6bb03a1..13eb47b997f94 100644 +--- a/drivers/md/dm-raid.c ++++ b/drivers/md/dm-raid.c +@@ -3329,14 +3329,14 @@ static int raid_map(struct dm_target *ti, struct bio *bio) + struct mddev *mddev = &rs->md; + + /* +- * If we're reshaping to add disk(s)), ti->len and ++ * If we're reshaping to add disk(s), ti->len and + * mddev->array_sectors will differ during the process + * (ti->len > mddev->array_sectors), so we have to requeue + * bios with addresses > mddev->array_sectors here or + * there will occur accesses past EOD of the component + * data images thus erroring the raid set. + */ +- if (unlikely(bio_end_sector(bio) > mddev->array_sectors)) ++ if (unlikely(bio_has_data(bio) && bio_end_sector(bio) > mddev->array_sectors)) + return DM_MAPIO_REQUEUE; + + md_handle_request(mddev, bio); +diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c +index ddcb2bc4a6179..9511dae5b556a 100644 +--- a/drivers/md/dm-raid1.c ++++ b/drivers/md/dm-raid1.c +@@ -278,7 +278,7 @@ static int mirror_flush(struct dm_target *ti) + } + + error_bits = -1; +- dm_io(&io_req, ms->nr_mirrors, io, &error_bits); ++ dm_io(&io_req, ms->nr_mirrors, io, &error_bits, IOPRIO_DEFAULT); + if (unlikely(error_bits != 0)) { + for (i = 0; i < ms->nr_mirrors; i++) + if (test_bit(i, &error_bits)) +@@ -554,7 +554,7 @@ static void read_async_bio(struct mirror *m, struct bio *bio) + + map_region(&io, m, bio); + bio_set_m(bio, m); +- BUG_ON(dm_io(&io_req, 1, &io, NULL)); ++ BUG_ON(dm_io(&io_req, 1, &io, NULL, IOPRIO_DEFAULT)); + } + + static inline int region_in_sync(struct mirror_set *ms, region_t region, +@@ -681,7 +681,7 @@ static void do_write(struct mirror_set *ms, struct bio *bio) + */ + bio_set_m(bio, get_default_mirror(ms)); + +- BUG_ON(dm_io(&io_req, ms->nr_mirrors, io, NULL)); ++ BUG_ON(dm_io(&io_req, ms->nr_mirrors, io, NULL, IOPRIO_DEFAULT)); + } + + static void do_writes(struct mirror_set *ms, struct bio_list *writes) +diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c +index 15649921f2a9b..568d10842b1f4 100644 +--- a/drivers/md/dm-snap-persistent.c ++++ b/drivers/md/dm-snap-persistent.c +@@ -223,7 +223,7 @@ static void do_metadata(struct work_struct *work) + { + struct mdata_req *req = container_of(work, struct mdata_req, work); + +- req->result = dm_io(req->io_req, 1, req->where, NULL); ++ req->result = dm_io(req->io_req, 1, req->where, NULL, IOPRIO_DEFAULT); + } + + /* +@@ -247,7 +247,7 @@ static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, blk_opf_t opf, + struct mdata_req req; + + if (!metadata) +- return dm_io(&io_req, 1, &where, NULL); ++ return dm_io(&io_req, 1, &where, NULL, IOPRIO_DEFAULT); + + req.where = &where; + req.io_req = &io_req; +diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c +index 1b591bfa90d5d..abc008bae9020 100644 +--- a/drivers/md/dm-verity-target.c ++++ b/drivers/md/dm-verity-target.c +@@ -511,7 +511,7 @@ static noinline int verity_recheck(struct dm_verity *v, struct dm_verity_io *io, + io_loc.bdev = v->data_dev->bdev; + io_loc.sector = cur_block << (v->data_dev_block_bits - SECTOR_SHIFT); + io_loc.count = 1 << (v->data_dev_block_bits - SECTOR_SHIFT); +- r = dm_io(&io_req, 1, &io_loc, NULL); ++ r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT); + if (unlikely(r)) + goto free_ret; + +diff --git a/drivers/md/dm-writecache.c b/drivers/md/dm-writecache.c +index b463c28c39ad3..01ab141bc51e3 100644 +--- a/drivers/md/dm-writecache.c ++++ b/drivers/md/dm-writecache.c +@@ -531,7 +531,7 @@ static void ssd_commit_flushed(struct dm_writecache *wc, bool wait_for_ios) + req.notify.context = &endio; + + /* writing via async dm-io (implied by notify.fn above) won't return an error */ +- (void) dm_io(&req, 1, ®ion, NULL); ++ (void) dm_io(&req, 1, ®ion, NULL, IOPRIO_DEFAULT); + i = j; + } + +@@ -568,7 +568,7 @@ static void ssd_commit_superblock(struct dm_writecache *wc) + req.notify.fn = NULL; + req.notify.context = NULL; + +- r = dm_io(&req, 1, ®ion, NULL); ++ r = dm_io(&req, 1, ®ion, NULL, IOPRIO_DEFAULT); + if (unlikely(r)) + writecache_error(wc, r, "error writing superblock"); + } +@@ -596,7 +596,7 @@ static void writecache_disk_flush(struct dm_writecache *wc, struct dm_dev *dev) + req.client = wc->dm_io; + req.notify.fn = NULL; + +- r = dm_io(&req, 1, ®ion, NULL); ++ r = dm_io(&req, 1, ®ion, NULL, IOPRIO_DEFAULT); + if (unlikely(r)) + writecache_error(wc, r, "error flushing metadata: %d", r); + } +@@ -990,7 +990,7 @@ static int writecache_read_metadata(struct dm_writecache *wc, sector_t n_sectors + req.client = wc->dm_io; + req.notify.fn = NULL; + +- return dm_io(&req, 1, ®ion, NULL); ++ return dm_io(&req, 1, ®ion, NULL, IOPRIO_DEFAULT); + } + + static void writecache_resume(struct dm_target *ti) +diff --git a/drivers/md/dm.c b/drivers/md/dm.c +index 8dcabf84d866e..0dc3650c7f4ca 100644 +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -2945,6 +2945,9 @@ static void __dm_internal_suspend(struct mapped_device *md, unsigned int suspend + + static void __dm_internal_resume(struct mapped_device *md) + { ++ int r; ++ struct dm_table *map; ++ + BUG_ON(!md->internal_suspend_count); + + if (--md->internal_suspend_count) +@@ -2953,12 +2956,23 @@ static void __dm_internal_resume(struct mapped_device *md) + if (dm_suspended_md(md)) + goto done; /* resume from nested suspend */ + +- /* +- * NOTE: existing callers don't need to call dm_table_resume_targets +- * (which may fail -- so best to avoid it for now by passing NULL map) +- */ +- (void) __dm_resume(md, NULL); +- ++ map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock)); ++ r = __dm_resume(md, map); ++ if (r) { ++ /* ++ * If a preresume method of some target failed, we are in a ++ * tricky situation. We can't return an error to the caller. We ++ * can't fake success because then the "resume" and ++ * "postsuspend" methods would not be paired correctly, and it ++ * would break various targets, for example it would cause list ++ * corruption in the "origin" target. ++ * ++ * So, we fake normal suspend here, to make sure that the ++ * "resume" and "postsuspend" methods will be paired correctly. ++ */ ++ DMERR("Preresume method failed: %d", r); ++ set_bit(DMF_SUSPENDED, &md->flags); ++ } + done: + clear_bit(DMF_SUSPENDED_INTERNALLY, &md->flags); + smp_mb__after_atomic(); +diff --git a/drivers/md/md.c b/drivers/md/md.c +index 9e41a9aaba8b5..d344e6fa3b26f 100644 +--- a/drivers/md/md.c ++++ b/drivers/md/md.c +@@ -2566,6 +2566,7 @@ static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev) + fail: + pr_warn("md: failed to register dev-%s for %s\n", + b, mdname(mddev)); ++ mddev_destroy_serial_pool(mddev, rdev); + return err; + } + +@@ -6278,7 +6279,15 @@ static void md_clean(struct mddev *mddev) + mddev->persistent = 0; + mddev->level = LEVEL_NONE; + mddev->clevel[0] = 0; +- mddev->flags = 0; ++ /* ++ * Don't clear MD_CLOSING, or mddev can be opened again. ++ * 'hold_active != 0' means mddev is still in the creation ++ * process and will be used later. ++ */ ++ if (mddev->hold_active) ++ mddev->flags = 0; ++ else ++ mddev->flags &= BIT_ULL_MASK(MD_CLOSING); + mddev->sb_flags = 0; + mddev->ro = MD_RDWR; + mddev->metadata_type[0] = 0; +@@ -7624,7 +7633,6 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode, + int err = 0; + void __user *argp = (void __user *)arg; + struct mddev *mddev = NULL; +- bool did_set_md_closing = false; + + if (!md_ioctl_valid(cmd)) + return -ENOTTY; +@@ -7708,7 +7716,6 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode, + err = -EBUSY; + goto out; + } +- did_set_md_closing = true; + mutex_unlock(&mddev->open_mutex); + sync_blockdev(bdev); + } +@@ -7850,7 +7857,7 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode, + mddev_unlock(mddev); + + out: +- if(did_set_md_closing) ++ if (cmd == STOP_ARRAY_RO || (err && cmd == STOP_ARRAY)) + clear_bit(MD_CLOSING, &mddev->flags); + return err; + } +diff --git a/drivers/md/md.h b/drivers/md/md.h +index 8d881cc597992..27d187ca6258a 100644 +--- a/drivers/md/md.h ++++ b/drivers/md/md.h +@@ -207,6 +207,7 @@ enum flag_bits { + * check if there is collision between raid1 + * serial bios. + */ ++ Nonrot, /* non-rotational device (SSD) */ + }; + + static inline int is_badblock(struct md_rdev *rdev, sector_t s, int sectors, +diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c +index 286f8b16c7bde..82c9bb404ccca 100644 +--- a/drivers/md/raid1.c ++++ b/drivers/md/raid1.c +@@ -601,14 +601,12 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect + const sector_t this_sector = r1_bio->sector; + int sectors; + int best_good_sectors; +- int best_disk, best_dist_disk, best_pending_disk; +- int has_nonrot_disk; ++ int best_disk, best_dist_disk, best_pending_disk, sequential_disk; + int disk; + sector_t best_dist; + unsigned int min_pending; + struct md_rdev *rdev; + int choose_first; +- int choose_next_idle; + + /* + * Check if we can balance. We can balance on the whole +@@ -619,12 +617,11 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect + sectors = r1_bio->sectors; + best_disk = -1; + best_dist_disk = -1; ++ sequential_disk = -1; + best_dist = MaxSector; + best_pending_disk = -1; + min_pending = UINT_MAX; + best_good_sectors = 0; +- has_nonrot_disk = 0; +- choose_next_idle = 0; + clear_bit(R1BIO_FailFast, &r1_bio->state); + + if ((conf->mddev->recovery_cp < this_sector + sectors) || +@@ -640,7 +637,6 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect + sector_t first_bad; + int bad_sectors; + unsigned int pending; +- bool nonrot; + + rdev = conf->mirrors[disk].rdev; + if (r1_bio->bios[disk] == IO_BLOCKED +@@ -706,8 +702,6 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect + /* At least two disks to choose from so failfast is OK */ + set_bit(R1BIO_FailFast, &r1_bio->state); + +- nonrot = bdev_nonrot(rdev->bdev); +- has_nonrot_disk |= nonrot; + pending = atomic_read(&rdev->nr_pending); + dist = abs(this_sector - conf->mirrors[disk].head_position); + if (choose_first) { +@@ -720,7 +714,6 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect + int opt_iosize = bdev_io_opt(rdev->bdev) >> 9; + struct raid1_info *mirror = &conf->mirrors[disk]; + +- best_disk = disk; + /* + * If buffered sequential IO size exceeds optimal + * iosize, check if there is idle disk. If yes, choose +@@ -734,20 +727,27 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect + * small, but not a big deal since when the second disk + * starts IO, the first disk is likely still busy. + */ +- if (nonrot && opt_iosize > 0 && ++ if (test_bit(Nonrot, &rdev->flags) && opt_iosize > 0 && + mirror->seq_start != MaxSector && + mirror->next_seq_sect > opt_iosize && + mirror->next_seq_sect - opt_iosize >= + mirror->seq_start) { +- choose_next_idle = 1; +- continue; ++ /* ++ * Add 'pending' to avoid choosing this disk if ++ * there is other idle disk. ++ */ ++ pending++; ++ /* ++ * If there is no other idle disk, this disk ++ * will be chosen. ++ */ ++ sequential_disk = disk; ++ } else { ++ best_disk = disk; ++ break; + } +- break; + } + +- if (choose_next_idle) +- continue; +- + if (min_pending > pending) { + min_pending = pending; + best_pending_disk = disk; +@@ -759,6 +759,13 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect + } + } + ++ /* ++ * sequential IO size exceeds optimal iosize, however, there is no other ++ * idle disk, so choose the sequential disk. ++ */ ++ if (best_disk == -1 && min_pending != 0) ++ best_disk = sequential_disk; ++ + /* + * If all disks are rotational, choose the closest disk. If any disk is + * non-rotational, choose the disk with less pending request even the +@@ -766,7 +773,7 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect + * mixed ratation/non-rotational disks depending on workload. + */ + if (best_disk == -1) { +- if (has_nonrot_disk || min_pending == 0) ++ if (READ_ONCE(conf->nonrot_disks) || min_pending == 0) + best_disk = best_pending_disk; + else + best_disk = best_dist_disk; +@@ -1760,6 +1767,52 @@ static int raid1_spare_active(struct mddev *mddev) + return count; + } + ++static bool raid1_add_conf(struct r1conf *conf, struct md_rdev *rdev, int disk, ++ bool replacement) ++{ ++ struct raid1_info *info = conf->mirrors + disk; ++ ++ if (replacement) ++ info += conf->raid_disks; ++ ++ if (info->rdev) ++ return false; ++ ++ if (bdev_nonrot(rdev->bdev)) { ++ set_bit(Nonrot, &rdev->flags); ++ WRITE_ONCE(conf->nonrot_disks, conf->nonrot_disks + 1); ++ } ++ ++ rdev->raid_disk = disk; ++ info->head_position = 0; ++ info->seq_start = MaxSector; ++ WRITE_ONCE(info->rdev, rdev); ++ ++ return true; ++} ++ ++static bool raid1_remove_conf(struct r1conf *conf, int disk) ++{ ++ struct raid1_info *info = conf->mirrors + disk; ++ struct md_rdev *rdev = info->rdev; ++ ++ if (!rdev || test_bit(In_sync, &rdev->flags) || ++ atomic_read(&rdev->nr_pending)) ++ return false; ++ ++ /* Only remove non-faulty devices if recovery is not possible. */ ++ if (!test_bit(Faulty, &rdev->flags) && ++ rdev->mddev->recovery_disabled != conf->recovery_disabled && ++ rdev->mddev->degraded < conf->raid_disks) ++ return false; ++ ++ if (test_and_clear_bit(Nonrot, &rdev->flags)) ++ WRITE_ONCE(conf->nonrot_disks, conf->nonrot_disks - 1); ++ ++ WRITE_ONCE(info->rdev, NULL); ++ return true; ++} ++ + static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev) + { + struct r1conf *conf = mddev->private; +@@ -1795,15 +1848,13 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev) + disk_stack_limits(mddev->gendisk, rdev->bdev, + rdev->data_offset << 9); + +- p->head_position = 0; +- rdev->raid_disk = mirror; ++ raid1_add_conf(conf, rdev, mirror, false); + err = 0; + /* As all devices are equivalent, we don't need a full recovery + * if this was recently any drive of the array + */ + if (rdev->saved_raid_disk < 0) + conf->fullsync = 1; +- WRITE_ONCE(p->rdev, rdev); + break; + } + if (test_bit(WantReplacement, &p->rdev->flags) && +@@ -1813,13 +1864,11 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev) + + if (err && repl_slot >= 0) { + /* Add this device as a replacement */ +- p = conf->mirrors + repl_slot; + clear_bit(In_sync, &rdev->flags); + set_bit(Replacement, &rdev->flags); +- rdev->raid_disk = repl_slot; ++ raid1_add_conf(conf, rdev, repl_slot, true); + err = 0; + conf->fullsync = 1; +- WRITE_ONCE(p[conf->raid_disks].rdev, rdev); + } + + print_conf(conf); +@@ -1836,27 +1885,20 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev) + if (unlikely(number >= conf->raid_disks)) + goto abort; + +- if (rdev != p->rdev) +- p = conf->mirrors + conf->raid_disks + number; ++ if (rdev != p->rdev) { ++ number += conf->raid_disks; ++ p = conf->mirrors + number; ++ } + + print_conf(conf); + if (rdev == p->rdev) { +- if (test_bit(In_sync, &rdev->flags) || +- atomic_read(&rdev->nr_pending)) { +- err = -EBUSY; +- goto abort; +- } +- /* Only remove non-faulty devices if recovery +- * is not possible. +- */ +- if (!test_bit(Faulty, &rdev->flags) && +- mddev->recovery_disabled != conf->recovery_disabled && +- mddev->degraded < conf->raid_disks) { ++ if (!raid1_remove_conf(conf, number)) { + err = -EBUSY; + goto abort; + } +- WRITE_ONCE(p->rdev, NULL); +- if (conf->mirrors[conf->raid_disks + number].rdev) { ++ ++ if (number < conf->raid_disks && ++ conf->mirrors[conf->raid_disks + number].rdev) { + /* We just removed a device that is being replaced. + * Move down the replacement. We drain all IO before + * doing this to avoid confusion. +@@ -3006,23 +3048,17 @@ static struct r1conf *setup_conf(struct mddev *mddev) + + err = -EINVAL; + spin_lock_init(&conf->device_lock); ++ conf->raid_disks = mddev->raid_disks; + rdev_for_each(rdev, mddev) { + int disk_idx = rdev->raid_disk; +- if (disk_idx >= mddev->raid_disks +- || disk_idx < 0) ++ ++ if (disk_idx >= conf->raid_disks || disk_idx < 0) + continue; +- if (test_bit(Replacement, &rdev->flags)) +- disk = conf->mirrors + mddev->raid_disks + disk_idx; +- else +- disk = conf->mirrors + disk_idx; + +- if (disk->rdev) ++ if (!raid1_add_conf(conf, rdev, disk_idx, ++ test_bit(Replacement, &rdev->flags))) + goto abort; +- disk->rdev = rdev; +- disk->head_position = 0; +- disk->seq_start = MaxSector; + } +- conf->raid_disks = mddev->raid_disks; + conf->mddev = mddev; + INIT_LIST_HEAD(&conf->retry_list); + INIT_LIST_HEAD(&conf->bio_end_io_list); +diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h +index 14d4211a123a8..5300cbaa58a41 100644 +--- a/drivers/md/raid1.h ++++ b/drivers/md/raid1.h +@@ -71,6 +71,7 @@ struct r1conf { + * allow for replacements. + */ + int raid_disks; ++ int nonrot_disks; + + spinlock_t device_lock; + +diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +index a366566f22c3b..642c48e8c1f58 100644 +--- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c ++++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +@@ -113,6 +113,7 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w) + { + unsigned pat; + unsigned plane; ++ int ret = 0; + + tpg->max_line_width = max_w; + for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) { +@@ -121,14 +122,18 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w) + + tpg->lines[pat][plane] = + vzalloc(array3_size(max_w, 2, pixelsz)); +- if (!tpg->lines[pat][plane]) +- return -ENOMEM; ++ if (!tpg->lines[pat][plane]) { ++ ret = -ENOMEM; ++ goto free_lines; ++ } + if (plane == 0) + continue; + tpg->downsampled_lines[pat][plane] = + vzalloc(array3_size(max_w, 2, pixelsz)); +- if (!tpg->downsampled_lines[pat][plane]) +- return -ENOMEM; ++ if (!tpg->downsampled_lines[pat][plane]) { ++ ret = -ENOMEM; ++ goto free_lines; ++ } + } + } + for (plane = 0; plane < TPG_MAX_PLANES; plane++) { +@@ -136,18 +141,45 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w) + + tpg->contrast_line[plane] = + vzalloc(array_size(pixelsz, max_w)); +- if (!tpg->contrast_line[plane]) +- return -ENOMEM; ++ if (!tpg->contrast_line[plane]) { ++ ret = -ENOMEM; ++ goto free_contrast_line; ++ } + tpg->black_line[plane] = + vzalloc(array_size(pixelsz, max_w)); +- if (!tpg->black_line[plane]) +- return -ENOMEM; ++ if (!tpg->black_line[plane]) { ++ ret = -ENOMEM; ++ goto free_contrast_line; ++ } + tpg->random_line[plane] = + vzalloc(array3_size(max_w, 2, pixelsz)); +- if (!tpg->random_line[plane]) +- return -ENOMEM; ++ if (!tpg->random_line[plane]) { ++ ret = -ENOMEM; ++ goto free_contrast_line; ++ } + } + return 0; ++ ++free_contrast_line: ++ for (plane = 0; plane < TPG_MAX_PLANES; plane++) { ++ vfree(tpg->contrast_line[plane]); ++ vfree(tpg->black_line[plane]); ++ vfree(tpg->random_line[plane]); ++ tpg->contrast_line[plane] = NULL; ++ tpg->black_line[plane] = NULL; ++ tpg->random_line[plane] = NULL; ++ } ++free_lines: ++ for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) ++ for (plane = 0; plane < TPG_MAX_PLANES; plane++) { ++ vfree(tpg->lines[pat][plane]); ++ tpg->lines[pat][plane] = NULL; ++ if (plane == 0) ++ continue; ++ vfree(tpg->downsampled_lines[pat][plane]); ++ tpg->downsampled_lines[pat][plane] = NULL; ++ } ++ return ret; + } + EXPORT_SYMBOL_GPL(tpg_alloc); + +diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c +index 49f0eb7d0b9d3..733d0bc4b4cc3 100644 +--- a/drivers/media/dvb-core/dvbdev.c ++++ b/drivers/media/dvb-core/dvbdev.c +@@ -490,6 +490,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, + dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL); + if (!dvbdevfops) { + kfree(dvbdev); ++ *pdvbdev = NULL; + mutex_unlock(&dvbdev_register_lock); + return -ENOMEM; + } +@@ -498,6 +499,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, + if (!new_node) { + kfree(dvbdevfops); + kfree(dvbdev); ++ *pdvbdev = NULL; + mutex_unlock(&dvbdev_register_lock); + return -ENOMEM; + } +@@ -531,6 +533,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, + } + list_del(&dvbdev->list_head); + kfree(dvbdev); ++ *pdvbdev = NULL; + up_write(&minor_rwsem); + mutex_unlock(&dvbdev_register_lock); + return -EINVAL; +@@ -553,6 +556,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, + dvb_media_device_free(dvbdev); + list_del(&dvbdev->list_head); + kfree(dvbdev); ++ *pdvbdev = NULL; + mutex_unlock(&dvbdev_register_lock); + return ret; + } +@@ -571,6 +575,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, + dvb_media_device_free(dvbdev); + list_del(&dvbdev->list_head); + kfree(dvbdev); ++ *pdvbdev = NULL; + mutex_unlock(&dvbdev_register_lock); + return PTR_ERR(clsdev); + } +diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c +index 48326434488c4..72540ef4e5f88 100644 +--- a/drivers/media/dvb-frontends/stv0367.c ++++ b/drivers/media/dvb-frontends/stv0367.c +@@ -118,50 +118,32 @@ static const s32 stv0367cab_RF_LookUp2[RF_LOOKUP_TABLE2_SIZE][RF_LOOKUP_TABLE2_S + } + }; + +-static +-int stv0367_writeregs(struct stv0367_state *state, u16 reg, u8 *data, int len) ++static noinline_for_stack ++int stv0367_writereg(struct stv0367_state *state, u16 reg, u8 data) + { +- u8 buf[MAX_XFER_SIZE]; ++ u8 buf[3] = { MSB(reg), LSB(reg), data }; + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, +- .len = len + 2 ++ .len = 3, + }; + int ret; + +- if (2 + len > sizeof(buf)) { +- printk(KERN_WARNING +- "%s: i2c wr reg=%04x: len=%d is too big!\n", +- KBUILD_MODNAME, reg, len); +- return -EINVAL; +- } +- +- +- buf[0] = MSB(reg); +- buf[1] = LSB(reg); +- memcpy(buf + 2, data, len); +- + if (i2cdebug) + printk(KERN_DEBUG "%s: [%02x] %02x: %02x\n", __func__, +- state->config->demod_address, reg, buf[2]); ++ state->config->demod_address, reg, data); + + ret = i2c_transfer(state->i2c, &msg, 1); + if (ret != 1) + printk(KERN_ERR "%s: i2c write error! ([%02x] %02x: %02x)\n", +- __func__, state->config->demod_address, reg, buf[2]); ++ __func__, state->config->demod_address, reg, data); + + return (ret != 1) ? -EREMOTEIO : 0; + } + +-static int stv0367_writereg(struct stv0367_state *state, u16 reg, u8 data) +-{ +- u8 tmp = data; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */ +- +- return stv0367_writeregs(state, reg, &tmp, 1); +-} +- +-static u8 stv0367_readreg(struct stv0367_state *state, u16 reg) ++static noinline_for_stack ++u8 stv0367_readreg(struct stv0367_state *state, u16 reg) + { + u8 b0[] = { 0, 0 }; + u8 b1[] = { 0 }; +diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c +index 9967f34774334..4150e6e4b9a63 100644 +--- a/drivers/media/i2c/imx290.c ++++ b/drivers/media/i2c/imx290.c +@@ -150,10 +150,10 @@ + + #define IMX290_PIXEL_ARRAY_WIDTH 1945 + #define IMX290_PIXEL_ARRAY_HEIGHT 1097 +-#define IMX920_PIXEL_ARRAY_MARGIN_LEFT 12 +-#define IMX920_PIXEL_ARRAY_MARGIN_RIGHT 13 +-#define IMX920_PIXEL_ARRAY_MARGIN_TOP 8 +-#define IMX920_PIXEL_ARRAY_MARGIN_BOTTOM 9 ++#define IMX290_PIXEL_ARRAY_MARGIN_LEFT 12 ++#define IMX290_PIXEL_ARRAY_MARGIN_RIGHT 13 ++#define IMX290_PIXEL_ARRAY_MARGIN_TOP 8 ++#define IMX290_PIXEL_ARRAY_MARGIN_BOTTOM 9 + #define IMX290_PIXEL_ARRAY_RECORDING_WIDTH 1920 + #define IMX290_PIXEL_ARRAY_RECORDING_HEIGHT 1080 + +@@ -1161,10 +1161,10 @@ static int imx290_get_selection(struct v4l2_subdev *sd, + * The sensor moves the readout by 1 pixel based on flips to + * keep the Bayer order the same. + */ +- sel->r.top = IMX920_PIXEL_ARRAY_MARGIN_TOP ++ sel->r.top = IMX290_PIXEL_ARRAY_MARGIN_TOP + + (IMX290_PIXEL_ARRAY_RECORDING_HEIGHT - format->height) / 2 + + imx290->vflip->val; +- sel->r.left = IMX920_PIXEL_ARRAY_MARGIN_LEFT ++ sel->r.left = IMX290_PIXEL_ARRAY_MARGIN_LEFT + + (IMX290_PIXEL_ARRAY_RECORDING_WIDTH - format->width) / 2 + + imx290->hflip->val; + sel->r.width = format->width; +@@ -1183,8 +1183,8 @@ static int imx290_get_selection(struct v4l2_subdev *sd, + return 0; + + case V4L2_SEL_TGT_CROP_DEFAULT: +- sel->r.top = IMX920_PIXEL_ARRAY_MARGIN_TOP; +- sel->r.left = IMX920_PIXEL_ARRAY_MARGIN_LEFT; ++ sel->r.top = IMX290_PIXEL_ARRAY_MARGIN_TOP; ++ sel->r.left = IMX290_PIXEL_ARRAY_MARGIN_LEFT; + sel->r.width = IMX290_PIXEL_ARRAY_RECORDING_WIDTH; + sel->r.height = IMX290_PIXEL_ARRAY_RECORDING_HEIGHT; + +diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c +index 2785935da497b..558152575d102 100644 +--- a/drivers/media/i2c/tc358743.c ++++ b/drivers/media/i2c/tc358743.c +@@ -2091,9 +2091,6 @@ static int tc358743_probe(struct i2c_client *client) + state->mbus_fmt_code = MEDIA_BUS_FMT_RGB888_1X24; + + sd->dev = &client->dev; +- err = v4l2_async_register_subdev(sd); +- if (err < 0) +- goto err_hdl; + + mutex_init(&state->confctl_mutex); + +@@ -2151,6 +2148,10 @@ static int tc358743_probe(struct i2c_client *client) + if (err) + goto err_work_queues; + ++ err = v4l2_async_register_subdev(sd); ++ if (err < 0) ++ goto err_work_queues; ++ + v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, + client->addr << 1, client->adapter->name); + +diff --git a/drivers/media/pci/intel/ivsc/mei_csi.c b/drivers/media/pci/intel/ivsc/mei_csi.c +index 15b905f66ab72..3c74d06a27fad 100644 +--- a/drivers/media/pci/intel/ivsc/mei_csi.c ++++ b/drivers/media/pci/intel/ivsc/mei_csi.c +@@ -71,8 +71,8 @@ enum ivsc_privacy_status { + }; + + enum csi_pads { +- CSI_PAD_SOURCE, + CSI_PAD_SINK, ++ CSI_PAD_SOURCE, + CSI_NUM_PADS + }; + +@@ -587,7 +587,7 @@ static int mei_csi_notify_bound(struct v4l2_async_notifier *notifier, + csi->remote_pad = pad; + + return media_create_pad_link(&subdev->entity, pad, +- &csi->subdev.entity, 1, ++ &csi->subdev.entity, CSI_PAD_SINK, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + } +diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c +index 230b104a7cdf0..a47c5850ef875 100644 +--- a/drivers/media/pci/ttpci/budget-av.c ++++ b/drivers/media/pci/ttpci/budget-av.c +@@ -1463,7 +1463,8 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio + budget_av->has_saa7113 = 1; + err = saa7146_vv_init(dev, &vv_data); + if (err != 0) { +- /* fixme: proper cleanup here */ ++ ttpci_budget_deinit(&budget_av->budget); ++ kfree(budget_av); + ERR("cannot init vv subsystem\n"); + return err; + } +@@ -1472,9 +1473,10 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio + vv_data.vid_ops.vidioc_s_input = vidioc_s_input; + + if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_VIDEO))) { +- /* fixme: proper cleanup here */ +- ERR("cannot register capture v4l2 device\n"); + saa7146_vv_release(dev); ++ ttpci_budget_deinit(&budget_av->budget); ++ kfree(budget_av); ++ ERR("cannot register capture v4l2 device\n"); + return err; + } + +diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c +index fead5426830e8..0ea5fa956fe9a 100644 +--- a/drivers/media/platform/cadence/cdns-csi2rx.c ++++ b/drivers/media/platform/cadence/cdns-csi2rx.c +@@ -468,7 +468,7 @@ static int csi2rx_async_bound(struct v4l2_async_notifier *notifier, + struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev); + + csi2rx->source_pad = media_entity_get_fwnode_pad(&s_subdev->entity, +- s_subdev->fwnode, ++ asd->match.fwnode, + MEDIA_PAD_FL_SOURCE); + if (csi2rx->source_pad < 0) { + dev_err(csi2rx->dev, "Couldn't find output pad for subdev %s\n", +diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_vpu.c b/drivers/media/platform/mediatek/mdp/mtk_mdp_vpu.c +index b065ccd069140..378a1cba0144f 100644 +--- a/drivers/media/platform/mediatek/mdp/mtk_mdp_vpu.c ++++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_vpu.c +@@ -26,7 +26,7 @@ static void mtk_mdp_vpu_handle_init_ack(const struct mdp_ipi_comm_ack *msg) + vpu->inst_addr = msg->vpu_inst_addr; + } + +-static void mtk_mdp_vpu_ipi_handler(const void *data, unsigned int len, ++static void mtk_mdp_vpu_ipi_handler(void *data, unsigned int len, + void *priv) + { + const struct mdp_ipi_comm_ack *msg = data; +diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c +index 9f6e4b59455da..4c34344dc7dcb 100644 +--- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c ++++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c +@@ -29,15 +29,7 @@ static int mtk_vcodec_vpu_set_ipi_register(struct mtk_vcodec_fw *fw, int id, + mtk_vcodec_ipi_handler handler, + const char *name, void *priv) + { +- /* +- * The handler we receive takes a void * as its first argument. We +- * cannot change this because it needs to be passed down to the rproc +- * subsystem when SCP is used. VPU takes a const argument, which is +- * more constrained, so the conversion below is safe. +- */ +- ipi_handler_t handler_const = (ipi_handler_t)handler; +- +- return vpu_ipi_register(fw->pdev, id, handler_const, name, priv); ++ return vpu_ipi_register(fw->pdev, id, handler, name, priv); + } + + static int mtk_vcodec_vpu_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf, +diff --git a/drivers/media/platform/mediatek/vpu/mtk_vpu.c b/drivers/media/platform/mediatek/vpu/mtk_vpu.c +index 7243604a82a5b..724ae7c2ab3ba 100644 +--- a/drivers/media/platform/mediatek/vpu/mtk_vpu.c ++++ b/drivers/media/platform/mediatek/vpu/mtk_vpu.c +@@ -635,7 +635,7 @@ int vpu_load_firmware(struct platform_device *pdev) + } + EXPORT_SYMBOL_GPL(vpu_load_firmware); + +-static void vpu_init_ipi_handler(const void *data, unsigned int len, void *priv) ++static void vpu_init_ipi_handler(void *data, unsigned int len, void *priv) + { + struct mtk_vpu *vpu = priv; + const struct vpu_run *run = data; +diff --git a/drivers/media/platform/mediatek/vpu/mtk_vpu.h b/drivers/media/platform/mediatek/vpu/mtk_vpu.h +index a56053ff135af..da05f3e740810 100644 +--- a/drivers/media/platform/mediatek/vpu/mtk_vpu.h ++++ b/drivers/media/platform/mediatek/vpu/mtk_vpu.h +@@ -17,7 +17,7 @@ + * VPU interfaces with other blocks by share memory and interrupt. + */ + +-typedef void (*ipi_handler_t) (const void *data, ++typedef void (*ipi_handler_t) (void *data, + unsigned int len, + void *priv); + +diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c +index 954fabec27f63..a1c35a2b68ed9 100644 +--- a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c ++++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c +@@ -66,6 +66,7 @@ static void deinterlace_device_run(void *priv) + struct vb2_v4l2_buffer *src, *dst; + unsigned int hstep, vstep; + dma_addr_t addr; ++ int i; + + src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); +@@ -160,6 +161,26 @@ static void deinterlace_device_run(void *priv) + deinterlace_write(dev, DEINTERLACE_CH1_HORZ_FACT, hstep); + deinterlace_write(dev, DEINTERLACE_CH1_VERT_FACT, vstep); + ++ /* neutral filter coefficients */ ++ deinterlace_set_bits(dev, DEINTERLACE_FRM_CTRL, ++ DEINTERLACE_FRM_CTRL_COEF_ACCESS); ++ readl_poll_timeout(dev->base + DEINTERLACE_STATUS, val, ++ val & DEINTERLACE_STATUS_COEF_STATUS, 2, 40); ++ ++ for (i = 0; i < 32; i++) { ++ deinterlace_write(dev, DEINTERLACE_CH0_HORZ_COEF0 + i * 4, ++ DEINTERLACE_IDENTITY_COEF); ++ deinterlace_write(dev, DEINTERLACE_CH0_VERT_COEF + i * 4, ++ DEINTERLACE_IDENTITY_COEF); ++ deinterlace_write(dev, DEINTERLACE_CH1_HORZ_COEF0 + i * 4, ++ DEINTERLACE_IDENTITY_COEF); ++ deinterlace_write(dev, DEINTERLACE_CH1_VERT_COEF + i * 4, ++ DEINTERLACE_IDENTITY_COEF); ++ } ++ ++ deinterlace_clr_set_bits(dev, DEINTERLACE_FRM_CTRL, ++ DEINTERLACE_FRM_CTRL_COEF_ACCESS, 0); ++ + deinterlace_clr_set_bits(dev, DEINTERLACE_FIELD_CTRL, + DEINTERLACE_FIELD_CTRL_FIELD_CNT_MSK, + DEINTERLACE_FIELD_CTRL_FIELD_CNT(ctx->field)); +@@ -248,7 +269,6 @@ static irqreturn_t deinterlace_irq(int irq, void *data) + static void deinterlace_init(struct deinterlace_dev *dev) + { + u32 val; +- int i; + + deinterlace_write(dev, DEINTERLACE_BYPASS, + DEINTERLACE_BYPASS_CSC); +@@ -284,27 +304,7 @@ static void deinterlace_init(struct deinterlace_dev *dev) + + deinterlace_clr_set_bits(dev, DEINTERLACE_CHROMA_DIFF, + DEINTERLACE_CHROMA_DIFF_TH_MSK, +- DEINTERLACE_CHROMA_DIFF_TH(5)); +- +- /* neutral filter coefficients */ +- deinterlace_set_bits(dev, DEINTERLACE_FRM_CTRL, +- DEINTERLACE_FRM_CTRL_COEF_ACCESS); +- readl_poll_timeout(dev->base + DEINTERLACE_STATUS, val, +- val & DEINTERLACE_STATUS_COEF_STATUS, 2, 40); +- +- for (i = 0; i < 32; i++) { +- deinterlace_write(dev, DEINTERLACE_CH0_HORZ_COEF0 + i * 4, +- DEINTERLACE_IDENTITY_COEF); +- deinterlace_write(dev, DEINTERLACE_CH0_VERT_COEF + i * 4, +- DEINTERLACE_IDENTITY_COEF); +- deinterlace_write(dev, DEINTERLACE_CH1_HORZ_COEF0 + i * 4, +- DEINTERLACE_IDENTITY_COEF); +- deinterlace_write(dev, DEINTERLACE_CH1_VERT_COEF + i * 4, +- DEINTERLACE_IDENTITY_COEF); +- } +- +- deinterlace_clr_set_bits(dev, DEINTERLACE_FRM_CTRL, +- DEINTERLACE_FRM_CTRL_COEF_ACCESS, 0); ++ DEINTERLACE_CHROMA_DIFF_TH(31)); + } + + static inline struct deinterlace_ctx *deinterlace_file2ctx(struct file *file) +@@ -929,11 +929,18 @@ static int deinterlace_runtime_resume(struct device *device) + return ret; + } + ++ ret = reset_control_deassert(dev->rstc); ++ if (ret) { ++ dev_err(dev->dev, "Failed to apply reset\n"); ++ ++ goto err_exclusive_rate; ++ } ++ + ret = clk_prepare_enable(dev->bus_clk); + if (ret) { + dev_err(dev->dev, "Failed to enable bus clock\n"); + +- goto err_exclusive_rate; ++ goto err_rst; + } + + ret = clk_prepare_enable(dev->mod_clk); +@@ -950,23 +957,16 @@ static int deinterlace_runtime_resume(struct device *device) + goto err_mod_clk; + } + +- ret = reset_control_deassert(dev->rstc); +- if (ret) { +- dev_err(dev->dev, "Failed to apply reset\n"); +- +- goto err_ram_clk; +- } +- + deinterlace_init(dev); + + return 0; + +-err_ram_clk: +- clk_disable_unprepare(dev->ram_clk); + err_mod_clk: + clk_disable_unprepare(dev->mod_clk); + err_bus_clk: + clk_disable_unprepare(dev->bus_clk); ++err_rst: ++ reset_control_assert(dev->rstc); + err_exclusive_rate: + clk_rate_exclusive_put(dev->mod_clk); + +@@ -977,11 +977,12 @@ static int deinterlace_runtime_suspend(struct device *device) + { + struct deinterlace_dev *dev = dev_get_drvdata(device); + +- reset_control_assert(dev->rstc); +- + clk_disable_unprepare(dev->ram_clk); + clk_disable_unprepare(dev->mod_clk); + clk_disable_unprepare(dev->bus_clk); ++ ++ reset_control_assert(dev->rstc); ++ + clk_rate_exclusive_put(dev->mod_clk); + + return 0; +diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c +index 4d037c92af7c5..bae76023cf71d 100644 +--- a/drivers/media/usb/em28xx/em28xx-cards.c ++++ b/drivers/media/usb/em28xx/em28xx-cards.c +@@ -4094,6 +4094,10 @@ static int em28xx_usb_probe(struct usb_interface *intf, + * topology will likely change after the load of the em28xx subdrivers. + */ + #ifdef CONFIG_MEDIA_CONTROLLER ++ /* ++ * No need to check the return value, the device will still be ++ * usable without media controller API. ++ */ + retval = media_device_register(dev->media_dev); + #endif + +diff --git a/drivers/media/usb/go7007/go7007-driver.c b/drivers/media/usb/go7007/go7007-driver.c +index 0c24e29843048..eb03f98b2ef11 100644 +--- a/drivers/media/usb/go7007/go7007-driver.c ++++ b/drivers/media/usb/go7007/go7007-driver.c +@@ -80,7 +80,7 @@ static int go7007_load_encoder(struct go7007 *go) + const struct firmware *fw_entry; + char fw_name[] = "go7007/go7007fw.bin"; + void *bounce; +- int fw_len, rv = 0; ++ int fw_len; + u16 intr_val, intr_data; + + if (go->boot_fw == NULL) { +@@ -109,9 +109,11 @@ static int go7007_load_encoder(struct go7007 *go) + go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || + (intr_val & ~0x1) != 0x5a5a) { + v4l2_err(go, "error transferring firmware\n"); +- rv = -1; ++ kfree(go->boot_fw); ++ go->boot_fw = NULL; ++ return -1; + } +- return rv; ++ return 0; + } + + MODULE_FIRMWARE("go7007/go7007fw.bin"); +diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c +index eeb85981e02b6..762c13e49bfa5 100644 +--- a/drivers/media/usb/go7007/go7007-usb.c ++++ b/drivers/media/usb/go7007/go7007-usb.c +@@ -1201,7 +1201,9 @@ static int go7007_usb_probe(struct usb_interface *intf, + u16 channel; + + /* read channel number from GPIO[1:0] */ +- go7007_read_addr(go, 0x3c81, &channel); ++ if (go7007_read_addr(go, 0x3c81, &channel)) ++ goto allocfail; ++ + channel &= 0x3; + go->board_id = GO7007_BOARDID_ADLINK_MPG24; + usb->board = board = &board_adlink_mpg24; +diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.c b/drivers/media/usb/pvrusb2/pvrusb2-context.c +index 1764674de98bc..73c95ba2328a4 100644 +--- a/drivers/media/usb/pvrusb2/pvrusb2-context.c ++++ b/drivers/media/usb/pvrusb2/pvrusb2-context.c +@@ -90,8 +90,10 @@ static void pvr2_context_destroy(struct pvr2_context *mp) + } + + +-static void pvr2_context_notify(struct pvr2_context *mp) ++static void pvr2_context_notify(void *ptr) + { ++ struct pvr2_context *mp = ptr; ++ + pvr2_context_set_notify(mp,!0); + } + +@@ -106,9 +108,7 @@ static void pvr2_context_check(struct pvr2_context *mp) + pvr2_trace(PVR2_TRACE_CTXT, + "pvr2_context %p (initialize)", mp); + /* Finish hardware initialization */ +- if (pvr2_hdw_initialize(mp->hdw, +- (void (*)(void *))pvr2_context_notify, +- mp)) { ++ if (pvr2_hdw_initialize(mp->hdw, pvr2_context_notify, mp)) { + mp->video_stream.stream = + pvr2_hdw_get_video_stream(mp->hdw); + /* Trigger interface initialization. By doing this +@@ -267,9 +267,9 @@ static void pvr2_context_exit(struct pvr2_context *mp) + void pvr2_context_disconnect(struct pvr2_context *mp) + { + pvr2_hdw_disconnect(mp->hdw); +- mp->disconnect_flag = !0; + if (!pvr2_context_shutok()) + pvr2_context_notify(mp); ++ mp->disconnect_flag = !0; + } + + +diff --git a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c +index 26811efe0fb58..9a9bae21c6147 100644 +--- a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c ++++ b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c +@@ -88,8 +88,10 @@ static int pvr2_dvb_feed_thread(void *data) + return stat; + } + +-static void pvr2_dvb_notify(struct pvr2_dvb_adapter *adap) ++static void pvr2_dvb_notify(void *ptr) + { ++ struct pvr2_dvb_adapter *adap = ptr; ++ + wake_up(&adap->buffer_wait_data); + } + +@@ -149,7 +151,7 @@ static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap) + } + + pvr2_stream_set_callback(pvr->video_stream.stream, +- (pvr2_stream_callback) pvr2_dvb_notify, adap); ++ pvr2_dvb_notify, adap); + + ret = pvr2_stream_set_buffer_count(stream, PVR2_DVB_BUFFER_COUNT); + if (ret < 0) return ret; +diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +index c04ab7258d645..d608b793fa847 100644 +--- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c ++++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +@@ -1033,8 +1033,10 @@ static int pvr2_v4l2_open(struct file *file) + } + + +-static void pvr2_v4l2_notify(struct pvr2_v4l2_fh *fhp) ++static void pvr2_v4l2_notify(void *ptr) + { ++ struct pvr2_v4l2_fh *fhp = ptr; ++ + wake_up(&fhp->wait_data); + } + +@@ -1067,7 +1069,7 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh) + + hdw = fh->channel.mc_head->hdw; + sp = fh->pdi->stream->stream; +- pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh); ++ pvr2_stream_set_callback(sp, pvr2_v4l2_notify, fh); + pvr2_hdw_set_stream_type(hdw,fh->pdi->config); + if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret; + return pvr2_ioread_set_enabled(fh->rhp,!0); +@@ -1198,11 +1200,6 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, + dip->minor_type = pvr2_v4l_type_video; + nr_ptr = video_nr; + caps |= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO; +- if (!dip->stream) { +- pr_err(KBUILD_MODNAME +- ": Failed to set up pvrusb2 v4l video dev due to missing stream instance\n"); +- return; +- } + break; + case VFL_TYPE_VBI: + dip->config = pvr2_config_vbi; +diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c +index 62a583040cd48..702f1c8bd2ab3 100644 +--- a/drivers/media/usb/usbtv/usbtv-video.c ++++ b/drivers/media/usb/usbtv/usbtv-video.c +@@ -963,15 +963,8 @@ int usbtv_video_init(struct usbtv *usbtv) + + void usbtv_video_free(struct usbtv *usbtv) + { +- mutex_lock(&usbtv->vb2q_lock); +- mutex_lock(&usbtv->v4l2_lock); +- +- usbtv_stop(usbtv); + vb2_video_unregister_device(&usbtv->vdev); + v4l2_device_disconnect(&usbtv->v4l2_dev); + +- mutex_unlock(&usbtv->v4l2_lock); +- mutex_unlock(&usbtv->vb2q_lock); +- + v4l2_device_put(&usbtv->v4l2_dev); + } +diff --git a/drivers/media/v4l2-core/v4l2-cci.c b/drivers/media/v4l2-core/v4l2-cci.c +index 10005c80f43b5..ee3475bed37fa 100644 +--- a/drivers/media/v4l2-core/v4l2-cci.c ++++ b/drivers/media/v4l2-core/v4l2-cci.c +@@ -32,7 +32,7 @@ int cci_read(struct regmap *map, u32 reg, u64 *val, int *err) + + ret = regmap_bulk_read(map, reg, buf, len); + if (ret) { +- dev_err(regmap_get_device(map), "Error reading reg 0x%4x: %d\n", ++ dev_err(regmap_get_device(map), "Error reading reg 0x%04x: %d\n", + reg, ret); + goto out; + } +@@ -131,7 +131,7 @@ int cci_write(struct regmap *map, u32 reg, u64 val, int *err) + + ret = regmap_bulk_write(map, reg, buf, len); + if (ret) +- dev_err(regmap_get_device(map), "Error writing reg 0x%4x: %d\n", ++ dev_err(regmap_get_device(map), "Error writing reg 0x%04x: %d\n", + reg, ret); + + out: +diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c +index 9e983176542be..75517134a5e94 100644 +--- a/drivers/media/v4l2-core/v4l2-mem2mem.c ++++ b/drivers/media/v4l2-core/v4l2-mem2mem.c +@@ -1087,11 +1087,17 @@ static int v4l2_m2m_register_entity(struct media_device *mdev, + entity->function = function; + + ret = media_entity_pads_init(entity, num_pads, pads); +- if (ret) ++ if (ret) { ++ kfree(entity->name); ++ entity->name = NULL; + return ret; ++ } + ret = media_device_register_entity(mdev, entity); +- if (ret) ++ if (ret) { ++ kfree(entity->name); ++ entity->name = NULL; + return ret; ++ } + + return 0; + } +diff --git a/drivers/memory/tegra/tegra234.c b/drivers/memory/tegra/tegra234.c +index abff87f917cb4..b8a7af2d36c11 100644 +--- a/drivers/memory/tegra/tegra234.c ++++ b/drivers/memory/tegra/tegra234.c +@@ -121,7 +121,7 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA1RDB, +- .name = "dla0rdb", ++ .name = "dla1rdb", + .sid = TEGRA234_SID_NVDLA1, + .regs = { + .sid = { +@@ -407,7 +407,7 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA1RDB1, +- .name = "dla0rdb1", ++ .name = "dla1rdb1", + .sid = TEGRA234_SID_NVDLA1, + .regs = { + .sid = { +@@ -417,7 +417,7 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA1WRB, +- .name = "dla0wrb", ++ .name = "dla1wrb", + .sid = TEGRA234_SID_NVDLA1, + .regs = { + .sid = { +@@ -699,7 +699,7 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA1RDA, +- .name = "dla0rda", ++ .name = "dla1rda", + .sid = TEGRA234_SID_NVDLA1, + .regs = { + .sid = { +@@ -709,7 +709,7 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA1FALRDB, +- .name = "dla0falrdb", ++ .name = "dla1falrdb", + .sid = TEGRA234_SID_NVDLA1, + .regs = { + .sid = { +@@ -719,7 +719,7 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA1WRA, +- .name = "dla0wra", ++ .name = "dla1wra", + .sid = TEGRA234_SID_NVDLA1, + .regs = { + .sid = { +@@ -729,7 +729,7 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA1FALWRB, +- .name = "dla0falwrb", ++ .name = "dla1falwrb", + .sid = TEGRA234_SID_NVDLA1, + .regs = { + .sid = { +@@ -917,7 +917,7 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA1RDA1, +- .name = "dla0rda1", ++ .name = "dla1rda1", + .sid = TEGRA234_SID_NVDLA1, + .regs = { + .sid = { +diff --git a/drivers/mfd/altera-sysmgr.c b/drivers/mfd/altera-sysmgr.c +index 0e52bd2ebd74b..fb5f988e61f37 100644 +--- a/drivers/mfd/altera-sysmgr.c ++++ b/drivers/mfd/altera-sysmgr.c +@@ -109,7 +109,9 @@ struct regmap *altr_sysmgr_regmap_lookup_by_phandle(struct device_node *np, + + dev = driver_find_device_by_of_node(&altr_sysmgr_driver.driver, + (void *)sysmgr_np); +- of_node_put(sysmgr_np); ++ if (property) ++ of_node_put(sysmgr_np); ++ + if (!dev) + return ERR_PTR(-EPROBE_DEFER); + +diff --git a/drivers/mfd/cs42l43.c b/drivers/mfd/cs42l43.c +index 7b6d07cbe6fc6..1cea3f8f467d4 100644 +--- a/drivers/mfd/cs42l43.c ++++ b/drivers/mfd/cs42l43.c +@@ -84,7 +84,7 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = { + { CS42L43_DRV_CTRL_5, 0x136C00C0 }, + { CS42L43_GPIO_CTRL1, 0x00000707 }, + { CS42L43_GPIO_CTRL2, 0x00000000 }, +- { CS42L43_GPIO_FN_SEL, 0x00000000 }, ++ { CS42L43_GPIO_FN_SEL, 0x00000004 }, + { CS42L43_MCLK_SRC_SEL, 0x00000000 }, + { CS42L43_SAMPLE_RATE1, 0x00000003 }, + { CS42L43_SAMPLE_RATE2, 0x00000003 }, +@@ -131,38 +131,38 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = { + { CS42L43_ASP_TX_CH4_CTRL, 0x00170091 }, + { CS42L43_ASP_TX_CH5_CTRL, 0x001700C1 }, + { CS42L43_ASP_TX_CH6_CTRL, 0x001700F1 }, +- { CS42L43_ASPTX1_INPUT, 0x00800000 }, +- { CS42L43_ASPTX2_INPUT, 0x00800000 }, +- { CS42L43_ASPTX3_INPUT, 0x00800000 }, +- { CS42L43_ASPTX4_INPUT, 0x00800000 }, +- { CS42L43_ASPTX5_INPUT, 0x00800000 }, +- { CS42L43_ASPTX6_INPUT, 0x00800000 }, +- { CS42L43_SWIRE_DP1_CH1_INPUT, 0x00800000 }, +- { CS42L43_SWIRE_DP1_CH2_INPUT, 0x00800000 }, +- { CS42L43_SWIRE_DP1_CH3_INPUT, 0x00800000 }, +- { CS42L43_SWIRE_DP1_CH4_INPUT, 0x00800000 }, +- { CS42L43_SWIRE_DP2_CH1_INPUT, 0x00800000 }, +- { CS42L43_SWIRE_DP2_CH2_INPUT, 0x00800000 }, +- { CS42L43_SWIRE_DP3_CH1_INPUT, 0x00800000 }, +- { CS42L43_SWIRE_DP3_CH2_INPUT, 0x00800000 }, +- { CS42L43_SWIRE_DP4_CH1_INPUT, 0x00800000 }, +- { CS42L43_SWIRE_DP4_CH2_INPUT, 0x00800000 }, +- { CS42L43_ASRC_INT1_INPUT1, 0x00800000 }, +- { CS42L43_ASRC_INT2_INPUT1, 0x00800000 }, +- { CS42L43_ASRC_INT3_INPUT1, 0x00800000 }, +- { CS42L43_ASRC_INT4_INPUT1, 0x00800000 }, +- { CS42L43_ASRC_DEC1_INPUT1, 0x00800000 }, +- { CS42L43_ASRC_DEC2_INPUT1, 0x00800000 }, +- { CS42L43_ASRC_DEC3_INPUT1, 0x00800000 }, +- { CS42L43_ASRC_DEC4_INPUT1, 0x00800000 }, +- { CS42L43_ISRC1INT1_INPUT1, 0x00800000 }, +- { CS42L43_ISRC1INT2_INPUT1, 0x00800000 }, +- { CS42L43_ISRC1DEC1_INPUT1, 0x00800000 }, +- { CS42L43_ISRC1DEC2_INPUT1, 0x00800000 }, +- { CS42L43_ISRC2INT1_INPUT1, 0x00800000 }, +- { CS42L43_ISRC2INT2_INPUT1, 0x00800000 }, +- { CS42L43_ISRC2DEC1_INPUT1, 0x00800000 }, +- { CS42L43_ISRC2DEC2_INPUT1, 0x00800000 }, ++ { CS42L43_ASPTX1_INPUT, 0x00000000 }, ++ { CS42L43_ASPTX2_INPUT, 0x00000000 }, ++ { CS42L43_ASPTX3_INPUT, 0x00000000 }, ++ { CS42L43_ASPTX4_INPUT, 0x00000000 }, ++ { CS42L43_ASPTX5_INPUT, 0x00000000 }, ++ { CS42L43_ASPTX6_INPUT, 0x00000000 }, ++ { CS42L43_SWIRE_DP1_CH1_INPUT, 0x00000000 }, ++ { CS42L43_SWIRE_DP1_CH2_INPUT, 0x00000000 }, ++ { CS42L43_SWIRE_DP1_CH3_INPUT, 0x00000000 }, ++ { CS42L43_SWIRE_DP1_CH4_INPUT, 0x00000000 }, ++ { CS42L43_SWIRE_DP2_CH1_INPUT, 0x00000000 }, ++ { CS42L43_SWIRE_DP2_CH2_INPUT, 0x00000000 }, ++ { CS42L43_SWIRE_DP3_CH1_INPUT, 0x00000000 }, ++ { CS42L43_SWIRE_DP3_CH2_INPUT, 0x00000000 }, ++ { CS42L43_SWIRE_DP4_CH1_INPUT, 0x00000000 }, ++ { CS42L43_SWIRE_DP4_CH2_INPUT, 0x00000000 }, ++ { CS42L43_ASRC_INT1_INPUT1, 0x00000000 }, ++ { CS42L43_ASRC_INT2_INPUT1, 0x00000000 }, ++ { CS42L43_ASRC_INT3_INPUT1, 0x00000000 }, ++ { CS42L43_ASRC_INT4_INPUT1, 0x00000000 }, ++ { CS42L43_ASRC_DEC1_INPUT1, 0x00000000 }, ++ { CS42L43_ASRC_DEC2_INPUT1, 0x00000000 }, ++ { CS42L43_ASRC_DEC3_INPUT1, 0x00000000 }, ++ { CS42L43_ASRC_DEC4_INPUT1, 0x00000000 }, ++ { CS42L43_ISRC1INT1_INPUT1, 0x00000000 }, ++ { CS42L43_ISRC1INT2_INPUT1, 0x00000000 }, ++ { CS42L43_ISRC1DEC1_INPUT1, 0x00000000 }, ++ { CS42L43_ISRC1DEC2_INPUT1, 0x00000000 }, ++ { CS42L43_ISRC2INT1_INPUT1, 0x00000000 }, ++ { CS42L43_ISRC2INT2_INPUT1, 0x00000000 }, ++ { CS42L43_ISRC2DEC1_INPUT1, 0x00000000 }, ++ { CS42L43_ISRC2DEC2_INPUT1, 0x00000000 }, + { CS42L43_EQ1MIX_INPUT1, 0x00800000 }, + { CS42L43_EQ1MIX_INPUT2, 0x00800000 }, + { CS42L43_EQ1MIX_INPUT3, 0x00800000 }, +@@ -171,8 +171,8 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = { + { CS42L43_EQ2MIX_INPUT2, 0x00800000 }, + { CS42L43_EQ2MIX_INPUT3, 0x00800000 }, + { CS42L43_EQ2MIX_INPUT4, 0x00800000 }, +- { CS42L43_SPDIF1_INPUT1, 0x00800000 }, +- { CS42L43_SPDIF2_INPUT1, 0x00800000 }, ++ { CS42L43_SPDIF1_INPUT1, 0x00000000 }, ++ { CS42L43_SPDIF2_INPUT1, 0x00000000 }, + { CS42L43_AMP1MIX_INPUT1, 0x00800000 }, + { CS42L43_AMP1MIX_INPUT2, 0x00800000 }, + { CS42L43_AMP1MIX_INPUT3, 0x00800000 }, +@@ -217,7 +217,7 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = { + { CS42L43_CTRL_REG, 0x00000006 }, + { CS42L43_FDIV_FRAC, 0x40000000 }, + { CS42L43_CAL_RATIO, 0x00000080 }, +- { CS42L43_SPI_CLK_CONFIG1, 0x00000000 }, ++ { CS42L43_SPI_CLK_CONFIG1, 0x00000001 }, + { CS42L43_SPI_CONFIG1, 0x00000000 }, + { CS42L43_SPI_CONFIG2, 0x00000000 }, + { CS42L43_SPI_CONFIG3, 0x00000001 }, +diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c +index c9550368d9ea5..7d0e91164cbaa 100644 +--- a/drivers/mfd/syscon.c ++++ b/drivers/mfd/syscon.c +@@ -238,7 +238,9 @@ struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, + return ERR_PTR(-ENODEV); + + regmap = syscon_node_to_regmap(syscon_np); +- of_node_put(syscon_np); ++ ++ if (property) ++ of_node_put(syscon_np); + + return regmap; + } +diff --git a/drivers/misc/mei/vsc-tp.c b/drivers/misc/mei/vsc-tp.c +index 55f7db490d3bb..682c62c635b63 100644 +--- a/drivers/misc/mei/vsc-tp.c ++++ b/drivers/misc/mei/vsc-tp.c +@@ -25,7 +25,8 @@ + #define VSC_TP_ROM_BOOTUP_DELAY_MS 10 + #define VSC_TP_ROM_XFER_POLL_TIMEOUT_US (500 * USEC_PER_MSEC) + #define VSC_TP_ROM_XFER_POLL_DELAY_US (20 * USEC_PER_MSEC) +-#define VSC_TP_WAIT_FW_ASSERTED_TIMEOUT (2 * HZ) ++#define VSC_TP_WAIT_FW_POLL_TIMEOUT (2 * HZ) ++#define VSC_TP_WAIT_FW_POLL_DELAY_US (20 * USEC_PER_MSEC) + #define VSC_TP_MAX_XFER_COUNT 5 + + #define VSC_TP_PACKET_SYNC 0x31 +@@ -101,13 +102,15 @@ static int vsc_tp_wakeup_request(struct vsc_tp *tp) + gpiod_set_value_cansleep(tp->wakeupfw, 0); + + ret = wait_event_timeout(tp->xfer_wait, +- atomic_read(&tp->assert_cnt) && +- gpiod_get_value_cansleep(tp->wakeuphost), +- VSC_TP_WAIT_FW_ASSERTED_TIMEOUT); ++ atomic_read(&tp->assert_cnt), ++ VSC_TP_WAIT_FW_POLL_TIMEOUT); + if (!ret) + return -ETIMEDOUT; + +- return 0; ++ return read_poll_timeout(gpiod_get_value_cansleep, ret, ret, ++ VSC_TP_WAIT_FW_POLL_DELAY_US, ++ VSC_TP_WAIT_FW_POLL_TIMEOUT, false, ++ tp->wakeuphost); + } + + static void vsc_tp_wakeup_release(struct vsc_tp *tp) +@@ -416,8 +419,6 @@ static irqreturn_t vsc_tp_isr(int irq, void *data) + + atomic_inc(&tp->assert_cnt); + +- wake_up(&tp->xfer_wait); +- + return IRQ_WAKE_THREAD; + } + +@@ -425,6 +426,8 @@ static irqreturn_t vsc_tp_thread_isr(int irq, void *data) + { + struct vsc_tp *tp = data; + ++ wake_up(&tp->xfer_wait); ++ + if (tp->event_notify) + tp->event_notify(tp->event_notify_context); + +diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c +index 77d5f1d244899..860380931b6cd 100644 +--- a/drivers/mmc/host/wmt-sdmmc.c ++++ b/drivers/mmc/host/wmt-sdmmc.c +@@ -883,7 +883,6 @@ static void wmt_mci_remove(struct platform_device *pdev) + { + struct mmc_host *mmc; + struct wmt_mci_priv *priv; +- struct resource *res; + u32 reg_tmp; + + mmc = platform_get_drvdata(pdev); +@@ -911,9 +910,6 @@ static void wmt_mci_remove(struct platform_device *pdev) + clk_disable_unprepare(priv->clk_sdmmc); + clk_put(priv->clk_sdmmc); + +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- release_mem_region(res->start, resource_size(res)); +- + mmc_free_host(mmc); + + dev_info(&pdev->dev, "WMT MCI device removed\n"); +diff --git a/drivers/mtd/maps/physmap-core.c b/drivers/mtd/maps/physmap-core.c +index 746a27d15d440..96eb2e782c382 100644 +--- a/drivers/mtd/maps/physmap-core.c ++++ b/drivers/mtd/maps/physmap-core.c +@@ -518,7 +518,7 @@ static int physmap_flash_probe(struct platform_device *dev) + if (!info->maps[i].phys) + info->maps[i].phys = res->start; + +- info->win_order = get_bitmask_order(resource_size(res)) - 1; ++ info->win_order = fls64(resource_size(res)) - 1; + info->maps[i].size = BIT(info->win_order + + (info->gpios ? + info->gpios->ndescs : 0)); +diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c +index f58cfb15d6e85..b69dade3f7ad0 100644 +--- a/drivers/mtd/maps/sun_uflash.c ++++ b/drivers/mtd/maps/sun_uflash.c +@@ -47,7 +47,7 @@ struct map_info uflash_map_templ = { + .bankwidth = UFLASH_BUSWIDTH, + }; + +-int uflash_devinit(struct platform_device *op, struct device_node *dp) ++static int uflash_devinit(struct platform_device *op, struct device_node *dp) + { + struct uflash_dev *up; + +diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c +index 8faca43ae1ff9..b8e70fc64348e 100644 +--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c ++++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c +@@ -625,7 +625,7 @@ enum { + /* Only for v7.2 */ + #define ACC_CONTROL_ECC_EXT_SHIFT 13 + +-static u8 brcmnand_status(struct brcmnand_host *host); ++static int brcmnand_status(struct brcmnand_host *host); + + static inline bool brcmnand_non_mmio_ops(struct brcmnand_controller *ctrl) + { +@@ -1690,7 +1690,7 @@ static int brcmnand_waitfunc(struct nand_chip *chip) + INTFC_FLASH_STATUS; + } + +-static u8 brcmnand_status(struct brcmnand_host *host) ++static int brcmnand_status(struct brcmnand_host *host) + { + struct nand_chip *chip = &host->chip; + struct mtd_info *mtd = nand_to_mtd(chip); +@@ -1701,7 +1701,7 @@ static u8 brcmnand_status(struct brcmnand_host *host) + return brcmnand_waitfunc(chip); + } + +-static u8 brcmnand_reset(struct brcmnand_host *host) ++static int brcmnand_reset(struct brcmnand_host *host) + { + struct nand_chip *chip = &host->chip; + +@@ -2433,7 +2433,11 @@ static int brcmnand_exec_op(struct nand_chip *chip, + + if (brcmnand_op_is_status(op)) { + status = op->instrs[1].ctx.data.buf.in; +- *status = brcmnand_status(host); ++ ret = brcmnand_status(host); ++ if (ret < 0) ++ return ret; ++ ++ *status = ret & 0xFF; + + return 0; + } +diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c +index 488fd452611a6..677fcb03f9bef 100644 +--- a/drivers/mtd/nand/raw/lpc32xx_mlc.c ++++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c +@@ -303,8 +303,9 @@ static int lpc32xx_nand_device_ready(struct nand_chip *nand_chip) + return 0; + } + +-static irqreturn_t lpc3xxx_nand_irq(int irq, struct lpc32xx_nand_host *host) ++static irqreturn_t lpc3xxx_nand_irq(int irq, void *data) + { ++ struct lpc32xx_nand_host *host = data; + uint8_t sr; + + /* Clear interrupt flag by reading status */ +@@ -780,7 +781,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) + goto release_dma_chan; + } + +- if (request_irq(host->irq, (irq_handler_t)&lpc3xxx_nand_irq, ++ if (request_irq(host->irq, &lpc3xxx_nand_irq, + IRQF_TRIGGER_HIGH, DRV_NAME, host)) { + dev_err(&pdev->dev, "Error requesting NAND IRQ\n"); + res = -ENXIO; +diff --git a/drivers/mtd/nand/spi/esmt.c b/drivers/mtd/nand/spi/esmt.c +index 31c439a557b18..4597a82de23a4 100644 +--- a/drivers/mtd/nand/spi/esmt.c ++++ b/drivers/mtd/nand/spi/esmt.c +@@ -104,7 +104,8 @@ static const struct mtd_ooblayout_ops f50l1g41lb_ooblayout = { + + static const struct spinand_info esmt_c8_spinand_table[] = { + SPINAND_INFO("F50L1G41LB", +- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01), ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01, 0x7f, ++ 0x7f, 0x7f), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, +@@ -113,7 +114,8 @@ static const struct spinand_info esmt_c8_spinand_table[] = { + 0, + SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)), + SPINAND_INFO("F50D1G41LB", +- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11), ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11, 0x7f, ++ 0x7f, 0x7f), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, +@@ -122,7 +124,8 @@ static const struct spinand_info esmt_c8_spinand_table[] = { + 0, + SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)), + SPINAND_INFO("F50D2G41KA", +- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51), ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51, 0x7f, ++ 0x7f, 0x7f), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, +diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c +index 16ecc11c7f62a..2395b1225cc8a 100644 +--- a/drivers/net/can/m_can/m_can.c ++++ b/drivers/net/can/m_can/m_can.c +@@ -418,6 +418,13 @@ static void m_can_config_endisable(struct m_can_classdev *cdev, bool enable) + + static inline void m_can_enable_all_interrupts(struct m_can_classdev *cdev) + { ++ if (!cdev->net->irq) { ++ dev_dbg(cdev->dev, "Start hrtimer\n"); ++ hrtimer_start(&cdev->hrtimer, ++ ms_to_ktime(HRTIMER_POLL_INTERVAL_MS), ++ HRTIMER_MODE_REL_PINNED); ++ } ++ + /* Only interrupt line 0 is used in this driver */ + m_can_write(cdev, M_CAN_ILE, ILE_EINT0); + } +@@ -425,6 +432,11 @@ static inline void m_can_enable_all_interrupts(struct m_can_classdev *cdev) + static inline void m_can_disable_all_interrupts(struct m_can_classdev *cdev) + { + m_can_write(cdev, M_CAN_ILE, 0x0); ++ ++ if (!cdev->net->irq) { ++ dev_dbg(cdev->dev, "Stop hrtimer\n"); ++ hrtimer_cancel(&cdev->hrtimer); ++ } + } + + /* Retrieve internal timestamp counter from TSCV.TSC, and shift it to 32-bit +@@ -1417,12 +1429,6 @@ static int m_can_start(struct net_device *dev) + + m_can_enable_all_interrupts(cdev); + +- if (!dev->irq) { +- dev_dbg(cdev->dev, "Start hrtimer\n"); +- hrtimer_start(&cdev->hrtimer, ms_to_ktime(HRTIMER_POLL_INTERVAL_MS), +- HRTIMER_MODE_REL_PINNED); +- } +- + return 0; + } + +@@ -1577,11 +1583,6 @@ static void m_can_stop(struct net_device *dev) + { + struct m_can_classdev *cdev = netdev_priv(dev); + +- if (!dev->irq) { +- dev_dbg(cdev->dev, "Stop hrtimer\n"); +- hrtimer_cancel(&cdev->hrtimer); +- } +- + /* disable all interrupts */ + m_can_disable_all_interrupts(cdev); + +diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c +index 245dfb7a7a315..25a49708f4842 100644 +--- a/drivers/net/dsa/microchip/ksz_common.c ++++ b/drivers/net/dsa/microchip/ksz_common.c +@@ -2185,6 +2185,8 @@ static int ksz_pirq_setup(struct ksz_device *dev, u8 p) + return ksz_irq_common_setup(dev, pirq); + } + ++static int ksz_parse_drive_strength(struct ksz_device *dev); ++ + static int ksz_setup(struct dsa_switch *ds) + { + struct ksz_device *dev = ds->priv; +@@ -2206,6 +2208,10 @@ static int ksz_setup(struct dsa_switch *ds) + return ret; + } + ++ ret = ksz_parse_drive_strength(dev); ++ if (ret) ++ return ret; ++ + /* set broadcast storm protection 10% rate */ + regmap_update_bits(ksz_regmap_16(dev), regs[S_BROADCAST_CTRL], + BROADCAST_STORM_RATE, +@@ -4242,10 +4248,6 @@ int ksz_switch_register(struct ksz_device *dev) + for (port_num = 0; port_num < dev->info->port_cnt; ++port_num) + dev->ports[port_num].interface = PHY_INTERFACE_MODE_NA; + if (dev->dev->of_node) { +- ret = ksz_parse_drive_strength(dev); +- if (ret) +- return ret; +- + ret = of_get_phy_mode(dev->dev->of_node, &interface); + if (ret == 0) + dev->compat_interface = interface; +diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c +index 3c1f657593a8f..40ae44c9945b1 100644 +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -998,20 +998,56 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface) + mutex_unlock(&priv->reg_mutex); + } + ++/* On page 205, section "8.6.3 Frame filtering" of the active standard, IEEE Std ++ * 802.1Qâ„¢-2022, it is stated that frames with 01:80:C2:00:00:00-0F as MAC DA ++ * must only be propagated to C-VLAN and MAC Bridge components. That means ++ * VLAN-aware and VLAN-unaware bridges. On the switch designs with CPU ports, ++ * these frames are supposed to be processed by the CPU (software). So we make ++ * the switch only forward them to the CPU port. And if received from a CPU ++ * port, forward to a single port. The software is responsible of making the ++ * switch conform to the latter by setting a single port as destination port on ++ * the special tag. ++ * ++ * This switch intellectual property cannot conform to this part of the standard ++ * fully. Whilst the REV_UN frame tag covers the remaining :04-0D and :0F MAC ++ * DAs, it also includes :22-FF which the scope of propagation is not supposed ++ * to be restricted for these MAC DAs. ++ */ + static void + mt753x_trap_frames(struct mt7530_priv *priv) + { +- /* Trap BPDUs to the CPU port(s) */ +- mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK, ++ /* Trap 802.1X PAE frames and BPDUs to the CPU port(s) and egress them ++ * VLAN-untagged. ++ */ ++ mt7530_rmw(priv, MT753X_BPC, MT753X_PAE_EG_TAG_MASK | ++ MT753X_PAE_PORT_FW_MASK | MT753X_BPDU_EG_TAG_MASK | ++ MT753X_BPDU_PORT_FW_MASK, ++ MT753X_PAE_EG_TAG(MT7530_VLAN_EG_UNTAGGED) | ++ MT753X_PAE_PORT_FW(MT753X_BPDU_CPU_ONLY) | ++ MT753X_BPDU_EG_TAG(MT7530_VLAN_EG_UNTAGGED) | + MT753X_BPDU_CPU_ONLY); + +- /* Trap 802.1X PAE frames to the CPU port(s) */ +- mt7530_rmw(priv, MT753X_BPC, MT753X_PAE_PORT_FW_MASK, +- MT753X_PAE_PORT_FW(MT753X_BPDU_CPU_ONLY)); ++ /* Trap frames with :01 and :02 MAC DAs to the CPU port(s) and egress ++ * them VLAN-untagged. ++ */ ++ mt7530_rmw(priv, MT753X_RGAC1, MT753X_R02_EG_TAG_MASK | ++ MT753X_R02_PORT_FW_MASK | MT753X_R01_EG_TAG_MASK | ++ MT753X_R01_PORT_FW_MASK, ++ MT753X_R02_EG_TAG(MT7530_VLAN_EG_UNTAGGED) | ++ MT753X_R02_PORT_FW(MT753X_BPDU_CPU_ONLY) | ++ MT753X_R01_EG_TAG(MT7530_VLAN_EG_UNTAGGED) | ++ MT753X_BPDU_CPU_ONLY); + +- /* Trap LLDP frames with :0E MAC DA to the CPU port(s) */ +- mt7530_rmw(priv, MT753X_RGAC2, MT753X_R0E_PORT_FW_MASK, +- MT753X_R0E_PORT_FW(MT753X_BPDU_CPU_ONLY)); ++ /* Trap frames with :03 and :0E MAC DAs to the CPU port(s) and egress ++ * them VLAN-untagged. ++ */ ++ mt7530_rmw(priv, MT753X_RGAC2, MT753X_R0E_EG_TAG_MASK | ++ MT753X_R0E_PORT_FW_MASK | MT753X_R03_EG_TAG_MASK | ++ MT753X_R03_PORT_FW_MASK, ++ MT753X_R0E_EG_TAG(MT7530_VLAN_EG_UNTAGGED) | ++ MT753X_R0E_PORT_FW(MT753X_BPDU_CPU_ONLY) | ++ MT753X_R03_EG_TAG(MT7530_VLAN_EG_UNTAGGED) | ++ MT753X_BPDU_CPU_ONLY); + } + + static int +@@ -2243,11 +2279,11 @@ mt7530_setup(struct dsa_switch *ds) + */ + if (priv->mcm) { + reset_control_assert(priv->rstc); +- usleep_range(1000, 1100); ++ usleep_range(5000, 5100); + reset_control_deassert(priv->rstc); + } else { + gpiod_set_value_cansleep(priv->reset, 0); +- usleep_range(1000, 1100); ++ usleep_range(5000, 5100); + gpiod_set_value_cansleep(priv->reset, 1); + } + +@@ -2449,11 +2485,11 @@ mt7531_setup(struct dsa_switch *ds) + */ + if (priv->mcm) { + reset_control_assert(priv->rstc); +- usleep_range(1000, 1100); ++ usleep_range(5000, 5100); + reset_control_deassert(priv->rstc); + } else { + gpiod_set_value_cansleep(priv->reset, 0); +- usleep_range(1000, 1100); ++ usleep_range(5000, 5100); + gpiod_set_value_cansleep(priv->reset, 1); + } + +diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h +index 17e42d30fff4b..75bc9043c8c0a 100644 +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -65,14 +65,33 @@ enum mt753x_id { + + /* Registers for BPDU and PAE frame control*/ + #define MT753X_BPC 0x24 +-#define MT753X_BPDU_PORT_FW_MASK GENMASK(2, 0) ++#define MT753X_PAE_EG_TAG_MASK GENMASK(24, 22) ++#define MT753X_PAE_EG_TAG(x) FIELD_PREP(MT753X_PAE_EG_TAG_MASK, x) + #define MT753X_PAE_PORT_FW_MASK GENMASK(18, 16) + #define MT753X_PAE_PORT_FW(x) FIELD_PREP(MT753X_PAE_PORT_FW_MASK, x) ++#define MT753X_BPDU_EG_TAG_MASK GENMASK(8, 6) ++#define MT753X_BPDU_EG_TAG(x) FIELD_PREP(MT753X_BPDU_EG_TAG_MASK, x) ++#define MT753X_BPDU_PORT_FW_MASK GENMASK(2, 0) ++ ++/* Register for :01 and :02 MAC DA frame control */ ++#define MT753X_RGAC1 0x28 ++#define MT753X_R02_EG_TAG_MASK GENMASK(24, 22) ++#define MT753X_R02_EG_TAG(x) FIELD_PREP(MT753X_R02_EG_TAG_MASK, x) ++#define MT753X_R02_PORT_FW_MASK GENMASK(18, 16) ++#define MT753X_R02_PORT_FW(x) FIELD_PREP(MT753X_R02_PORT_FW_MASK, x) ++#define MT753X_R01_EG_TAG_MASK GENMASK(8, 6) ++#define MT753X_R01_EG_TAG(x) FIELD_PREP(MT753X_R01_EG_TAG_MASK, x) ++#define MT753X_R01_PORT_FW_MASK GENMASK(2, 0) + + /* Register for :03 and :0E MAC DA frame control */ + #define MT753X_RGAC2 0x2c ++#define MT753X_R0E_EG_TAG_MASK GENMASK(24, 22) ++#define MT753X_R0E_EG_TAG(x) FIELD_PREP(MT753X_R0E_EG_TAG_MASK, x) + #define MT753X_R0E_PORT_FW_MASK GENMASK(18, 16) + #define MT753X_R0E_PORT_FW(x) FIELD_PREP(MT753X_R0E_PORT_FW_MASK, x) ++#define MT753X_R03_EG_TAG_MASK GENMASK(8, 6) ++#define MT753X_R03_EG_TAG(x) FIELD_PREP(MT753X_R03_EG_TAG_MASK, x) ++#define MT753X_R03_PORT_FW_MASK GENMASK(2, 0) + + enum mt753x_bpdu_port_fw { + MT753X_BPDU_FOLLOW_MFC, +@@ -253,6 +272,7 @@ enum mt7530_port_mode { + enum mt7530_vlan_port_eg_tag { + MT7530_VLAN_EG_DISABLED = 0, + MT7530_VLAN_EG_CONSISTENT = 1, ++ MT7530_VLAN_EG_UNTAGGED = 4, + }; + + enum mt7530_vlan_port_attr { +diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c +index 1c0a7828d397b..5482015411f2f 100644 +--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c ++++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c +@@ -2670,22 +2670,6 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev) + return NETDEV_TX_OK; + } + +-static u16 ena_select_queue(struct net_device *dev, struct sk_buff *skb, +- struct net_device *sb_dev) +-{ +- u16 qid; +- /* we suspect that this is good for in--kernel network services that +- * want to loop incoming skb rx to tx in normal user generated traffic, +- * most probably we will not get to this +- */ +- if (skb_rx_queue_recorded(skb)) +- qid = skb_get_rx_queue(skb); +- else +- qid = netdev_pick_tx(dev, skb, NULL); +- +- return qid; +-} +- + static void ena_config_host_info(struct ena_com_dev *ena_dev, struct pci_dev *pdev) + { + struct device *dev = &pdev->dev; +@@ -2863,7 +2847,6 @@ static const struct net_device_ops ena_netdev_ops = { + .ndo_open = ena_open, + .ndo_stop = ena_close, + .ndo_start_xmit = ena_start_xmit, +- .ndo_select_queue = ena_select_queue, + .ndo_get_stats64 = ena_get_stats64, + .ndo_tx_timeout = ena_tx_timeout, + .ndo_change_mtu = ena_change_mtu, +diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +index d8b1824c334d3..0bc1367fd6492 100644 +--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h ++++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +@@ -1002,9 +1002,6 @@ static inline void bnx2x_set_fw_mac_addr(__le16 *fw_hi, __le16 *fw_mid, + static inline void bnx2x_free_rx_mem_pool(struct bnx2x *bp, + struct bnx2x_alloc_pool *pool) + { +- if (!pool->page) +- return; +- + put_page(pool->page); + + pool->page = NULL; +@@ -1015,6 +1012,9 @@ static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp, + { + int i; + ++ if (!fp->page_pool.page) ++ return; ++ + if (fp->mode == TPA_MODE_DISABLED) + return; + +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c b/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c +index 3b6dbf158b98d..f72dc0cee30e5 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c +@@ -76,7 +76,7 @@ static int hns3_dcbnl_ieee_delapp(struct net_device *ndev, struct dcb_app *app) + if (hns3_nic_resetting(ndev)) + return -EBUSY; + +- if (h->kinfo.dcb_ops->ieee_setapp) ++ if (h->kinfo.dcb_ops->ieee_delapp) + return h->kinfo.dcb_ops->ieee_delapp(h, app); + + return -EOPNOTSUPP; +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +index 5ea9e59569eff..609d3799d7738 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +@@ -2890,7 +2890,10 @@ static int hclge_mac_init(struct hclge_dev *hdev) + int ret; + + hdev->support_sfp_query = true; +- hdev->hw.mac.duplex = HCLGE_MAC_FULL; ++ ++ if (!test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) ++ hdev->hw.mac.duplex = HCLGE_MAC_FULL; ++ + ret = hclge_cfg_mac_speed_dup_hw(hdev, hdev->hw.mac.speed, + hdev->hw.mac.duplex, hdev->hw.mac.lane_num); + if (ret) +diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c +index 80a2a0073d97a..507d7ce26d831 100644 +--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c ++++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ptp.c +@@ -108,7 +108,7 @@ void hclge_ptp_get_rx_hwts(struct hnae3_handle *handle, struct sk_buff *skb, + u64 ns = nsec; + u32 sec_h; + +- if (!test_bit(HCLGE_PTP_FLAG_RX_EN, &hdev->ptp->flags)) ++ if (!hdev->ptp || !test_bit(HCLGE_PTP_FLAG_RX_EN, &hdev->ptp->flags)) + return; + + /* Since the BD does not have enough space for the higher 16 bits of +diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c +index df6a68ab747ee..6d256dbcb77d0 100644 +--- a/drivers/net/ethernet/intel/ice/ice_main.c ++++ b/drivers/net/ethernet/intel/ice/ice_main.c +@@ -6737,6 +6737,7 @@ static void ice_update_vsi_ring_stats(struct ice_vsi *vsi) + { + struct rtnl_link_stats64 *net_stats, *stats_prev; + struct rtnl_link_stats64 *vsi_stats; ++ struct ice_pf *pf = vsi->back; + u64 pkts, bytes; + int i; + +@@ -6782,21 +6783,18 @@ static void ice_update_vsi_ring_stats(struct ice_vsi *vsi) + net_stats = &vsi->net_stats; + stats_prev = &vsi->net_stats_prev; + +- /* clear prev counters after reset */ +- if (vsi_stats->tx_packets < stats_prev->tx_packets || +- vsi_stats->rx_packets < stats_prev->rx_packets) { +- stats_prev->tx_packets = 0; +- stats_prev->tx_bytes = 0; +- stats_prev->rx_packets = 0; +- stats_prev->rx_bytes = 0; ++ /* Update netdev counters, but keep in mind that values could start at ++ * random value after PF reset. And as we increase the reported stat by ++ * diff of Prev-Cur, we need to be sure that Prev is valid. If it's not, ++ * let's skip this round. ++ */ ++ if (likely(pf->stat_prev_loaded)) { ++ net_stats->tx_packets += vsi_stats->tx_packets - stats_prev->tx_packets; ++ net_stats->tx_bytes += vsi_stats->tx_bytes - stats_prev->tx_bytes; ++ net_stats->rx_packets += vsi_stats->rx_packets - stats_prev->rx_packets; ++ net_stats->rx_bytes += vsi_stats->rx_bytes - stats_prev->rx_bytes; + } + +- /* update netdev counters */ +- net_stats->tx_packets += vsi_stats->tx_packets - stats_prev->tx_packets; +- net_stats->tx_bytes += vsi_stats->tx_bytes - stats_prev->tx_bytes; +- net_stats->rx_packets += vsi_stats->rx_packets - stats_prev->rx_packets; +- net_stats->rx_bytes += vsi_stats->rx_bytes - stats_prev->rx_bytes; +- + stats_prev->tx_packets = vsi_stats->tx_packets; + stats_prev->tx_bytes = vsi_stats->tx_bytes; + stats_prev->rx_packets = vsi_stats->rx_packets; +diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c +index cebb44f51d5f5..7662c42e35c11 100644 +--- a/drivers/net/ethernet/intel/igb/igb_main.c ++++ b/drivers/net/ethernet/intel/igb/igb_main.c +@@ -6985,44 +6985,31 @@ static void igb_extts(struct igb_adapter *adapter, int tsintr_tt) + static void igb_tsync_interrupt(struct igb_adapter *adapter) + { + struct e1000_hw *hw = &adapter->hw; +- u32 ack = 0, tsicr = rd32(E1000_TSICR); ++ u32 tsicr = rd32(E1000_TSICR); + struct ptp_clock_event event; + + if (tsicr & TSINTR_SYS_WRAP) { + event.type = PTP_CLOCK_PPS; + if (adapter->ptp_caps.pps) + ptp_clock_event(adapter->ptp_clock, &event); +- ack |= TSINTR_SYS_WRAP; + } + + if (tsicr & E1000_TSICR_TXTS) { + /* retrieve hardware timestamp */ + schedule_work(&adapter->ptp_tx_work); +- ack |= E1000_TSICR_TXTS; + } + +- if (tsicr & TSINTR_TT0) { ++ if (tsicr & TSINTR_TT0) + igb_perout(adapter, 0); +- ack |= TSINTR_TT0; +- } + +- if (tsicr & TSINTR_TT1) { ++ if (tsicr & TSINTR_TT1) + igb_perout(adapter, 1); +- ack |= TSINTR_TT1; +- } + +- if (tsicr & TSINTR_AUTT0) { ++ if (tsicr & TSINTR_AUTT0) + igb_extts(adapter, 0); +- ack |= TSINTR_AUTT0; +- } + +- if (tsicr & TSINTR_AUTT1) { ++ if (tsicr & TSINTR_AUTT1) + igb_extts(adapter, 1); +- ack |= TSINTR_AUTT1; +- } +- +- /* acknowledge the interrupts */ +- wr32(E1000_TSICR, ack); + } + + static irqreturn_t igb_msix_other(int irq, void *data) +diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c +index 81c21a893ede9..e447ba0370568 100644 +--- a/drivers/net/ethernet/intel/igc/igc_main.c ++++ b/drivers/net/ethernet/intel/igc/igc_main.c +@@ -5302,25 +5302,22 @@ igc_features_check(struct sk_buff *skb, struct net_device *dev, + + static void igc_tsync_interrupt(struct igc_adapter *adapter) + { +- u32 ack, tsauxc, sec, nsec, tsicr; + struct igc_hw *hw = &adapter->hw; ++ u32 tsauxc, sec, nsec, tsicr; + struct ptp_clock_event event; + struct timespec64 ts; + + tsicr = rd32(IGC_TSICR); +- ack = 0; + + if (tsicr & IGC_TSICR_SYS_WRAP) { + event.type = PTP_CLOCK_PPS; + if (adapter->ptp_caps.pps) + ptp_clock_event(adapter->ptp_clock, &event); +- ack |= IGC_TSICR_SYS_WRAP; + } + + if (tsicr & IGC_TSICR_TXTS) { + /* retrieve hardware timestamp */ + igc_ptp_tx_tstamp_event(adapter); +- ack |= IGC_TSICR_TXTS; + } + + if (tsicr & IGC_TSICR_TT0) { +@@ -5334,7 +5331,6 @@ static void igc_tsync_interrupt(struct igc_adapter *adapter) + wr32(IGC_TSAUXC, tsauxc); + adapter->perout[0].start = ts; + spin_unlock(&adapter->tmreg_lock); +- ack |= IGC_TSICR_TT0; + } + + if (tsicr & IGC_TSICR_TT1) { +@@ -5348,7 +5344,6 @@ static void igc_tsync_interrupt(struct igc_adapter *adapter) + wr32(IGC_TSAUXC, tsauxc); + adapter->perout[1].start = ts; + spin_unlock(&adapter->tmreg_lock); +- ack |= IGC_TSICR_TT1; + } + + if (tsicr & IGC_TSICR_AUTT0) { +@@ -5358,7 +5353,6 @@ static void igc_tsync_interrupt(struct igc_adapter *adapter) + event.index = 0; + event.timestamp = sec * NSEC_PER_SEC + nsec; + ptp_clock_event(adapter->ptp_clock, &event); +- ack |= IGC_TSICR_AUTT0; + } + + if (tsicr & IGC_TSICR_AUTT1) { +@@ -5368,11 +5362,7 @@ static void igc_tsync_interrupt(struct igc_adapter *adapter) + event.index = 1; + event.timestamp = sec * NSEC_PER_SEC + nsec; + ptp_clock_event(adapter->ptp_clock, &event); +- ack |= IGC_TSICR_AUTT1; + } +- +- /* acknowledge the interrupts */ +- wr32(IGC_TSICR, ack); + } + + /** +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +index 6c70c84986904..3c0f55b3e48ea 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +@@ -1338,7 +1338,7 @@ static irqreturn_t cgx_fwi_event_handler(int irq, void *data) + + /* Release thread waiting for completion */ + lmac->cmd_pend = false; +- wake_up_interruptible(&lmac->wq_cmd_cmplt); ++ wake_up(&lmac->wq_cmd_cmplt); + break; + case CGX_EVT_ASYNC: + if (cgx_event_is_linkevent(event)) +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.c b/drivers/net/ethernet/marvell/octeontx2/af/mbox.c +index b92264d0a77e7..1e5aa53975040 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.c +@@ -214,11 +214,12 @@ int otx2_mbox_busy_poll_for_rsp(struct otx2_mbox *mbox, int devid) + } + EXPORT_SYMBOL(otx2_mbox_busy_poll_for_rsp); + +-void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid) ++static void otx2_mbox_msg_send_data(struct otx2_mbox *mbox, int devid, u64 data) + { + struct otx2_mbox_dev *mdev = &mbox->dev[devid]; + struct mbox_hdr *tx_hdr, *rx_hdr; + void *hw_mbase = mdev->hwbase; ++ u64 intr_val; + + tx_hdr = hw_mbase + mbox->tx_start; + rx_hdr = hw_mbase + mbox->rx_start; +@@ -254,14 +255,52 @@ void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid) + + spin_unlock(&mdev->mbox_lock); + ++ /* Check if interrupt pending */ ++ intr_val = readq((void __iomem *)mbox->reg_base + ++ (mbox->trigger | (devid << mbox->tr_shift))); ++ ++ intr_val |= data; + /* The interrupt should be fired after num_msgs is written + * to the shared memory + */ +- writeq(1, (void __iomem *)mbox->reg_base + ++ writeq(intr_val, (void __iomem *)mbox->reg_base + + (mbox->trigger | (devid << mbox->tr_shift))); + } ++ ++void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid) ++{ ++ otx2_mbox_msg_send_data(mbox, devid, MBOX_DOWN_MSG); ++} + EXPORT_SYMBOL(otx2_mbox_msg_send); + ++void otx2_mbox_msg_send_up(struct otx2_mbox *mbox, int devid) ++{ ++ otx2_mbox_msg_send_data(mbox, devid, MBOX_UP_MSG); ++} ++EXPORT_SYMBOL(otx2_mbox_msg_send_up); ++ ++bool otx2_mbox_wait_for_zero(struct otx2_mbox *mbox, int devid) ++{ ++ u64 data; ++ ++ data = readq((void __iomem *)mbox->reg_base + ++ (mbox->trigger | (devid << mbox->tr_shift))); ++ ++ /* If data is non-zero wait for ~1ms and return to caller ++ * whether data has changed to zero or not after the wait. ++ */ ++ if (!data) ++ return true; ++ ++ usleep_range(950, 1000); ++ ++ data = readq((void __iomem *)mbox->reg_base + ++ (mbox->trigger | (devid << mbox->tr_shift))); ++ ++ return data == 0; ++} ++EXPORT_SYMBOL(otx2_mbox_wait_for_zero); ++ + struct mbox_msghdr *otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid, + int size, int size_rsp) + { +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +index edeb0f7373121..98e203a0e26b6 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h ++++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +@@ -16,6 +16,9 @@ + + #define MBOX_SIZE SZ_64K + ++#define MBOX_DOWN_MSG 1 ++#define MBOX_UP_MSG 2 ++ + /* AF/PF: PF initiated, PF/VF VF initiated */ + #define MBOX_DOWN_RX_START 0 + #define MBOX_DOWN_RX_SIZE (46 * SZ_1K) +@@ -101,6 +104,7 @@ int otx2_mbox_regions_init(struct otx2_mbox *mbox, void __force **hwbase, + struct pci_dev *pdev, void __force *reg_base, + int direction, int ndevs, unsigned long *bmap); + void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid); ++void otx2_mbox_msg_send_up(struct otx2_mbox *mbox, int devid); + int otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid); + int otx2_mbox_busy_poll_for_rsp(struct otx2_mbox *mbox, int devid); + struct mbox_msghdr *otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid, +@@ -118,6 +122,8 @@ static inline struct mbox_msghdr *otx2_mbox_alloc_msg(struct otx2_mbox *mbox, + return otx2_mbox_alloc_msg_rsp(mbox, devid, size, 0); + } + ++bool otx2_mbox_wait_for_zero(struct otx2_mbox *mbox, int devid); ++ + /* Mailbox message types */ + #define MBOX_MSG_MASK 0xFFFF + #define MBOX_MSG_INVALID 0xFFFE +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mcs_rvu_if.c b/drivers/net/ethernet/marvell/octeontx2/af/mcs_rvu_if.c +index dfd23580e3b8e..d39d86e694ccf 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/mcs_rvu_if.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/mcs_rvu_if.c +@@ -121,13 +121,17 @@ int mcs_add_intr_wq_entry(struct mcs *mcs, struct mcs_intr_event *event) + static int mcs_notify_pfvf(struct mcs_intr_event *event, struct rvu *rvu) + { + struct mcs_intr_info *req; +- int err, pf; ++ int pf; + + pf = rvu_get_pf(event->pcifunc); + ++ mutex_lock(&rvu->mbox_lock); ++ + req = otx2_mbox_alloc_msg_mcs_intr_notify(rvu, pf); +- if (!req) ++ if (!req) { ++ mutex_unlock(&rvu->mbox_lock); + return -ENOMEM; ++ } + + req->mcs_id = event->mcs_id; + req->intr_mask = event->intr_mask; +@@ -135,10 +139,11 @@ static int mcs_notify_pfvf(struct mcs_intr_event *event, struct rvu *rvu) + req->hdr.pcifunc = event->pcifunc; + req->lmac_id = event->lmac_id; + +- otx2_mbox_msg_send(&rvu->afpf_wq_info.mbox_up, pf); +- err = otx2_mbox_wait_for_rsp(&rvu->afpf_wq_info.mbox_up, pf); +- if (err) +- dev_warn(rvu->dev, "MCS notification to pf %d failed\n", pf); ++ otx2_mbox_wait_for_zero(&rvu->afpf_wq_info.mbox_up, pf); ++ ++ otx2_mbox_msg_send_up(&rvu->afpf_wq_info.mbox_up, pf); ++ ++ mutex_unlock(&rvu->mbox_lock); + + return 0; + } +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +index 5c1d04a3c559b..6a911ea0cff9b 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +@@ -2117,7 +2117,7 @@ MBOX_MESSAGES + } + } + +-static void __rvu_mbox_handler(struct rvu_work *mwork, int type) ++static void __rvu_mbox_handler(struct rvu_work *mwork, int type, bool poll) + { + struct rvu *rvu = mwork->rvu; + int offset, err, id, devid; +@@ -2184,6 +2184,9 @@ static void __rvu_mbox_handler(struct rvu_work *mwork, int type) + } + mw->mbox_wrk[devid].num_msgs = 0; + ++ if (poll) ++ otx2_mbox_wait_for_zero(mbox, devid); ++ + /* Send mbox responses to VF/PF */ + otx2_mbox_msg_send(mbox, devid); + } +@@ -2191,15 +2194,18 @@ static void __rvu_mbox_handler(struct rvu_work *mwork, int type) + static inline void rvu_afpf_mbox_handler(struct work_struct *work) + { + struct rvu_work *mwork = container_of(work, struct rvu_work, work); ++ struct rvu *rvu = mwork->rvu; + +- __rvu_mbox_handler(mwork, TYPE_AFPF); ++ mutex_lock(&rvu->mbox_lock); ++ __rvu_mbox_handler(mwork, TYPE_AFPF, true); ++ mutex_unlock(&rvu->mbox_lock); + } + + static inline void rvu_afvf_mbox_handler(struct work_struct *work) + { + struct rvu_work *mwork = container_of(work, struct rvu_work, work); + +- __rvu_mbox_handler(mwork, TYPE_AFVF); ++ __rvu_mbox_handler(mwork, TYPE_AFVF, false); + } + + static void __rvu_mbox_up_handler(struct rvu_work *mwork, int type) +@@ -2374,6 +2380,8 @@ static int rvu_mbox_init(struct rvu *rvu, struct mbox_wq_info *mw, + } + } + ++ mutex_init(&rvu->mbox_lock); ++ + mbox_regions = kcalloc(num, sizeof(void *), GFP_KERNEL); + if (!mbox_regions) { + err = -ENOMEM; +@@ -2523,10 +2531,9 @@ static void rvu_queue_work(struct mbox_wq_info *mw, int first, + } + } + +-static irqreturn_t rvu_mbox_intr_handler(int irq, void *rvu_irq) ++static irqreturn_t rvu_mbox_pf_intr_handler(int irq, void *rvu_irq) + { + struct rvu *rvu = (struct rvu *)rvu_irq; +- int vfs = rvu->vfs; + u64 intr; + + intr = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_PFAF_MBOX_INT); +@@ -2540,6 +2547,18 @@ static irqreturn_t rvu_mbox_intr_handler(int irq, void *rvu_irq) + + rvu_queue_work(&rvu->afpf_wq_info, 0, rvu->hw->total_pfs, intr); + ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t rvu_mbox_intr_handler(int irq, void *rvu_irq) ++{ ++ struct rvu *rvu = (struct rvu *)rvu_irq; ++ int vfs = rvu->vfs; ++ u64 intr; ++ ++ /* Sync with mbox memory region */ ++ rmb(); ++ + /* Handle VF interrupts */ + if (vfs > 64) { + intr = rvupf_read64(rvu, RVU_PF_VFPF_MBOX_INTX(1)); +@@ -2881,7 +2900,7 @@ static int rvu_register_interrupts(struct rvu *rvu) + /* Register mailbox interrupt handler */ + sprintf(&rvu->irq_name[RVU_AF_INT_VEC_MBOX * NAME_SIZE], "RVUAF Mbox"); + ret = request_irq(pci_irq_vector(rvu->pdev, RVU_AF_INT_VEC_MBOX), +- rvu_mbox_intr_handler, 0, ++ rvu_mbox_pf_intr_handler, 0, + &rvu->irq_name[RVU_AF_INT_VEC_MBOX * NAME_SIZE], rvu); + if (ret) { + dev_err(rvu->dev, +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +index 43be37dd1f325..d44a400e1b502 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +@@ -570,6 +570,8 @@ struct rvu { + spinlock_t mcs_intrq_lock; + /* CPT interrupt lock */ + spinlock_t cpt_intr_lock; ++ ++ struct mutex mbox_lock; /* Serialize mbox up and down msgs */ + }; + + static inline void rvu_write64(struct rvu *rvu, u64 block, u64 offset, u64 val) +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c +index 38acdc7a73bbe..72e060cf6b618 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c +@@ -232,7 +232,7 @@ static void cgx_notify_pfs(struct cgx_link_event *event, struct rvu *rvu) + struct cgx_link_user_info *linfo; + struct cgx_link_info_msg *msg; + unsigned long pfmap; +- int err, pfid; ++ int pfid; + + linfo = &event->link_uinfo; + pfmap = cgxlmac_to_pfmap(rvu, event->cgx_id, event->lmac_id); +@@ -255,16 +255,22 @@ static void cgx_notify_pfs(struct cgx_link_event *event, struct rvu *rvu) + continue; + } + ++ mutex_lock(&rvu->mbox_lock); ++ + /* Send mbox message to PF */ + msg = otx2_mbox_alloc_msg_cgx_link_event(rvu, pfid); +- if (!msg) ++ if (!msg) { ++ mutex_unlock(&rvu->mbox_lock); + continue; ++ } ++ + msg->link_info = *linfo; +- otx2_mbox_msg_send(&rvu->afpf_wq_info.mbox_up, pfid); +- err = otx2_mbox_wait_for_rsp(&rvu->afpf_wq_info.mbox_up, pfid); +- if (err) +- dev_warn(rvu->dev, "notification to pf %d failed\n", +- pfid); ++ ++ otx2_mbox_wait_for_zero(&rvu->afpf_wq_info.mbox_up, pfid); ++ ++ otx2_mbox_msg_send_up(&rvu->afpf_wq_info.mbox_up, pfid); ++ ++ mutex_unlock(&rvu->mbox_lock); + } while (pfmap); + } + +diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c +index 1e6fbd98423dc..96c04f7d93f8b 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c ++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c +@@ -1235,8 +1235,8 @@ static int rvu_af_dl_dwrr_mtu_get(struct devlink *devlink, u32 id, + enum rvu_af_dl_param_id { + RVU_AF_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, + RVU_AF_DEVLINK_PARAM_ID_DWRR_MTU, +- RVU_AF_DEVLINK_PARAM_ID_NPC_EXACT_FEATURE_DISABLE, + RVU_AF_DEVLINK_PARAM_ID_NPC_MCAM_ZONE_PERCENT, ++ RVU_AF_DEVLINK_PARAM_ID_NPC_EXACT_FEATURE_DISABLE, + RVU_AF_DEVLINK_PARAM_ID_NIX_MAXLF, + }; + +@@ -1434,15 +1434,6 @@ static const struct devlink_param rvu_af_dl_params[] = { + BIT(DEVLINK_PARAM_CMODE_RUNTIME), + rvu_af_dl_dwrr_mtu_get, rvu_af_dl_dwrr_mtu_set, + rvu_af_dl_dwrr_mtu_validate), +-}; +- +-static const struct devlink_param rvu_af_dl_param_exact_match[] = { +- DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NPC_EXACT_FEATURE_DISABLE, +- "npc_exact_feature_disable", DEVLINK_PARAM_TYPE_STRING, +- BIT(DEVLINK_PARAM_CMODE_RUNTIME), +- rvu_af_npc_exact_feature_get, +- rvu_af_npc_exact_feature_disable, +- rvu_af_npc_exact_feature_validate), + DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NPC_MCAM_ZONE_PERCENT, + "npc_mcam_high_zone_percent", DEVLINK_PARAM_TYPE_U8, + BIT(DEVLINK_PARAM_CMODE_RUNTIME), +@@ -1457,6 +1448,15 @@ static const struct devlink_param rvu_af_dl_param_exact_match[] = { + rvu_af_dl_nix_maxlf_validate), + }; + ++static const struct devlink_param rvu_af_dl_param_exact_match[] = { ++ DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NPC_EXACT_FEATURE_DISABLE, ++ "npc_exact_feature_disable", DEVLINK_PARAM_TYPE_STRING, ++ BIT(DEVLINK_PARAM_CMODE_RUNTIME), ++ rvu_af_npc_exact_feature_get, ++ rvu_af_npc_exact_feature_disable, ++ rvu_af_npc_exact_feature_validate), ++}; ++ + /* Devlink switch mode */ + static int rvu_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode) + { +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +index 02d0b707aea5b..a85ac039d779b 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +@@ -1592,7 +1592,7 @@ int otx2_detach_resources(struct mbox *mbox) + detach->partial = false; + + /* Send detach request to AF */ +- otx2_mbox_msg_send(&mbox->mbox, 0); ++ otx2_sync_mbox_msg(mbox); + mutex_unlock(&mbox->lock); + return 0; + } +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +index 06910307085ef..7e16a341ec588 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +@@ -815,7 +815,7 @@ static inline int otx2_sync_mbox_up_msg(struct mbox *mbox, int devid) + + if (!otx2_mbox_nonempty(&mbox->mbox_up, devid)) + return 0; +- otx2_mbox_msg_send(&mbox->mbox_up, devid); ++ otx2_mbox_msg_send_up(&mbox->mbox_up, devid); + err = otx2_mbox_wait_for_rsp(&mbox->mbox_up, devid); + if (err) + return err; +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +index e5fe67e738655..b40bd0e467514 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +@@ -292,8 +292,8 @@ static int otx2_pf_flr_init(struct otx2_nic *pf, int num_vfs) + return 0; + } + +-static void otx2_queue_work(struct mbox *mw, struct workqueue_struct *mbox_wq, +- int first, int mdevs, u64 intr, int type) ++static void otx2_queue_vf_work(struct mbox *mw, struct workqueue_struct *mbox_wq, ++ int first, int mdevs, u64 intr) + { + struct otx2_mbox_dev *mdev; + struct otx2_mbox *mbox; +@@ -307,40 +307,26 @@ static void otx2_queue_work(struct mbox *mw, struct workqueue_struct *mbox_wq, + + mbox = &mw->mbox; + mdev = &mbox->dev[i]; +- if (type == TYPE_PFAF) +- otx2_sync_mbox_bbuf(mbox, i); + hdr = mdev->mbase + mbox->rx_start; + /* The hdr->num_msgs is set to zero immediately in the interrupt +- * handler to ensure that it holds a correct value next time +- * when the interrupt handler is called. +- * pf->mbox.num_msgs holds the data for use in pfaf_mbox_handler +- * pf>mbox.up_num_msgs holds the data for use in +- * pfaf_mbox_up_handler. ++ * handler to ensure that it holds a correct value next time ++ * when the interrupt handler is called. pf->mw[i].num_msgs ++ * holds the data for use in otx2_pfvf_mbox_handler and ++ * pf->mw[i].up_num_msgs holds the data for use in ++ * otx2_pfvf_mbox_up_handler. + */ + if (hdr->num_msgs) { + mw[i].num_msgs = hdr->num_msgs; + hdr->num_msgs = 0; +- if (type == TYPE_PFAF) +- memset(mbox->hwbase + mbox->rx_start, 0, +- ALIGN(sizeof(struct mbox_hdr), +- sizeof(u64))); +- + queue_work(mbox_wq, &mw[i].mbox_wrk); + } + + mbox = &mw->mbox_up; + mdev = &mbox->dev[i]; +- if (type == TYPE_PFAF) +- otx2_sync_mbox_bbuf(mbox, i); + hdr = mdev->mbase + mbox->rx_start; + if (hdr->num_msgs) { + mw[i].up_num_msgs = hdr->num_msgs; + hdr->num_msgs = 0; +- if (type == TYPE_PFAF) +- memset(mbox->hwbase + mbox->rx_start, 0, +- ALIGN(sizeof(struct mbox_hdr), +- sizeof(u64))); +- + queue_work(mbox_wq, &mw[i].mbox_up_wrk); + } + } +@@ -356,8 +342,10 @@ static void otx2_forward_msg_pfvf(struct otx2_mbox_dev *mdev, + /* Msgs are already copied, trigger VF's mbox irq */ + smp_wmb(); + ++ otx2_mbox_wait_for_zero(pfvf_mbox, devid); ++ + offset = pfvf_mbox->trigger | (devid << pfvf_mbox->tr_shift); +- writeq(1, (void __iomem *)pfvf_mbox->reg_base + offset); ++ writeq(MBOX_DOWN_MSG, (void __iomem *)pfvf_mbox->reg_base + offset); + + /* Restore VF's mbox bounce buffer region address */ + src_mdev->mbase = bbuf_base; +@@ -547,7 +535,7 @@ static void otx2_pfvf_mbox_up_handler(struct work_struct *work) + end: + offset = mbox->rx_start + msg->next_msgoff; + if (mdev->msgs_acked == (vf_mbox->up_num_msgs - 1)) +- __otx2_mbox_reset(mbox, 0); ++ __otx2_mbox_reset(mbox, vf_idx); + mdev->msgs_acked++; + } + } +@@ -564,8 +552,7 @@ static irqreturn_t otx2_pfvf_mbox_intr_handler(int irq, void *pf_irq) + if (vfs > 64) { + intr = otx2_read64(pf, RVU_PF_VFPF_MBOX_INTX(1)); + otx2_write64(pf, RVU_PF_VFPF_MBOX_INTX(1), intr); +- otx2_queue_work(mbox, pf->mbox_pfvf_wq, 64, vfs, intr, +- TYPE_PFVF); ++ otx2_queue_vf_work(mbox, pf->mbox_pfvf_wq, 64, vfs, intr); + if (intr) + trace_otx2_msg_interrupt(mbox->mbox.pdev, "VF(s) to PF", intr); + vfs = 64; +@@ -574,7 +561,7 @@ static irqreturn_t otx2_pfvf_mbox_intr_handler(int irq, void *pf_irq) + intr = otx2_read64(pf, RVU_PF_VFPF_MBOX_INTX(0)); + otx2_write64(pf, RVU_PF_VFPF_MBOX_INTX(0), intr); + +- otx2_queue_work(mbox, pf->mbox_pfvf_wq, 0, vfs, intr, TYPE_PFVF); ++ otx2_queue_vf_work(mbox, pf->mbox_pfvf_wq, 0, vfs, intr); + + if (intr) + trace_otx2_msg_interrupt(mbox->mbox.pdev, "VF(s) to PF", intr); +@@ -597,8 +584,9 @@ static int otx2_pfvf_mbox_init(struct otx2_nic *pf, int numvfs) + if (!pf->mbox_pfvf) + return -ENOMEM; + +- pf->mbox_pfvf_wq = alloc_ordered_workqueue("otx2_pfvf_mailbox", +- WQ_HIGHPRI | WQ_MEM_RECLAIM); ++ pf->mbox_pfvf_wq = alloc_workqueue("otx2_pfvf_mailbox", ++ WQ_UNBOUND | WQ_HIGHPRI | ++ WQ_MEM_RECLAIM, 0); + if (!pf->mbox_pfvf_wq) + return -ENOMEM; + +@@ -821,20 +809,22 @@ static void otx2_pfaf_mbox_handler(struct work_struct *work) + struct mbox *af_mbox; + struct otx2_nic *pf; + int offset, id; ++ u16 num_msgs; + + af_mbox = container_of(work, struct mbox, mbox_wrk); + mbox = &af_mbox->mbox; + mdev = &mbox->dev[0]; + rsp_hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start); ++ num_msgs = rsp_hdr->num_msgs; + + offset = mbox->rx_start + ALIGN(sizeof(*rsp_hdr), MBOX_MSG_ALIGN); + pf = af_mbox->pfvf; + +- for (id = 0; id < af_mbox->num_msgs; id++) { ++ for (id = 0; id < num_msgs; id++) { + msg = (struct mbox_msghdr *)(mdev->mbase + offset); + otx2_process_pfaf_mbox_msg(pf, msg); + offset = mbox->rx_start + msg->next_msgoff; +- if (mdev->msgs_acked == (af_mbox->num_msgs - 1)) ++ if (mdev->msgs_acked == (num_msgs - 1)) + __otx2_mbox_reset(mbox, 0); + mdev->msgs_acked++; + } +@@ -945,12 +935,14 @@ static void otx2_pfaf_mbox_up_handler(struct work_struct *work) + int offset, id, devid = 0; + struct mbox_hdr *rsp_hdr; + struct mbox_msghdr *msg; ++ u16 num_msgs; + + rsp_hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start); ++ num_msgs = rsp_hdr->num_msgs; + + offset = mbox->rx_start + ALIGN(sizeof(*rsp_hdr), MBOX_MSG_ALIGN); + +- for (id = 0; id < af_mbox->up_num_msgs; id++) { ++ for (id = 0; id < num_msgs; id++) { + msg = (struct mbox_msghdr *)(mdev->mbase + offset); + + devid = msg->pcifunc & RVU_PFVF_FUNC_MASK; +@@ -959,10 +951,11 @@ static void otx2_pfaf_mbox_up_handler(struct work_struct *work) + otx2_process_mbox_msg_up(pf, msg); + offset = mbox->rx_start + msg->next_msgoff; + } +- if (devid) { ++ /* Forward to VF iff VFs are really present */ ++ if (devid && pci_num_vf(pf->pdev)) { + otx2_forward_vf_mbox_msgs(pf, &pf->mbox.mbox_up, + MBOX_DIR_PFVF_UP, devid - 1, +- af_mbox->up_num_msgs); ++ num_msgs); + return; + } + +@@ -972,16 +965,49 @@ static void otx2_pfaf_mbox_up_handler(struct work_struct *work) + static irqreturn_t otx2_pfaf_mbox_intr_handler(int irq, void *pf_irq) + { + struct otx2_nic *pf = (struct otx2_nic *)pf_irq; +- struct mbox *mbox; ++ struct mbox *mw = &pf->mbox; ++ struct otx2_mbox_dev *mdev; ++ struct otx2_mbox *mbox; ++ struct mbox_hdr *hdr; ++ u64 mbox_data; + + /* Clear the IRQ */ + otx2_write64(pf, RVU_PF_INT, BIT_ULL(0)); + +- mbox = &pf->mbox; + +- trace_otx2_msg_interrupt(mbox->mbox.pdev, "AF to PF", BIT_ULL(0)); ++ mbox_data = otx2_read64(pf, RVU_PF_PFAF_MBOX0); ++ ++ if (mbox_data & MBOX_UP_MSG) { ++ mbox_data &= ~MBOX_UP_MSG; ++ otx2_write64(pf, RVU_PF_PFAF_MBOX0, mbox_data); ++ ++ mbox = &mw->mbox_up; ++ mdev = &mbox->dev[0]; ++ otx2_sync_mbox_bbuf(mbox, 0); ++ ++ hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start); ++ if (hdr->num_msgs) ++ queue_work(pf->mbox_wq, &mw->mbox_up_wrk); ++ ++ trace_otx2_msg_interrupt(pf->pdev, "UP message from AF to PF", ++ BIT_ULL(0)); ++ } ++ ++ if (mbox_data & MBOX_DOWN_MSG) { ++ mbox_data &= ~MBOX_DOWN_MSG; ++ otx2_write64(pf, RVU_PF_PFAF_MBOX0, mbox_data); ++ ++ mbox = &mw->mbox; ++ mdev = &mbox->dev[0]; ++ otx2_sync_mbox_bbuf(mbox, 0); ++ ++ hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start); ++ if (hdr->num_msgs) ++ queue_work(pf->mbox_wq, &mw->mbox_wrk); + +- otx2_queue_work(mbox, pf->mbox_wq, 0, 1, 1, TYPE_PFAF); ++ trace_otx2_msg_interrupt(pf->pdev, "DOWN reply from AF to PF", ++ BIT_ULL(0)); ++ } + + return IRQ_HANDLED; + } +@@ -3087,6 +3113,7 @@ static void otx2_vf_link_event_task(struct work_struct *work) + struct otx2_vf_config *config; + struct cgx_link_info_msg *req; + struct mbox_msghdr *msghdr; ++ struct delayed_work *dwork; + struct otx2_nic *pf; + int vf_idx; + +@@ -3095,10 +3122,24 @@ static void otx2_vf_link_event_task(struct work_struct *work) + vf_idx = config - config->pf->vf_configs; + pf = config->pf; + ++ if (config->intf_down) ++ return; ++ ++ mutex_lock(&pf->mbox.lock); ++ ++ dwork = &config->link_event_work; ++ ++ if (!otx2_mbox_wait_for_zero(&pf->mbox_pfvf[0].mbox_up, vf_idx)) { ++ schedule_delayed_work(dwork, msecs_to_jiffies(100)); ++ mutex_unlock(&pf->mbox.lock); ++ return; ++ } ++ + msghdr = otx2_mbox_alloc_msg_rsp(&pf->mbox_pfvf[0].mbox_up, vf_idx, + sizeof(*req), sizeof(struct msg_rsp)); + if (!msghdr) { + dev_err(pf->dev, "Failed to create VF%d link event\n", vf_idx); ++ mutex_unlock(&pf->mbox.lock); + return; + } + +@@ -3107,7 +3148,11 @@ static void otx2_vf_link_event_task(struct work_struct *work) + req->hdr.sig = OTX2_MBOX_REQ_SIG; + memcpy(&req->link_info, &pf->linfo, sizeof(req->link_info)); + ++ otx2_mbox_wait_for_zero(&pf->mbox_pfvf[0].mbox_up, vf_idx); ++ + otx2_sync_mbox_up_msg(&pf->mbox_pfvf[0], vf_idx); ++ ++ mutex_unlock(&pf->mbox.lock); + } + + static int otx2_sriov_enable(struct pci_dev *pdev, int numvfs) +diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c +index 35e06048356f4..cf0aa16d75407 100644 +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c +@@ -89,16 +89,20 @@ static void otx2vf_vfaf_mbox_handler(struct work_struct *work) + struct otx2_mbox *mbox; + struct mbox *af_mbox; + int offset, id; ++ u16 num_msgs; + + af_mbox = container_of(work, struct mbox, mbox_wrk); + mbox = &af_mbox->mbox; + mdev = &mbox->dev[0]; + rsp_hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start); +- if (af_mbox->num_msgs == 0) ++ num_msgs = rsp_hdr->num_msgs; ++ ++ if (num_msgs == 0) + return; ++ + offset = mbox->rx_start + ALIGN(sizeof(*rsp_hdr), MBOX_MSG_ALIGN); + +- for (id = 0; id < af_mbox->num_msgs; id++) { ++ for (id = 0; id < num_msgs; id++) { + msg = (struct mbox_msghdr *)(mdev->mbase + offset); + otx2vf_process_vfaf_mbox_msg(af_mbox->pfvf, msg); + offset = mbox->rx_start + msg->next_msgoff; +@@ -151,6 +155,7 @@ static void otx2vf_vfaf_mbox_up_handler(struct work_struct *work) + struct mbox *vf_mbox; + struct otx2_nic *vf; + int offset, id; ++ u16 num_msgs; + + vf_mbox = container_of(work, struct mbox, mbox_up_wrk); + vf = vf_mbox->pfvf; +@@ -158,12 +163,14 @@ static void otx2vf_vfaf_mbox_up_handler(struct work_struct *work) + mdev = &mbox->dev[0]; + + rsp_hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start); +- if (vf_mbox->up_num_msgs == 0) ++ num_msgs = rsp_hdr->num_msgs; ++ ++ if (num_msgs == 0) + return; + + offset = mbox->rx_start + ALIGN(sizeof(*rsp_hdr), MBOX_MSG_ALIGN); + +- for (id = 0; id < vf_mbox->up_num_msgs; id++) { ++ for (id = 0; id < num_msgs; id++) { + msg = (struct mbox_msghdr *)(mdev->mbase + offset); + otx2vf_process_mbox_msg_up(vf, msg); + offset = mbox->rx_start + msg->next_msgoff; +@@ -178,40 +185,48 @@ static irqreturn_t otx2vf_vfaf_mbox_intr_handler(int irq, void *vf_irq) + struct otx2_mbox_dev *mdev; + struct otx2_mbox *mbox; + struct mbox_hdr *hdr; ++ u64 mbox_data; + + /* Clear the IRQ */ + otx2_write64(vf, RVU_VF_INT, BIT_ULL(0)); + ++ mbox_data = otx2_read64(vf, RVU_VF_VFPF_MBOX0); ++ + /* Read latest mbox data */ + smp_rmb(); + +- /* Check for PF => VF response messages */ +- mbox = &vf->mbox.mbox; +- mdev = &mbox->dev[0]; +- otx2_sync_mbox_bbuf(mbox, 0); ++ if (mbox_data & MBOX_DOWN_MSG) { ++ mbox_data &= ~MBOX_DOWN_MSG; ++ otx2_write64(vf, RVU_VF_VFPF_MBOX0, mbox_data); ++ ++ /* Check for PF => VF response messages */ ++ mbox = &vf->mbox.mbox; ++ mdev = &mbox->dev[0]; ++ otx2_sync_mbox_bbuf(mbox, 0); + +- trace_otx2_msg_interrupt(mbox->pdev, "PF to VF", BIT_ULL(0)); ++ hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start); ++ if (hdr->num_msgs) ++ queue_work(vf->mbox_wq, &vf->mbox.mbox_wrk); + +- hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start); +- if (hdr->num_msgs) { +- vf->mbox.num_msgs = hdr->num_msgs; +- hdr->num_msgs = 0; +- memset(mbox->hwbase + mbox->rx_start, 0, +- ALIGN(sizeof(struct mbox_hdr), sizeof(u64))); +- queue_work(vf->mbox_wq, &vf->mbox.mbox_wrk); ++ trace_otx2_msg_interrupt(mbox->pdev, "DOWN reply from PF to VF", ++ BIT_ULL(0)); + } +- /* Check for PF => VF notification messages */ +- mbox = &vf->mbox.mbox_up; +- mdev = &mbox->dev[0]; +- otx2_sync_mbox_bbuf(mbox, 0); + +- hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start); +- if (hdr->num_msgs) { +- vf->mbox.up_num_msgs = hdr->num_msgs; +- hdr->num_msgs = 0; +- memset(mbox->hwbase + mbox->rx_start, 0, +- ALIGN(sizeof(struct mbox_hdr), sizeof(u64))); +- queue_work(vf->mbox_wq, &vf->mbox.mbox_up_wrk); ++ if (mbox_data & MBOX_UP_MSG) { ++ mbox_data &= ~MBOX_UP_MSG; ++ otx2_write64(vf, RVU_VF_VFPF_MBOX0, mbox_data); ++ ++ /* Check for PF => VF notification messages */ ++ mbox = &vf->mbox.mbox_up; ++ mdev = &mbox->dev[0]; ++ otx2_sync_mbox_bbuf(mbox, 0); ++ ++ hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start); ++ if (hdr->num_msgs) ++ queue_work(vf->mbox_wq, &vf->mbox.mbox_up_wrk); ++ ++ trace_otx2_msg_interrupt(mbox->pdev, "UP message from PF to VF", ++ BIT_ULL(0)); + } + + return IRQ_HANDLED; +@@ -760,8 +775,8 @@ static void otx2vf_remove(struct pci_dev *pdev) + otx2_mcam_flow_del(vf); + otx2_shutdown_tc(vf); + otx2_shutdown_qos(vf); +- otx2vf_disable_mbox_intr(vf); + otx2_detach_resources(&vf->mbox); ++ otx2vf_disable_mbox_intr(vf); + free_percpu(vf->hw.lmt_info); + if (test_bit(CN10K_LMTST, &vf->hw.cap_flag)) + qmem_free(vf->dev, vf->dync_lmt); +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index de123350bd46b..caa13b9cedff0 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -677,8 +677,7 @@ static int mtk_mac_finish(struct phylink_config *config, unsigned int mode, + mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); + mcr_new = mcr_cur; + mcr_new |= MAC_MCR_IPG_CFG | MAC_MCR_FORCE_MODE | +- MAC_MCR_BACKOFF_EN | MAC_MCR_BACKPR_EN | MAC_MCR_FORCE_LINK | +- MAC_MCR_RX_FIFO_CLR_DIS; ++ MAC_MCR_BACKOFF_EN | MAC_MCR_BACKPR_EN | MAC_MCR_RX_FIFO_CLR_DIS; + + /* Only update control register when needed! */ + if (mcr_new != mcr_cur) +@@ -694,7 +693,7 @@ static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode, + phylink_config); + u32 mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); + +- mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN); ++ mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK); + mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); + } + +@@ -803,7 +802,7 @@ static void mtk_mac_link_up(struct phylink_config *config, + if (rx_pause) + mcr |= MAC_MCR_FORCE_RX_FC; + +- mcr |= MAC_MCR_TX_EN | MAC_MCR_RX_EN; ++ mcr |= MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK; + mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); + } + +diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c +index b2a5d9c3733d4..6ce0db3a1a920 100644 +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -994,7 +994,7 @@ void mtk_ppe_start(struct mtk_ppe *ppe) + MTK_PPE_KEEPALIVE_DISABLE) | + FIELD_PREP(MTK_PPE_TB_CFG_HASH_MODE, 1) | + FIELD_PREP(MTK_PPE_TB_CFG_SCAN_MODE, +- MTK_PPE_SCAN_MODE_KEEPALIVE_AGE) | ++ MTK_PPE_SCAN_MODE_CHECK_AGE) | + FIELD_PREP(MTK_PPE_TB_CFG_ENTRY_NUM, + MTK_PPE_ENTRIES_SHIFT); + if (mtk_is_netsys_v2_or_greater(ppe->eth)) +@@ -1090,17 +1090,21 @@ int mtk_ppe_stop(struct mtk_ppe *ppe) + + mtk_ppe_cache_enable(ppe, false); + +- /* disable offload engine */ +- ppe_clear(ppe, MTK_PPE_GLO_CFG, MTK_PPE_GLO_CFG_EN); +- ppe_w32(ppe, MTK_PPE_FLOW_CFG, 0); +- + /* disable aging */ + val = MTK_PPE_TB_CFG_AGE_NON_L4 | + MTK_PPE_TB_CFG_AGE_UNBIND | + MTK_PPE_TB_CFG_AGE_TCP | + MTK_PPE_TB_CFG_AGE_UDP | +- MTK_PPE_TB_CFG_AGE_TCP_FIN; ++ MTK_PPE_TB_CFG_AGE_TCP_FIN | ++ MTK_PPE_TB_CFG_SCAN_MODE; + ppe_clear(ppe, MTK_PPE_TB_CFG, val); + +- return mtk_ppe_wait_busy(ppe); ++ if (mtk_ppe_wait_busy(ppe)) ++ return -ETIMEDOUT; ++ ++ /* disable offload engine */ ++ ppe_clear(ppe, MTK_PPE_GLO_CFG, MTK_PPE_GLO_CFG_EN); ++ ppe_w32(ppe, MTK_PPE_FLOW_CFG, 0); ++ ++ return 0; + } +diff --git a/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c b/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c +index 361d7c495e2d8..2c7bd6e80d993 100644 +--- a/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c ++++ b/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c +@@ -337,6 +337,11 @@ static void nfp_fl_lag_do_work(struct work_struct *work) + + acti_netdevs = kmalloc_array(entry->slave_cnt, + sizeof(*acti_netdevs), GFP_KERNEL); ++ if (!acti_netdevs) { ++ schedule_delayed_work(&lag->work, ++ NFP_FL_LAG_DELAY); ++ continue; ++ } + + /* Include sanity check in the loop. It may be that a bond has + * changed between processing the last notification and the +diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +index 1b84d495d14e8..29997e4b2d6ca 100644 +--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c ++++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +@@ -556,7 +556,7 @@ static int txgbe_clock_register(struct txgbe *txgbe) + char clk_name[32]; + struct clk *clk; + +- snprintf(clk_name, sizeof(clk_name), "i2c_designware.%d", ++ snprintf(clk_name, sizeof(clk_name), "i2c_dw.%d", + pci_dev_id(pdev)); + + clk = clk_register_fixed_rate(NULL, clk_name, NULL, 0, 156250000); +diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c +index b7cb71817780c..29e1cbea6dc0c 100644 +--- a/drivers/net/phy/dp83822.c ++++ b/drivers/net/phy/dp83822.c +@@ -380,7 +380,7 @@ static int dp83822_config_init(struct phy_device *phydev) + { + struct dp83822_private *dp83822 = phydev->priv; + struct device *dev = &phydev->mdio.dev; +- int rgmii_delay; ++ int rgmii_delay = 0; + s32 rx_int_delay; + s32 tx_int_delay; + int err = 0; +@@ -390,30 +390,33 @@ static int dp83822_config_init(struct phy_device *phydev) + rx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0, + true); + +- if (rx_int_delay <= 0) +- rgmii_delay = 0; +- else +- rgmii_delay = DP83822_RX_CLK_SHIFT; ++ /* Set DP83822_RX_CLK_SHIFT to enable rx clk internal delay */ ++ if (rx_int_delay > 0) ++ rgmii_delay |= DP83822_RX_CLK_SHIFT; + + tx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0, + false); ++ ++ /* Set DP83822_TX_CLK_SHIFT to disable tx clk internal delay */ + if (tx_int_delay <= 0) +- rgmii_delay &= ~DP83822_TX_CLK_SHIFT; +- else + rgmii_delay |= DP83822_TX_CLK_SHIFT; + +- if (rgmii_delay) { +- err = phy_set_bits_mmd(phydev, DP83822_DEVADDR, +- MII_DP83822_RCSR, rgmii_delay); +- if (err) +- return err; +- } ++ err = phy_modify_mmd(phydev, DP83822_DEVADDR, MII_DP83822_RCSR, ++ DP83822_RX_CLK_SHIFT | DP83822_TX_CLK_SHIFT, rgmii_delay); ++ if (err) ++ return err; ++ ++ err = phy_set_bits_mmd(phydev, DP83822_DEVADDR, ++ MII_DP83822_RCSR, DP83822_RGMII_MODE_EN); + +- phy_set_bits_mmd(phydev, DP83822_DEVADDR, +- MII_DP83822_RCSR, DP83822_RGMII_MODE_EN); ++ if (err) ++ return err; + } else { +- phy_clear_bits_mmd(phydev, DP83822_DEVADDR, +- MII_DP83822_RCSR, DP83822_RGMII_MODE_EN); ++ err = phy_clear_bits_mmd(phydev, DP83822_DEVADDR, ++ MII_DP83822_RCSR, DP83822_RGMII_MODE_EN); ++ ++ if (err) ++ return err; + } + + if (dp83822->fx_enabled) { +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 3611ea64875ef..6125418ca93f3 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -2706,8 +2706,8 @@ EXPORT_SYMBOL(genphy_resume); + int genphy_loopback(struct phy_device *phydev, bool enable) + { + if (enable) { +- u16 val, ctl = BMCR_LOOPBACK; +- int ret; ++ u16 ctl = BMCR_LOOPBACK; ++ int ret, val; + + ctl |= mii_bmcr_encode_fixed(phydev->speed, phydev->duplex); + +@@ -2959,7 +2959,7 @@ s32 phy_get_internal_delay(struct phy_device *phydev, struct device *dev, + if (delay < 0) + return delay; + +- if (delay && size == 0) ++ if (size == 0) + return delay; + + if (delay < delay_values[0] || delay > delay_values[size - 1]) { +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index 0d0672d2a6545..51fe00c2b896e 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -10078,7 +10078,7 @@ static int rtl8152_cfgselector_choose_configuration(struct usb_device *udev) + * driver supports it. + */ + if (__rtl_get_hw_ver(udev) == RTL_VER_UNKNOWN) +- return 0; ++ return -ENODEV; + + /* The vendor mode is not always config #1, so to find it out. */ + c = udev->config; +diff --git a/drivers/net/usb/sr9800.c b/drivers/net/usb/sr9800.c +index 143bd4ab160df..57947a5590cca 100644 +--- a/drivers/net/usb/sr9800.c ++++ b/drivers/net/usb/sr9800.c +@@ -737,7 +737,9 @@ static int sr9800_bind(struct usbnet *dev, struct usb_interface *intf) + + data->eeprom_len = SR9800_EEPROM_LEN; + +- usbnet_get_endpoints(dev, intf); ++ ret = usbnet_get_endpoints(dev, intf); ++ if (ret) ++ goto out; + + /* LED Setting Rule : + * AABB:CCDD +diff --git a/drivers/net/veth.c b/drivers/net/veth.c +index cd4a6fe458f95..f0b2c4d5fe43a 100644 +--- a/drivers/net/veth.c ++++ b/drivers/net/veth.c +@@ -1533,8 +1533,6 @@ static netdev_features_t veth_fix_features(struct net_device *dev, + if (peer_priv->_xdp_prog) + features &= ~NETIF_F_GSO_SOFTWARE; + } +- if (priv->_xdp_prog) +- features |= NETIF_F_GRO; + + return features; + } +@@ -1638,14 +1636,6 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog, + } + + if (!old_prog) { +- if (!veth_gro_requested(dev)) { +- /* user-space did not require GRO, but adding +- * XDP is supposed to get GRO working +- */ +- dev->features |= NETIF_F_GRO; +- netdev_features_change(dev); +- } +- + peer->hw_features &= ~NETIF_F_GSO_SOFTWARE; + peer->max_mtu = max_mtu; + } +@@ -1661,14 +1651,6 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog, + if (dev->flags & IFF_UP) + veth_disable_xdp(dev); + +- /* if user-space did not require GRO, since adding XDP +- * enabled it, clear it now +- */ +- if (!veth_gro_requested(dev)) { +- dev->features &= ~NETIF_F_GRO; +- netdev_features_change(dev); +- } +- + if (peer) { + peer->hw_features |= NETIF_F_GSO_SOFTWARE; + peer->max_mtu = ETH_MAX_MTU; +diff --git a/drivers/net/vmxnet3/vmxnet3_xdp.c b/drivers/net/vmxnet3/vmxnet3_xdp.c +index 80ddaff759d47..a6c787454a1ae 100644 +--- a/drivers/net/vmxnet3/vmxnet3_xdp.c ++++ b/drivers/net/vmxnet3/vmxnet3_xdp.c +@@ -382,12 +382,12 @@ vmxnet3_process_xdp(struct vmxnet3_adapter *adapter, + page = rbi->page; + dma_sync_single_for_cpu(&adapter->pdev->dev, + page_pool_get_dma_addr(page) + +- rq->page_pool->p.offset, rcd->len, ++ rq->page_pool->p.offset, rbi->len, + page_pool_get_dma_dir(rq->page_pool)); + +- xdp_init_buff(&xdp, rbi->len, &rq->xdp_rxq); ++ xdp_init_buff(&xdp, PAGE_SIZE, &rq->xdp_rxq); + xdp_prepare_buff(&xdp, page_address(page), rq->page_pool->p.offset, +- rcd->len, false); ++ rbi->len, false); + xdp_buff_clear_frags_flag(&xdp); + + xdp_prog = rcu_dereference(rq->adapter->xdp_bpf_prog); +diff --git a/drivers/net/wireguard/receive.c b/drivers/net/wireguard/receive.c +index a176653c88616..db01ec03bda00 100644 +--- a/drivers/net/wireguard/receive.c ++++ b/drivers/net/wireguard/receive.c +@@ -251,7 +251,7 @@ static bool decrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair) + + if (unlikely(!READ_ONCE(keypair->receiving.is_valid) || + wg_birthdate_has_expired(keypair->receiving.birthdate, REJECT_AFTER_TIME) || +- keypair->receiving_counter.counter >= REJECT_AFTER_MESSAGES)) { ++ READ_ONCE(keypair->receiving_counter.counter) >= REJECT_AFTER_MESSAGES)) { + WRITE_ONCE(keypair->receiving.is_valid, false); + return false; + } +@@ -318,7 +318,7 @@ static bool counter_validate(struct noise_replay_counter *counter, u64 their_cou + for (i = 1; i <= top; ++i) + counter->backtrack[(i + index_current) & + ((COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1)] = 0; +- counter->counter = their_counter; ++ WRITE_ONCE(counter->counter, their_counter); + } + + index &= (COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1; +@@ -463,7 +463,7 @@ int wg_packet_rx_poll(struct napi_struct *napi, int budget) + net_dbg_ratelimited("%s: Packet has invalid nonce %llu (max %llu)\n", + peer->device->dev->name, + PACKET_CB(skb)->nonce, +- keypair->receiving_counter.counter); ++ READ_ONCE(keypair->receiving_counter.counter)); + goto next; + } + +diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c +index 6b6aa3c367448..0ce08e9a0a3d2 100644 +--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c ++++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c +@@ -851,6 +851,10 @@ ath10k_wmi_tlv_op_pull_mgmt_tx_compl_ev(struct ath10k *ar, struct sk_buff *skb, + } + + ev = tb[WMI_TLV_TAG_STRUCT_MGMT_TX_COMPL_EVENT]; ++ if (!ev) { ++ kfree(tb); ++ return -EPROTO; ++ } + + arg->desc_id = ev->desc_id; + arg->status = ev->status; +diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h +index 02e160d831bed..cd829ec70d76b 100644 +--- a/drivers/net/wireless/ath/ath11k/core.h ++++ b/drivers/net/wireless/ath/ath11k/core.h +@@ -918,6 +918,7 @@ struct ath11k_base { + * This may or may not be used during the runtime + */ + struct ieee80211_regdomain *new_regd[MAX_RADIOS]; ++ struct cur_regulatory_info *reg_info_store; + + /* Current DFS Regulatory */ + enum ath11k_dfs_region dfs_region; +diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c +index b13525bbbb808..cc80310088ce1 100644 +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -2297,6 +2297,8 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, + mcs_160_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); + mcs_80_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); + ++ /* Initialize rx_mcs_160 to 9 which is an invalid value */ ++ rx_mcs_160 = 9; + if (support_160) { + for (i = 7; i >= 0; i--) { + u8 mcs_160 = (mcs_160_map >> (2 * i)) & 3; +@@ -2308,6 +2310,8 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, + } + } + ++ /* Initialize rx_mcs_80 to 9 which is an invalid value */ ++ rx_mcs_80 = 9; + for (i = 7; i >= 0; i--) { + u8 mcs_80 = (mcs_80_map >> (2 * i)) & 3; + +@@ -3026,7 +3030,14 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, + + rcu_read_unlock(); + ++ if (!ath11k_mac_vif_recalc_sta_he_txbf(ar, vif, &he_cap)) { ++ ath11k_warn(ar->ab, "failed to recalc he txbf for vdev %i on bss %pM\n", ++ arvif->vdev_id, bss_conf->bssid); ++ return; ++ } ++ + peer_arg.is_assoc = true; ++ + ret = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg); + if (ret) { + ath11k_warn(ar->ab, "failed to run peer assoc for %pM vdev %i: %d\n", +@@ -3049,12 +3060,6 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, + return; + } + +- if (!ath11k_mac_vif_recalc_sta_he_txbf(ar, vif, &he_cap)) { +- ath11k_warn(ar->ab, "failed to recalc he txbf for vdev %i on bss %pM\n", +- arvif->vdev_id, bss_conf->bssid); +- return; +- } +- + WARN_ON(arvif->is_up); + + arvif->aid = vif->cfg.aid; +diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c +index b4fd4d2107c71..d4fd3509e608c 100644 +--- a/drivers/net/wireless/ath/ath11k/reg.c ++++ b/drivers/net/wireless/ath/ath11k/reg.c +@@ -618,25 +618,68 @@ ath11k_reg_update_weather_radar_band(struct ath11k_base *ab, + *rule_idx = i; + } + ++enum wmi_reg_6ghz_ap_type ++ath11k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type) ++{ ++ switch (power_type) { ++ case IEEE80211_REG_LPI_AP: ++ return WMI_REG_INDOOR_AP; ++ case IEEE80211_REG_SP_AP: ++ return WMI_REG_STANDARD_POWER_AP; ++ case IEEE80211_REG_VLP_AP: ++ return WMI_REG_VERY_LOW_POWER_AP; ++ default: ++ return WMI_REG_MAX_AP_TYPE; ++ } ++} ++ + struct ieee80211_regdomain * + ath11k_reg_build_regd(struct ath11k_base *ab, +- struct cur_regulatory_info *reg_info, bool intersect) ++ struct cur_regulatory_info *reg_info, bool intersect, ++ enum wmi_vdev_type vdev_type, ++ enum ieee80211_ap_reg_power power_type) + { + struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL; +- struct cur_reg_rule *reg_rule; ++ struct cur_reg_rule *reg_rule, *reg_rule_6ghz; + u8 i = 0, j = 0, k = 0; + u8 num_rules; + u16 max_bw; +- u32 flags; ++ u32 flags, reg_6ghz_number, max_bw_6ghz; + char alpha2[3]; + + num_rules = reg_info->num_5ghz_reg_rules + reg_info->num_2ghz_reg_rules; + +- /* FIXME: Currently taking reg rules for 6 GHz only from Indoor AP mode list. +- * This can be updated after complete 6 GHz regulatory support is added. +- */ +- if (reg_info->is_ext_reg_event) +- num_rules += reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP]; ++ if (reg_info->is_ext_reg_event) { ++ if (vdev_type == WMI_VDEV_TYPE_STA) { ++ enum wmi_reg_6ghz_ap_type ap_type; ++ ++ ap_type = ath11k_reg_ap_pwr_convert(power_type); ++ ++ if (ap_type == WMI_REG_MAX_AP_TYPE) ++ ap_type = WMI_REG_INDOOR_AP; ++ ++ reg_6ghz_number = reg_info->num_6ghz_rules_client ++ [ap_type][WMI_REG_DEFAULT_CLIENT]; ++ ++ if (reg_6ghz_number == 0) { ++ ap_type = WMI_REG_INDOOR_AP; ++ reg_6ghz_number = reg_info->num_6ghz_rules_client ++ [ap_type][WMI_REG_DEFAULT_CLIENT]; ++ } ++ ++ reg_rule_6ghz = reg_info->reg_rules_6ghz_client_ptr ++ [ap_type][WMI_REG_DEFAULT_CLIENT]; ++ max_bw_6ghz = reg_info->max_bw_6ghz_client ++ [ap_type][WMI_REG_DEFAULT_CLIENT]; ++ } else { ++ reg_6ghz_number = reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP]; ++ reg_rule_6ghz = ++ reg_info->reg_rules_6ghz_ap_ptr[WMI_REG_INDOOR_AP]; ++ max_bw_6ghz = reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP]; ++ } ++ ++ num_rules += reg_6ghz_number; ++ } + + if (!num_rules) + goto ret; +@@ -683,13 +726,10 @@ ath11k_reg_build_regd(struct ath11k_base *ab, + * per other BW rule flags we pass from here + */ + flags = NL80211_RRF_AUTO_BW; +- } else if (reg_info->is_ext_reg_event && +- reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP] && +- (k < reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP])) { +- reg_rule = reg_info->reg_rules_6ghz_ap_ptr[WMI_REG_INDOOR_AP] + +- k++; +- max_bw = min_t(u16, reg_rule->max_bw, +- reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP]); ++ } else if (reg_info->is_ext_reg_event && reg_6ghz_number && ++ k < reg_6ghz_number) { ++ reg_rule = reg_rule_6ghz + k++; ++ max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz); + flags = NL80211_RRF_AUTO_BW; + } else { + break; +@@ -758,6 +798,159 @@ ath11k_reg_build_regd(struct ath11k_base *ab, + return new_regd; + } + ++static bool ath11k_reg_is_world_alpha(char *alpha) ++{ ++ if (alpha[0] == '0' && alpha[1] == '0') ++ return true; ++ ++ if (alpha[0] == 'n' && alpha[1] == 'a') ++ return true; ++ ++ return false; ++} ++ ++static enum wmi_vdev_type ath11k_reg_get_ar_vdev_type(struct ath11k *ar) ++{ ++ struct ath11k_vif *arvif; ++ ++ /* Currently each struct ath11k maps to one struct ieee80211_hw/wiphy ++ * and one struct ieee80211_regdomain, so it could only store one group ++ * reg rules. It means multi-interface concurrency in the same ath11k is ++ * not support for the regdomain. So get the vdev type of the first entry ++ * now. After concurrency support for the regdomain, this should change. ++ */ ++ arvif = list_first_entry_or_null(&ar->arvifs, struct ath11k_vif, list); ++ if (arvif) ++ return arvif->vdev_type; ++ ++ return WMI_VDEV_TYPE_UNSPEC; ++} ++ ++int ath11k_reg_handle_chan_list(struct ath11k_base *ab, ++ struct cur_regulatory_info *reg_info, ++ enum ieee80211_ap_reg_power power_type) ++{ ++ struct ieee80211_regdomain *regd; ++ bool intersect = false; ++ int pdev_idx; ++ struct ath11k *ar; ++ enum wmi_vdev_type vdev_type; ++ ++ ath11k_dbg(ab, ATH11K_DBG_WMI, "event reg handle chan list"); ++ ++ if (reg_info->status_code != REG_SET_CC_STATUS_PASS) { ++ /* In case of failure to set the requested ctry, ++ * fw retains the current regd. We print a failure info ++ * and return from here. ++ */ ++ ath11k_warn(ab, "Failed to set the requested Country regulatory setting\n"); ++ return -EINVAL; ++ } ++ ++ pdev_idx = reg_info->phy_id; ++ ++ /* Avoid default reg rule updates sent during FW recovery if ++ * it is already available ++ */ ++ spin_lock_bh(&ab->base_lock); ++ if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags) && ++ ab->default_regd[pdev_idx]) { ++ spin_unlock_bh(&ab->base_lock); ++ goto retfail; ++ } ++ spin_unlock_bh(&ab->base_lock); ++ ++ if (pdev_idx >= ab->num_radios) { ++ /* Process the event for phy0 only if single_pdev_only ++ * is true. If pdev_idx is valid but not 0, discard the ++ * event. Otherwise, it goes to fallback. In either case ++ * ath11k_reg_reset_info() needs to be called to avoid ++ * memory leak issue. ++ */ ++ ath11k_reg_reset_info(reg_info); ++ ++ if (ab->hw_params.single_pdev_only && ++ pdev_idx < ab->hw_params.num_rxmda_per_pdev) ++ return 0; ++ goto fallback; ++ } ++ ++ /* Avoid multiple overwrites to default regd, during core ++ * stop-start after mac registration. ++ */ ++ if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] && ++ !memcmp((char *)ab->default_regd[pdev_idx]->alpha2, ++ (char *)reg_info->alpha2, 2)) ++ goto retfail; ++ ++ /* Intersect new rules with default regd if a new country setting was ++ * requested, i.e a default regd was already set during initialization ++ * and the regd coming from this event has a valid country info. ++ */ ++ if (ab->default_regd[pdev_idx] && ++ !ath11k_reg_is_world_alpha((char *) ++ ab->default_regd[pdev_idx]->alpha2) && ++ !ath11k_reg_is_world_alpha((char *)reg_info->alpha2)) ++ intersect = true; ++ ++ ar = ab->pdevs[pdev_idx].ar; ++ vdev_type = ath11k_reg_get_ar_vdev_type(ar); ++ ++ ath11k_dbg(ab, ATH11K_DBG_WMI, ++ "wmi handle chan list power type %d vdev type %d intersect %d\n", ++ power_type, vdev_type, intersect); ++ ++ regd = ath11k_reg_build_regd(ab, reg_info, intersect, vdev_type, power_type); ++ if (!regd) { ++ ath11k_warn(ab, "failed to build regd from reg_info\n"); ++ goto fallback; ++ } ++ ++ if (power_type == IEEE80211_REG_UNSET_AP) { ++ ath11k_reg_reset_info(&ab->reg_info_store[pdev_idx]); ++ ab->reg_info_store[pdev_idx] = *reg_info; ++ } ++ ++ spin_lock_bh(&ab->base_lock); ++ if (ab->default_regd[pdev_idx]) { ++ /* The initial rules from FW after WMI Init is to build ++ * the default regd. From then on, any rules updated for ++ * the pdev could be due to user reg changes. ++ * Free previously built regd before assigning the newly ++ * generated regd to ar. NULL pointer handling will be ++ * taken care by kfree itself. ++ */ ++ ar = ab->pdevs[pdev_idx].ar; ++ kfree(ab->new_regd[pdev_idx]); ++ ab->new_regd[pdev_idx] = regd; ++ queue_work(ab->workqueue, &ar->regd_update_work); ++ } else { ++ /* This regd would be applied during mac registration and is ++ * held constant throughout for regd intersection purpose ++ */ ++ ab->default_regd[pdev_idx] = regd; ++ } ++ ab->dfs_region = reg_info->dfs_region; ++ spin_unlock_bh(&ab->base_lock); ++ ++ return 0; ++ ++fallback: ++ /* Fallback to older reg (by sending previous country setting ++ * again if fw has succeeded and we failed to process here. ++ * The Regdomain should be uniform across driver and fw. Since the ++ * FW has processed the command and sent a success status, we expect ++ * this function to succeed as well. If it doesn't, CTRY needs to be ++ * reverted at the fw and the old SCAN_CHAN_LIST cmd needs to be sent. ++ */ ++ /* TODO: This is rare, but still should also be handled */ ++ WARN_ON(1); ++ ++retfail: ++ ++ return -EINVAL; ++} ++ + void ath11k_regd_update_work(struct work_struct *work) + { + struct ath11k *ar = container_of(work, struct ath11k, +@@ -781,10 +974,36 @@ void ath11k_reg_init(struct ath11k *ar) + ar->hw->wiphy->reg_notifier = ath11k_reg_notifier; + } + ++void ath11k_reg_reset_info(struct cur_regulatory_info *reg_info) ++{ ++ int i, j; ++ ++ if (!reg_info) ++ return; ++ ++ kfree(reg_info->reg_rules_2ghz_ptr); ++ kfree(reg_info->reg_rules_5ghz_ptr); ++ ++ for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) { ++ kfree(reg_info->reg_rules_6ghz_ap_ptr[i]); ++ ++ for (j = 0; j < WMI_REG_MAX_CLIENT_TYPE; j++) ++ kfree(reg_info->reg_rules_6ghz_client_ptr[i][j]); ++ } ++ ++ memset(reg_info, 0, sizeof(*reg_info)); ++} ++ + void ath11k_reg_free(struct ath11k_base *ab) + { + int i; + ++ for (i = 0; i < ab->num_radios; i++) ++ ath11k_reg_reset_info(&ab->reg_info_store[i]); ++ ++ kfree(ab->reg_info_store); ++ ab->reg_info_store = NULL; ++ + for (i = 0; i < ab->hw_params.max_radios; i++) { + kfree(ab->default_regd[i]); + kfree(ab->new_regd[i]); +diff --git a/drivers/net/wireless/ath/ath11k/reg.h b/drivers/net/wireless/ath/ath11k/reg.h +index f28902f85e419..64edb794260ab 100644 +--- a/drivers/net/wireless/ath/ath11k/reg.h ++++ b/drivers/net/wireless/ath/ath11k/reg.h +@@ -30,11 +30,20 @@ enum ath11k_dfs_region { + + /* ATH11K Regulatory API's */ + void ath11k_reg_init(struct ath11k *ar); ++void ath11k_reg_reset_info(struct cur_regulatory_info *reg_info); + void ath11k_reg_free(struct ath11k_base *ab); + void ath11k_regd_update_work(struct work_struct *work); + struct ieee80211_regdomain * + ath11k_reg_build_regd(struct ath11k_base *ab, +- struct cur_regulatory_info *reg_info, bool intersect); ++ struct cur_regulatory_info *reg_info, bool intersect, ++ enum wmi_vdev_type vdev_type, ++ enum ieee80211_ap_reg_power power_type); + int ath11k_regd_update(struct ath11k *ar); + int ath11k_reg_update_chan_list(struct ath11k *ar, bool wait); ++enum wmi_reg_6ghz_ap_type ++ath11k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type); ++int ath11k_reg_handle_chan_list(struct ath11k_base *ab, ++ struct cur_regulatory_info *reg_info, ++ enum ieee80211_ap_reg_power power_type); ++ + #endif +diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c +index 8a65fa04b48d9..442afda7ec885 100644 +--- a/drivers/net/wireless/ath/ath11k/wmi.c ++++ b/drivers/net/wireless/ath/ath11k/wmi.c +@@ -4749,6 +4749,14 @@ static int ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(struct ath11k_base *soc, + soc->pdevs[0].pdev_id = 0; + } + ++ if (!soc->reg_info_store) { ++ soc->reg_info_store = kcalloc(soc->num_radios, ++ sizeof(*soc->reg_info_store), ++ GFP_ATOMIC); ++ if (!soc->reg_info_store) ++ return -ENOMEM; ++ } ++ + return 0; + } + +@@ -7060,32 +7068,15 @@ static void ath11k_wmi_htc_tx_complete(struct ath11k_base *ab, + wake_up(&wmi->tx_ce_desc_wq); + } + +-static bool ath11k_reg_is_world_alpha(char *alpha) +-{ +- if (alpha[0] == '0' && alpha[1] == '0') +- return true; +- +- if (alpha[0] == 'n' && alpha[1] == 'a') +- return true; +- +- return false; +-} +- +-static int ath11k_reg_chan_list_event(struct ath11k_base *ab, +- struct sk_buff *skb, ++static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *skb, + enum wmi_reg_chan_list_cmd_type id) + { +- struct cur_regulatory_info *reg_info = NULL; +- struct ieee80211_regdomain *regd = NULL; +- bool intersect = false; +- int ret = 0, pdev_idx, i, j; +- struct ath11k *ar; ++ struct cur_regulatory_info *reg_info; ++ int ret; + + reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC); +- if (!reg_info) { +- ret = -ENOMEM; +- goto fallback; +- } ++ if (!reg_info) ++ return -ENOMEM; + + if (id == WMI_REG_CHAN_LIST_CC_ID) + ret = ath11k_pull_reg_chan_list_update_ev(ab, skb, reg_info); +@@ -7093,118 +7084,22 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, + ret = ath11k_pull_reg_chan_list_ext_update_ev(ab, skb, reg_info); + + if (ret) { +- ath11k_warn(ab, "failed to extract regulatory info from received event\n"); +- goto fallback; +- } +- +- ath11k_dbg(ab, ATH11K_DBG_WMI, "event reg chan list id %d", id); +- +- if (reg_info->status_code != REG_SET_CC_STATUS_PASS) { +- /* In case of failure to set the requested ctry, +- * fw retains the current regd. We print a failure info +- * and return from here. +- */ +- ath11k_warn(ab, "Failed to set the requested Country regulatory setting\n"); +- goto mem_free; +- } +- +- pdev_idx = reg_info->phy_id; +- +- /* Avoid default reg rule updates sent during FW recovery if +- * it is already available +- */ +- spin_lock(&ab->base_lock); +- if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags) && +- ab->default_regd[pdev_idx]) { +- spin_unlock(&ab->base_lock); ++ ath11k_warn(ab, "failed to extract regulatory info\n"); + goto mem_free; + } +- spin_unlock(&ab->base_lock); + +- if (pdev_idx >= ab->num_radios) { +- /* Process the event for phy0 only if single_pdev_only +- * is true. If pdev_idx is valid but not 0, discard the +- * event. Otherwise, it goes to fallback. +- */ +- if (ab->hw_params.single_pdev_only && +- pdev_idx < ab->hw_params.num_rxmda_per_pdev) +- goto mem_free; +- else +- goto fallback; +- } +- +- /* Avoid multiple overwrites to default regd, during core +- * stop-start after mac registration. +- */ +- if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] && +- !memcmp((char *)ab->default_regd[pdev_idx]->alpha2, +- (char *)reg_info->alpha2, 2)) ++ ret = ath11k_reg_handle_chan_list(ab, reg_info, IEEE80211_REG_UNSET_AP); ++ if (ret) { ++ ath11k_warn(ab, "failed to process regulatory info %d\n", ret); + goto mem_free; +- +- /* Intersect new rules with default regd if a new country setting was +- * requested, i.e a default regd was already set during initialization +- * and the regd coming from this event has a valid country info. +- */ +- if (ab->default_regd[pdev_idx] && +- !ath11k_reg_is_world_alpha((char *) +- ab->default_regd[pdev_idx]->alpha2) && +- !ath11k_reg_is_world_alpha((char *)reg_info->alpha2)) +- intersect = true; +- +- regd = ath11k_reg_build_regd(ab, reg_info, intersect); +- if (!regd) { +- ath11k_warn(ab, "failed to build regd from reg_info\n"); +- goto fallback; +- } +- +- spin_lock(&ab->base_lock); +- if (ab->default_regd[pdev_idx]) { +- /* The initial rules from FW after WMI Init is to build +- * the default regd. From then on, any rules updated for +- * the pdev could be due to user reg changes. +- * Free previously built regd before assigning the newly +- * generated regd to ar. NULL pointer handling will be +- * taken care by kfree itself. +- */ +- ar = ab->pdevs[pdev_idx].ar; +- kfree(ab->new_regd[pdev_idx]); +- ab->new_regd[pdev_idx] = regd; +- queue_work(ab->workqueue, &ar->regd_update_work); +- } else { +- /* This regd would be applied during mac registration and is +- * held constant throughout for regd intersection purpose +- */ +- ab->default_regd[pdev_idx] = regd; + } +- ab->dfs_region = reg_info->dfs_region; +- spin_unlock(&ab->base_lock); + +- goto mem_free; ++ kfree(reg_info); ++ return 0; + +-fallback: +- /* Fallback to older reg (by sending previous country setting +- * again if fw has succeeded and we failed to process here. +- * The Regdomain should be uniform across driver and fw. Since the +- * FW has processed the command and sent a success status, we expect +- * this function to succeed as well. If it doesn't, CTRY needs to be +- * reverted at the fw and the old SCAN_CHAN_LIST cmd needs to be sent. +- */ +- /* TODO: This is rare, but still should also be handled */ +- WARN_ON(1); + mem_free: +- if (reg_info) { +- kfree(reg_info->reg_rules_2ghz_ptr); +- kfree(reg_info->reg_rules_5ghz_ptr); +- if (reg_info->is_ext_reg_event) { +- for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) +- kfree(reg_info->reg_rules_6ghz_ap_ptr[i]); +- +- for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) +- for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) +- kfree(reg_info->reg_rules_6ghz_client_ptr[j][i]); +- } +- kfree(reg_info); +- } ++ ath11k_reg_reset_info(reg_info); ++ kfree(reg_info); + return ret; + } + +diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h +index ff0a9a92beeb0..cd2098d78e861 100644 +--- a/drivers/net/wireless/ath/ath11k/wmi.h ++++ b/drivers/net/wireless/ath/ath11k/wmi.h +@@ -4951,6 +4951,7 @@ struct ath11k_targ_cap { + }; + + enum wmi_vdev_type { ++ WMI_VDEV_TYPE_UNSPEC = 0, + WMI_VDEV_TYPE_AP = 1, + WMI_VDEV_TYPE_STA = 2, + WMI_VDEV_TYPE_IBSS = 3, +diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h +index 8458dc292821a..01fb9b2ae4314 100644 +--- a/drivers/net/wireless/ath/ath12k/core.h ++++ b/drivers/net/wireless/ath/ath12k/core.h +@@ -420,7 +420,7 @@ struct ath12k_sta { + }; + + #define ATH12K_MIN_5G_FREQ 4150 +-#define ATH12K_MIN_6G_FREQ 5945 ++#define ATH12K_MIN_6G_FREQ 5925 + #define ATH12K_MAX_6G_FREQ 7115 + #define ATH12K_NUM_CHANS 100 + #define ATH12K_MAX_5G_CHAN 173 +diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c +index a489369d80687..1bdab8604db94 100644 +--- a/drivers/net/wireless/ath/ath12k/hal.c ++++ b/drivers/net/wireless/ath/ath12k/hal.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: BSD-3-Clause-Clear + /* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. +- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. ++ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + #include + #include "hal_tx.h" +@@ -449,8 +449,8 @@ static u8 *ath12k_hw_qcn9274_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) + + static bool ath12k_hw_qcn9274_rx_desc_is_da_mcbc(struct hal_rx_desc *desc) + { +- return __le16_to_cpu(desc->u.qcn9274.msdu_end.info5) & +- RX_MSDU_END_INFO5_DA_IS_MCBC; ++ return __le32_to_cpu(desc->u.qcn9274.mpdu_start.info6) & ++ RX_MPDU_START_INFO6_MCAST_BCAST; + } + + static void ath12k_hw_qcn9274_rx_desc_get_dot11_hdr(struct hal_rx_desc *desc, +diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c +index 88cec54c6c2e6..b965fc46ad89a 100644 +--- a/drivers/net/wireless/ath/ath12k/mac.c ++++ b/drivers/net/wireless/ath/ath12k/mac.c +@@ -5269,7 +5269,7 @@ ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif) + do { + if (ab->free_vdev_stats_id_map & (1LL << vdev_stats_id)) { + vdev_stats_id++; +- if (vdev_stats_id <= ATH12K_INVAL_VDEV_STATS_ID) { ++ if (vdev_stats_id >= ATH12K_MAX_VDEV_STATS_ID) { + vdev_stats_id = ATH12K_INVAL_VDEV_STATS_ID; + break; + } +@@ -7198,7 +7198,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, + } + + if (supported_bands & WMI_HOST_WLAN_5G_CAP) { +- if (reg_cap->high_5ghz_chan >= ATH12K_MAX_6G_FREQ) { ++ if (reg_cap->high_5ghz_chan >= ATH12K_MIN_6G_FREQ) { + channels = kmemdup(ath12k_6ghz_channels, + sizeof(ath12k_6ghz_channels), GFP_KERNEL); + if (!channels) { +diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c +index f924bc13ccff5..29542c46b0941 100644 +--- a/drivers/net/wireless/ath/ath12k/reg.c ++++ b/drivers/net/wireless/ath/ath12k/reg.c +@@ -103,7 +103,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar) + + bands = hw->wiphy->bands; + for (band = 0; band < NUM_NL80211_BANDS; band++) { +- if (!bands[band]) ++ if (!(ar->mac.sbands[band].channels && bands[band])) + continue; + + for (i = 0; i < bands[band]->n_channels; i++) { +@@ -129,7 +129,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar) + ch = arg->channel; + + for (band = 0; band < NUM_NL80211_BANDS; band++) { +- if (!bands[band]) ++ if (!(ar->mac.sbands[band].channels && bands[band])) + continue; + + for (i = 0; i < bands[band]->n_channels; i++) { +diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h +index 237f4ec2cffd7..6c33e898b3000 100644 +--- a/drivers/net/wireless/ath/ath9k/htc.h ++++ b/drivers/net/wireless/ath/ath9k/htc.h +@@ -306,7 +306,6 @@ struct ath9k_htc_tx { + DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM); + struct timer_list cleanup_timer; + spinlock_t tx_lock; +- bool initialized; + }; + + struct ath9k_htc_tx_ctl { +@@ -515,6 +514,7 @@ struct ath9k_htc_priv { + unsigned long ps_usecount; + bool ps_enabled; + bool ps_idle; ++ bool initialized; + + #ifdef CONFIG_MAC80211_LEDS + enum led_brightness brightness; +diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c +index 0aa5bdeb44a1b..3633f9eb2c559 100644 +--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c ++++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c +@@ -966,6 +966,10 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, + + htc_handle->drv_priv = priv; + ++ /* Allow ath9k_wmi_event_tasklet() to operate. */ ++ smp_wmb(); ++ priv->initialized = true; ++ + return 0; + + err_init: +diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +index efcaeccb055aa..ce9c04e418b8d 100644 +--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c ++++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +@@ -815,10 +815,6 @@ int ath9k_tx_init(struct ath9k_htc_priv *priv) + skb_queue_head_init(&priv->tx.data_vo_queue); + skb_queue_head_init(&priv->tx.tx_failed); + +- /* Allow ath9k_wmi_event_tasklet(WMI_TXSTATUS_EVENTID) to operate. */ +- smp_wmb(); +- priv->tx.initialized = true; +- + return 0; + } + +diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c +index 1476b42b52a91..805ad31edba2b 100644 +--- a/drivers/net/wireless/ath/ath9k/wmi.c ++++ b/drivers/net/wireless/ath/ath9k/wmi.c +@@ -155,6 +155,12 @@ void ath9k_wmi_event_tasklet(struct tasklet_struct *t) + } + spin_unlock_irqrestore(&wmi->wmi_lock, flags); + ++ /* Check if ath9k_htc_probe_device() completed. */ ++ if (!data_race(priv->initialized)) { ++ kfree_skb(skb); ++ continue; ++ } ++ + hdr = (struct wmi_cmd_hdr *) skb->data; + cmd_id = be16_to_cpu(hdr->command_id); + wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr)); +@@ -169,10 +175,6 @@ void ath9k_wmi_event_tasklet(struct tasklet_struct *t) + &wmi->drv_priv->fatal_work); + break; + case WMI_TXSTATUS_EVENTID: +- /* Check if ath9k_tx_init() completed. */ +- if (!data_race(priv->tx.initialized)) +- break; +- + spin_lock_bh(&priv->tx.tx_lock); + if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) { + spin_unlock_bh(&priv->tx.tx_lock); +diff --git a/drivers/net/wireless/broadcom/b43/b43.h b/drivers/net/wireless/broadcom/b43/b43.h +index 67b4bac048e58..c0d8fc0b22fb2 100644 +--- a/drivers/net/wireless/broadcom/b43/b43.h ++++ b/drivers/net/wireless/broadcom/b43/b43.h +@@ -1082,6 +1082,22 @@ static inline bool b43_using_pio_transfers(struct b43_wldev *dev) + return dev->__using_pio_transfers; + } + ++static inline void b43_wake_queue(struct b43_wldev *dev, int queue_prio) ++{ ++ if (dev->qos_enabled) ++ ieee80211_wake_queue(dev->wl->hw, queue_prio); ++ else ++ ieee80211_wake_queue(dev->wl->hw, 0); ++} ++ ++static inline void b43_stop_queue(struct b43_wldev *dev, int queue_prio) ++{ ++ if (dev->qos_enabled) ++ ieee80211_stop_queue(dev->wl->hw, queue_prio); ++ else ++ ieee80211_stop_queue(dev->wl->hw, 0); ++} ++ + /* Message printing */ + __printf(2, 3) void b43info(struct b43_wl *wl, const char *fmt, ...); + __printf(2, 3) void b43err(struct b43_wl *wl, const char *fmt, ...); +diff --git a/drivers/net/wireless/broadcom/b43/dma.c b/drivers/net/wireless/broadcom/b43/dma.c +index 760d1a28edc6c..6ac7dcebfff9d 100644 +--- a/drivers/net/wireless/broadcom/b43/dma.c ++++ b/drivers/net/wireless/broadcom/b43/dma.c +@@ -1399,7 +1399,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) + should_inject_overflow(ring)) { + /* This TX ring is full. */ + unsigned int skb_mapping = skb_get_queue_mapping(skb); +- ieee80211_stop_queue(dev->wl->hw, skb_mapping); ++ b43_stop_queue(dev, skb_mapping); + dev->wl->tx_queue_stopped[skb_mapping] = true; + ring->stopped = true; + if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { +@@ -1570,7 +1570,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, + } else { + /* If the driver queue is running wake the corresponding + * mac80211 queue. */ +- ieee80211_wake_queue(dev->wl->hw, ring->queue_prio); ++ b43_wake_queue(dev, ring->queue_prio); + if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { + b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); + } +diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c +index 92ca0b2ca286d..effb6c23f8257 100644 +--- a/drivers/net/wireless/broadcom/b43/main.c ++++ b/drivers/net/wireless/broadcom/b43/main.c +@@ -2587,7 +2587,8 @@ static void b43_request_firmware(struct work_struct *work) + + start_ieee80211: + wl->hw->queues = B43_QOS_QUEUE_NUM; +- if (!modparam_qos || dev->fw.opensource) ++ if (!modparam_qos || dev->fw.opensource || ++ dev->dev->chip_id == BCMA_CHIP_ID_BCM4331) + wl->hw->queues = 1; + + err = ieee80211_register_hw(wl->hw); +@@ -3603,7 +3604,7 @@ static void b43_tx_work(struct work_struct *work) + err = b43_dma_tx(dev, skb); + if (err == -ENOSPC) { + wl->tx_queue_stopped[queue_num] = true; +- ieee80211_stop_queue(wl->hw, queue_num); ++ b43_stop_queue(dev, queue_num); + skb_queue_head(&wl->tx_queue[queue_num], skb); + break; + } +@@ -3627,6 +3628,7 @@ static void b43_op_tx(struct ieee80211_hw *hw, + struct sk_buff *skb) + { + struct b43_wl *wl = hw_to_b43_wl(hw); ++ u16 skb_queue_mapping; + + if (unlikely(skb->len < 2 + 2 + 6)) { + /* Too short, this can't be a valid frame. */ +@@ -3635,12 +3637,12 @@ static void b43_op_tx(struct ieee80211_hw *hw, + } + B43_WARN_ON(skb_shinfo(skb)->nr_frags); + +- skb_queue_tail(&wl->tx_queue[skb->queue_mapping], skb); +- if (!wl->tx_queue_stopped[skb->queue_mapping]) { ++ skb_queue_mapping = skb_get_queue_mapping(skb); ++ skb_queue_tail(&wl->tx_queue[skb_queue_mapping], skb); ++ if (!wl->tx_queue_stopped[skb_queue_mapping]) + ieee80211_queue_work(wl->hw, &wl->tx_work); +- } else { +- ieee80211_stop_queue(wl->hw, skb->queue_mapping); +- } ++ else ++ b43_stop_queue(wl->current_dev, skb_queue_mapping); + } + + static void b43_qos_params_upload(struct b43_wldev *dev, +diff --git a/drivers/net/wireless/broadcom/b43/pio.c b/drivers/net/wireless/broadcom/b43/pio.c +index 0cf70fdb60a6a..e41f2f5b4c266 100644 +--- a/drivers/net/wireless/broadcom/b43/pio.c ++++ b/drivers/net/wireless/broadcom/b43/pio.c +@@ -525,7 +525,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) + if (total_len > (q->buffer_size - q->buffer_used)) { + /* Not enough memory on the queue. */ + err = -EBUSY; +- ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); ++ b43_stop_queue(dev, skb_get_queue_mapping(skb)); + q->stopped = true; + goto out; + } +@@ -552,7 +552,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) + if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || + (q->free_packet_slots == 0)) { + /* The queue is full. */ +- ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); ++ b43_stop_queue(dev, skb_get_queue_mapping(skb)); + q->stopped = true; + } + +@@ -587,7 +587,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, + list_add(&pack->list, &q->packets_list); + + if (q->stopped) { +- ieee80211_wake_queue(dev->wl->hw, q->queue_prio); ++ b43_wake_queue(dev, q->queue_prio); + q->stopped = false; + } + } +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +index 28d6a30cc0106..1a5d7494f5e80 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +@@ -4322,6 +4322,9 @@ brcmf_pmksa_v3_op(struct brcmf_if *ifp, struct cfg80211_pmksa *pmksa, + int ret; + + pmk_op = kzalloc(sizeof(*pmk_op), GFP_KERNEL); ++ if (!pmk_op) ++ return -ENOMEM; ++ + pmk_op->version = cpu_to_le16(BRCMF_PMKSA_VER_3); + + if (!pmksa) { +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c +index ccc621b8ed9f2..4a1fe982a948e 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c +@@ -383,8 +383,9 @@ struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp) + return sh; + } + +-static void wlc_phy_timercb_phycal(struct brcms_phy *pi) ++static void wlc_phy_timercb_phycal(void *ptr) + { ++ struct brcms_phy *pi = ptr; + uint delay = 5; + + if (PHY_PERICAL_MPHASE_PENDING(pi)) { +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.c +index a0de5db0cd646..b723817915365 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.c ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.c +@@ -57,12 +57,11 @@ void wlc_phy_shim_detach(struct phy_shim_info *physhim) + } + + struct wlapi_timer *wlapi_init_timer(struct phy_shim_info *physhim, +- void (*fn)(struct brcms_phy *pi), ++ void (*fn)(void *pi), + void *arg, const char *name) + { + return (struct wlapi_timer *) +- brcms_init_timer(physhim->wl, (void (*)(void *))fn, +- arg, name); ++ brcms_init_timer(physhim->wl, fn, arg, name); + } + + void wlapi_free_timer(struct wlapi_timer *t) +diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.h +index dd8774717adee..27d0934e600ed 100644 +--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.h ++++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy_shim.h +@@ -131,7 +131,7 @@ void wlc_phy_shim_detach(struct phy_shim_info *physhim); + + /* PHY to WL utility functions */ + struct wlapi_timer *wlapi_init_timer(struct phy_shim_info *physhim, +- void (*fn)(struct brcms_phy *pi), ++ void (*fn)(void *pi), + void *arg, const char *name); + void wlapi_free_timer(struct wlapi_timer *t); + void wlapi_add_timer(struct wlapi_timer *t, uint ms, int periodic); +diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +index dcc4810cb3247..e161b44539069 100644 +--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c ++++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +@@ -767,7 +767,7 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) + * from index 1, so the maximum value allowed here is + * ACPI_SAR_PROFILES_NUM - 1. + */ +- if (n_profiles <= 0 || n_profiles >= ACPI_SAR_PROFILE_NUM) { ++ if (n_profiles >= ACPI_SAR_PROFILE_NUM) { + ret = -EINVAL; + goto out_free; + } +@@ -1296,7 +1296,6 @@ void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, + if (IS_ERR(data)) + return; + +- /* try to read wtas table revision 1 or revision 0*/ + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WPFC_WIFI_DATA_SIZE, + &tbl_rev); +@@ -1306,13 +1305,14 @@ void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, + if (tbl_rev != 0) + goto out_free; + +- BUILD_BUG_ON(ARRAY_SIZE(filters->filter_cfg_chains) != ACPI_WPFC_WIFI_DATA_SIZE); ++ BUILD_BUG_ON(ARRAY_SIZE(filters->filter_cfg_chains) != ++ ACPI_WPFC_WIFI_DATA_SIZE - 1); + + for (i = 0; i < ARRAY_SIZE(filters->filter_cfg_chains); i++) { +- if (wifi_pkg->package.elements[i].type != ACPI_TYPE_INTEGER) +- return; ++ if (wifi_pkg->package.elements[i + 1].type != ACPI_TYPE_INTEGER) ++ goto out_free; + tmp.filter_cfg_chains[i] = +- cpu_to_le32(wifi_pkg->package.elements[i].integer.value); ++ cpu_to_le32(wifi_pkg->package.elements[i + 1].integer.value); + } + + IWL_DEBUG_RADIO(fwrt, "Loaded WPFC filter config from ACPI\n"); +diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +index e9277f6f35821..39106ccb4b9b6 100644 +--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h ++++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +@@ -56,7 +56,7 @@ + #define ACPI_EWRD_WIFI_DATA_SIZE_REV2 ((ACPI_SAR_PROFILE_NUM - 1) * \ + ACPI_SAR_NUM_CHAINS_REV2 * \ + ACPI_SAR_NUM_SUB_BANDS_REV2 + 3) +-#define ACPI_WPFC_WIFI_DATA_SIZE 4 /* 4 filter config words */ ++#define ACPI_WPFC_WIFI_DATA_SIZE 5 /* domain and 4 filter config words */ + + /* revision 0 and 1 are identical, except for the semantics in the FW */ + #define ACPI_GEO_NUM_BANDS_REV0 2 +diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +index 650e4bde9c17b..56ee0ceed78ab 100644 +--- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c ++++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +@@ -255,21 +255,27 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len) + struct pnvm_sku_package *package; + u8 *image = NULL; + +- /* First attempt to get the PNVM from BIOS */ +- package = iwl_uefi_get_pnvm(trans_p, len); +- if (!IS_ERR_OR_NULL(package)) { +- if (*len >= sizeof(*package)) { +- /* we need only the data */ +- *len -= sizeof(*package); +- image = kmemdup(package->data, *len, GFP_KERNEL); ++ /* Get PNVM from BIOS for non-Intel SKU */ ++ if (trans_p->sku_id[2]) { ++ package = iwl_uefi_get_pnvm(trans_p, len); ++ if (!IS_ERR_OR_NULL(package)) { ++ if (*len >= sizeof(*package)) { ++ /* we need only the data */ ++ *len -= sizeof(*package); ++ image = kmemdup(package->data, ++ *len, GFP_KERNEL); ++ } ++ /* ++ * free package regardless of whether kmemdup ++ * succeeded ++ */ ++ kfree(package); ++ if (image) ++ return image; + } +- /* free package regardless of whether kmemdup succeeded */ +- kfree(package); +- if (image) +- return image; + } + +- /* If it's not available, try from the filesystem */ ++ /* If it's not available, or for Intel SKU, try from the filesystem */ + if (iwl_pnvm_get_from_fs(trans_p, &image, len)) + return NULL; + return image; +diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +index 357727774db90..baabb8e321f8d 100644 +--- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h ++++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +@@ -173,9 +173,9 @@ struct iwl_fw_runtime { + struct iwl_sar_offset_mapping_cmd sgom_table; + bool sgom_enabled; + u8 reduced_power_flags; +- bool uats_enabled; + struct iwl_uats_table_cmd uats_table; + #endif ++ bool uats_enabled; + }; + + void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans, +diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +index 72075720969c0..3442dfab50b53 100644 +--- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c ++++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +@@ -103,6 +103,12 @@ static int iwl_dbg_tlv_alloc_debug_info(struct iwl_trans *trans, + if (le32_to_cpu(tlv->length) != sizeof(*debug_info)) + return -EINVAL; + ++ /* we use this as a string, ensure input was NUL terminated */ ++ if (strnlen(debug_info->debug_cfg_name, ++ sizeof(debug_info->debug_cfg_name)) == ++ sizeof(debug_info->debug_cfg_name)) ++ return -EINVAL; ++ + IWL_DEBUG_FW(trans, "WRT: Loading debug cfg: %s\n", + debug_info->debug_cfg_name); + +diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +index 2f6774ec37b22..501a8cc2134cf 100644 +--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c ++++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +@@ -2097,7 +2097,7 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, + !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED); + nvm->sku_cap_mimo_disabled = + !!(mac_flags & NVM_MAC_SKU_FLAGS_MIMO_DISABLED); +- if (CSR_HW_RFID_TYPE(trans->hw_rf_id) == IWL_CFG_RF_TYPE_FM) ++ if (CSR_HW_RFID_TYPE(trans->hw_rf_id) >= IWL_CFG_RF_TYPE_FM) + nvm->sku_cap_11be_enable = true; + + /* Initialize PHY sku data */ +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +index 05b64176859e8..2a08369238f23 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +@@ -461,12 +461,10 @@ static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm, + struct wowlan_key_rsc_v5_data data = {}; + int i; + +- data.rsc = kmalloc(sizeof(*data.rsc), GFP_KERNEL); ++ data.rsc = kzalloc(sizeof(*data.rsc), GFP_KERNEL); + if (!data.rsc) + return -ENOMEM; + +- memset(data.rsc, 0xff, sizeof(*data.rsc)); +- + for (i = 0; i < ARRAY_SIZE(data.rsc->mcast_key_id_map); i++) + data.rsc->mcast_key_id_map[i] = + IWL_MCAST_KEY_MAP_INVALID; +@@ -2200,7 +2198,10 @@ static void iwl_mvm_convert_gtk_v3(struct iwl_wowlan_status_data *status, + static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status, + struct iwl_wowlan_igtk_status *data) + { ++ int i; ++ + BUILD_BUG_ON(sizeof(status->igtk.key) < sizeof(data->key)); ++ BUILD_BUG_ON(sizeof(status->igtk.ipn) != sizeof(data->ipn)); + + if (!data->key_len) + return; +@@ -2212,7 +2213,10 @@ static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status, + + WOWLAN_IGTK_MIN_INDEX; + + memcpy(status->igtk.key, data->key, sizeof(data->key)); +- memcpy(status->igtk.ipn, data->ipn, sizeof(data->ipn)); ++ ++ /* mac80211 expects big endian for memcmp() to work, convert */ ++ for (i = 0; i < sizeof(data->ipn); i++) ++ status->igtk.ipn[i] = data->ipn[sizeof(data->ipn) - i - 1]; + } + + static void iwl_mvm_convert_bigtk(struct iwl_wowlan_status_data *status, +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +index 53e26c3c3a9af..f60d4258e1b95 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +@@ -3698,6 +3698,19 @@ iwl_mvm_sta_state_notexist_to_none(struct iwl_mvm *mvm, + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) + mvmvif->ap_sta = sta; + ++ /* ++ * Initialize the rates here already - this really tells ++ * the firmware only what the supported legacy rates are ++ * (may be) since it's initialized already from what the ++ * AP advertised in the beacon/probe response. This will ++ * allow the firmware to send auth/assoc frames with one ++ * of the supported rates already, rather than having to ++ * use a mandatory rate. ++ * If we're the AP, we'll just assume mandatory rates at ++ * this point, but we know nothing about the STA anyway. ++ */ ++ iwl_mvm_rs_rate_init_all_links(mvm, vif, sta); ++ + return 0; + } + +@@ -3796,13 +3809,17 @@ iwl_mvm_sta_state_assoc_to_authorized(struct iwl_mvm *mvm, + + mvm_sta->authorized = true; + +- iwl_mvm_rs_rate_init_all_links(mvm, vif, sta); +- + /* MFP is set by default before the station is authorized. + * Clear it here in case it's not used. + */ +- if (!sta->mfp) +- return callbacks->update_sta(mvm, vif, sta); ++ if (!sta->mfp) { ++ int ret = callbacks->update_sta(mvm, vif, sta); ++ ++ if (ret) ++ return ret; ++ } ++ ++ iwl_mvm_rs_rate_init_all_links(mvm, vif, sta); + + return 0; + } +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c +index ea3e9e9c6e26c..fe4b39b19a612 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + /* +- * Copyright (C) 2022 - 2023 Intel Corporation ++ * Copyright (C) 2022 - 2024 Intel Corporation + */ + #include + #include +@@ -62,11 +62,13 @@ u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm, + struct ieee80211_key_conf *keyconf) + { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); ++ bool pairwise = keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE; ++ bool igtk = keyconf->keyidx == 4 || keyconf->keyidx == 5; + u32 flags = 0; + + lockdep_assert_held(&mvm->mutex); + +- if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) ++ if (!pairwise) + flags |= IWL_SEC_KEY_FLAG_MCAST_KEY; + + switch (keyconf->cipher) { +@@ -96,12 +98,14 @@ u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm, + if (!sta && vif->type == NL80211_IFTYPE_STATION) + sta = mvmvif->ap_sta; + +- /* Set the MFP flag also for an AP interface where the key is an IGTK +- * key as in such a case the station would always be NULL ++ /* ++ * If we are installing an iGTK (in AP or STA mode), we need to tell ++ * the firmware this key will en/decrypt MGMT frames. ++ * Same goes if we are installing a pairwise key for an MFP station. ++ * In case we're installing a groupwise key (which is not an iGTK), ++ * then, we will not use this key for MGMT frames. + */ +- if ((!IS_ERR_OR_NULL(sta) && sta->mfp) || +- (vif->type == NL80211_IFTYPE_AP && +- (keyconf->keyidx == 4 || keyconf->keyidx == 5))) ++ if ((!IS_ERR_OR_NULL(sta) && sta->mfp && pairwise) || igtk) + flags |= IWL_SEC_KEY_FLAG_MFP; + + return flags; +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c +index f313a8d771e42..ad78c69cc6cb7 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c +@@ -167,7 +167,7 @@ static int iwl_mvm_mld_mac_ctxt_cmd_listener(struct iwl_mvm *mvm, + iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action); + + cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_PROMISC | +- MAC_FILTER_IN_CONTROL_AND_MGMT | ++ MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT | + MAC_CFG_FILTER_ACCEPT_BEACON | + MAC_CFG_FILTER_ACCEPT_PROBE_REQ | + MAC_CFG_FILTER_ACCEPT_GRP); +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +index 81dbef6947f55..fe0fa9ff533d7 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +@@ -121,7 +121,7 @@ struct iwl_mvm_time_event_data { + * if the te is in the time event list or not (when id == TE_MAX) + */ + u32 id; +- u8 link_id; ++ s8 link_id; + }; + + /* Power management */ +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +index af15d470c69bd..7bf2a5947e5e9 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +@@ -282,6 +282,7 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, + u32 status, + struct ieee80211_rx_status *stats) + { ++ struct wireless_dev *wdev; + struct iwl_mvm_sta *mvmsta; + struct iwl_mvm_vif *mvmvif; + u8 keyid; +@@ -303,9 +304,15 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, + if (!ieee80211_is_beacon(hdr->frame_control)) + return 0; + ++ if (!sta) ++ return -1; ++ ++ mvmsta = iwl_mvm_sta_from_mac80211(sta); ++ mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); ++ + /* key mismatch - will also report !MIC_OK but we shouldn't count it */ + if (!(status & IWL_RX_MPDU_STATUS_KEY_VALID)) +- return -1; ++ goto report; + + /* good cases */ + if (likely(status & IWL_RX_MPDU_STATUS_MIC_OK && +@@ -314,13 +321,6 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, + return 0; + } + +- if (!sta) +- return -1; +- +- mvmsta = iwl_mvm_sta_from_mac80211(sta); +- +- mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); +- + /* + * both keys will have the same cipher and MIC length, use + * whichever one is available +@@ -329,11 +329,11 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, + if (!key) { + key = rcu_dereference(mvmvif->bcn_prot.keys[1]); + if (!key) +- return -1; ++ goto report; + } + + if (len < key->icv_len + IEEE80211_GMAC_PN_LEN + 2) +- return -1; ++ goto report; + + /* get the real key ID */ + keyid = frame[len - key->icv_len - IEEE80211_GMAC_PN_LEN - 2]; +@@ -347,7 +347,7 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, + return -1; + key = rcu_dereference(mvmvif->bcn_prot.keys[keyid - 6]); + if (!key) +- return -1; ++ goto report; + } + + /* Report status to mac80211 */ +@@ -355,6 +355,10 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, + ieee80211_key_mic_failure(key); + else if (status & IWL_RX_MPDU_STATUS_REPLAY_ERROR) + ieee80211_key_replay(key); ++report: ++ wdev = ieee80211_vif_to_wdev(mvmsta->vif); ++ if (wdev->netdev) ++ cfg80211_rx_unprot_mlme_mgmt(wdev->netdev, (void *)hdr, len); + + return -1; + } +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +index 2e653a417d626..da00ef6e4fbcf 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +@@ -692,7 +692,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, + /* Determine whether mac or link id should be used, and validate the link id */ + static int iwl_mvm_get_session_prot_id(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, +- u32 link_id) ++ s8 link_id) + { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int ver = iwl_fw_lookup_cmd_ver(mvm->fw, +@@ -706,8 +706,7 @@ static int iwl_mvm_get_session_prot_id(struct iwl_mvm *mvm, + "Invalid link ID for session protection: %u\n", link_id)) + return -EINVAL; + +- if (WARN(ieee80211_vif_is_mld(vif) && +- !(vif->active_links & BIT(link_id)), ++ if (WARN(!mvmvif->link[link_id]->active, + "Session Protection on an inactive link: %u\n", link_id)) + return -EINVAL; + +@@ -716,7 +715,7 @@ static int iwl_mvm_get_session_prot_id(struct iwl_mvm *mvm, + + static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, +- u32 id, u32 link_id) ++ u32 id, s8 link_id) + { + int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif, link_id); + struct iwl_mvm_session_prot_cmd cmd = { +@@ -745,7 +744,7 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, + struct ieee80211_vif *vif = te_data->vif; + struct iwl_mvm_vif *mvmvif; + enum nl80211_iftype iftype; +- unsigned int link_id; ++ s8 link_id; + + if (!vif) + return false; +@@ -1297,7 +1296,7 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, + struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; + const u16 notif[] = { WIDE_ID(MAC_CONF_GROUP, SESSION_PROTECTION_NOTIF) }; + struct iwl_notification_wait wait_notif; +- int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif, link_id); ++ int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif, (s8)link_id); + struct iwl_mvm_session_prot_cmd cmd = { + .id_and_color = cpu_to_le32(mac_link_id), + .action = cpu_to_le32(FW_CTXT_ACTION_ADD), +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +index 461f26d9214e4..930742e75c02a 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + /* +- * Copyright (C) 2012-2014, 2018-2023 Intel Corporation ++ * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2013-2015 Intel Mobile Communications GmbH + * Copyright (C) 2016-2017 Intel Deutschland GmbH + */ +@@ -1636,12 +1636,18 @@ static void iwl_mvm_tx_status_check_trigger(struct iwl_mvm *mvm, + * of the batch. This is why the SSN of the SCD is written at the end of the + * whole struct at a variable offset. This function knows how to cope with the + * variable offset and returns the SSN of the SCD. ++ * ++ * For 22000-series and lower, this is just 12 bits. For later, 16 bits. + */ + static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm *mvm, + struct iwl_mvm_tx_resp *tx_resp) + { +- return le32_to_cpup((__le32 *)iwl_mvm_get_agg_status(mvm, tx_resp) + +- tx_resp->frame_count) & 0xfff; ++ u32 val = le32_to_cpup((__le32 *)iwl_mvm_get_agg_status(mvm, tx_resp) + ++ tx_resp->frame_count); ++ ++ if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) ++ return val & 0xFFFF; ++ return val & 0xFFF; + } + + static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, +diff --git a/drivers/net/wireless/marvell/libertas/cmd.c b/drivers/net/wireless/marvell/libertas/cmd.c +index 104d2b6dc9af6..5a525da434c28 100644 +--- a/drivers/net/wireless/marvell/libertas/cmd.c ++++ b/drivers/net/wireless/marvell/libertas/cmd.c +@@ -1132,7 +1132,7 @@ int lbs_allocate_cmd_buffer(struct lbs_private *priv) + if (!cmdarray[i].cmdbuf) { + lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n"); + ret = -1; +- goto done; ++ goto free_cmd_array; + } + } + +@@ -1140,8 +1140,17 @@ int lbs_allocate_cmd_buffer(struct lbs_private *priv) + init_waitqueue_head(&cmdarray[i].cmdwait_q); + lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]); + } +- ret = 0; ++ return 0; + ++free_cmd_array: ++ for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) { ++ if (cmdarray[i].cmdbuf) { ++ kfree(cmdarray[i].cmdbuf); ++ cmdarray[i].cmdbuf = NULL; ++ } ++ } ++ kfree(priv->cmd_array); ++ priv->cmd_array = NULL; + done: + return ret; + } +diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c +index f9c9fec7c792a..d14a0f4c1b6d7 100644 +--- a/drivers/net/wireless/marvell/mwifiex/debugfs.c ++++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c +@@ -970,9 +970,6 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv) + priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name, + mwifiex_dfs_dir); + +- if (!priv->dfs_dev_dir) +- return; +- + MWIFIEX_DFS_ADD_FILE(info); + MWIFIEX_DFS_ADD_FILE(debug); + MWIFIEX_DFS_ADD_FILE(getlog); +diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +index 3a20ba0d24928..ae19174b46ee5 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +@@ -66,7 +66,7 @@ int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len, + + if ((!is_connac_v1(dev) && addr == MCU_PATCH_ADDRESS) || + (is_mt7921(dev) && addr == 0x900000) || +- (is_mt7925(dev) && addr == 0x900000) || ++ (is_mt7925(dev) && (addr == 0x900000 || addr == 0xe0002800)) || + (is_mt7996(dev) && addr == 0x900000) || + (is_mt7992(dev) && addr == 0x900000)) + cmd = MCU_CMD(PATCH_START_REQ); +@@ -2101,7 +2101,7 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, + int j, msg_len, num_ch; + struct sk_buff *skb; + +- num_ch = i == batch_size - 1 ? n_chan % batch_len : batch_len; ++ num_ch = i == batch_size - 1 ? n_chan - i * batch_len : batch_len; + msg_len = sizeof(tx_power_tlv) + num_ch * sizeof(sku_tlbv); + skb = mt76_mcu_msg_alloc(dev, NULL, msg_len); + if (!skb) { +diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +index ae6d0179727df..657a4d1f856b2 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h ++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +@@ -808,6 +808,7 @@ enum { + STA_REC_MLD = 0x20, + STA_REC_EHT = 0x22, + STA_REC_PN_INFO = 0x26, ++ STA_REC_KEY_V3 = 0x27, + STA_REC_HDRT = 0x28, + STA_REC_HDR_TRANS = 0x2B, + STA_REC_MAX_NUM +@@ -935,6 +936,9 @@ enum { + PHY_TYPE_INDEX_NUM + }; + ++#define HR_DSSS_ERP_BASIC_RATE GENMASK(3, 0) ++#define OFDM_BASIC_RATE (BIT(6) | BIT(8) | BIT(10)) ++ + #define PHY_TYPE_BIT_HR_DSSS BIT(PHY_TYPE_HR_DSSS_INDEX) + #define PHY_TYPE_BIT_ERP BIT(PHY_TYPE_ERP_INDEX) + #define PHY_TYPE_BIT_OFDM BIT(PHY_TYPE_OFDM_INDEX) +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +index f5582477c7e4c..8b4ce32a2cd12 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +@@ -1272,7 +1272,7 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, + .mtcl_conf = mt792x_acpi_get_mtcl_conf(&dev->phy, alpha2), + }; + int ret, valid_cnt = 0; +- u16 buf_len = 0; ++ u32 buf_len = 0; + u8 *pos; + + if (!clc) +@@ -1283,7 +1283,7 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, + if (mt76_find_power_limits_node(&dev->mt76)) + req.cap |= CLC_CAP_DTS_EN; + +- buf_len = le16_to_cpu(clc->len) - sizeof(*clc); ++ buf_len = le32_to_cpu(clc->len) - sizeof(*clc); + pos = clc->data; + while (buf_len > 16) { + struct mt7921_clc_rule *rule = (struct mt7921_clc_rule *)pos; +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +index dde26f3274783..82cf3ce90b52f 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +@@ -387,6 +387,7 @@ static void mt7921_pci_remove(struct pci_dev *pdev) + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + + mt7921e_unregister_device(dev); ++ set_bit(MT76_REMOVED, &mdev->phy.state); + devm_free_irq(&pdev->dev, pdev->irq, dev); + mt76_free_device(&dev->mt76); + pci_free_irq_vectors(pdev); +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +index 125a1be3cb64c..6179798a8845a 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c +@@ -359,6 +359,7 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) + mvif->sta.wcid.phy_idx = mvif->mt76.band_idx; + mvif->sta.wcid.hw_key_idx = -1; + mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; ++ mvif->sta.vif = mvif; + mt76_wcid_init(&mvif->sta.wcid); + + mt7925_mac_wtbl_update(dev, idx, +@@ -526,7 +527,7 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + if (cmd == SET_KEY && !mvif->mt76.cipher) { + struct mt792x_phy *phy = mt792x_hw_phy(hw); + +- mvif->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher); ++ mvif->mt76.cipher = mt7925_mcu_get_cipher(key->cipher); + mt7925_mcu_add_bss_info(phy, mvif->mt76.ctx, vif, sta, true); + } + +@@ -710,7 +711,7 @@ static void mt7925_bss_info_changed(struct ieee80211_hw *hw, + + if (slottime != phy->slottime) { + phy->slottime = slottime; +- mt792x_mac_set_timeing(phy); ++ mt7925_mcu_set_timing(phy, vif); + } + } + +@@ -1273,6 +1274,25 @@ mt7925_channel_switch_beacon(struct ieee80211_hw *hw, + mt792x_mutex_release(dev); + } + ++static int ++mt7925_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ++ unsigned int link_id, u16 queue, ++ const struct ieee80211_tx_queue_params *params) ++{ ++ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; ++ static const u8 mq_to_aci[] = { ++ [IEEE80211_AC_VO] = 3, ++ [IEEE80211_AC_VI] = 2, ++ [IEEE80211_AC_BE] = 0, ++ [IEEE80211_AC_BK] = 1, ++ }; ++ ++ /* firmware uses access class index */ ++ mvif->queue_params[mq_to_aci[queue]] = *params; ++ ++ return 0; ++} ++ + static int + mt7925_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) +@@ -1396,7 +1416,7 @@ const struct ieee80211_ops mt7925_ops = { + .add_interface = mt7925_add_interface, + .remove_interface = mt792x_remove_interface, + .config = mt7925_config, +- .conf_tx = mt792x_conf_tx, ++ .conf_tx = mt7925_conf_tx, + .configure_filter = mt7925_configure_filter, + .bss_info_changed = mt7925_bss_info_changed, + .start_ap = mt7925_start_ap, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +index c5fd7116929b7..e1dd89a7a79ca 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +@@ -814,6 +814,7 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) + { ++ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct sta_rec_hdr_trans *hdr_trans; + struct mt76_wcid *wcid; + struct tlv *tlv; +@@ -827,7 +828,11 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, + else + hdr_trans->from_ds = true; + +- wcid = (struct mt76_wcid *)sta->drv_priv; ++ if (sta) ++ wcid = (struct mt76_wcid *)sta->drv_priv; ++ else ++ wcid = &mvif->sta.wcid; ++ + if (!wcid) + return; + +@@ -895,7 +900,7 @@ int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif) + + e = (struct edca *)tlv; + e->set = WMM_PARAM_SET; +- e->queue = ac + mvif->mt76.wmm_idx * MT76_CONNAC_MAX_WMM_SETS; ++ e->queue = ac; + e->aifs = q->aifs; + e->txop = cpu_to_le16(q->txop); + +@@ -921,61 +926,67 @@ mt7925_mcu_sta_key_tlv(struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, + enum set_key_cmd cmd) + { ++ struct mt792x_sta *msta = container_of(wcid, struct mt792x_sta, wcid); + struct sta_rec_sec_uni *sec; ++ struct mt792x_vif *mvif = msta->vif; ++ struct ieee80211_sta *sta; ++ struct ieee80211_vif *vif; + struct tlv *tlv; + +- tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec)); ++ sta = msta == &mvif->sta ? ++ NULL : ++ container_of((void *)msta, struct ieee80211_sta, drv_priv); ++ vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); ++ ++ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V3, sizeof(*sec)); + sec = (struct sta_rec_sec_uni *)tlv; +- sec->add = cmd; ++ sec->bss_idx = mvif->mt76.idx; ++ sec->is_authenticator = 0; ++ sec->mgmt_prot = 0; ++ sec->wlan_idx = (u8)wcid->idx; ++ ++ if (sta) { ++ sec->tx_key = 1; ++ sec->key_type = 1; ++ memcpy(sec->peer_addr, sta->addr, ETH_ALEN); ++ } else { ++ memcpy(sec->peer_addr, vif->bss_conf.bssid, ETH_ALEN); ++ } + + if (cmd == SET_KEY) { +- struct sec_key_uni *sec_key; + u8 cipher; + +- cipher = mt76_connac_mcu_get_cipher(key->cipher); +- if (cipher == MCU_CIPHER_NONE) ++ sec->add = 1; ++ cipher = mt7925_mcu_get_cipher(key->cipher); ++ if (cipher == CONNAC3_CIPHER_NONE) + return -EOPNOTSUPP; + +- sec_key = &sec->key[0]; +- sec_key->cipher_len = sizeof(*sec_key); +- +- if (cipher == MCU_CIPHER_BIP_CMAC_128) { +- sec_key->wlan_idx = cpu_to_le16(wcid->idx); +- sec_key->cipher_id = MCU_CIPHER_AES_CCMP; +- sec_key->key_id = sta_key_conf->keyidx; +- sec_key->key_len = 16; +- memcpy(sec_key->key, sta_key_conf->key, 16); +- +- sec_key = &sec->key[1]; +- sec_key->wlan_idx = cpu_to_le16(wcid->idx); +- sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128; +- sec_key->cipher_len = sizeof(*sec_key); +- sec_key->key_len = 16; +- memcpy(sec_key->key, key->key, 16); +- sec->n_cipher = 2; ++ if (cipher == CONNAC3_CIPHER_BIP_CMAC_128) { ++ sec->cipher_id = CONNAC3_CIPHER_BIP_CMAC_128; ++ sec->key_id = sta_key_conf->keyidx; ++ sec->key_len = 32; ++ memcpy(sec->key, sta_key_conf->key, 16); ++ memcpy(sec->key + 16, key->key, 16); + } else { +- sec_key->wlan_idx = cpu_to_le16(wcid->idx); +- sec_key->cipher_id = cipher; +- sec_key->key_id = key->keyidx; +- sec_key->key_len = key->keylen; +- memcpy(sec_key->key, key->key, key->keylen); ++ sec->cipher_id = cipher; ++ sec->key_id = key->keyidx; ++ sec->key_len = key->keylen; ++ memcpy(sec->key, key->key, key->keylen); + +- if (cipher == MCU_CIPHER_TKIP) { ++ if (cipher == CONNAC3_CIPHER_TKIP) { + /* Rx/Tx MIC keys are swapped */ +- memcpy(sec_key->key + 16, key->key + 24, 8); +- memcpy(sec_key->key + 24, key->key + 16, 8); ++ memcpy(sec->key + 16, key->key + 24, 8); ++ memcpy(sec->key + 24, key->key + 16, 8); + } + + /* store key_conf for BIP batch update */ +- if (cipher == MCU_CIPHER_AES_CCMP) { ++ if (cipher == CONNAC3_CIPHER_AES_CCMP) { + memcpy(sta_key_conf->key, key->key, key->keylen); + sta_key_conf->keyidx = key->keyidx; + } +- +- sec->n_cipher = 1; + } + } else { +- sec->n_cipher = 0; ++ sec->add = 0; + } + + return 0; +@@ -1460,12 +1471,10 @@ mt7925_mcu_sta_phy_tlv(struct sk_buff *skb, + struct tlv *tlv; + u8 af = 0, mm = 0; + +- if (!sta->deflink.ht_cap.ht_supported && !sta->deflink.he_6ghz_capa.capa) +- return; +- + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy)); + phy = (struct sta_rec_phy *)tlv; + phy->phy_type = mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif, chandef->chan->band, sta); ++ phy->basic_rate = cpu_to_le16((u16)vif->bss_conf.basic_rates); + if (sta->deflink.ht_cap.ht_supported) { + af = sta->deflink.ht_cap.ampdu_factor; + mm = sta->deflink.ht_cap.ampdu_density; +@@ -1573,8 +1582,6 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, + { + struct mt76_vif *mvif = (struct mt76_vif *)info->vif->drv_priv; + struct mt76_dev *dev = phy->dev; +- struct wtbl_req_hdr *wtbl_hdr; +- struct tlv *sta_wtbl; + struct sk_buff *skb; + + skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, info->wcid, +@@ -1598,30 +1605,11 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, + mt7925_mcu_sta_state_v2_tlv(phy, skb, info->sta, + info->vif, info->rcpi, + info->state); +- mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, info->sta); + mt7925_mcu_sta_mld_tlv(skb, info->vif, info->sta); + } + +- sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, +- sizeof(struct tlv)); +- +- wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(dev, info->wcid, +- WTBL_RESET_AND_SET, +- sta_wtbl, &skb); +- if (IS_ERR(wtbl_hdr)) +- return PTR_ERR(wtbl_hdr); +- +- if (info->enable) { +- mt76_connac_mcu_wtbl_generic_tlv(dev, skb, info->vif, +- info->sta, sta_wtbl, +- wtbl_hdr); +- mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, info->vif, info->wcid, +- sta_wtbl, wtbl_hdr); +- if (info->sta) +- mt76_connac_mcu_wtbl_ht_tlv(dev, skb, info->sta, +- sta_wtbl, wtbl_hdr, +- true, true); +- } ++ if (info->enable) ++ mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, info->sta); + + return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true); + } +@@ -2049,9 +2037,9 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, + struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->chandef; + enum nl80211_band band = chandef->chan->band; + struct mt76_connac_bss_basic_tlv *basic_req; +- u8 idx, basic_phy; + struct tlv *tlv; + int conn_type; ++ u8 idx; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BASIC, sizeof(*basic_req)); + basic_req = (struct mt76_connac_bss_basic_tlv *)tlv; +@@ -2062,8 +2050,10 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, + + basic_req->phymode_ext = mt7925_get_phy_mode_ext(phy, vif, band, sta); + +- basic_phy = mt76_connac_get_phy_mode_v2(phy, vif, band, sta); +- basic_req->nonht_basic_phy = cpu_to_le16(basic_phy); ++ if (band == NL80211_BAND_2GHZ) ++ basic_req->nonht_basic_phy = cpu_to_le16(PHY_TYPE_ERP_INDEX); ++ else ++ basic_req->nonht_basic_phy = cpu_to_le16(PHY_TYPE_OFDM_INDEX); + + memcpy(basic_req->bssid, vif->bss_conf.bssid, ETH_ALEN); + basic_req->phymode = mt76_connac_get_phy_mode(phy, vif, band, sta); +@@ -2122,21 +2112,21 @@ mt7925_mcu_bss_sec_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) + sec = (struct bss_sec_tlv *)tlv; + + switch (mvif->cipher) { +- case MCU_CIPHER_GCMP_256: +- case MCU_CIPHER_GCMP: ++ case CONNAC3_CIPHER_GCMP_256: ++ case CONNAC3_CIPHER_GCMP: + sec->mode = MODE_WPA3_SAE; + sec->status = 8; + break; +- case MCU_CIPHER_AES_CCMP: ++ case CONNAC3_CIPHER_AES_CCMP: + sec->mode = MODE_WPA2_PSK; + sec->status = 6; + break; +- case MCU_CIPHER_TKIP: ++ case CONNAC3_CIPHER_TKIP: + sec->mode = MODE_WPA2_PSK; + sec->status = 4; + break; +- case MCU_CIPHER_WEP104: +- case MCU_CIPHER_WEP40: ++ case CONNAC3_CIPHER_WEP104: ++ case CONNAC3_CIPHER_WEP40: + sec->mode = MODE_SHARED; + sec->status = 0; + break; +@@ -2167,6 +2157,11 @@ mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy, + + bmc = (struct bss_rate_tlv *)tlv; + ++ if (band == NL80211_BAND_2GHZ) ++ bmc->basic_rate = cpu_to_le16(HR_DSSS_ERP_BASIC_RATE); ++ else ++ bmc->basic_rate = cpu_to_le16(OFDM_BASIC_RATE); ++ + bmc->short_preamble = (band == NL80211_BAND_2GHZ); + bmc->bc_fixed_rate = idx; + bmc->mc_fixed_rate = idx; +@@ -2249,6 +2244,38 @@ mt7925_mcu_bss_color_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + vif->bss_conf.he_bss_color.color : 0; + } + ++static void ++mt7925_mcu_bss_ifs_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) ++{ ++ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; ++ struct mt792x_phy *phy = mvif->phy; ++ struct bss_ifs_time_tlv *ifs_time; ++ struct tlv *tlv; ++ ++ tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_IFS_TIME, sizeof(*ifs_time)); ++ ifs_time = (struct bss_ifs_time_tlv *)tlv; ++ ifs_time->slot_valid = true; ++ ifs_time->slot_time = cpu_to_le16(phy->slottime); ++} ++ ++int mt7925_mcu_set_timing(struct mt792x_phy *phy, ++ struct ieee80211_vif *vif) ++{ ++ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; ++ struct mt792x_dev *dev = phy->dev; ++ struct sk_buff *skb; ++ ++ skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76, ++ MT7925_BSS_UPDATE_MAX_SIZE); ++ if (IS_ERR(skb)) ++ return PTR_ERR(skb); ++ ++ mt7925_mcu_bss_ifs_tlv(skb, vif); ++ ++ return mt76_mcu_skb_send_msg(&dev->mt76, skb, ++ MCU_UNI_CMD(BSS_INFO_UPDATE), true); ++} ++ + int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, + struct ieee80211_chanctx_conf *ctx, + struct ieee80211_vif *vif, +@@ -2273,6 +2300,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, + mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, vif, sta); + mt7925_mcu_bss_qos_tlv(skb, vif); + mt7925_mcu_bss_mld_tlv(skb, vif, sta); ++ mt7925_mcu_bss_ifs_tlv(skb, vif); + + if (vif->bss_conf.he_support) { + mt7925_mcu_bss_he_tlv(skb, vif, phy); +@@ -2845,12 +2873,16 @@ int mt7925_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, + if (cmd & __MCU_CMD_FIELD_UNI) { + uni_txd = (struct mt76_connac2_mcu_uni_txd *)txd; + uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd)); +- uni_txd->option = MCU_CMD_UNI_EXT_ACK; + uni_txd->cid = cpu_to_le16(mcu_cmd); + uni_txd->s2d_index = MCU_S2D_H2N; + uni_txd->pkt_type = MCU_PKT_ID; + uni_txd->seq = seq; + ++ if (cmd & __MCU_CMD_FIELD_QUERY) ++ uni_txd->option = MCU_CMD_UNI_QUERY_ACK; ++ else ++ uni_txd->option = MCU_CMD_UNI_EXT_ACK; ++ + goto exit; + } + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +index 3c41e21303b1f..2cf39276118eb 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +@@ -159,6 +159,20 @@ enum { + UNI_EVENT_SCAN_DONE_NLO = 3, + }; + ++enum connac3_mcu_cipher_type { ++ CONNAC3_CIPHER_NONE = 0, ++ CONNAC3_CIPHER_WEP40 = 1, ++ CONNAC3_CIPHER_TKIP = 2, ++ CONNAC3_CIPHER_AES_CCMP = 4, ++ CONNAC3_CIPHER_WEP104 = 5, ++ CONNAC3_CIPHER_BIP_CMAC_128 = 6, ++ CONNAC3_CIPHER_WEP128 = 7, ++ CONNAC3_CIPHER_WAPI = 8, ++ CONNAC3_CIPHER_CCMP_256 = 10, ++ CONNAC3_CIPHER_GCMP = 11, ++ CONNAC3_CIPHER_GCMP_256 = 12, ++}; ++ + struct mt7925_mcu_scan_chinfo_event { + u8 nr_chan; + u8 alpha2[3]; +@@ -334,7 +348,8 @@ struct bss_req_hdr { + struct bss_rate_tlv { + __le16 tag; + __le16 len; +- u8 __rsv1[4]; ++ u8 __rsv1[2]; ++ __le16 basic_rate; + __le16 bc_trans; + __le16 mc_trans; + u8 short_preamble; +@@ -382,25 +397,22 @@ struct sta_rec_eht { + u8 _rsv2[3]; + } __packed; + +-struct sec_key_uni { +- __le16 wlan_idx; +- u8 mgmt_prot; +- u8 cipher_id; +- u8 cipher_len; +- u8 key_id; +- u8 key_len; +- u8 need_resp; +- u8 key[32]; +-} __packed; +- + struct sta_rec_sec_uni { + __le16 tag; + __le16 len; + u8 add; +- u8 n_cipher; +- u8 rsv[2]; +- +- struct sec_key_uni key[2]; ++ u8 tx_key; ++ u8 key_type; ++ u8 is_authenticator; ++ u8 peer_addr[6]; ++ u8 bss_idx; ++ u8 cipher_id; ++ u8 key_id; ++ u8 key_len; ++ u8 wlan_idx; ++ u8 mgmt_prot; ++ u8 key[32]; ++ u8 key_rsc[16]; + } __packed; + + struct sta_rec_hdr_trans { +@@ -428,6 +440,22 @@ struct sta_rec_mld { + } __packed link[2]; + } __packed; + ++struct bss_ifs_time_tlv { ++ __le16 tag; ++ __le16 len; ++ u8 slot_valid; ++ u8 sifs_valid; ++ u8 rifs_valid; ++ u8 eifs_valid; ++ __le16 slot_time; ++ __le16 sifs_time; ++ __le16 rifs_time; ++ __le16 eifs_time; ++ u8 eifs_cck_valid; ++ u8 rsv; ++ __le16 eifs_cck_time; ++} __packed; ++ + #define MT7925_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \ + sizeof(struct sta_rec_basic) + \ + sizeof(struct sta_rec_bf) + \ +@@ -440,7 +468,7 @@ struct sta_rec_mld { + sizeof(struct sta_rec_bfee) + \ + sizeof(struct sta_rec_phy) + \ + sizeof(struct sta_rec_ra) + \ +- sizeof(struct sta_rec_sec) + \ ++ sizeof(struct sta_rec_sec_uni) + \ + sizeof(struct sta_rec_ra_fixed) + \ + sizeof(struct sta_rec_he_6g_capa) + \ + sizeof(struct sta_rec_eht) + \ +@@ -455,6 +483,7 @@ struct sta_rec_mld { + sizeof(struct bss_mld_tlv) + \ + sizeof(struct bss_info_uni_he) + \ + sizeof(struct bss_info_uni_bss_color) + \ ++ sizeof(struct bss_ifs_time_tlv) + \ + sizeof(struct tlv)) + + #define MT_CONNAC3_SKU_POWER_LIMIT 449 +@@ -509,6 +538,33 @@ struct mt7925_wow_pattern_tlv { + u8 rsv[4]; + } __packed; + ++static inline enum connac3_mcu_cipher_type ++mt7925_mcu_get_cipher(int cipher) ++{ ++ switch (cipher) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ return CONNAC3_CIPHER_WEP40; ++ case WLAN_CIPHER_SUITE_WEP104: ++ return CONNAC3_CIPHER_WEP104; ++ case WLAN_CIPHER_SUITE_TKIP: ++ return CONNAC3_CIPHER_TKIP; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ return CONNAC3_CIPHER_BIP_CMAC_128; ++ case WLAN_CIPHER_SUITE_CCMP: ++ return CONNAC3_CIPHER_AES_CCMP; ++ case WLAN_CIPHER_SUITE_CCMP_256: ++ return CONNAC3_CIPHER_CCMP_256; ++ case WLAN_CIPHER_SUITE_GCMP: ++ return CONNAC3_CIPHER_GCMP; ++ case WLAN_CIPHER_SUITE_GCMP_256: ++ return CONNAC3_CIPHER_GCMP_256; ++ case WLAN_CIPHER_SUITE_SMS4: ++ return CONNAC3_CIPHER_WAPI; ++ default: ++ return CONNAC3_CIPHER_NONE; ++ } ++} ++ + int mt7925_mcu_set_dbdc(struct mt76_phy *phy); + int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_scan_request *scan_req); +@@ -525,6 +581,8 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + int enable); ++int mt7925_mcu_set_timing(struct mt792x_phy *phy, ++ struct ieee80211_vif *vif); + int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable); + int mt7925_mcu_set_channel_domain(struct mt76_phy *phy); + int mt7925_mcu_set_radio_en(struct mt792x_phy *phy, bool enable); +diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +index 1fd99a8565415..07b74d492ce15 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +@@ -386,6 +386,8 @@ static int mt7925_pci_probe(struct pci_dev *pdev, + + dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev); + ++ mt76_rmw_field(dev, MT_HW_EMI_CTL, MT_HW_EMI_CTL_SLPPROT_EN, 1); ++ + ret = mt792x_wfsys_reset(dev); + if (ret) + goto err_free_dev; +@@ -425,6 +427,7 @@ static void mt7925_pci_remove(struct pci_dev *pdev) + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + + mt7925e_unregister_device(dev); ++ set_bit(MT76_REMOVED, &mdev->phy.state); + devm_free_irq(&pdev->dev, pdev->irq, dev); + mt76_free_device(&dev->mt76); + pci_free_irq_vectors(pdev); +diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c +index e7afea87e82e2..8fee3d481df0d 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c ++++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c +@@ -66,13 +66,15 @@ mt792x_acpi_read(struct mt792x_dev *dev, u8 *method, u8 **tbl, u32 *len) + } + + /* MTCL : Country List Table for 6G band */ +-static void ++static int + mt792x_asar_acpi_read_mtcl(struct mt792x_dev *dev, u8 **table, u8 *version) + { +- if (mt792x_acpi_read(dev, MT792x_ACPI_MTCL, table, NULL) < 0) +- *version = 1; +- else +- *version = 2; ++ int ret; ++ ++ *version = ((ret = mt792x_acpi_read(dev, MT792x_ACPI_MTCL, table, NULL)) < 0) ++ ? 1 : 2; ++ ++ return ret; + } + + /* MTDS : Dynamic SAR Power Table */ +@@ -166,16 +168,16 @@ int mt792x_init_acpi_sar(struct mt792x_dev *dev) + if (!asar) + return -ENOMEM; + +- mt792x_asar_acpi_read_mtcl(dev, (u8 **)&asar->countrylist, &asar->ver); ++ ret = mt792x_asar_acpi_read_mtcl(dev, (u8 **)&asar->countrylist, &asar->ver); ++ if (ret) { ++ devm_kfree(dev->mt76.dev, asar->countrylist); ++ asar->countrylist = NULL; ++ } + +- /* MTDS is mandatory. Return error if table is invalid */ + ret = mt792x_asar_acpi_read_mtds(dev, (u8 **)&asar->dyn, asar->ver); + if (ret) { + devm_kfree(dev->mt76.dev, asar->dyn); +- devm_kfree(dev->mt76.dev, asar->countrylist); +- devm_kfree(dev->mt76.dev, asar); +- +- return ret; ++ asar->dyn = NULL; + } + + /* MTGS is optional */ +@@ -290,7 +292,7 @@ int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default) + const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa; + int i; + +- if (!phy->acpisar) ++ if (!phy->acpisar || !((struct mt792x_acpi_sar *)phy->acpisar)->dyn) + return 0; + + /* When ACPI SAR enabled in HW, we should apply rules for .frp +diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c +index c42101aa9e45e..9ac5161dfff8c 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c ++++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c +@@ -354,6 +354,7 @@ static const char mt792x_gstrings_stats[][ETH_GSTRING_LEN] = { + "v_tx_bw_40", + "v_tx_bw_80", + "v_tx_bw_160", ++ "v_tx_bw_320", + "v_tx_mcs_0", + "v_tx_mcs_1", + "v_tx_mcs_2", +diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_dma.c b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c +index 488326ce5ed4d..5cc2d59b774af 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt792x_dma.c ++++ b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c +@@ -12,6 +12,8 @@ irqreturn_t mt792x_irq_handler(int irq, void *dev_instance) + { + struct mt792x_dev *dev = dev_instance; + ++ if (test_bit(MT76_REMOVED, &dev->mt76.phy.state)) ++ return IRQ_NONE; + mt76_wr(dev, dev->irq_map->host_irq_enable, 0); + + if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) +@@ -123,14 +125,13 @@ static void mt792x_dma_prefetch(struct mt792x_dev *dev) + + int mt792x_dma_enable(struct mt792x_dev *dev) + { +- if (is_mt7925(&dev->mt76)) +- mt76_rmw(dev, MT_UWFDMA0_GLO_CFG_EXT1, BIT(28), BIT(28)); +- + /* configure perfetch settings */ + mt792x_dma_prefetch(dev); + + /* reset dma idx */ + mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0); ++ if (is_mt7925(&dev->mt76)) ++ mt76_wr(dev, MT_WFDMA0_RST_DRX_PTR, ~0); + + /* configure delay interrupt */ + mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0, 0); +@@ -140,12 +141,20 @@ int mt792x_dma_enable(struct mt792x_dev *dev) + MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN | + MT_WFDMA0_GLO_CFG_CLK_GAT_DIS | + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | ++ FIELD_PREP(MT_WFDMA0_GLO_CFG_DMA_SIZE, 3) | ++ MT_WFDMA0_GLO_CFG_FIFO_DIS_CHECK | ++ MT_WFDMA0_GLO_CFG_RX_WB_DDONE | + MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); + + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); + ++ if (is_mt7925(&dev->mt76)) { ++ mt76_rmw(dev, MT_UWFDMA0_GLO_CFG_EXT1, BIT(28), BIT(28)); ++ mt76_set(dev, MT_WFDMA0_INT_RX_PRI, 0x0F00); ++ mt76_set(dev, MT_WFDMA0_INT_TX_PRI, 0x7F00); ++ } + mt76_set(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT); + + /* enable interrupts for TX/RX rings */ +diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h +index a99af23e4b564..458cfd0260b13 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h ++++ b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h +@@ -292,9 +292,12 @@ + #define MT_WFDMA0_GLO_CFG_TX_DMA_BUSY BIT(1) + #define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2) + #define MT_WFDMA0_GLO_CFG_RX_DMA_BUSY BIT(3) ++#define MT_WFDMA0_GLO_CFG_DMA_SIZE GENMASK(5, 4) + #define MT_WFDMA0_GLO_CFG_TX_WB_DDONE BIT(6) + #define MT_WFDMA0_GLO_CFG_FW_DWLD_BYPASS_DMASHDL BIT(9) ++#define MT_WFDMA0_GLO_CFG_FIFO_DIS_CHECK BIT(11) + #define MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN BIT(12) ++#define MT_WFDMA0_GLO_CFG_RX_WB_DDONE BIT(13) + #define MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN BIT(15) + #define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 BIT(21) + #define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27) +@@ -322,6 +325,8 @@ + + #define MT_WFDMA0_RST_DTX_PTR MT_WFDMA0(0x20c) + #define MT_WFDMA0_RST_DRX_PTR MT_WFDMA0(0x280) ++#define MT_WFDMA0_INT_RX_PRI MT_WFDMA0(0x298) ++#define MT_WFDMA0_INT_TX_PRI MT_WFDMA0(0x29c) + #define MT_WFDMA0_GLO_CFG_EXT0 MT_WFDMA0(0x2b0) + #define MT_WFDMA0_CSR_TX_DMASHDL_ENABLE BIT(6) + #define MT_WFDMA0_PRI_DLY_INT_CFG0 MT_WFDMA0(0x2f0) +@@ -389,6 +394,9 @@ + #define MT_HW_CHIPID 0x70010200 + #define MT_HW_REV 0x70010204 + ++#define MT_HW_EMI_CTL 0x18011100 ++#define MT_HW_EMI_CTL_SLPPROT_EN BIT(1) ++ + #define MT_PCIE_MAC_BASE 0x10000 + #define MT_PCIE_MAC(ofs) (MT_PCIE_MAC_BASE + (ofs)) + #define MT_PCIE_MAC_INT_ENABLE MT_PCIE_MAC(0x188) +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +index 483ad81b6eec6..fe37110e66875 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +@@ -237,7 +237,8 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) + MT_WFDMA0_GLO_CFG_TX_DMA_EN | + MT_WFDMA0_GLO_CFG_RX_DMA_EN | + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | +- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); ++ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 | ++ MT_WFDMA0_GLO_CFG_EXT_EN); + + if (dev->hif2) + mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +index 0cf0d1fe420a2..a929c657be1c4 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c +@@ -493,7 +493,7 @@ static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev) + + void mt7996_mac_init(struct mt7996_dev *dev) + { +-#define HIF_TXD_V2_1 4 ++#define HIF_TXD_V2_1 0x21 + int i; + + mt76_clear(dev, MT_MDP_DCR2, MT_MDP_DCR2_RX_TRANS_SHORT); +@@ -1012,11 +1012,12 @@ mt7996_set_stream_he_txbf_caps(struct mt7996_phy *phy, + /* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */ + elem->phy_cap_info[7] |= min_t(int, sts - 1, 2) << 3; + +- if (vif != NL80211_IFTYPE_AP) ++ if (!(vif == NL80211_IFTYPE_AP || vif == NL80211_IFTYPE_STATION)) + return; + + elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER; +- elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; ++ if (vif == NL80211_IFTYPE_AP) ++ elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; + + c = FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, + sts - 1) | +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +index 53258488d49f3..63d34844c1223 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +@@ -1188,25 +1188,28 @@ mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid, + struct ieee80211_tx_info *info; + struct sk_buff_head list; + struct rate_info rate = {}; +- struct sk_buff *skb; ++ struct sk_buff *skb = NULL; + bool cck = false; + u32 txrate, txs, mode, stbc; + + txs = le32_to_cpu(txs_data[0]); + + mt76_tx_status_lock(mdev, &list); +- skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); + +- if (skb) { +- info = IEEE80211_SKB_CB(skb); +- if (!(txs & MT_TXS0_ACK_ERROR_MASK)) +- info->flags |= IEEE80211_TX_STAT_ACK; ++ /* only report MPDU TXS */ ++ if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) == 0) { ++ skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); ++ if (skb) { ++ info = IEEE80211_SKB_CB(skb); ++ if (!(txs & MT_TXS0_ACK_ERROR_MASK)) ++ info->flags |= IEEE80211_TX_STAT_ACK; + +- info->status.ampdu_len = 1; +- info->status.ampdu_ack_len = +- !!(info->flags & IEEE80211_TX_STAT_ACK); ++ info->status.ampdu_len = 1; ++ info->status.ampdu_ack_len = ++ !!(info->flags & IEEE80211_TX_STAT_ACK); + +- info->status.rates[0].idx = -1; ++ info->status.rates[0].idx = -1; ++ } + } + + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && wcid->sta) { +@@ -2527,6 +2530,34 @@ static int mt7996_mac_check_twt_req(struct ieee80211_twt_setup *twt) + return 0; + } + ++static bool ++mt7996_mac_twt_param_equal(struct mt7996_sta *msta, ++ struct ieee80211_twt_params *twt_agrt) ++{ ++ u16 type = le16_to_cpu(twt_agrt->req_type); ++ u8 exp; ++ int i; ++ ++ exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, type); ++ for (i = 0; i < MT7996_MAX_STA_TWT_AGRT; i++) { ++ struct mt7996_twt_flow *f; ++ ++ if (!(msta->twt.flowid_mask & BIT(i))) ++ continue; ++ ++ f = &msta->twt.flow[i]; ++ if (f->duration == twt_agrt->min_twt_dur && ++ f->mantissa == twt_agrt->mantissa && ++ f->exp == exp && ++ f->protection == !!(type & IEEE80211_TWT_REQTYPE_PROTECTION) && ++ f->flowtype == !!(type & IEEE80211_TWT_REQTYPE_FLOWTYPE) && ++ f->trigger == !!(type & IEEE80211_TWT_REQTYPE_TRIGGER)) ++ return true; ++ } ++ ++ return false; ++} ++ + void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct ieee80211_twt_setup *twt) +@@ -2538,8 +2569,7 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, + enum ieee80211_twt_setup_cmd sta_setup_cmd; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_twt_flow *flow; +- int flowid, table_id; +- u8 exp; ++ u8 flowid, table_id, exp; + + if (mt7996_mac_check_twt_req(twt)) + goto out; +@@ -2552,9 +2582,19 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, + if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow)) + goto unlock; + ++ if (twt_agrt->min_twt_dur < MT7996_MIN_TWT_DUR) { ++ setup_cmd = TWT_SETUP_CMD_DICTATE; ++ twt_agrt->min_twt_dur = MT7996_MIN_TWT_DUR; ++ goto unlock; ++ } ++ ++ if (mt7996_mac_twt_param_equal(msta, twt_agrt)) ++ goto unlock; ++ + flowid = ffs(~msta->twt.flowid_mask) - 1; +- le16p_replace_bits(&twt_agrt->req_type, flowid, +- IEEE80211_TWT_REQTYPE_FLOWID); ++ twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_FLOWID); ++ twt_agrt->req_type |= le16_encode_bits(flowid, ++ IEEE80211_TWT_REQTYPE_FLOWID); + + table_id = ffs(~dev->twt.table_mask) - 1; + exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, req_type); +@@ -2601,10 +2641,10 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, + unlock: + mutex_unlock(&dev->mt76.mutex); + out: +- le16p_replace_bits(&twt_agrt->req_type, setup_cmd, +- IEEE80211_TWT_REQTYPE_SETUP_CMD); +- twt->control = (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT) | +- (twt->control & IEEE80211_TWT_CONTROL_RX_DISABLED); ++ twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_SETUP_CMD); ++ twt_agrt->req_type |= ++ le16_encode_bits(setup_cmd, IEEE80211_TWT_REQTYPE_SETUP_CMD); ++ twt->control = twt->control & IEEE80211_TWT_CONTROL_RX_DISABLED; + } + + void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev, +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +index 699be57309c2e..9e70b960086ac 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +@@ -1240,6 +1240,9 @@ mt7996_mcu_sta_he_6g_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) + static void + mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) + { ++ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; ++ struct ieee80211_vif *vif = container_of((void *)msta->vif, ++ struct ieee80211_vif, drv_priv); + struct ieee80211_eht_mcs_nss_supp *mcs_map; + struct ieee80211_eht_cap_elem_fixed *elem; + struct sta_rec_eht *eht; +@@ -1259,8 +1262,17 @@ mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) + eht->phy_cap = cpu_to_le64(*(u64 *)elem->phy_cap_info); + eht->phy_cap_ext = cpu_to_le64(elem->phy_cap_info[8]); + +- if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20) +- memcpy(eht->mcs_map_bw20, &mcs_map->only_20mhz, sizeof(eht->mcs_map_bw20)); ++ if (vif->type != NL80211_IFTYPE_STATION && ++ (sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] & ++ (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)) == 0) { ++ memcpy(eht->mcs_map_bw20, &mcs_map->only_20mhz, ++ sizeof(eht->mcs_map_bw20)); ++ return; ++ } ++ + memcpy(eht->mcs_map_bw80, &mcs_map->bw._80, sizeof(eht->mcs_map_bw80)); + memcpy(eht->mcs_map_bw160, &mcs_map->bw._160, sizeof(eht->mcs_map_bw160)); + memcpy(eht->mcs_map_bw320, &mcs_map->bw._320, sizeof(eht->mcs_map_bw320)); +@@ -3539,7 +3551,7 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset) + u32 addr = le32_to_cpu(*(__le32 *)(skb->data + 12)); + u8 *buf = (u8 *)dev->mt76.eeprom.data + addr; + +- skb_pull(skb, 64); ++ skb_pull(skb, 48); + memcpy(buf, skb->data, MT7996_EEPROM_BLOCK_SIZE); + } + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +index bc73bcb47bf02..8154ad37827f0 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +@@ -53,6 +53,7 @@ + + #define MT7996_MAX_TWT_AGRT 16 + #define MT7996_MAX_STA_TWT_AGRT 8 ++#define MT7996_MIN_TWT_DUR 64 + #define MT7996_MAX_QUEUE (__MT_RXQ_MAX + __MT_MCUQ_MAX + 3) + + /* NOTE: used to map mt76_rates. idx may change if firmware expands table */ +@@ -320,7 +321,7 @@ struct mt7996_dev { + struct rchan *relay_fwlog; + + struct { +- u8 table_mask; ++ u16 table_mask; + u8 n_agrt; + } twt; + +diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c +index ad2509d8c99a4..f03fd15c0c97a 100644 +--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c ++++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c +@@ -1609,7 +1609,6 @@ static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) + cfg80211_unregister_netdevice(vif->ndev); + vif->monitor_flag = 0; + +- wilc_set_operation_mode(vif, 0, 0, 0); + mutex_lock(&wl->vif_mutex); + list_del_rcu(&vif->list); + wl->vif_num--; +@@ -1804,15 +1803,24 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, + INIT_LIST_HEAD(&wl->rxq_head.list); + INIT_LIST_HEAD(&wl->vif_list); + ++ wl->hif_workqueue = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, ++ wiphy_name(wl->wiphy)); ++ if (!wl->hif_workqueue) { ++ ret = -ENOMEM; ++ goto free_cfg; ++ } + vif = wilc_netdev_ifc_init(wl, "wlan%d", WILC_STATION_MODE, + NL80211_IFTYPE_STATION, false); + if (IS_ERR(vif)) { + ret = PTR_ERR(vif); +- goto free_cfg; ++ goto free_hq; + } + + return 0; + ++free_hq: ++ destroy_workqueue(wl->hif_workqueue); ++ + free_cfg: + wilc_wlan_cfg_deinit(wl); + +diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c +index 839f142663e86..d2b8c26308198 100644 +--- a/drivers/net/wireless/microchip/wilc1000/hif.c ++++ b/drivers/net/wireless/microchip/wilc1000/hif.c +@@ -377,38 +377,49 @@ struct wilc_join_bss_param * + wilc_parse_join_bss_param(struct cfg80211_bss *bss, + struct cfg80211_crypto_settings *crypto) + { +- struct wilc_join_bss_param *param; +- struct ieee80211_p2p_noa_attr noa_attr; +- u8 rates_len = 0; +- const u8 *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie; ++ const u8 *ies_data, *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie; + const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie; ++ struct ieee80211_p2p_noa_attr noa_attr; ++ const struct cfg80211_bss_ies *ies; ++ struct wilc_join_bss_param *param; ++ u8 rates_len = 0, ies_len; + int ret; +- const struct cfg80211_bss_ies *ies = rcu_dereference(bss->ies); + + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) + return NULL; + ++ rcu_read_lock(); ++ ies = rcu_dereference(bss->ies); ++ ies_data = kmemdup(ies->data, ies->len, GFP_ATOMIC); ++ if (!ies_data) { ++ rcu_read_unlock(); ++ kfree(param); ++ return NULL; ++ } ++ ies_len = ies->len; ++ rcu_read_unlock(); ++ + param->beacon_period = cpu_to_le16(bss->beacon_interval); + param->cap_info = cpu_to_le16(bss->capability); + param->bss_type = WILC_FW_BSS_TYPE_INFRA; + param->ch = ieee80211_frequency_to_channel(bss->channel->center_freq); + ether_addr_copy(param->bssid, bss->bssid); + +- ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len); ++ ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies_data, ies_len); + if (ssid_elm) { + if (ssid_elm[1] <= IEEE80211_MAX_SSID_LEN) + memcpy(param->ssid, ssid_elm + 2, ssid_elm[1]); + } + +- tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len); ++ tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies_data, ies_len); + if (tim_elm && tim_elm[1] >= 2) + param->dtim_period = tim_elm[3]; + + memset(param->p_suites, 0xFF, 3); + memset(param->akm_suites, 0xFF, 3); + +- rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies->data, ies->len); ++ rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies_data, ies_len); + if (rates_ie) { + rates_len = rates_ie[1]; + if (rates_len > WILC_MAX_RATES_SUPPORTED) +@@ -419,7 +430,7 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, + + if (rates_len < WILC_MAX_RATES_SUPPORTED) { + supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, +- ies->data, ies->len); ++ ies_data, ies_len); + if (supp_rates_ie) { + u8 ext_rates = supp_rates_ie[1]; + +@@ -434,11 +445,11 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, + } + } + +- ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies->data, ies->len); ++ ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies_data, ies_len); + if (ht_ie) + param->ht_capable = true; + +- ret = cfg80211_get_p2p_attr(ies->data, ies->len, ++ ret = cfg80211_get_p2p_attr(ies_data, ies_len, + IEEE80211_P2P_ATTR_ABSENCE_NOTICE, + (u8 *)&noa_attr, sizeof(noa_attr)); + if (ret > 0) { +@@ -462,7 +473,7 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, + } + wmm_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WMM, +- ies->data, ies->len); ++ ies_data, ies_len); + if (wmm_ie) { + struct ieee80211_wmm_param_ie *ie; + +@@ -477,13 +488,13 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, + + wpa_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WPA, +- ies->data, ies->len); ++ ies_data, ies_len); + if (wpa_ie) { + param->mode_802_11i = 1; + param->rsn_found = true; + } + +- rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies->data, ies->len); ++ rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies_data, ies_len); + if (rsn_ie) { + int rsn_ie_len = sizeof(struct element) + rsn_ie[1]; + int offset = 8; +@@ -517,6 +528,7 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, + param->akm_suites[i] = crypto->akm_suites[i] & 0xFF; + } + ++ kfree(ies_data); + return (void *)param; + } + +diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c +index 81e8f25863f5b..6068699e44109 100644 +--- a/drivers/net/wireless/microchip/wilc1000/netdev.c ++++ b/drivers/net/wireless/microchip/wilc1000/netdev.c +@@ -890,8 +890,7 @@ static const struct net_device_ops wilc_netdev_ops = { + + void wilc_netdev_cleanup(struct wilc *wilc) + { +- struct wilc_vif *vif; +- int srcu_idx, ifc_cnt = 0; ++ struct wilc_vif *vif, *vif_tmp; + + if (!wilc) + return; +@@ -901,32 +900,19 @@ void wilc_netdev_cleanup(struct wilc *wilc) + wilc->firmware = NULL; + } + +- srcu_idx = srcu_read_lock(&wilc->srcu); +- list_for_each_entry_rcu(vif, &wilc->vif_list, list) { ++ list_for_each_entry_safe(vif, vif_tmp, &wilc->vif_list, list) { ++ mutex_lock(&wilc->vif_mutex); ++ list_del_rcu(&vif->list); ++ wilc->vif_num--; ++ mutex_unlock(&wilc->vif_mutex); ++ synchronize_srcu(&wilc->srcu); + if (vif->ndev) + unregister_netdev(vif->ndev); + } +- srcu_read_unlock(&wilc->srcu, srcu_idx); + + wilc_wfi_deinit_mon_interface(wilc, false); + destroy_workqueue(wilc->hif_workqueue); + +- while (ifc_cnt < WILC_NUM_CONCURRENT_IFC) { +- mutex_lock(&wilc->vif_mutex); +- if (wilc->vif_num <= 0) { +- mutex_unlock(&wilc->vif_mutex); +- break; +- } +- vif = wilc_get_wl_to_vif(wilc); +- if (!IS_ERR(vif)) +- list_del_rcu(&vif->list); +- +- wilc->vif_num--; +- mutex_unlock(&wilc->vif_mutex); +- synchronize_srcu(&wilc->srcu); +- ifc_cnt++; +- } +- + wilc_wlan_cfg_deinit(wilc); + wlan_deinit_locks(wilc); + wiphy_unregister(wilc->wiphy); +@@ -989,13 +975,6 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, + goto error; + } + +- wl->hif_workqueue = alloc_ordered_workqueue("%s-wq", WQ_MEM_RECLAIM, +- ndev->name); +- if (!wl->hif_workqueue) { +- ret = -ENOMEM; +- goto unregister_netdev; +- } +- + ndev->needs_free_netdev = true; + vif->iftype = vif_type; + vif->idx = wilc_get_available_idx(wl); +@@ -1008,12 +987,11 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, + + return vif; + +-unregister_netdev: ++error: + if (rtnl_locked) + cfg80211_unregister_netdevice(ndev); + else + unregister_netdev(ndev); +- error: + free_netdev(ndev); + return ERR_PTR(ret); + } +diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c +index 1d8b241ce43ca..6a82b6ca2769e 100644 +--- a/drivers/net/wireless/microchip/wilc1000/spi.c ++++ b/drivers/net/wireless/microchip/wilc1000/spi.c +@@ -192,11 +192,11 @@ static void wilc_wlan_power(struct wilc *wilc, bool on) + /* assert ENABLE: */ + gpiod_set_value(gpios->enable, 1); + mdelay(5); +- /* assert RESET: */ +- gpiod_set_value(gpios->reset, 1); +- } else { + /* deassert RESET: */ + gpiod_set_value(gpios->reset, 0); ++ } else { ++ /* assert RESET: */ ++ gpiod_set_value(gpios->reset, 1); + /* deassert ENABLE: */ + gpiod_set_value(gpios->enable, 0); + } +diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +index 180907319e8cd..04df0f54aa667 100644 +--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c ++++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +@@ -7304,6 +7304,7 @@ static void rtl8xxxu_stop(struct ieee80211_hw *hw) + if (priv->usb_interrupts) + rtl8xxxu_write32(priv, REG_USB_HIMR, 0); + ++ cancel_work_sync(&priv->c2hcmd_work); + cancel_delayed_work_sync(&priv->ra_watchdog); + + rtl8xxxu_free_rx_resources(priv); +diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c +index 6d22628129d0d..ffba6b88f392c 100644 +--- a/drivers/net/wireless/realtek/rtw88/main.c ++++ b/drivers/net/wireless/realtek/rtw88/main.c +@@ -2032,8 +2032,6 @@ static int rtw_chip_board_info_setup(struct rtw_dev *rtwdev) + rtw_phy_setup_phy_cond(rtwdev, hal->pkg_type); + + rtw_phy_init_tx_power(rtwdev); +- if (rfe_def->agc_btg_tbl) +- rtw_load_table(rtwdev, rfe_def->agc_btg_tbl); + rtw_load_table(rtwdev, rfe_def->phy_pg_tbl); + rtw_load_table(rtwdev, rfe_def->txpwr_lmt_tbl); + rtw_phy_tx_power_by_rate_config(hal); +diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c +index 128e75a81bf3c..37ef80c9091db 100644 +--- a/drivers/net/wireless/realtek/rtw88/phy.c ++++ b/drivers/net/wireless/realtek/rtw88/phy.c +@@ -1761,12 +1761,15 @@ static void rtw_load_rfk_table(struct rtw_dev *rtwdev) + + void rtw_phy_load_tables(struct rtw_dev *rtwdev) + { ++ const struct rtw_rfe_def *rfe_def = rtw_get_rfe_def(rtwdev); + const struct rtw_chip_info *chip = rtwdev->chip; + u8 rf_path; + + rtw_load_table(rtwdev, chip->mac_tbl); + rtw_load_table(rtwdev, chip->bb_tbl); + rtw_load_table(rtwdev, chip->agc_tbl); ++ if (rfe_def->agc_btg_tbl) ++ rtw_load_table(rtwdev, rfe_def->agc_btg_tbl); + rtw_load_rfk_table(rtwdev); + + for (rf_path = 0; rf_path < rtwdev->hal.rf_path_num; rf_path++) { +diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c +index 429bb420b0563..fe5d8e1883509 100644 +--- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c ++++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c +@@ -773,9 +773,9 @@ static void rtw8821c_false_alarm_statistics(struct rtw_dev *rtwdev) + + dm_info->cck_fa_cnt = cck_fa_cnt; + dm_info->ofdm_fa_cnt = ofdm_fa_cnt; ++ dm_info->total_fa_cnt = ofdm_fa_cnt; + if (cck_enable) + dm_info->total_fa_cnt += cck_fa_cnt; +- dm_info->total_fa_cnt = ofdm_fa_cnt; + + crc32_cnt = rtw_read32(rtwdev, REG_CRC_CCK); + dm_info->cck_ok_cnt = FIELD_GET(GENMASK(15, 0), crc32_cnt); +diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c +index e6ab1ac6d7093..a0188511099a1 100644 +--- a/drivers/net/wireless/realtek/rtw88/usb.c ++++ b/drivers/net/wireless/realtek/rtw88/usb.c +@@ -33,6 +33,36 @@ static void rtw_usb_fill_tx_checksum(struct rtw_usb *rtwusb, + rtw_tx_fill_txdesc_checksum(rtwdev, &pkt_info, skb->data); + } + ++static void rtw_usb_reg_sec(struct rtw_dev *rtwdev, u32 addr, __le32 *data) ++{ ++ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); ++ struct usb_device *udev = rtwusb->udev; ++ bool reg_on_section = false; ++ u16 t_reg = 0x4e0; ++ u8 t_len = 1; ++ int status; ++ ++ /* There are three sections: ++ * 1. on (0x00~0xFF; 0x1000~0x10FF): this section is always powered on ++ * 2. off (< 0xFE00, excluding "on" section): this section could be ++ * powered off ++ * 3. local (>= 0xFE00): usb specific registers section ++ */ ++ if (addr <= 0xff || (addr >= 0x1000 && addr <= 0x10ff)) ++ reg_on_section = true; ++ ++ if (!reg_on_section) ++ return; ++ ++ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), ++ RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE, ++ t_reg, 0, data, t_len, 500); ++ ++ if (status != t_len && status != -ENODEV) ++ rtw_err(rtwdev, "%s: reg 0x%x, usb write %u fail, status: %d\n", ++ __func__, t_reg, t_len, status); ++} ++ + static u32 rtw_usb_read(struct rtw_dev *rtwdev, u32 addr, u16 len) + { + struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); +@@ -58,6 +88,11 @@ static u32 rtw_usb_read(struct rtw_dev *rtwdev, u32 addr, u16 len) + rtw_err(rtwdev, "read register 0x%x failed with %d\n", + addr, ret); + ++ if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C || ++ rtwdev->chip->id == RTW_CHIP_TYPE_8822B || ++ rtwdev->chip->id == RTW_CHIP_TYPE_8821C) ++ rtw_usb_reg_sec(rtwdev, addr, data); ++ + return le32_to_cpu(*data); + } + +@@ -102,6 +137,11 @@ static void rtw_usb_write(struct rtw_dev *rtwdev, u32 addr, u32 val, int len) + if (ret < 0 && ret != -ENODEV && count++ < 4) + rtw_err(rtwdev, "write register 0x%x failed with %d\n", + addr, ret); ++ ++ if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C || ++ rtwdev->chip->id == RTW_CHIP_TYPE_8822B || ++ rtwdev->chip->id == RTW_CHIP_TYPE_8821C) ++ rtw_usb_reg_sec(rtwdev, addr, data); + } + + static void rtw_usb_write8(struct rtw_dev *rtwdev, u32 addr, u8 val) +diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c +index 537caf9d914a7..bb4446b88c12b 100644 +--- a/drivers/net/wireless/silabs/wfx/sta.c ++++ b/drivers/net/wireless/silabs/wfx/sta.c +@@ -344,6 +344,7 @@ static int wfx_set_mfp_ap(struct wfx_vif *wvif) + const int pairwise_cipher_suite_count_offset = 8 / sizeof(u16); + const int pairwise_cipher_suite_size = 4 / sizeof(u16); + const int akm_suite_size = 4 / sizeof(u16); ++ int ret = -EINVAL; + const u16 *ptr; + + if (unlikely(!skb)) +@@ -352,22 +353,26 @@ static int wfx_set_mfp_ap(struct wfx_vif *wvif) + ptr = (u16 *)cfg80211_find_ie(WLAN_EID_RSN, skb->data + ieoffset, + skb->len - ieoffset); + if (unlikely(!ptr)) +- return -EINVAL; ++ goto free_skb; + + ptr += pairwise_cipher_suite_count_offset; + if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) +- return -EINVAL; ++ goto free_skb; + + ptr += 1 + pairwise_cipher_suite_size * *ptr; + if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) +- return -EINVAL; ++ goto free_skb; + + ptr += 1 + akm_suite_size * *ptr; + if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) +- return -EINVAL; ++ goto free_skb; + + wfx_hif_set_mfp(wvif, *ptr & BIT(7), *ptr & BIT(6)); +- return 0; ++ ret = 0; ++ ++free_skb: ++ dev_kfree_skb(skb); ++ return ret; + } + + int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +diff --git a/drivers/ntb/core.c b/drivers/ntb/core.c +index 27dd93deff6e5..d702bee780826 100644 +--- a/drivers/ntb/core.c ++++ b/drivers/ntb/core.c +@@ -100,6 +100,8 @@ EXPORT_SYMBOL(ntb_unregister_client); + + int ntb_register_device(struct ntb_dev *ntb) + { ++ int ret; ++ + if (!ntb) + return -EINVAL; + if (!ntb->pdev) +@@ -120,7 +122,11 @@ int ntb_register_device(struct ntb_dev *ntb) + ntb->ctx_ops = NULL; + spin_lock_init(&ntb->ctx_lock); + +- return device_register(&ntb->dev); ++ ret = device_register(&ntb->dev); ++ if (ret) ++ put_device(&ntb->dev); ++ ++ return ret; + } + EXPORT_SYMBOL(ntb_register_device); + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 0a96362912ced..fe3627c5bdc99 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -4359,7 +4359,8 @@ int nvme_alloc_admin_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set, + set->ops = ops; + set->queue_depth = NVME_AQ_MQ_TAG_DEPTH; + if (ctrl->ops->flags & NVME_F_FABRICS) +- set->reserved_tags = NVMF_RESERVED_TAGS; ++ /* Reserved for fabric connect and keep alive */ ++ set->reserved_tags = 2; + set->numa_node = ctrl->numa_node; + set->flags = BLK_MQ_F_NO_SCHED; + if (ctrl->ops->flags & NVME_F_BLOCKING) +@@ -4428,7 +4429,8 @@ int nvme_alloc_io_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set, + if (ctrl->quirks & NVME_QUIRK_SHARED_TAGS) + set->reserved_tags = NVME_AQ_DEPTH; + else if (ctrl->ops->flags & NVME_F_FABRICS) +- set->reserved_tags = NVMF_RESERVED_TAGS; ++ /* Reserved for fabric connect */ ++ set->reserved_tags = 1; + set->numa_node = ctrl->numa_node; + set->flags = BLK_MQ_F_SHOULD_MERGE; + if (ctrl->ops->flags & NVME_F_BLOCKING) +diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h +index 06cc54851b1be..37c974c38dcb0 100644 +--- a/drivers/nvme/host/fabrics.h ++++ b/drivers/nvme/host/fabrics.h +@@ -18,13 +18,6 @@ + /* default is -1: the fail fast mechanism is disabled */ + #define NVMF_DEF_FAIL_FAST_TMO -1 + +-/* +- * Reserved one command for internal usage. This command is used for sending +- * the connect command, as well as for the keep alive command on the admin +- * queue once live. +- */ +-#define NVMF_RESERVED_TAGS 1 +- + /* + * Define a host as seen by the target. We allocate one at boot, but also + * allow the override it when creating controllers. This is both to provide +diff --git a/drivers/nvme/host/sysfs.c b/drivers/nvme/host/sysfs.c +index f2832f70e7e0a..09fcaa519e5bc 100644 +--- a/drivers/nvme/host/sysfs.c ++++ b/drivers/nvme/host/sysfs.c +@@ -221,14 +221,11 @@ static int ns_update_nuse(struct nvme_ns *ns) + + ret = nvme_identify_ns(ns->ctrl, ns->head->ns_id, &id); + if (ret) +- goto out_free_id; ++ return ret; + + ns->head->nuse = le64_to_cpu(id->nuse); +- +-out_free_id: + kfree(id); +- +- return ret; ++ return 0; + } + + static ssize_t nuse_show(struct device *dev, struct device_attribute *attr, +diff --git a/drivers/opp/debugfs.c b/drivers/opp/debugfs.c +index ec030b19164a3..f157fb50be50c 100644 +--- a/drivers/opp/debugfs.c ++++ b/drivers/opp/debugfs.c +@@ -37,10 +37,12 @@ static ssize_t bw_name_read(struct file *fp, char __user *userbuf, + size_t count, loff_t *ppos) + { + struct icc_path *path = fp->private_data; ++ const char *name = icc_get_name(path); + char buf[64]; +- int i; ++ int i = 0; + +- i = scnprintf(buf, sizeof(buf), "%.62s\n", icc_get_name(path)); ++ if (name) ++ i = scnprintf(buf, sizeof(buf), "%.62s\n", name); + + return simple_read_from_buffer(userbuf, count, ppos, buf, i); + } +diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c +index 5b0730c3891b8..c08683febdd40 100644 +--- a/drivers/pci/controller/pcie-brcmstb.c ++++ b/drivers/pci/controller/pcie-brcmstb.c +@@ -336,7 +336,7 @@ static int brcm_pcie_mdio_write(void __iomem *base, u8 port, + readl(base + PCIE_RC_DL_MDIO_ADDR); + writel(MDIO_DATA_DONE_MASK | wrdata, base + PCIE_RC_DL_MDIO_WR_DATA); + +- err = readw_poll_timeout_atomic(base + PCIE_RC_DL_MDIO_WR_DATA, data, ++ err = readl_poll_timeout_atomic(base + PCIE_RC_DL_MDIO_WR_DATA, data, + MDIO_WT_DONE(data), 10, 100); + return err; + } +diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c +index e75a2af77328e..5b84821c0d602 100644 +--- a/drivers/pci/endpoint/functions/pci-epf-vntb.c ++++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c +@@ -1275,15 +1275,11 @@ static int pci_vntb_probe(struct pci_dev *pdev, const struct pci_device_id *id) + ret = ntb_register_device(&ndev->ntb); + if (ret) { + dev_err(dev, "Failed to register NTB device\n"); +- goto err_register_dev; ++ return ret; + } + + dev_dbg(dev, "PCI Virtual NTB driver loaded\n"); + return 0; +- +-err_register_dev: +- put_device(&ndev->ntb.dev); +- return -EINVAL; + } + + static struct pci_device_id pci_vntb_table[] = { +diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c +index 0c361561b855c..4f47a13cb500f 100644 +--- a/drivers/pci/p2pdma.c ++++ b/drivers/pci/p2pdma.c +@@ -661,7 +661,7 @@ calc_map_type_and_dist(struct pci_dev *provider, struct pci_dev *client, + p2pdma = rcu_dereference(provider->p2pdma); + if (p2pdma) + xa_store(&p2pdma->map_types, map_types_idx(client), +- xa_mk_value(map_type), GFP_KERNEL); ++ xa_mk_value(map_type), GFP_ATOMIC); + rcu_read_unlock(); + return map_type; + } +diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h +index e9750b1b19bad..bfc56f7bee1c9 100644 +--- a/drivers/pci/pci.h ++++ b/drivers/pci/pci.h +@@ -368,11 +368,6 @@ static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused) + return 0; + } + +-static inline bool pci_dev_is_disconnected(const struct pci_dev *dev) +-{ +- return dev->error_state == pci_channel_io_perm_failure; +-} +- + /* pci_dev priv_flags */ + #define PCI_DEV_ADDED 0 + #define PCI_DPC_RECOVERED 1 +diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c +index 94111e4382413..e5d7c12854fa0 100644 +--- a/drivers/pci/pcie/dpc.c ++++ b/drivers/pci/pcie/dpc.c +@@ -234,7 +234,7 @@ static void dpc_process_rp_pio_error(struct pci_dev *pdev) + + for (i = 0; i < pdev->dpc_rp_log_size - 5; i++) { + pci_read_config_dword(pdev, +- cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG, &prefix); ++ cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG + i * 4, &prefix); + pci_err(pdev, "TLP Prefix Header: dw%d, %#010x\n", i, prefix); + } + clear_status: +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index d797df6e5f3e9..2ebbe51a7efe0 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -5527,6 +5527,7 @@ static void quirk_no_ext_tags(struct pci_dev *pdev) + + pci_walk_bus(bridge->bus, pci_configure_extended_tags, NULL); + } ++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1004, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0132, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0140, quirk_no_ext_tags); + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0141, quirk_no_ext_tags); +diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c +index 1804794d0e686..5a4adf6c04cf8 100644 +--- a/drivers/pci/switch/switchtec.c ++++ b/drivers/pci/switch/switchtec.c +@@ -1672,7 +1672,7 @@ static int switchtec_pci_probe(struct pci_dev *pdev, + rc = switchtec_init_isr(stdev); + if (rc) { + dev_err(&stdev->dev, "failed to init isr.\n"); +- goto err_put; ++ goto err_exit_pci; + } + + iowrite32(SWITCHTEC_EVENT_CLEAR | +@@ -1693,6 +1693,8 @@ static int switchtec_pci_probe(struct pci_dev *pdev, + + err_devadd: + stdev_kill(stdev); ++err_exit_pci: ++ switchtec_exit_pci(stdev); + err_put: + ida_free(&switchtec_minor_ida, MINOR(stdev->dev.devt)); + put_device(&stdev->dev); +diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile +index ffd609ac62336..eb60e950ad533 100644 +--- a/drivers/phy/qualcomm/Makefile ++++ b/drivers/phy/qualcomm/Makefile +@@ -7,7 +7,7 @@ obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o + obj-$(CONFIG_PHY_QCOM_M31_USB) += phy-qcom-m31.o + obj-$(CONFIG_PHY_QCOM_PCIE2) += phy-qcom-pcie2.o + +-obj-$(CONFIG_PHY_QCOM_QMP_COMBO) += phy-qcom-qmp-combo.o ++obj-$(CONFIG_PHY_QCOM_QMP_COMBO) += phy-qcom-qmp-combo.o phy-qcom-qmp-usbc.o + obj-$(CONFIG_PHY_QCOM_QMP_PCIE) += phy-qcom-qmp-pcie.o + obj-$(CONFIG_PHY_QCOM_QMP_PCIE_8996) += phy-qcom-qmp-pcie-msm8996.o + obj-$(CONFIG_PHY_QCOM_QMP_UFS) += phy-qcom-qmp-ufs.o +diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c +index 5c003988c35d3..4c32304dae87f 100644 +--- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c ++++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c +@@ -121,15 +121,6 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_PCS_MISC_CLAMP_ENABLE] = QPHY_V3_PCS_MISC_CLAMP_ENABLE, + }; + +-static const unsigned int qmp_v3_usb3phy_regs_layout_qcm2290[QPHY_LAYOUT_SIZE] = { +- [QPHY_SW_RESET] = QPHY_V3_PCS_SW_RESET, +- [QPHY_START_CTRL] = QPHY_V3_PCS_START_CONTROL, +- [QPHY_PCS_STATUS] = QPHY_V3_PCS_PCS_STATUS, +- [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL, +- [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V3_PCS_LFPS_RXTERM_IRQ_CLEAR, +- [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V3_PCS_POWER_DOWN_CONTROL, +-}; +- + static const unsigned int qmp_v4_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_SW_RESET] = QPHY_V4_PCS_SW_RESET, + [QPHY_START_CTRL] = QPHY_V4_PCS_START_CONTROL, +@@ -514,115 +505,6 @@ static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG2, 0x60), + }; + +-static const struct qmp_phy_init_tbl msm8998_usb3_serdes_tbl[] = { +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x06), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x80), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x34), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x15), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x04), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_CFG, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x0a), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_INITVAL, 0x80), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_MODE, 0x01), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x31), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x85), +- QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x07), +-}; +- +-static const struct qmp_phy_init_tbl msm8998_usb3_tx_tbl[] = { +- QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10), +- QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12), +- QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x16), +- QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x00), +-}; +- +-static const struct qmp_phy_init_tbl msm8998_usb3_rx_tbl[] = { +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x07), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x43), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1c), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x03), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x05), +-}; +- +-static const struct qmp_phy_init_tbl msm8998_usb3_pcs_tbl[] = { +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x40), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG2, 0x1b), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V1, 0x9f), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V2, 0xb7), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V3, 0x4e), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V4, 0x65), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_LS, 0x6b), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x15), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0d), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V1, 0x15), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V1, 0x0d), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V2, 0x15), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V2, 0x0d), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V3, 0x15), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V3, 0x0d), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V4, 0x15), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V4, 0x0d), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_LS, 0x15), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_LS, 0x0d), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_RATE_SLEW_CNTRL, 0x02), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x8a), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13), +-}; +- + static const struct qmp_phy_init_tbl sm8150_usb3_uniphy_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL, 0x11), +@@ -1089,99 +971,6 @@ static const struct qmp_phy_init_tbl sm8350_usb3_uniphy_pcs_usb_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8), + }; + +-static const struct qmp_phy_init_tbl qcm2290_usb3_serdes_tbl[] = { +- QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14), +- QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), +- QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), +- QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06), +- QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL2, 0x08), +- QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f), +- QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01), +- QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), +- QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55), +- QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55), +- QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x03), +- QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), +- QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), +- QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), +- QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), +- QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a), +- QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x15), +- QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x34), +- QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a), +- QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x01), +- QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31), +- QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x01), +- QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0xde), +- QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x07), +- QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), +- QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x06), +- QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_INITVAL, 0x80), +- QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CTRL_BY_PSM, 0x01), +-}; +- +-static const struct qmp_phy_init_tbl qcm2290_usb3_tx_tbl[] = { +- QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10), +- QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12), +- QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0xc6), +- QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x00), +-}; +- +-static const struct qmp_phy_init_tbl qcm2290_usb3_rx_tbl[] = { +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x0a), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x16), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x00), +- QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x00), +-}; +- +-static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = { +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x17), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0f), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x85), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00), +- QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88), +-}; +- + static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_HSCLK_SEL, 0x11), +@@ -1579,16 +1368,6 @@ static const struct qmp_usb_offsets qmp_usb_offsets_v3_msm8996 = { + .rx = 0x400, + }; + +-static const struct qmp_usb_offsets qmp_usb_offsets_v3_qcm2290 = { +- .serdes = 0x0, +- .pcs = 0xc00, +- .pcs_misc = 0xa00, +- .tx = 0x200, +- .rx = 0x400, +- .tx2 = 0x600, +- .rx2 = 0x800, +-}; +- + static const struct qmp_usb_offsets qmp_usb_offsets_v4 = { + .serdes = 0, + .pcs = 0x0800, +@@ -1753,24 +1532,6 @@ static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = { + .has_pwrdn_delay = true, + }; + +-static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { +- .lanes = 2, +- +- .offsets = &qmp_usb_offsets_v3_qcm2290, +- +- .serdes_tbl = msm8998_usb3_serdes_tbl, +- .serdes_tbl_num = ARRAY_SIZE(msm8998_usb3_serdes_tbl), +- .tx_tbl = msm8998_usb3_tx_tbl, +- .tx_tbl_num = ARRAY_SIZE(msm8998_usb3_tx_tbl), +- .rx_tbl = msm8998_usb3_rx_tbl, +- .rx_tbl_num = ARRAY_SIZE(msm8998_usb3_rx_tbl), +- .pcs_tbl = msm8998_usb3_pcs_tbl, +- .pcs_tbl_num = ARRAY_SIZE(msm8998_usb3_pcs_tbl), +- .vreg_list = qmp_phy_vreg_l, +- .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), +- .regs = qmp_v3_usb3phy_regs_layout, +-}; +- + static const struct qmp_phy_cfg sm8150_usb3_uniphy_cfg = { + .lanes = 1, + +@@ -1908,24 +1669,6 @@ static const struct qmp_phy_cfg sm8350_usb3_uniphy_cfg = { + .has_pwrdn_delay = true, + }; + +-static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = { +- .lanes = 2, +- +- .offsets = &qmp_usb_offsets_v3_qcm2290, +- +- .serdes_tbl = qcm2290_usb3_serdes_tbl, +- .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl), +- .tx_tbl = qcm2290_usb3_tx_tbl, +- .tx_tbl_num = ARRAY_SIZE(qcm2290_usb3_tx_tbl), +- .rx_tbl = qcm2290_usb3_rx_tbl, +- .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl), +- .pcs_tbl = qcm2290_usb3_pcs_tbl, +- .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), +- .vreg_list = qmp_phy_vreg_l, +- .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), +- .regs = qmp_v3_usb3phy_regs_layout_qcm2290, +-}; +- + static const struct qmp_phy_cfg x1e80100_usb3_uniphy_cfg = { + .lanes = 1, + +@@ -2599,12 +2342,6 @@ static const struct of_device_id qmp_usb_of_match_table[] = { + }, { + .compatible = "qcom,msm8996-qmp-usb3-phy", + .data = &msm8996_usb3phy_cfg, +- }, { +- .compatible = "qcom,msm8998-qmp-usb3-phy", +- .data = &msm8998_usb3phy_cfg, +- }, { +- .compatible = "qcom,qcm2290-qmp-usb3-phy", +- .data = &qcm2290_usb3phy_cfg, + }, { + .compatible = "qcom,sa8775p-qmp-usb3-uni-phy", + .data = &sa8775p_usb3_uniphy_cfg, +@@ -2623,9 +2360,6 @@ static const struct of_device_id qmp_usb_of_match_table[] = { + }, { + .compatible = "qcom,sdx75-qmp-usb3-uni-phy", + .data = &sdx75_usb3_uniphy_cfg, +- }, { +- .compatible = "qcom,sm6115-qmp-usb3-phy", +- .data = &qcm2290_usb3phy_cfg, + }, { + .compatible = "qcom,sm8150-qmp-usb3-uni-phy", + .data = &sm8150_usb3_uniphy_cfg, +diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +new file mode 100644 +index 0000000000000..3a4b4849db0f5 +--- /dev/null ++++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c +@@ -0,0 +1,1195 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2017, The Linux Foundation. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "phy-qcom-qmp.h" ++#include "phy-qcom-qmp-pcs-misc-v3.h" ++ ++/* QPHY_SW_RESET bit */ ++#define SW_RESET BIT(0) ++/* QPHY_POWER_DOWN_CONTROL */ ++#define SW_PWRDN BIT(0) ++/* QPHY_START_CONTROL bits */ ++#define SERDES_START BIT(0) ++#define PCS_START BIT(1) ++/* QPHY_PCS_STATUS bit */ ++#define PHYSTATUS BIT(6) ++ ++/* QPHY_V3_DP_COM_RESET_OVRD_CTRL register bits */ ++/* DP PHY soft reset */ ++#define SW_DPPHY_RESET BIT(0) ++/* mux to select DP PHY reset control, 0:HW control, 1: software reset */ ++#define SW_DPPHY_RESET_MUX BIT(1) ++/* USB3 PHY soft reset */ ++#define SW_USB3PHY_RESET BIT(2) ++/* mux to select USB3 PHY reset control, 0:HW control, 1: software reset */ ++#define SW_USB3PHY_RESET_MUX BIT(3) ++ ++/* QPHY_V3_DP_COM_PHY_MODE_CTRL register bits */ ++#define USB3_MODE BIT(0) /* enables USB3 mode */ ++#define DP_MODE BIT(1) /* enables DP mode */ ++ ++/* QPHY_PCS_AUTONOMOUS_MODE_CTRL register bits */ ++#define ARCVR_DTCT_EN BIT(0) ++#define ALFPS_DTCT_EN BIT(1) ++#define ARCVR_DTCT_EVENT_SEL BIT(4) ++ ++/* QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR register bits */ ++#define IRQ_CLEAR BIT(0) ++ ++#define PHY_INIT_COMPLETE_TIMEOUT 10000 ++ ++struct qmp_phy_init_tbl { ++ unsigned int offset; ++ unsigned int val; ++ /* ++ * mask of lanes for which this register is written ++ * for cases when second lane needs different values ++ */ ++ u8 lane_mask; ++}; ++ ++#define QMP_PHY_INIT_CFG(o, v) \ ++ { \ ++ .offset = o, \ ++ .val = v, \ ++ .lane_mask = 0xff, \ ++ } ++ ++#define QMP_PHY_INIT_CFG_LANE(o, v, l) \ ++ { \ ++ .offset = o, \ ++ .val = v, \ ++ .lane_mask = l, \ ++ } ++ ++/* set of registers with offsets different per-PHY */ ++enum qphy_reg_layout { ++ /* PCS registers */ ++ QPHY_SW_RESET, ++ QPHY_START_CTRL, ++ QPHY_PCS_STATUS, ++ QPHY_PCS_AUTONOMOUS_MODE_CTRL, ++ QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR, ++ QPHY_PCS_POWER_DOWN_CONTROL, ++ /* Keep last to ensure regs_layout arrays are properly initialized */ ++ QPHY_LAYOUT_SIZE ++}; ++ ++static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { ++ [QPHY_SW_RESET] = QPHY_V3_PCS_SW_RESET, ++ [QPHY_START_CTRL] = QPHY_V3_PCS_START_CONTROL, ++ [QPHY_PCS_STATUS] = QPHY_V3_PCS_PCS_STATUS, ++ [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL, ++ [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V3_PCS_LFPS_RXTERM_IRQ_CLEAR, ++ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V3_PCS_POWER_DOWN_CONTROL, ++}; ++ ++static const unsigned int qmp_v3_usb3phy_regs_layout_qcm2290[QPHY_LAYOUT_SIZE] = { ++ [QPHY_SW_RESET] = QPHY_V3_PCS_SW_RESET, ++ [QPHY_START_CTRL] = QPHY_V3_PCS_START_CONTROL, ++ [QPHY_PCS_STATUS] = QPHY_V3_PCS_PCS_STATUS, ++ [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL, ++ [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V3_PCS_LFPS_RXTERM_IRQ_CLEAR, ++ [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V3_PCS_POWER_DOWN_CONTROL, ++}; ++ ++static const struct qmp_phy_init_tbl msm8998_usb3_serdes_tbl[] = { ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x06), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x80), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x34), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x15), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x04), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_CFG, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x0a), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_INITVAL, 0x80), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_MODE, 0x01), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x31), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x85), ++ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x07), ++}; ++ ++static const struct qmp_phy_init_tbl msm8998_usb3_tx_tbl[] = { ++ QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10), ++ QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12), ++ QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x16), ++ QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x00), ++}; ++ ++static const struct qmp_phy_init_tbl msm8998_usb3_rx_tbl[] = { ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x07), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x43), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1c), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x03), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x05), ++}; ++ ++static const struct qmp_phy_init_tbl msm8998_usb3_pcs_tbl[] = { ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x40), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG2, 0x1b), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V1, 0x9f), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V2, 0xb7), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V3, 0x4e), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V4, 0x65), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_LS, 0x6b), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x15), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0d), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V1, 0x15), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V1, 0x0d), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V2, 0x15), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V2, 0x0d), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V3, 0x15), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V3, 0x0d), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V4, 0x15), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V4, 0x0d), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_LS, 0x15), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_LS, 0x0d), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RATE_SLEW_CNTRL, 0x02), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x8a), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13), ++}; ++ ++static const struct qmp_phy_init_tbl qcm2290_usb3_serdes_tbl[] = { ++ QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14), ++ QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), ++ QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), ++ QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06), ++ QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL2, 0x08), ++ QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f), ++ QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01), ++ QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), ++ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55), ++ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55), ++ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x03), ++ QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), ++ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), ++ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), ++ QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), ++ QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a), ++ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x15), ++ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x34), ++ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a), ++ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x01), ++ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31), ++ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x01), ++ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0xde), ++ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x07), ++ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), ++ QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x06), ++ QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_INITVAL, 0x80), ++ QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CTRL_BY_PSM, 0x01), ++}; ++ ++static const struct qmp_phy_init_tbl qcm2290_usb3_tx_tbl[] = { ++ QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10), ++ QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12), ++ QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0xc6), ++ QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x00), ++}; ++ ++static const struct qmp_phy_init_tbl qcm2290_usb3_rx_tbl[] = { ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x0a), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x16), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x00), ++ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x00), ++}; ++ ++static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = { ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x17), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0f), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x85), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00), ++ QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88), ++}; ++ ++struct qmp_usbc_offsets { ++ u16 serdes; ++ u16 pcs; ++ u16 pcs_misc; ++ u16 tx; ++ u16 rx; ++ /* for PHYs with >= 2 lanes */ ++ u16 tx2; ++ u16 rx2; ++}; ++ ++/* struct qmp_phy_cfg - per-PHY initialization config */ ++struct qmp_phy_cfg { ++ const struct qmp_usbc_offsets *offsets; ++ ++ /* Init sequence for PHY blocks - serdes, tx, rx, pcs */ ++ const struct qmp_phy_init_tbl *serdes_tbl; ++ int serdes_tbl_num; ++ const struct qmp_phy_init_tbl *tx_tbl; ++ int tx_tbl_num; ++ const struct qmp_phy_init_tbl *rx_tbl; ++ int rx_tbl_num; ++ const struct qmp_phy_init_tbl *pcs_tbl; ++ int pcs_tbl_num; ++ ++ /* regulators to be requested */ ++ const char * const *vreg_list; ++ int num_vregs; ++ ++ /* array of registers with different offsets */ ++ const unsigned int *regs; ++ ++ /* true, if PHY needs delay after POWER_DOWN */ ++ bool has_pwrdn_delay; ++}; ++ ++struct qmp_usbc { ++ struct device *dev; ++ ++ const struct qmp_phy_cfg *cfg; ++ ++ void __iomem *serdes; ++ void __iomem *pcs; ++ void __iomem *pcs_misc; ++ void __iomem *tx; ++ void __iomem *rx; ++ void __iomem *tx2; ++ void __iomem *rx2; ++ ++ struct regmap *tcsr_map; ++ u32 vls_clamp_reg; ++ ++ struct clk *pipe_clk; ++ struct clk_bulk_data *clks; ++ int num_clks; ++ int num_resets; ++ struct reset_control_bulk_data *resets; ++ struct regulator_bulk_data *vregs; ++ ++ struct mutex phy_mutex; ++ ++ enum phy_mode mode; ++ unsigned int usb_init_count; ++ ++ struct phy *phy; ++ ++ struct clk_fixed_rate pipe_clk_fixed; ++ ++ struct typec_switch_dev *sw; ++ enum typec_orientation orientation; ++}; ++ ++static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) ++{ ++ u32 reg; ++ ++ reg = readl(base + offset); ++ reg |= val; ++ writel(reg, base + offset); ++ ++ /* ensure that above write is through */ ++ readl(base + offset); ++} ++ ++static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val) ++{ ++ u32 reg; ++ ++ reg = readl(base + offset); ++ reg &= ~val; ++ writel(reg, base + offset); ++ ++ /* ensure that above write is through */ ++ readl(base + offset); ++} ++ ++/* list of clocks required by phy */ ++static const char * const qmp_usbc_phy_clk_l[] = { ++ "aux", "cfg_ahb", "ref", "com_aux", ++}; ++ ++/* list of resets */ ++static const char * const usb3phy_legacy_reset_l[] = { ++ "phy", "common", ++}; ++ ++static const char * const usb3phy_reset_l[] = { ++ "phy_phy", "phy", ++}; ++ ++/* list of regulators */ ++static const char * const qmp_phy_vreg_l[] = { ++ "vdda-phy", "vdda-pll", ++}; ++ ++static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = { ++ .serdes = 0x0, ++ .pcs = 0xc00, ++ .pcs_misc = 0xa00, ++ .tx = 0x200, ++ .rx = 0x400, ++ .tx2 = 0x600, ++ .rx2 = 0x800, ++}; ++ ++static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { ++ .offsets = &qmp_usbc_offsets_v3_qcm2290, ++ ++ .serdes_tbl = msm8998_usb3_serdes_tbl, ++ .serdes_tbl_num = ARRAY_SIZE(msm8998_usb3_serdes_tbl), ++ .tx_tbl = msm8998_usb3_tx_tbl, ++ .tx_tbl_num = ARRAY_SIZE(msm8998_usb3_tx_tbl), ++ .rx_tbl = msm8998_usb3_rx_tbl, ++ .rx_tbl_num = ARRAY_SIZE(msm8998_usb3_rx_tbl), ++ .pcs_tbl = msm8998_usb3_pcs_tbl, ++ .pcs_tbl_num = ARRAY_SIZE(msm8998_usb3_pcs_tbl), ++ .vreg_list = qmp_phy_vreg_l, ++ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), ++ .regs = qmp_v3_usb3phy_regs_layout, ++}; ++ ++static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = { ++ .offsets = &qmp_usbc_offsets_v3_qcm2290, ++ ++ .serdes_tbl = qcm2290_usb3_serdes_tbl, ++ .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl), ++ .tx_tbl = qcm2290_usb3_tx_tbl, ++ .tx_tbl_num = ARRAY_SIZE(qcm2290_usb3_tx_tbl), ++ .rx_tbl = qcm2290_usb3_rx_tbl, ++ .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl), ++ .pcs_tbl = qcm2290_usb3_pcs_tbl, ++ .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), ++ .vreg_list = qmp_phy_vreg_l, ++ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), ++ .regs = qmp_v3_usb3phy_regs_layout_qcm2290, ++}; ++ ++static void qmp_usbc_configure_lane(void __iomem *base, ++ const struct qmp_phy_init_tbl tbl[], ++ int num, ++ u8 lane_mask) ++{ ++ int i; ++ const struct qmp_phy_init_tbl *t = tbl; ++ ++ if (!t) ++ return; ++ ++ for (i = 0; i < num; i++, t++) { ++ if (!(t->lane_mask & lane_mask)) ++ continue; ++ ++ writel(t->val, base + t->offset); ++ } ++} ++ ++static void qmp_usbc_configure(void __iomem *base, ++ const struct qmp_phy_init_tbl tbl[], ++ int num) ++{ ++ qmp_usbc_configure_lane(base, tbl, num, 0xff); ++} ++ ++static int qmp_usbc_init(struct phy *phy) ++{ ++ struct qmp_usbc *qmp = phy_get_drvdata(phy); ++ const struct qmp_phy_cfg *cfg = qmp->cfg; ++ void __iomem *pcs = qmp->pcs; ++ u32 val = 0; ++ int ret; ++ ++ ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); ++ if (ret) { ++ dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret); ++ return ret; ++ } ++ ++ ret = reset_control_bulk_assert(qmp->num_resets, qmp->resets); ++ if (ret) { ++ dev_err(qmp->dev, "reset assert failed\n"); ++ goto err_disable_regulators; ++ } ++ ++ ret = reset_control_bulk_deassert(qmp->num_resets, qmp->resets); ++ if (ret) { ++ dev_err(qmp->dev, "reset deassert failed\n"); ++ goto err_disable_regulators; ++ } ++ ++ ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks); ++ if (ret) ++ goto err_assert_reset; ++ ++ qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN); ++ ++#define SW_PORTSELECT_VAL BIT(0) ++#define SW_PORTSELECT_MUX BIT(1) ++ /* Use software based port select and switch on typec orientation */ ++ val = SW_PORTSELECT_MUX; ++ if (qmp->orientation == TYPEC_ORIENTATION_REVERSE) ++ val |= SW_PORTSELECT_VAL; ++ writel(val, qmp->pcs_misc); ++ ++ return 0; ++ ++err_assert_reset: ++ reset_control_bulk_assert(qmp->num_resets, qmp->resets); ++err_disable_regulators: ++ regulator_bulk_disable(cfg->num_vregs, qmp->vregs); ++ ++ return ret; ++} ++ ++static int qmp_usbc_exit(struct phy *phy) ++{ ++ struct qmp_usbc *qmp = phy_get_drvdata(phy); ++ const struct qmp_phy_cfg *cfg = qmp->cfg; ++ ++ reset_control_bulk_assert(qmp->num_resets, qmp->resets); ++ ++ clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); ++ ++ regulator_bulk_disable(cfg->num_vregs, qmp->vregs); ++ ++ return 0; ++} ++ ++static int qmp_usbc_power_on(struct phy *phy) ++{ ++ struct qmp_usbc *qmp = phy_get_drvdata(phy); ++ const struct qmp_phy_cfg *cfg = qmp->cfg; ++ void __iomem *status; ++ unsigned int val; ++ int ret; ++ ++ qmp_usbc_configure(qmp->serdes, cfg->serdes_tbl, cfg->serdes_tbl_num); ++ ++ ret = clk_prepare_enable(qmp->pipe_clk); ++ if (ret) { ++ dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret); ++ return ret; ++ } ++ ++ /* Tx, Rx, and PCS configurations */ ++ qmp_usbc_configure_lane(qmp->tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); ++ qmp_usbc_configure_lane(qmp->rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); ++ ++ qmp_usbc_configure_lane(qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2); ++ qmp_usbc_configure_lane(qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2); ++ ++ qmp_usbc_configure(qmp->pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); ++ ++ if (cfg->has_pwrdn_delay) ++ usleep_range(10, 20); ++ ++ /* Pull PHY out of reset state */ ++ qphy_clrbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); ++ ++ /* start SerDes and Phy-Coding-Sublayer */ ++ qphy_setbits(qmp->pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START); ++ ++ status = qmp->pcs + cfg->regs[QPHY_PCS_STATUS]; ++ ret = readl_poll_timeout(status, val, !(val & PHYSTATUS), 200, ++ PHY_INIT_COMPLETE_TIMEOUT); ++ if (ret) { ++ dev_err(qmp->dev, "phy initialization timed-out\n"); ++ goto err_disable_pipe_clk; ++ } ++ ++ return 0; ++ ++err_disable_pipe_clk: ++ clk_disable_unprepare(qmp->pipe_clk); ++ ++ return ret; ++} ++ ++static int qmp_usbc_power_off(struct phy *phy) ++{ ++ struct qmp_usbc *qmp = phy_get_drvdata(phy); ++ const struct qmp_phy_cfg *cfg = qmp->cfg; ++ ++ clk_disable_unprepare(qmp->pipe_clk); ++ ++ /* PHY reset */ ++ qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); ++ ++ /* stop SerDes and Phy-Coding-Sublayer */ ++ qphy_clrbits(qmp->pcs, cfg->regs[QPHY_START_CTRL], ++ SERDES_START | PCS_START); ++ ++ /* Put PHY into POWER DOWN state: active low */ ++ qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], ++ SW_PWRDN); ++ ++ return 0; ++} ++ ++static int qmp_usbc_enable(struct phy *phy) ++{ ++ struct qmp_usbc *qmp = phy_get_drvdata(phy); ++ int ret; ++ ++ mutex_lock(&qmp->phy_mutex); ++ ++ ret = qmp_usbc_init(phy); ++ if (ret) ++ goto out_unlock; ++ ++ ret = qmp_usbc_power_on(phy); ++ if (ret) { ++ qmp_usbc_exit(phy); ++ goto out_unlock; ++ } ++ ++ qmp->usb_init_count++; ++out_unlock: ++ mutex_unlock(&qmp->phy_mutex); ++ ++ return ret; ++} ++ ++static int qmp_usbc_disable(struct phy *phy) ++{ ++ struct qmp_usbc *qmp = phy_get_drvdata(phy); ++ int ret; ++ ++ qmp->usb_init_count--; ++ ret = qmp_usbc_power_off(phy); ++ if (ret) ++ return ret; ++ return qmp_usbc_exit(phy); ++} ++ ++static int qmp_usbc_set_mode(struct phy *phy, enum phy_mode mode, int submode) ++{ ++ struct qmp_usbc *qmp = phy_get_drvdata(phy); ++ ++ qmp->mode = mode; ++ ++ return 0; ++} ++ ++static const struct phy_ops qmp_usbc_phy_ops = { ++ .init = qmp_usbc_enable, ++ .exit = qmp_usbc_disable, ++ .set_mode = qmp_usbc_set_mode, ++ .owner = THIS_MODULE, ++}; ++ ++static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp) ++{ ++ const struct qmp_phy_cfg *cfg = qmp->cfg; ++ void __iomem *pcs = qmp->pcs; ++ u32 intr_mask; ++ ++ if (qmp->mode == PHY_MODE_USB_HOST_SS || ++ qmp->mode == PHY_MODE_USB_DEVICE_SS) ++ intr_mask = ARCVR_DTCT_EN | ALFPS_DTCT_EN; ++ else ++ intr_mask = ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL; ++ ++ /* Clear any pending interrupts status */ ++ qphy_setbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); ++ /* Writing 1 followed by 0 clears the interrupt */ ++ qphy_clrbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); ++ ++ qphy_clrbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], ++ ARCVR_DTCT_EN | ALFPS_DTCT_EN | ARCVR_DTCT_EVENT_SEL); ++ ++ /* Enable required PHY autonomous mode interrupts */ ++ qphy_setbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], intr_mask); ++ ++ /* Enable i/o clamp_n for autonomous mode */ ++ if (qmp->tcsr_map && qmp->vls_clamp_reg) ++ regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 1); ++} ++ ++static void qmp_usbc_disable_autonomous_mode(struct qmp_usbc *qmp) ++{ ++ const struct qmp_phy_cfg *cfg = qmp->cfg; ++ void __iomem *pcs = qmp->pcs; ++ ++ /* Disable i/o clamp_n on resume for normal mode */ ++ if (qmp->tcsr_map && qmp->vls_clamp_reg) ++ regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 0); ++ ++ qphy_clrbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], ++ ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL | ALFPS_DTCT_EN); ++ ++ qphy_setbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); ++ /* Writing 1 followed by 0 clears the interrupt */ ++ qphy_clrbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); ++} ++ ++static int __maybe_unused qmp_usbc_runtime_suspend(struct device *dev) ++{ ++ struct qmp_usbc *qmp = dev_get_drvdata(dev); ++ ++ dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode); ++ ++ if (!qmp->phy->init_count) { ++ dev_vdbg(dev, "PHY not initialized, bailing out\n"); ++ return 0; ++ } ++ ++ qmp_usbc_enable_autonomous_mode(qmp); ++ ++ clk_disable_unprepare(qmp->pipe_clk); ++ clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); ++ ++ return 0; ++} ++ ++static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev) ++{ ++ struct qmp_usbc *qmp = dev_get_drvdata(dev); ++ int ret = 0; ++ ++ dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode); ++ ++ if (!qmp->phy->init_count) { ++ dev_vdbg(dev, "PHY not initialized, bailing out\n"); ++ return 0; ++ } ++ ++ ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(qmp->pipe_clk); ++ if (ret) { ++ dev_err(dev, "pipe_clk enable failed, err=%d\n", ret); ++ clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); ++ return ret; ++ } ++ ++ qmp_usbc_disable_autonomous_mode(qmp); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops qmp_usbc_pm_ops = { ++ SET_RUNTIME_PM_OPS(qmp_usbc_runtime_suspend, ++ qmp_usbc_runtime_resume, NULL) ++}; ++ ++static int qmp_usbc_vreg_init(struct qmp_usbc *qmp) ++{ ++ const struct qmp_phy_cfg *cfg = qmp->cfg; ++ struct device *dev = qmp->dev; ++ int num = cfg->num_vregs; ++ int i; ++ ++ qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL); ++ if (!qmp->vregs) ++ return -ENOMEM; ++ ++ for (i = 0; i < num; i++) ++ qmp->vregs[i].supply = cfg->vreg_list[i]; ++ ++ return devm_regulator_bulk_get(dev, num, qmp->vregs); ++} ++ ++static int qmp_usbc_reset_init(struct qmp_usbc *qmp, ++ const char *const *reset_list, ++ int num_resets) ++{ ++ struct device *dev = qmp->dev; ++ int i; ++ int ret; ++ ++ qmp->resets = devm_kcalloc(dev, num_resets, ++ sizeof(*qmp->resets), GFP_KERNEL); ++ if (!qmp->resets) ++ return -ENOMEM; ++ ++ for (i = 0; i < num_resets; i++) ++ qmp->resets[i].id = reset_list[i]; ++ ++ qmp->num_resets = num_resets; ++ ++ ret = devm_reset_control_bulk_get_exclusive(dev, num_resets, qmp->resets); ++ if (ret) ++ return dev_err_probe(dev, ret, "failed to get resets\n"); ++ ++ return 0; ++} ++ ++static int qmp_usbc_clk_init(struct qmp_usbc *qmp) ++{ ++ struct device *dev = qmp->dev; ++ int num = ARRAY_SIZE(qmp_usbc_phy_clk_l); ++ int i; ++ ++ qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL); ++ if (!qmp->clks) ++ return -ENOMEM; ++ ++ for (i = 0; i < num; i++) ++ qmp->clks[i].id = qmp_usbc_phy_clk_l[i]; ++ ++ qmp->num_clks = num; ++ ++ return devm_clk_bulk_get_optional(dev, num, qmp->clks); ++} ++ ++static void phy_clk_release_provider(void *res) ++{ ++ of_clk_del_provider(res); ++} ++ ++/* ++ * Register a fixed rate pipe clock. ++ * ++ * The _pipe_clksrc generated by PHY goes to the GCC that gate ++ * controls it. The _pipe_clk coming out of the GCC is requested ++ * by the PHY driver for its operations. ++ * We register the _pipe_clksrc here. The gcc driver takes care ++ * of assigning this _pipe_clksrc as parent to _pipe_clk. ++ * Below picture shows this relationship. ++ * ++ * +---------------+ ++ * | PHY block |<<---------------------------------------+ ++ * | | | ++ * | +-------+ | +-----+ | ++ * I/P---^-->| PLL |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+ ++ * clk | +-------+ | +-----+ ++ * +---------------+ ++ */ ++static int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np) ++{ ++ struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed; ++ struct clk_init_data init = { }; ++ int ret; ++ ++ ret = of_property_read_string(np, "clock-output-names", &init.name); ++ if (ret) { ++ dev_err(qmp->dev, "%pOFn: No clock-output-names\n", np); ++ return ret; ++ } ++ ++ init.ops = &clk_fixed_rate_ops; ++ ++ /* controllers using QMP phys use 125MHz pipe clock interface */ ++ fixed->fixed_rate = 125000000; ++ fixed->hw.init = &init; ++ ++ ret = devm_clk_hw_register(qmp->dev, &fixed->hw); ++ if (ret) ++ return ret; ++ ++ ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &fixed->hw); ++ if (ret) ++ return ret; ++ ++ /* ++ * Roll a devm action because the clock provider is the child node, but ++ * the child node is not actually a device. ++ */ ++ return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, np); ++} ++ ++#if IS_ENABLED(CONFIG_TYPEC) ++static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw, ++ enum typec_orientation orientation) ++{ ++ struct qmp_usbc *qmp = typec_switch_get_drvdata(sw); ++ ++ if (orientation == qmp->orientation || orientation == TYPEC_ORIENTATION_NONE) ++ return 0; ++ ++ mutex_lock(&qmp->phy_mutex); ++ qmp->orientation = orientation; ++ ++ if (qmp->usb_init_count) { ++ qmp_usbc_power_off(qmp->phy); ++ qmp_usbc_exit(qmp->phy); ++ ++ qmp_usbc_init(qmp->phy); ++ qmp_usbc_power_on(qmp->phy); ++ } ++ ++ mutex_unlock(&qmp->phy_mutex); ++ ++ return 0; ++} ++ ++static void qmp_usbc_typec_unregister(void *data) ++{ ++ struct qmp_usbc *qmp = data; ++ ++ typec_switch_unregister(qmp->sw); ++} ++ ++static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp) ++{ ++ struct typec_switch_desc sw_desc = {}; ++ struct device *dev = qmp->dev; ++ ++ sw_desc.drvdata = qmp; ++ sw_desc.fwnode = dev->fwnode; ++ sw_desc.set = qmp_usbc_typec_switch_set; ++ qmp->sw = typec_switch_register(dev, &sw_desc); ++ if (IS_ERR(qmp->sw)) { ++ dev_err(dev, "Unable to register typec switch: %pe\n", qmp->sw); ++ return PTR_ERR(qmp->sw); ++ } ++ ++ return devm_add_action_or_reset(dev, qmp_usbc_typec_unregister, qmp); ++} ++#else ++static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp) ++{ ++ return 0; ++} ++#endif ++ ++static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np) ++{ ++ struct platform_device *pdev = to_platform_device(qmp->dev); ++ struct device *dev = qmp->dev; ++ int ret; ++ ++ qmp->serdes = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(qmp->serdes)) ++ return PTR_ERR(qmp->serdes); ++ ++ /* ++ * Get memory resources for the PHY: ++ * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2. ++ * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5 ++ * For single lane PHYs: pcs_misc (optional) -> 3. ++ */ ++ qmp->tx = devm_of_iomap(dev, np, 0, NULL); ++ if (IS_ERR(qmp->tx)) ++ return PTR_ERR(qmp->tx); ++ ++ qmp->rx = devm_of_iomap(dev, np, 1, NULL); ++ if (IS_ERR(qmp->rx)) ++ return PTR_ERR(qmp->rx); ++ ++ qmp->pcs = devm_of_iomap(dev, np, 2, NULL); ++ if (IS_ERR(qmp->pcs)) ++ return PTR_ERR(qmp->pcs); ++ ++ qmp->tx2 = devm_of_iomap(dev, np, 3, NULL); ++ if (IS_ERR(qmp->tx2)) ++ return PTR_ERR(qmp->tx2); ++ ++ qmp->rx2 = devm_of_iomap(dev, np, 4, NULL); ++ if (IS_ERR(qmp->rx2)) ++ return PTR_ERR(qmp->rx2); ++ ++ qmp->pcs_misc = devm_of_iomap(dev, np, 5, NULL); ++ if (IS_ERR(qmp->pcs_misc)) { ++ dev_vdbg(dev, "PHY pcs_misc-reg not used\n"); ++ qmp->pcs_misc = NULL; ++ } ++ ++ qmp->pipe_clk = devm_get_clk_from_child(dev, np, NULL); ++ if (IS_ERR(qmp->pipe_clk)) { ++ return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk), ++ "failed to get pipe clock\n"); ++ } ++ ++ ret = devm_clk_bulk_get_all(qmp->dev, &qmp->clks); ++ if (ret < 0) ++ return ret; ++ ++ qmp->num_clks = ret; ++ ++ ret = qmp_usbc_reset_init(qmp, usb3phy_legacy_reset_l, ++ ARRAY_SIZE(usb3phy_legacy_reset_l)); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int qmp_usbc_parse_dt(struct qmp_usbc *qmp) ++{ ++ struct platform_device *pdev = to_platform_device(qmp->dev); ++ const struct qmp_phy_cfg *cfg = qmp->cfg; ++ const struct qmp_usbc_offsets *offs = cfg->offsets; ++ struct device *dev = qmp->dev; ++ void __iomem *base; ++ int ret; ++ ++ if (!offs) ++ return -EINVAL; ++ ++ base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ qmp->serdes = base + offs->serdes; ++ qmp->pcs = base + offs->pcs; ++ if (offs->pcs_misc) ++ qmp->pcs_misc = base + offs->pcs_misc; ++ qmp->tx = base + offs->tx; ++ qmp->rx = base + offs->rx; ++ ++ qmp->tx2 = base + offs->tx2; ++ qmp->rx2 = base + offs->rx2; ++ ++ ret = qmp_usbc_clk_init(qmp); ++ if (ret) ++ return ret; ++ ++ qmp->pipe_clk = devm_clk_get(dev, "pipe"); ++ if (IS_ERR(qmp->pipe_clk)) { ++ return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk), ++ "failed to get pipe clock\n"); ++ } ++ ++ ret = qmp_usbc_reset_init(qmp, usb3phy_reset_l, ++ ARRAY_SIZE(usb3phy_reset_l)); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int qmp_usbc_parse_vls_clamp(struct qmp_usbc *qmp) ++{ ++ struct of_phandle_args tcsr_args; ++ struct device *dev = qmp->dev; ++ int ret; ++ ++ /* for backwards compatibility ignore if there is no property */ ++ ret = of_parse_phandle_with_fixed_args(dev->of_node, "qcom,tcsr-reg", 1, 0, ++ &tcsr_args); ++ if (ret == -ENOENT) ++ return 0; ++ else if (ret < 0) ++ return dev_err_probe(dev, ret, "Failed to parse qcom,tcsr-reg\n"); ++ ++ qmp->tcsr_map = syscon_node_to_regmap(tcsr_args.np); ++ of_node_put(tcsr_args.np); ++ if (IS_ERR(qmp->tcsr_map)) ++ return PTR_ERR(qmp->tcsr_map); ++ ++ qmp->vls_clamp_reg = tcsr_args.args[0]; ++ ++ return 0; ++} ++ ++static int qmp_usbc_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct phy_provider *phy_provider; ++ struct device_node *np; ++ struct qmp_usbc *qmp; ++ int ret; ++ ++ qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL); ++ if (!qmp) ++ return -ENOMEM; ++ ++ qmp->dev = dev; ++ ++ qmp->orientation = TYPEC_ORIENTATION_NORMAL; ++ ++ qmp->cfg = of_device_get_match_data(dev); ++ if (!qmp->cfg) ++ return -EINVAL; ++ ++ mutex_init(&qmp->phy_mutex); ++ ++ ret = qmp_usbc_vreg_init(qmp); ++ if (ret) ++ return ret; ++ ++ ret = qmp_usbc_typec_switch_register(qmp); ++ if (ret) ++ return ret; ++ ++ ret = qmp_usbc_parse_vls_clamp(qmp); ++ if (ret) ++ return ret; ++ ++ /* Check for legacy binding with child node. */ ++ np = of_get_child_by_name(dev->of_node, "phy"); ++ if (np) { ++ ret = qmp_usbc_parse_dt_legacy(qmp, np); ++ } else { ++ np = of_node_get(dev->of_node); ++ ret = qmp_usbc_parse_dt(qmp); ++ } ++ if (ret) ++ goto err_node_put; ++ ++ pm_runtime_set_active(dev); ++ ret = devm_pm_runtime_enable(dev); ++ if (ret) ++ goto err_node_put; ++ /* ++ * Prevent runtime pm from being ON by default. Users can enable ++ * it using power/control in sysfs. ++ */ ++ pm_runtime_forbid(dev); ++ ++ ret = phy_pipe_clk_register(qmp, np); ++ if (ret) ++ goto err_node_put; ++ ++ qmp->phy = devm_phy_create(dev, np, &qmp_usbc_phy_ops); ++ if (IS_ERR(qmp->phy)) { ++ ret = PTR_ERR(qmp->phy); ++ dev_err(dev, "failed to create PHY: %d\n", ret); ++ goto err_node_put; ++ } ++ ++ phy_set_drvdata(qmp->phy, qmp); ++ ++ of_node_put(np); ++ ++ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); ++ ++ return PTR_ERR_OR_ZERO(phy_provider); ++ ++err_node_put: ++ of_node_put(np); ++ return ret; ++} ++ ++static const struct of_device_id qmp_usbc_of_match_table[] = { ++ { ++ .compatible = "qcom,msm8998-qmp-usb3-phy", ++ .data = &msm8998_usb3phy_cfg, ++ }, { ++ .compatible = "qcom,qcm2290-qmp-usb3-phy", ++ .data = &qcm2290_usb3phy_cfg, ++ }, { ++ .compatible = "qcom,sm6115-qmp-usb3-phy", ++ .data = &qcm2290_usb3phy_cfg, ++ }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, qmp_usbc_of_match_table); ++ ++static struct platform_driver qmp_usbc_driver = { ++ .probe = qmp_usbc_probe, ++ .driver = { ++ .name = "qcom-qmp-usbc-phy", ++ .pm = &qmp_usbc_pm_ops, ++ .of_match_table = qmp_usbc_of_match_table, ++ }, ++}; ++ ++module_platform_driver(qmp_usbc_driver); ++ ++MODULE_AUTHOR("Vivek Gautam "); ++MODULE_DESCRIPTION("Qualcomm QMP USB-C PHY driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8186.c b/drivers/pinctrl/mediatek/pinctrl-mt8186.c +index 7be591591cce5..dd19e74856a92 100644 +--- a/drivers/pinctrl/mediatek/pinctrl-mt8186.c ++++ b/drivers/pinctrl/mediatek/pinctrl-mt8186.c +@@ -1198,7 +1198,6 @@ static const struct mtk_pin_reg_calc mt8186_reg_cals[PINCTRL_PIN_REG_MAX] = { + [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt8186_pin_dir_range), + [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt8186_pin_di_range), + [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt8186_pin_do_range), +- [PINCTRL_PIN_REG_SR] = MTK_RANGE(mt8186_pin_dir_range), + [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt8186_pin_smt_range), + [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt8186_pin_ies_range), + [PINCTRL_PIN_REG_PU] = MTK_RANGE(mt8186_pin_pu_range), +diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8192.c b/drivers/pinctrl/mediatek/pinctrl-mt8192.c +index e3a76381f7f4e..3f8a9dbcb7041 100644 +--- a/drivers/pinctrl/mediatek/pinctrl-mt8192.c ++++ b/drivers/pinctrl/mediatek/pinctrl-mt8192.c +@@ -1379,7 +1379,6 @@ static const struct mtk_pin_reg_calc mt8192_reg_cals[PINCTRL_PIN_REG_MAX] = { + [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt8192_pin_dir_range), + [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt8192_pin_di_range), + [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt8192_pin_do_range), +- [PINCTRL_PIN_REG_SR] = MTK_RANGE(mt8192_pin_dir_range), + [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt8192_pin_smt_range), + [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt8192_pin_ies_range), + [PINCTRL_PIN_REG_PU] = MTK_RANGE(mt8192_pin_pu_range), +diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c +index 7911353ac97d5..4f7c4af4f93cb 100644 +--- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c ++++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c +@@ -1579,8 +1579,10 @@ static int nmk_pmx_set(struct pinctrl_dev *pctldev, unsigned function, + * Then mask the pins that need to be sleeping now when we're + * switching to the ALT C function. + */ +- for (i = 0; i < g->grp.npins; i++) +- slpm[g->grp.pins[i] / NMK_GPIO_PER_CHIP] &= ~BIT(g->grp.pins[i]); ++ for (i = 0; i < g->grp.npins; i++) { ++ unsigned int bit = g->grp.pins[i] % NMK_GPIO_PER_CHIP; ++ slpm[g->grp.pins[i] / NMK_GPIO_PER_CHIP] &= ~BIT(bit); ++ } + nmk_gpio_glitch_slpm_init(slpm); + } + +diff --git a/drivers/pinctrl/renesas/core.c b/drivers/pinctrl/renesas/core.c +index 93e51abbf519a..d1e92bbed33ad 100644 +--- a/drivers/pinctrl/renesas/core.c ++++ b/drivers/pinctrl/renesas/core.c +@@ -731,10 +731,12 @@ static int sh_pfc_resume_noirq(struct device *dev) + sh_pfc_walk_regs(pfc, sh_pfc_restore_reg); + return 0; + } ++#define pm_psci_sleep_ptr(_ptr) pm_sleep_ptr(_ptr) + #else + static int sh_pfc_suspend_init(struct sh_pfc *pfc) { return 0; } + static int sh_pfc_suspend_noirq(struct device *dev) { return 0; } + static int sh_pfc_resume_noirq(struct device *dev) { return 0; } ++#define pm_psci_sleep_ptr(_ptr) PTR_IF(false, (_ptr)) + #endif /* CONFIG_ARM_PSCI_FW */ + + static DEFINE_NOIRQ_DEV_PM_OPS(sh_pfc_pm, sh_pfc_suspend_noirq, sh_pfc_resume_noirq); +@@ -1415,7 +1417,7 @@ static struct platform_driver sh_pfc_driver = { + .driver = { + .name = DRV_NAME, + .of_match_table = of_match_ptr(sh_pfc_of_table), +- .pm = pm_sleep_ptr(&sh_pfc_pm), ++ .pm = pm_psci_sleep_ptr(&sh_pfc_pm), + }, + }; + +diff --git a/drivers/pinctrl/renesas/pfc-r8a779g0.c b/drivers/pinctrl/renesas/pfc-r8a779g0.c +index acdea6ac15253..d2de526a3b588 100644 +--- a/drivers/pinctrl/renesas/pfc-r8a779g0.c ++++ b/drivers/pinctrl/renesas/pfc-r8a779g0.c +@@ -2384,6 +2384,14 @@ static const unsigned int scif_clk_mux[] = { + SCIF_CLK_MARK, + }; + ++static const unsigned int scif_clk2_pins[] = { ++ /* SCIF_CLK2 */ ++ RCAR_GP_PIN(8, 11), ++}; ++static const unsigned int scif_clk2_mux[] = { ++ SCIF_CLK2_MARK, ++}; ++ + /* - SSI ------------------------------------------------- */ + static const unsigned int ssi_data_pins[] = { + /* SSI_SD */ +@@ -2694,6 +2702,7 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { + SH_PFC_PIN_GROUP(scif4_clk), + SH_PFC_PIN_GROUP(scif4_ctrl), + SH_PFC_PIN_GROUP(scif_clk), ++ SH_PFC_PIN_GROUP(scif_clk2), + + SH_PFC_PIN_GROUP(ssi_data), + SH_PFC_PIN_GROUP(ssi_ctrl), +@@ -3015,6 +3024,10 @@ static const char * const scif_clk_groups[] = { + "scif_clk", + }; + ++static const char * const scif_clk2_groups[] = { ++ "scif_clk2", ++}; ++ + static const char * const ssi_groups[] = { + "ssi_data", + "ssi_ctrl", +@@ -3102,6 +3115,7 @@ static const struct sh_pfc_function pinmux_functions[] = { + SH_PFC_FUNCTION(scif3), + SH_PFC_FUNCTION(scif4), + SH_PFC_FUNCTION(scif_clk), ++ SH_PFC_FUNCTION(scif_clk2), + + SH_PFC_FUNCTION(ssi), + +diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c +index 80fb5011c7bbc..01ef6921cb35c 100644 +--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c ++++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c +@@ -447,6 +447,16 @@ static int rzg2l_dt_subnode_to_map(struct pinctrl_dev *pctldev, + name = np->name; + } + ++ if (num_configs) { ++ ret = rzg2l_map_add_config(&maps[idx], name, ++ PIN_MAP_TYPE_CONFIGS_GROUP, ++ configs, num_configs); ++ if (ret < 0) ++ goto done; ++ ++ idx++; ++ } ++ + mutex_lock(&pctrl->mutex); + + /* Register a single pin group listing all the pins we read from DT */ +@@ -474,16 +484,6 @@ static int rzg2l_dt_subnode_to_map(struct pinctrl_dev *pctldev, + maps[idx].data.mux.function = name; + idx++; + +- if (num_configs) { +- ret = rzg2l_map_add_config(&maps[idx], name, +- PIN_MAP_TYPE_CONFIGS_GROUP, +- configs, num_configs); +- if (ret < 0) +- goto remove_group; +- +- idx++; +- } +- + dev_dbg(pctrl->dev, "Parsed %pOF with %d pins\n", np, num_pinmux); + ret = 0; + goto done; +diff --git a/drivers/platform/x86/amd/pmf/tee-if.c b/drivers/platform/x86/amd/pmf/tee-if.c +index dcbe8f85e1229..4ebfe0f5a7fb2 100644 +--- a/drivers/platform/x86/amd/pmf/tee-if.c ++++ b/drivers/platform/x86/amd/pmf/tee-if.c +@@ -249,8 +249,8 @@ static int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev) + u32 cookie, length; + int res; + +- cookie = readl(dev->policy_buf + POLICY_COOKIE_OFFSET); +- length = readl(dev->policy_buf + POLICY_COOKIE_LEN); ++ cookie = *(u32 *)(dev->policy_buf + POLICY_COOKIE_OFFSET); ++ length = *(u32 *)(dev->policy_buf + POLICY_COOKIE_LEN); + + if (cookie != POLICY_SIGN_COOKIE || !length) { + dev_dbg(dev->dev, "cookie doesn't match\n"); +diff --git a/drivers/platform/x86/intel/pmc/arl.c b/drivers/platform/x86/intel/pmc/arl.c +index 683ae828276b8..34b4cd23bfe59 100644 +--- a/drivers/platform/x86/intel/pmc/arl.c ++++ b/drivers/platform/x86/intel/pmc/arl.c +@@ -673,6 +673,7 @@ static struct pmc_info arl_pmc_info_list[] = { + }; + + #define ARL_NPU_PCI_DEV 0xad1d ++#define ARL_GNA_PCI_DEV 0xae4c + /* + * Set power state of select devices that do not have drivers to D3 + * so that they do not block Package C entry. +@@ -680,6 +681,7 @@ static struct pmc_info arl_pmc_info_list[] = { + static void arl_d3_fixup(void) + { + pmc_core_set_device_d3(ARL_NPU_PCI_DEV); ++ pmc_core_set_device_d3(ARL_GNA_PCI_DEV); + } + + static int arl_resume(struct pmc_dev *pmcdev) +diff --git a/drivers/platform/x86/intel/pmc/lnl.c b/drivers/platform/x86/intel/pmc/lnl.c +index abad17cdd3d78..068d72504683f 100644 +--- a/drivers/platform/x86/intel/pmc/lnl.c ++++ b/drivers/platform/x86/intel/pmc/lnl.c +@@ -13,21 +13,6 @@ + + #include "core.h" + +-#define SOCM_LPM_REQ_GUID 0x11594920 +- +-#define PMC_DEVID_SOCM 0xa87f +- +-static const u8 LNL_LPM_REG_INDEX[] = {0, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20}; +- +-static struct pmc_info lnl_pmc_info_list[] = { +- { +- .guid = SOCM_LPM_REQ_GUID, +- .devid = PMC_DEVID_SOCM, +- .map = &lnl_socm_reg_map, +- }, +- {} +-}; +- + const struct pmc_bit_map lnl_ltr_show_map[] = { + {"SOUTHPORT_A", CNP_PMC_LTR_SPA}, + {"SOUTHPORT_B", CNP_PMC_LTR_SPB}, +@@ -490,7 +475,6 @@ const struct pmc_reg_map lnl_socm_reg_map = { + .lpm_sts = lnl_lpm_maps, + .lpm_status_offset = MTL_LPM_STATUS_OFFSET, + .lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET, +- .lpm_reg_index = LNL_LPM_REG_INDEX, + }; + + #define LNL_NPU_PCI_DEV 0x643e +@@ -517,33 +501,19 @@ static int lnl_resume(struct pmc_dev *pmcdev) + int lnl_core_init(struct pmc_dev *pmcdev) + { + int ret; +- int func = 2; +- bool ssram_init = true; + struct pmc *pmc = pmcdev->pmcs[PMC_IDX_SOC]; + + lnl_d3_fixup(); + + pmcdev->suspend = cnl_suspend; + pmcdev->resume = lnl_resume; +- pmcdev->regmap_list = lnl_pmc_info_list; +- ret = pmc_core_ssram_init(pmcdev, func); +- +- /* If regbase not assigned, set map and discover using legacy method */ +- if (ret) { +- ssram_init = false; +- pmc->map = &lnl_socm_reg_map; +- ret = get_primary_reg_base(pmc); +- if (ret) +- return ret; +- } + +- pmc_core_get_low_power_modes(pmcdev); ++ pmc->map = &lnl_socm_reg_map; ++ ret = get_primary_reg_base(pmc); ++ if (ret) ++ return ret; + +- if (ssram_init) { +- ret = pmc_core_ssram_get_lpm_reqs(pmcdev); +- if (ret) +- return ret; +- } ++ pmc_core_get_low_power_modes(pmcdev); + + return 0; + } +diff --git a/drivers/pmdomain/qcom/rpmhpd.c b/drivers/pmdomain/qcom/rpmhpd.c +index 47df910645f66..de9121ef4216b 100644 +--- a/drivers/pmdomain/qcom/rpmhpd.c ++++ b/drivers/pmdomain/qcom/rpmhpd.c +@@ -217,7 +217,6 @@ static struct rpmhpd *sa8540p_rpmhpds[] = { + [SC8280XP_CX] = &cx, + [SC8280XP_CX_AO] = &cx_ao, + [SC8280XP_EBI] = &ebi, +- [SC8280XP_GFX] = &gfx, + [SC8280XP_LCX] = &lcx, + [SC8280XP_LMX] = &lmx, + [SC8280XP_MMCX] = &mmcx, +diff --git a/drivers/power/supply/mm8013.c b/drivers/power/supply/mm8013.c +index caa272b035649..20c1651ca38e0 100644 +--- a/drivers/power/supply/mm8013.c ++++ b/drivers/power/supply/mm8013.c +@@ -71,7 +71,6 @@ static int mm8013_checkdevice(struct mm8013_chip *chip) + + static enum power_supply_property mm8013_battery_props[] = { + POWER_SUPPLY_PROP_CAPACITY, +- POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_NOW, +@@ -103,16 +102,6 @@ static int mm8013_get_property(struct power_supply *psy, + + val->intval = regval; + break; +- case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: +- ret = regmap_read(chip->regmap, REG_FLAGS, ®val); +- if (ret < 0) +- return ret; +- +- if (regval & MM8013_FLAG_CHG_INH) +- val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE; +- else +- val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO; +- break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + ret = regmap_read(chip->regmap, REG_FULL_CHARGE_CAPACITY, ®val); + if (ret < 0) +@@ -187,6 +176,8 @@ static int mm8013_get_property(struct power_supply *psy, + + if (regval & MM8013_FLAG_DSG) + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; ++ else if (regval & MM8013_FLAG_CHG_INH) ++ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + else if (regval & MM8013_FLAG_CHG) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else if (regval & MM8013_FLAG_FC) +diff --git a/drivers/powercap/dtpm_cpu.c b/drivers/powercap/dtpm_cpu.c +index 9193c3b8edebe..ae7ee611978ba 100644 +--- a/drivers/powercap/dtpm_cpu.c ++++ b/drivers/powercap/dtpm_cpu.c +@@ -219,7 +219,7 @@ static int __dtpm_cpu_setup(int cpu, struct dtpm *parent) + ret = freq_qos_add_request(&policy->constraints, + &dtpm_cpu->qos_req, FREQ_QOS_MAX, + pd->table[pd->nr_perf_states - 1].frequency); +- if (ret) ++ if (ret < 0) + goto out_dtpm_unregister; + + cpufreq_cpu_put(policy); +diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c +index 3f2c5031a3ba8..1f6fc9a9fcf3e 100644 +--- a/drivers/pwm/pwm-atmel-hlcdc.c ++++ b/drivers/pwm/pwm-atmel-hlcdc.c +@@ -185,7 +185,7 @@ static int atmel_hlcdc_pwm_suspend(struct device *dev) + struct atmel_hlcdc_pwm *atmel = dev_get_drvdata(dev); + + /* Keep the periph clock enabled if the PWM is still running. */ +- if (pwm_is_enabled(&atmel->chip.pwms[0])) ++ if (!pwm_is_enabled(&atmel->chip.pwms[0])) + clk_disable_unprepare(atmel->hlcdc->periph_clk); + + return 0; +diff --git a/drivers/pwm/pwm-dwc.c b/drivers/pwm/pwm-dwc.c +index 4929354f8cd95..a4a057ae03ea2 100644 +--- a/drivers/pwm/pwm-dwc.c ++++ b/drivers/pwm/pwm-dwc.c +@@ -120,7 +120,7 @@ static struct pci_driver dwc_pwm_driver = { + .remove = dwc_pwm_remove, + .id_table = dwc_pwm_id_table, + .driver = { +- .pm = pm_ptr(&dwc_pwm_pm_ops), ++ .pm = pm_sleep_ptr(&dwc_pwm_pm_ops), + }, + }; + +diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c +index 6cf55cf34d39f..69b1113c6b821 100644 +--- a/drivers/pwm/pwm-sti.c ++++ b/drivers/pwm/pwm-sti.c +@@ -395,8 +395,17 @@ static int sti_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm, + static int sti_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) + { ++ struct sti_pwm_chip *pc = to_sti_pwmchip(chip); ++ struct sti_pwm_compat_data *cdata = pc->cdata; ++ struct device *dev = pc->dev; + int err; + ++ if (pwm->hwpwm >= cdata->pwm_num_devs) { ++ dev_err(dev, "device %u is not valid for pwm mode\n", ++ pwm->hwpwm); ++ return -EINVAL; ++ } ++ + if (state->polarity != PWM_POLARITY_NORMAL) + return -EINVAL; + +@@ -646,7 +655,7 @@ static int sti_pwm_probe(struct platform_device *pdev) + + pc->chip.dev = dev; + pc->chip.ops = &sti_pwm_ops; +- pc->chip.npwm = pc->cdata->pwm_num_devs; ++ pc->chip.npwm = max(cdata->pwm_num_devs, cdata->cpt_num_devs); + + for (i = 0; i < cdata->cpt_num_devs; i++) { + struct sti_cpt_ddata *ddata = &cdata->ddata[i]; +diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c +index 53d1b9d6f69c5..86a626a4f610a 100644 +--- a/drivers/regulator/userspace-consumer.c ++++ b/drivers/regulator/userspace-consumer.c +@@ -208,6 +208,7 @@ static const struct of_device_id regulator_userspace_consumer_of_match[] = { + { .compatible = "regulator-output", }, + {}, + }; ++MODULE_DEVICE_TABLE(of, regulator_userspace_consumer_of_match); + + static struct platform_driver regulator_userspace_consumer_driver = { + .probe = regulator_userspace_consumer_probe, +diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c +index 4f469f0bcf8b2..10b442c6f6323 100644 +--- a/drivers/remoteproc/stm32_rproc.c ++++ b/drivers/remoteproc/stm32_rproc.c +@@ -120,7 +120,7 @@ static int stm32_rproc_mem_alloc(struct rproc *rproc, + void *va; + + dev_dbg(dev, "map memory: %pad+%zx\n", &mem->dma, mem->len); +- va = ioremap_wc(mem->dma, mem->len); ++ va = (__force void *)ioremap_wc(mem->dma, mem->len); + if (IS_ERR_OR_NULL(va)) { + dev_err(dev, "Unable to map memory region: %pad+0x%zx\n", + &mem->dma, mem->len); +@@ -137,7 +137,7 @@ static int stm32_rproc_mem_release(struct rproc *rproc, + struct rproc_mem_entry *mem) + { + dev_dbg(rproc->dev.parent, "unmap memory: %pa\n", &mem->dma); +- iounmap(mem->va); ++ iounmap((__force __iomem void *)mem->va); + + return 0; + } +@@ -657,7 +657,7 @@ stm32_rproc_get_loaded_rsc_table(struct rproc *rproc, size_t *table_sz) + * entire area by overwriting it with the initial values stored in rproc->clean_table. + */ + *table_sz = RSC_TBL_SIZE; +- return (struct resource_table *)ddata->rsc_va; ++ return (__force struct resource_table *)ddata->rsc_va; + } + + static const struct rproc_ops st_rproc_ops = { +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index e37a4341f442d..c63e32d012f23 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1858,7 +1858,8 @@ config RTC_DRV_MT2712 + + config RTC_DRV_MT6397 + tristate "MediaTek PMIC based RTC" +- depends on MFD_MT6397 || (COMPILE_TEST && IRQ_DOMAIN) ++ depends on MFD_MT6397 || COMPILE_TEST ++ select IRQ_DOMAIN + help + This selects the MediaTek(R) RTC driver. RTC is part of MediaTek + MT6397 PMIC. You should enable MT6397 PMIC MFD before select +diff --git a/drivers/rtc/lib_test.c b/drivers/rtc/lib_test.c +index d5caf36c56cdc..225c859d6da55 100644 +--- a/drivers/rtc/lib_test.c ++++ b/drivers/rtc/lib_test.c +@@ -54,7 +54,7 @@ static void rtc_time64_to_tm_test_date_range(struct kunit *test) + + days = div_s64(secs, 86400); + +- #define FAIL_MSG "%d/%02d/%02d (%2d) : %ld", \ ++ #define FAIL_MSG "%d/%02d/%02d (%2d) : %lld", \ + year, month, mday, yday, days + + KUNIT_ASSERT_EQ_MSG(test, year - 1900, result.tm_year, FAIL_MSG); +diff --git a/drivers/rtc/rtc-max31335.c b/drivers/rtc/rtc-max31335.c +index 402fda8fd5488..a2441e5c2c74d 100644 +--- a/drivers/rtc/rtc-max31335.c ++++ b/drivers/rtc/rtc-max31335.c +@@ -204,7 +204,7 @@ static bool max31335_volatile_reg(struct device *dev, unsigned int reg) + return true; + + /* interrupt status register */ +- if (reg == MAX31335_INT_EN1_A1IE) ++ if (reg == MAX31335_STATUS1) + return true; + + /* temperature registers */ +diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c +index 7327e81352e9c..30851faade97b 100644 +--- a/drivers/s390/block/dasd.c ++++ b/drivers/s390/block/dasd.c +@@ -8,9 +8,6 @@ + * Copyright IBM Corp. 1999, 2009 + */ + +-#define KMSG_COMPONENT "dasd" +-#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +- + #include + #include + #include +@@ -3402,8 +3399,7 @@ static void dasd_generic_auto_online(void *data, async_cookie_t cookie) + + ret = ccw_device_set_online(cdev); + if (ret) +- pr_warn("%s: Setting the DASD online failed with rc=%d\n", +- dev_name(&cdev->dev), ret); ++ dev_warn(&cdev->dev, "Setting the DASD online failed with rc=%d\n", ret); + } + + /* +@@ -3490,8 +3486,11 @@ int dasd_generic_set_online(struct ccw_device *cdev, + { + struct dasd_discipline *discipline; + struct dasd_device *device; ++ struct device *dev; + int rc; + ++ dev = &cdev->dev; ++ + /* first online clears initial online feature flag */ + dasd_set_feature(cdev, DASD_FEATURE_INITIAL_ONLINE, 0); + device = dasd_create_device(cdev); +@@ -3504,11 +3503,10 @@ int dasd_generic_set_online(struct ccw_device *cdev, + /* Try to load the required module. */ + rc = request_module(DASD_DIAG_MOD); + if (rc) { +- pr_warn("%s Setting the DASD online failed " +- "because the required module %s " +- "could not be loaded (rc=%d)\n", +- dev_name(&cdev->dev), DASD_DIAG_MOD, +- rc); ++ dev_warn(dev, "Setting the DASD online failed " ++ "because the required module %s " ++ "could not be loaded (rc=%d)\n", ++ DASD_DIAG_MOD, rc); + dasd_delete_device(device); + return -ENODEV; + } +@@ -3516,8 +3514,7 @@ int dasd_generic_set_online(struct ccw_device *cdev, + /* Module init could have failed, so check again here after + * request_module(). */ + if (!dasd_diag_discipline_pointer) { +- pr_warn("%s Setting the DASD online failed because of missing DIAG discipline\n", +- dev_name(&cdev->dev)); ++ dev_warn(dev, "Setting the DASD online failed because of missing DIAG discipline\n"); + dasd_delete_device(device); + return -ENODEV; + } +@@ -3527,37 +3524,33 @@ int dasd_generic_set_online(struct ccw_device *cdev, + dasd_delete_device(device); + return -EINVAL; + } ++ device->base_discipline = base_discipline; + if (!try_module_get(discipline->owner)) { +- module_put(base_discipline->owner); + dasd_delete_device(device); + return -EINVAL; + } +- device->base_discipline = base_discipline; + device->discipline = discipline; + + /* check_device will allocate block device if necessary */ + rc = discipline->check_device(device); + if (rc) { +- pr_warn("%s Setting the DASD online with discipline %s failed with rc=%i\n", +- dev_name(&cdev->dev), discipline->name, rc); +- module_put(discipline->owner); +- module_put(base_discipline->owner); ++ dev_warn(dev, "Setting the DASD online with discipline %s failed with rc=%i\n", ++ discipline->name, rc); + dasd_delete_device(device); + return rc; + } + + dasd_set_target_state(device, DASD_STATE_ONLINE); + if (device->state <= DASD_STATE_KNOWN) { +- pr_warn("%s Setting the DASD online failed because of a missing discipline\n", +- dev_name(&cdev->dev)); ++ dev_warn(dev, "Setting the DASD online failed because of a missing discipline\n"); + rc = -ENODEV; + dasd_set_target_state(device, DASD_STATE_NEW); + if (device->block) + dasd_free_block(device->block); + dasd_delete_device(device); +- } else +- pr_debug("dasd_generic device %s found\n", +- dev_name(&cdev->dev)); ++ } else { ++ dev_dbg(dev, "dasd_generic device found\n"); ++ } + + wait_event(dasd_init_waitq, _wait_for_device(device)); + +@@ -3568,10 +3561,13 @@ EXPORT_SYMBOL_GPL(dasd_generic_set_online); + + int dasd_generic_set_offline(struct ccw_device *cdev) + { ++ int max_count, open_count, rc; + struct dasd_device *device; + struct dasd_block *block; +- int max_count, open_count, rc; + unsigned long flags; ++ struct device *dev; ++ ++ dev = &cdev->dev; + + rc = 0; + spin_lock_irqsave(get_ccwdev_lock(cdev), flags); +@@ -3592,11 +3588,10 @@ int dasd_generic_set_offline(struct ccw_device *cdev) + open_count = atomic_read(&device->block->open_count); + if (open_count > max_count) { + if (open_count > 0) +- pr_warn("%s: The DASD cannot be set offline with open count %i\n", +- dev_name(&cdev->dev), open_count); ++ dev_warn(dev, "The DASD cannot be set offline with open count %i\n", ++ open_count); + else +- pr_warn("%s: The DASD cannot be set offline while it is in use\n", +- dev_name(&cdev->dev)); ++ dev_warn(dev, "The DASD cannot be set offline while it is in use\n"); + rc = -EBUSY; + goto out_err; + } +@@ -3956,8 +3951,8 @@ static int dasd_handle_autoquiesce(struct dasd_device *device, + if (dasd_eer_enabled(device)) + dasd_eer_write(device, NULL, DASD_EER_AUTOQUIESCE); + +- pr_info("%s: The DASD has been put in the quiesce state\n", +- dev_name(&device->cdev->dev)); ++ dev_info(&device->cdev->dev, ++ "The DASD has been put in the quiesce state\n"); + dasd_device_set_stop_bits(device, DASD_STOPPED_QUIESCE); + + if (device->features & DASD_FEATURE_REQUEUEQUIESCE) +diff --git a/drivers/scsi/bfa/bfa.h b/drivers/scsi/bfa/bfa.h +index 7bd2ba1ad4d11..f30fe324e6ecc 100644 +--- a/drivers/scsi/bfa/bfa.h ++++ b/drivers/scsi/bfa/bfa.h +@@ -20,7 +20,6 @@ + struct bfa_s; + + typedef void (*bfa_isr_func_t) (struct bfa_s *bfa, struct bfi_msg_s *m); +-typedef void (*bfa_cb_cbfn_status_t) (void *cbarg, bfa_status_t status); + + /* + * Interrupt message handlers +@@ -437,4 +436,12 @@ struct bfa_cb_pending_q_s { + (__qe)->data = (__data); \ + } while (0) + ++#define bfa_pending_q_init_status(__qe, __cbfn, __cbarg, __data) do { \ ++ bfa_q_qe_init(&((__qe)->hcb_qe.qe)); \ ++ (__qe)->hcb_qe.cbfn_status = (__cbfn); \ ++ (__qe)->hcb_qe.cbarg = (__cbarg); \ ++ (__qe)->hcb_qe.pre_rmv = BFA_TRUE; \ ++ (__qe)->data = (__data); \ ++} while (0) ++ + #endif /* __BFA_H__ */ +diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c +index 6846ca8f7313c..3438d0b8ba062 100644 +--- a/drivers/scsi/bfa/bfa_core.c ++++ b/drivers/scsi/bfa/bfa_core.c +@@ -1907,15 +1907,13 @@ bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q) + struct list_head *qe; + struct list_head *qen; + struct bfa_cb_qe_s *hcb_qe; +- bfa_cb_cbfn_status_t cbfn; + + list_for_each_safe(qe, qen, comp_q) { + hcb_qe = (struct bfa_cb_qe_s *) qe; + if (hcb_qe->pre_rmv) { + /* qe is invalid after return, dequeue before cbfn() */ + list_del(qe); +- cbfn = (bfa_cb_cbfn_status_t)(hcb_qe->cbfn); +- cbfn(hcb_qe->cbarg, hcb_qe->fw_status); ++ hcb_qe->cbfn_status(hcb_qe->cbarg, hcb_qe->fw_status); + } else + hcb_qe->cbfn(hcb_qe->cbarg, BFA_TRUE); + } +diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h +index 933a1c3890ff5..5e568d6d7b261 100644 +--- a/drivers/scsi/bfa/bfa_ioc.h ++++ b/drivers/scsi/bfa/bfa_ioc.h +@@ -361,14 +361,18 @@ struct bfa_reqq_wait_s { + void *cbarg; + }; + +-typedef void (*bfa_cb_cbfn_t) (void *cbarg, bfa_boolean_t complete); ++typedef void (*bfa_cb_cbfn_t) (void *cbarg, bfa_boolean_t complete); ++typedef void (*bfa_cb_cbfn_status_t) (void *cbarg, bfa_status_t status); + + /* + * Generic BFA callback element. + */ + struct bfa_cb_qe_s { + struct list_head qe; +- bfa_cb_cbfn_t cbfn; ++ union { ++ bfa_cb_cbfn_status_t cbfn_status; ++ bfa_cb_cbfn_t cbfn; ++ }; + bfa_boolean_t once; + bfa_boolean_t pre_rmv; /* set for stack based qe(s) */ + bfa_status_t fw_status; /* to access fw status in comp proc */ +diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c +index d4ceca2d435ee..54bd11e6d5933 100644 +--- a/drivers/scsi/bfa/bfad_bsg.c ++++ b/drivers/scsi/bfa/bfad_bsg.c +@@ -2135,8 +2135,7 @@ bfad_iocmd_fcport_get_stats(struct bfad_s *bfad, void *cmd) + struct bfa_cb_pending_q_s cb_qe; + + init_completion(&fcomp.comp); +- bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp, +- &fcomp, &iocmd->stats); ++ bfa_pending_q_init_status(&cb_qe, bfad_hcb_comp, &fcomp, &iocmd->stats); + spin_lock_irqsave(&bfad->bfad_lock, flags); + iocmd->status = bfa_fcport_get_stats(&bfad->bfa, &cb_qe); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); +@@ -2159,7 +2158,7 @@ bfad_iocmd_fcport_reset_stats(struct bfad_s *bfad, void *cmd) + struct bfa_cb_pending_q_s cb_qe; + + init_completion(&fcomp.comp); +- bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp, &fcomp, NULL); ++ bfa_pending_q_init_status(&cb_qe, bfad_hcb_comp, &fcomp, NULL); + + spin_lock_irqsave(&bfad->bfad_lock, flags); + iocmd->status = bfa_fcport_clear_stats(&bfad->bfa, &cb_qe); +@@ -2443,8 +2442,7 @@ bfad_iocmd_qos_get_stats(struct bfad_s *bfad, void *cmd) + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa); + + init_completion(&fcomp.comp); +- bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp, +- &fcomp, &iocmd->stats); ++ bfa_pending_q_init_status(&cb_qe, bfad_hcb_comp, &fcomp, &iocmd->stats); + + spin_lock_irqsave(&bfad->bfad_lock, flags); + WARN_ON(!bfa_ioc_get_fcmode(&bfad->bfa.ioc)); +@@ -2474,8 +2472,7 @@ bfad_iocmd_qos_reset_stats(struct bfad_s *bfad, void *cmd) + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa); + + init_completion(&fcomp.comp); +- bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp, +- &fcomp, NULL); ++ bfa_pending_q_init_status(&cb_qe, bfad_hcb_comp, &fcomp, NULL); + + spin_lock_irqsave(&bfad->bfad_lock, flags); + WARN_ON(!bfa_ioc_get_fcmode(&bfad->bfa.ioc)); +diff --git a/drivers/scsi/csiostor/csio_defs.h b/drivers/scsi/csiostor/csio_defs.h +index c38017b4af982..e50e93e7fe5a1 100644 +--- a/drivers/scsi/csiostor/csio_defs.h ++++ b/drivers/scsi/csiostor/csio_defs.h +@@ -73,7 +73,21 @@ csio_list_deleted(struct list_head *list) + #define csio_list_prev(elem) (((struct list_head *)(elem))->prev) + + /* State machine */ +-typedef void (*csio_sm_state_t)(void *, uint32_t); ++struct csio_lnode; ++ ++/* State machine evets */ ++enum csio_ln_ev { ++ CSIO_LNE_NONE = (uint32_t)0, ++ CSIO_LNE_LINKUP, ++ CSIO_LNE_FAB_INIT_DONE, ++ CSIO_LNE_LINK_DOWN, ++ CSIO_LNE_DOWN_LINK, ++ CSIO_LNE_LOGO, ++ CSIO_LNE_CLOSE, ++ CSIO_LNE_MAX_EVENT, ++}; ++ ++typedef void (*csio_sm_state_t)(struct csio_lnode *ln, enum csio_ln_ev evt); + + struct csio_sm { + struct list_head sm_list; +@@ -83,7 +97,7 @@ struct csio_sm { + static inline void + csio_set_state(void *smp, void *state) + { +- ((struct csio_sm *)smp)->sm_state = (csio_sm_state_t)state; ++ ((struct csio_sm *)smp)->sm_state = state; + } + + static inline void +diff --git a/drivers/scsi/csiostor/csio_lnode.c b/drivers/scsi/csiostor/csio_lnode.c +index d5ac938970232..5b3ffefae476d 100644 +--- a/drivers/scsi/csiostor/csio_lnode.c ++++ b/drivers/scsi/csiostor/csio_lnode.c +@@ -1095,7 +1095,7 @@ csio_handle_link_down(struct csio_hw *hw, uint8_t portid, uint32_t fcfi, + int + csio_is_lnode_ready(struct csio_lnode *ln) + { +- return (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_ready)); ++ return (csio_get_state(ln) == csio_lns_ready); + } + + /*****************************************************************************/ +@@ -1366,15 +1366,15 @@ csio_free_fcfinfo(struct kref *kref) + void + csio_lnode_state_to_str(struct csio_lnode *ln, int8_t *str) + { +- if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_uninit)) { ++ if (csio_get_state(ln) == csio_lns_uninit) { + strcpy(str, "UNINIT"); + return; + } +- if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_ready)) { ++ if (csio_get_state(ln) == csio_lns_ready) { + strcpy(str, "READY"); + return; + } +- if (csio_get_state(ln) == ((csio_sm_state_t)csio_lns_offline)) { ++ if (csio_get_state(ln) == csio_lns_offline) { + strcpy(str, "OFFLINE"); + return; + } +diff --git a/drivers/scsi/csiostor/csio_lnode.h b/drivers/scsi/csiostor/csio_lnode.h +index 372a67d122d38..607698a0f0631 100644 +--- a/drivers/scsi/csiostor/csio_lnode.h ++++ b/drivers/scsi/csiostor/csio_lnode.h +@@ -53,19 +53,6 @@ + extern int csio_fcoe_rnodes; + extern int csio_fdmi_enable; + +-/* State machine evets */ +-enum csio_ln_ev { +- CSIO_LNE_NONE = (uint32_t)0, +- CSIO_LNE_LINKUP, +- CSIO_LNE_FAB_INIT_DONE, +- CSIO_LNE_LINK_DOWN, +- CSIO_LNE_DOWN_LINK, +- CSIO_LNE_LOGO, +- CSIO_LNE_CLOSE, +- CSIO_LNE_MAX_EVENT, +-}; +- +- + struct csio_fcf_info { + struct list_head list; + uint8_t priority; +diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c +index bbb7b2d9ffcfb..1abc62b07d24c 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_main.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c +@@ -1962,9 +1962,17 @@ static bool hisi_sas_internal_abort_timeout(struct sas_task *task, + struct hisi_sas_internal_abort_data *timeout = data; + + if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct) { +- down(&hisi_hba->sem); ++ /* ++ * If timeout occurs in device gone scenario, to avoid ++ * circular dependency like: ++ * hisi_sas_dev_gone() -> down() -> ... -> ++ * hisi_sas_internal_abort_timeout() -> down(). ++ */ ++ if (!timeout->rst_ha_timeout) ++ down(&hisi_hba->sem); + hisi_hba->hw->debugfs_snapshot_regs(hisi_hba); +- up(&hisi_hba->sem); ++ if (!timeout->rst_ha_timeout) ++ up(&hisi_hba->sem); + } + + if (task->task_state_flags & SAS_TASK_STATE_DONE) { +diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c +index 1d2b27e3ea63f..b811446e0fa55 100644 +--- a/drivers/soc/fsl/dpio/dpio-service.c ++++ b/drivers/soc/fsl/dpio/dpio-service.c +@@ -523,7 +523,7 @@ int dpaa2_io_service_enqueue_multiple_desc_fq(struct dpaa2_io *d, + struct qbman_eq_desc *ed; + int i, ret; + +- ed = kcalloc(sizeof(struct qbman_eq_desc), 32, GFP_KERNEL); ++ ed = kcalloc(32, sizeof(struct qbman_eq_desc), GFP_KERNEL); + if (!ed) + return -ENOMEM; + +diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c +index 4ca88eaebf06a..cbef0dea1d5d7 100644 +--- a/drivers/soc/qcom/llcc-qcom.c ++++ b/drivers/soc/qcom/llcc-qcom.c +@@ -859,6 +859,8 @@ static int llcc_update_act_ctrl(u32 sid, + ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg, + slice_status, !(slice_status & status), + 0, LLCC_STATUS_READ_DELAY); ++ if (ret) ++ return ret; + + if (drv_data->version >= LLCC_VERSION_4_1_0_0) + ret = regmap_write(drv_data->bcast_regmap, act_clear_reg, +diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c +index 6349a0debeb57..a980020ab854f 100644 +--- a/drivers/soc/qcom/socinfo.c ++++ b/drivers/soc/qcom/socinfo.c +@@ -124,7 +124,7 @@ static const char *const pmic_models[] = { + [50] = "PM8350B", + [51] = "PMR735A", + [52] = "PMR735B", +- [55] = "PM2250", ++ [55] = "PM4125", + [58] = "PM8450", + [65] = "PM8010", + [69] = "PM8550VS", +diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c +index 11991eb126364..079035db7dd85 100644 +--- a/drivers/spi/spi-fsl-lpspi.c ++++ b/drivers/spi/spi-fsl-lpspi.c +@@ -830,11 +830,11 @@ static int fsl_lpspi_probe(struct platform_device *pdev) + + is_target = of_property_read_bool((&pdev->dev)->of_node, "spi-slave"); + if (is_target) +- controller = spi_alloc_target(&pdev->dev, +- sizeof(struct fsl_lpspi_data)); ++ controller = devm_spi_alloc_target(&pdev->dev, ++ sizeof(struct fsl_lpspi_data)); + else +- controller = spi_alloc_host(&pdev->dev, +- sizeof(struct fsl_lpspi_data)); ++ controller = devm_spi_alloc_host(&pdev->dev, ++ sizeof(struct fsl_lpspi_data)); + + if (!controller) + return -ENOMEM; +diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c +index 833a1bb7a9143..c3e5cee18bea7 100644 +--- a/drivers/spi/spi-imx.c ++++ b/drivers/spi/spi-imx.c +@@ -668,8 +668,8 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx, + ctrl |= (MX51_ECSPI_CTRL_MAX_BURST * BITS_PER_BYTE - 1) + << MX51_ECSPI_CTRL_BL_OFFSET; + else +- ctrl |= spi_imx->count / DIV_ROUND_UP(spi_imx->bits_per_word, +- BITS_PER_BYTE) * spi_imx->bits_per_word ++ ctrl |= (spi_imx->count / DIV_ROUND_UP(spi_imx->bits_per_word, ++ BITS_PER_BYTE) * spi_imx->bits_per_word - 1) + << MX51_ECSPI_CTRL_BL_OFFSET; + } + } +diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c +index 2dc8ceb85374b..17b8baf749e6a 100644 +--- a/drivers/spi/spi-mem.c ++++ b/drivers/spi/spi-mem.c +@@ -297,6 +297,49 @@ static void spi_mem_access_end(struct spi_mem *mem) + pm_runtime_put(ctlr->dev.parent); + } + ++static void spi_mem_add_op_stats(struct spi_statistics __percpu *pcpu_stats, ++ const struct spi_mem_op *op, int exec_op_ret) ++{ ++ struct spi_statistics *stats; ++ u64 len, l2len; ++ ++ get_cpu(); ++ stats = this_cpu_ptr(pcpu_stats); ++ u64_stats_update_begin(&stats->syncp); ++ ++ /* ++ * We do not have the concept of messages or transfers. Let's consider ++ * that one operation is equivalent to one message and one transfer. ++ */ ++ u64_stats_inc(&stats->messages); ++ u64_stats_inc(&stats->transfers); ++ ++ /* Use the sum of all lengths as bytes count and histogram value. */ ++ len = op->cmd.nbytes + op->addr.nbytes; ++ len += op->dummy.nbytes + op->data.nbytes; ++ u64_stats_add(&stats->bytes, len); ++ l2len = min(fls(len), SPI_STATISTICS_HISTO_SIZE) - 1; ++ u64_stats_inc(&stats->transfer_bytes_histo[l2len]); ++ ++ /* Only account for data bytes as transferred bytes. */ ++ if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT) ++ u64_stats_add(&stats->bytes_tx, op->data.nbytes); ++ if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN) ++ u64_stats_add(&stats->bytes_rx, op->data.nbytes); ++ ++ /* ++ * A timeout is not an error, following the same behavior as ++ * spi_transfer_one_message(). ++ */ ++ if (exec_op_ret == -ETIMEDOUT) ++ u64_stats_inc(&stats->timedout); ++ else if (exec_op_ret) ++ u64_stats_inc(&stats->errors); ++ ++ u64_stats_update_end(&stats->syncp); ++ put_cpu(); ++} ++ + /** + * spi_mem_exec_op() - Execute a memory operation + * @mem: the SPI memory +@@ -339,8 +382,12 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) + * read path) and expect the core to use the regular SPI + * interface in other cases. + */ +- if (!ret || ret != -ENOTSUPP || ret != -EOPNOTSUPP) ++ if (!ret || (ret != -ENOTSUPP && ret != -EOPNOTSUPP)) { ++ spi_mem_add_op_stats(ctlr->pcpu_statistics, op, ret); ++ spi_mem_add_op_stats(mem->spi->pcpu_statistics, op, ret); ++ + return ret; ++ } + } + + tmpbufsize = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes; +diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c +index 8d5d170d49cc4..109dac2e69df2 100644 +--- a/drivers/spi/spi-mt65xx.c ++++ b/drivers/spi/spi-mt65xx.c +@@ -787,17 +787,19 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) + mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, len); + mtk_spi_setup_packet(host); + +- cnt = mdata->xfer_len / 4; +- iowrite32_rep(mdata->base + SPI_TX_DATA_REG, +- trans->tx_buf + mdata->num_xfered, cnt); ++ if (trans->tx_buf) { ++ cnt = mdata->xfer_len / 4; ++ iowrite32_rep(mdata->base + SPI_TX_DATA_REG, ++ trans->tx_buf + mdata->num_xfered, cnt); + +- remainder = mdata->xfer_len % 4; +- if (remainder > 0) { +- reg_val = 0; +- memcpy(®_val, +- trans->tx_buf + (cnt * 4) + mdata->num_xfered, +- remainder); +- writel(reg_val, mdata->base + SPI_TX_DATA_REG); ++ remainder = mdata->xfer_len % 4; ++ if (remainder > 0) { ++ reg_val = 0; ++ memcpy(®_val, ++ trans->tx_buf + (cnt * 4) + mdata->num_xfered, ++ remainder); ++ writel(reg_val, mdata->base + SPI_TX_DATA_REG); ++ } + } + + mtk_spi_enable_transfer(host); +diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c +index f2170f4b50775..46f1535487608 100644 +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -1042,10 +1042,14 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force) + if (spi->mode & SPI_CS_HIGH) + enable = !enable; + +- if (spi_is_csgpiod(spi)) { +- if (!spi->controller->set_cs_timing && !activate) +- spi_delay_exec(&spi->cs_hold, NULL); ++ /* ++ * Handle chip select delays for GPIO based CS or controllers without ++ * programmable chip select timing. ++ */ ++ if ((spi_is_csgpiod(spi) || !spi->controller->set_cs_timing) && !activate) ++ spi_delay_exec(&spi->cs_hold, NULL); + ++ if (spi_is_csgpiod(spi)) { + if (!(spi->mode & SPI_NO_CS)) { + /* + * Historically ACPI has no means of the GPIO polarity and +@@ -1079,16 +1083,16 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force) + if ((spi->controller->flags & SPI_CONTROLLER_GPIO_SS) && + spi->controller->set_cs) + spi->controller->set_cs(spi, !enable); +- +- if (!spi->controller->set_cs_timing) { +- if (activate) +- spi_delay_exec(&spi->cs_setup, NULL); +- else +- spi_delay_exec(&spi->cs_inactive, NULL); +- } + } else if (spi->controller->set_cs) { + spi->controller->set_cs(spi, !enable); + } ++ ++ if (spi_is_csgpiod(spi) || !spi->controller->set_cs_timing) { ++ if (activate) ++ spi_delay_exec(&spi->cs_setup, NULL); ++ else ++ spi_delay_exec(&spi->cs_inactive, NULL); ++ } + } + + #ifdef CONFIG_HAS_DMA +@@ -1747,13 +1751,37 @@ static int __spi_pump_transfer_message(struct spi_controller *ctlr, + + trace_spi_message_start(msg); + +- ret = spi_split_transfers_maxsize(ctlr, msg, +- spi_max_transfer_size(msg->spi), +- GFP_KERNEL | GFP_DMA); +- if (ret) { +- msg->status = ret; +- spi_finalize_current_message(ctlr); +- return ret; ++ /* ++ * If an SPI controller does not support toggling the CS line on each ++ * transfer (indicated by the SPI_CS_WORD flag) or we are using a GPIO ++ * for the CS line, we can emulate the CS-per-word hardware function by ++ * splitting transfers into one-word transfers and ensuring that ++ * cs_change is set for each transfer. ++ */ ++ if ((msg->spi->mode & SPI_CS_WORD) && (!(ctlr->mode_bits & SPI_CS_WORD) || ++ spi_is_csgpiod(msg->spi))) { ++ ret = spi_split_transfers_maxwords(ctlr, msg, 1, GFP_KERNEL); ++ if (ret) { ++ msg->status = ret; ++ spi_finalize_current_message(ctlr); ++ return ret; ++ } ++ ++ list_for_each_entry(xfer, &msg->transfers, transfer_list) { ++ /* Don't change cs_change on the last entry in the list */ ++ if (list_is_last(&xfer->transfer_list, &msg->transfers)) ++ break; ++ xfer->cs_change = 1; ++ } ++ } else { ++ ret = spi_split_transfers_maxsize(ctlr, msg, ++ spi_max_transfer_size(msg->spi), ++ GFP_KERNEL | GFP_DMA); ++ if (ret) { ++ msg->status = ret; ++ spi_finalize_current_message(ctlr); ++ return ret; ++ } + } + + if (ctlr->prepare_message) { +@@ -4063,33 +4091,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) + if (list_empty(&message->transfers)) + return -EINVAL; + +- /* +- * If an SPI controller does not support toggling the CS line on each +- * transfer (indicated by the SPI_CS_WORD flag) or we are using a GPIO +- * for the CS line, we can emulate the CS-per-word hardware function by +- * splitting transfers into one-word transfers and ensuring that +- * cs_change is set for each transfer. +- */ +- if ((spi->mode & SPI_CS_WORD) && (!(ctlr->mode_bits & SPI_CS_WORD) || +- spi_is_csgpiod(spi))) { +- size_t maxsize = BITS_TO_BYTES(spi->bits_per_word); +- int ret; +- +- /* spi_split_transfers_maxsize() requires message->spi */ +- message->spi = spi; +- +- ret = spi_split_transfers_maxsize(ctlr, message, maxsize, +- GFP_KERNEL); +- if (ret) +- return ret; +- +- list_for_each_entry(xfer, &message->transfers, transfer_list) { +- /* Don't change cs_change on the last entry in the list */ +- if (list_is_last(&xfer->transfer_list, &message->transfers)) +- break; +- xfer->cs_change = 1; +- } +- } ++ message->spi = spi; + + /* + * Half-duplex links include original MicroWire, and ones with +@@ -4214,8 +4216,6 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) + if (!ctlr->transfer) + return -ENOTSUPP; + +- message->spi = spi; +- + SPI_STATISTICS_INCREMENT_FIELD(ctlr->pcpu_statistics, spi_async); + SPI_STATISTICS_INCREMENT_FIELD(spi->pcpu_statistics, spi_async); + +@@ -4395,8 +4395,6 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message) + if (status != 0) + return status; + +- message->spi = spi; +- + SPI_STATISTICS_INCREMENT_FIELD(ctlr->pcpu_statistics, spi_sync); + SPI_STATISTICS_INCREMENT_FIELD(spi->pcpu_statistics, spi_sync); + +diff --git a/drivers/staging/greybus/light.c b/drivers/staging/greybus/light.c +index 87d36948c6106..c6bd86a5335ab 100644 +--- a/drivers/staging/greybus/light.c ++++ b/drivers/staging/greybus/light.c +@@ -100,15 +100,15 @@ static struct led_classdev *get_channel_cdev(struct gb_channel *channel) + static struct gb_channel *get_channel_from_mode(struct gb_light *light, + u32 mode) + { +- struct gb_channel *channel = NULL; ++ struct gb_channel *channel; + int i; + + for (i = 0; i < light->channels_count; i++) { + channel = &light->channels[i]; +- if (channel && channel->mode == mode) +- break; ++ if (channel->mode == mode) ++ return channel; + } +- return channel; ++ return NULL; + } + + static int __gb_lights_flash_intensity_set(struct gb_channel *channel, +diff --git a/drivers/staging/media/imx/imx-media-csc-scaler.c b/drivers/staging/media/imx/imx-media-csc-scaler.c +index 1fd39a2fca98a..95cca281e8a37 100644 +--- a/drivers/staging/media/imx/imx-media-csc-scaler.c ++++ b/drivers/staging/media/imx/imx-media-csc-scaler.c +@@ -803,6 +803,7 @@ static int ipu_csc_scaler_release(struct file *file) + + dev_dbg(priv->dev, "Releasing instance %p\n", ctx); + ++ v4l2_ctrl_handler_free(&ctx->ctrl_hdlr); + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); +diff --git a/drivers/staging/media/starfive/camss/stf-capture.c b/drivers/staging/media/starfive/camss/stf-capture.c +index 70c24b050a1b5..ec5169e7b3918 100644 +--- a/drivers/staging/media/starfive/camss/stf-capture.c ++++ b/drivers/staging/media/starfive/camss/stf-capture.c +@@ -20,28 +20,28 @@ static const struct stfcamss_format_info stf_wr_fmts[] = { + .pixelformat = V4L2_PIX_FMT_SRGGB10, + .planes = 1, + .vsub = { 1 }, +- .bpp = 10, ++ .bpp = 16, + }, + { + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .pixelformat = V4L2_PIX_FMT_SGRBG10, + .planes = 1, + .vsub = { 1 }, +- .bpp = 10, ++ .bpp = 16, + }, + { + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .pixelformat = V4L2_PIX_FMT_SGBRG10, + .planes = 1, + .vsub = { 1 }, +- .bpp = 10, ++ .bpp = 16, + }, + { + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .pixelformat = V4L2_PIX_FMT_SBGGR10, + .planes = 1, + .vsub = { 1 }, +- .bpp = 10, ++ .bpp = 16, + }, + }; + +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +index 52e94c8f2f01a..780da4a8b5af1 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +@@ -427,11 +427,11 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) + unsigned int ctb_addr_x, ctb_addr_y; + struct cedrus_buffer *cedrus_buf; + dma_addr_t src_buf_addr; +- dma_addr_t src_buf_end_addr; + u32 chroma_log2_weight_denom; + u32 num_entry_point_offsets; + u32 output_pic_list_index; + u32 pic_order_cnt[2]; ++ size_t slice_bytes; + u8 padding; + int count; + u32 reg; +@@ -443,6 +443,7 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) + pred_weight_table = &slice_params->pred_weight_table; + num_entry_point_offsets = slice_params->num_entry_point_offsets; + cedrus_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf); ++ slice_bytes = vb2_get_plane_payload(&run->src->vb2_buf, 0); + + /* + * If entry points offsets are present, we should get them +@@ -490,7 +491,7 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) + + cedrus_write(dev, VE_DEC_H265_BITS_OFFSET, 0); + +- reg = slice_params->bit_size; ++ reg = slice_bytes * 8; + cedrus_write(dev, VE_DEC_H265_BITS_LEN, reg); + + /* Source beginning and end addresses. */ +@@ -504,10 +505,7 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) + + cedrus_write(dev, VE_DEC_H265_BITS_ADDR, reg); + +- src_buf_end_addr = src_buf_addr + +- DIV_ROUND_UP(slice_params->bit_size, 8); +- +- reg = VE_DEC_H265_BITS_END_ADDR_BASE(src_buf_end_addr); ++ reg = VE_DEC_H265_BITS_END_ADDR_BASE(src_buf_addr + slice_bytes); + cedrus_write(dev, VE_DEC_H265_BITS_END_ADDR, reg); + + /* Coding tree block address */ +diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c +index 98d9c80bd4c62..fd4bd650c77a6 100644 +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -719,8 +719,10 @@ static int lvts_calibration_read(struct device *dev, struct lvts_domain *lvts_td + + lvts_td->calib = devm_krealloc(dev, lvts_td->calib, + lvts_td->calib_len + len, GFP_KERNEL); +- if (!lvts_td->calib) ++ if (!lvts_td->calib) { ++ kfree(efuse); + return -ENOMEM; ++ } + + memcpy(lvts_td->calib + lvts_td->calib_len, efuse, len); + +diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c +index ccc2eea7f9f54..404f01cca4dab 100644 +--- a/drivers/thermal/qoriq_thermal.c ++++ b/drivers/thermal/qoriq_thermal.c +@@ -57,6 +57,9 @@ + #define REGS_TTRnCR(n) (0xf10 + 4 * (n)) /* Temperature Range n + * Control Register + */ ++#define NUM_TTRCR_V1 4 ++#define NUM_TTRCR_MAX 16 ++ + #define REGS_IPBRR(n) (0xbf8 + 4 * (n)) /* IP Block Revision + * Register n + */ +@@ -71,6 +74,7 @@ struct qoriq_sensor { + + struct qoriq_tmu_data { + int ver; ++ u32 ttrcr[NUM_TTRCR_MAX]; + struct regmap *regmap; + struct clk *clk; + struct qoriq_sensor sensor[SITES_MAX]; +@@ -182,17 +186,17 @@ static int qoriq_tmu_calibration(struct device *dev, + struct qoriq_tmu_data *data) + { + int i, val, len; +- u32 range[4]; + const u32 *calibration; + struct device_node *np = dev->of_node; + + len = of_property_count_u32_elems(np, "fsl,tmu-range"); +- if (len < 0 || len > 4) { ++ if (len < 0 || (data->ver == TMU_VER1 && len > NUM_TTRCR_V1) || ++ (data->ver > TMU_VER1 && len > NUM_TTRCR_MAX)) { + dev_err(dev, "invalid range data.\n"); + return len; + } + +- val = of_property_read_u32_array(np, "fsl,tmu-range", range, len); ++ val = of_property_read_u32_array(np, "fsl,tmu-range", data->ttrcr, len); + if (val != 0) { + dev_err(dev, "failed to read range data.\n"); + return val; +@@ -200,7 +204,7 @@ static int qoriq_tmu_calibration(struct device *dev, + + /* Init temperature range registers */ + for (i = 0; i < len; i++) +- regmap_write(data->regmap, REGS_TTRnCR(i), range[i]); ++ regmap_write(data->regmap, REGS_TTRnCR(i), data->ttrcr[i]); + + calibration = of_get_property(np, "fsl,tmu-calibration", &len); + if (calibration == NULL || len % 8) { +diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c +index aac80b69a069c..afbf7738c7c47 100644 +--- a/drivers/tty/mips_ejtag_fdc.c ++++ b/drivers/tty/mips_ejtag_fdc.c +@@ -309,7 +309,7 @@ static void mips_ejtag_fdc_console_write(struct console *c, const char *s, + unsigned int i, buf_len, cpu; + bool done_cr = false; + char buf[4]; +- const char *buf_ptr = buf; ++ const u8 *buf_ptr = buf; + /* Number of bytes of input data encoded up to each byte in buf */ + u8 inc[4]; + +diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c +index 23366f868ae3a..dab94835b6f5f 100644 +--- a/drivers/tty/serial/8250/8250_exar.c ++++ b/drivers/tty/serial/8250/8250_exar.c +@@ -753,6 +753,7 @@ static void exar_pci_remove(struct pci_dev *pcidev) + for (i = 0; i < priv->nr; i++) + serial8250_unregister_port(priv->line[i]); + ++ /* Ensure that every init quirk is properly torn down */ + if (priv->board->exit) + priv->board->exit(pcidev); + } +@@ -767,10 +768,6 @@ static int __maybe_unused exar_suspend(struct device *dev) + if (priv->line[i] >= 0) + serial8250_suspend_port(priv->line[i]); + +- /* Ensure that every init quirk is properly torn down */ +- if (priv->board->exit) +- priv->board->exit(pcidev); +- + return 0; + } + +diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c +index 10bf6d75bf9ee..f70e2c277ab7e 100644 +--- a/drivers/tty/serial/max310x.c ++++ b/drivers/tty/serial/max310x.c +@@ -1461,7 +1461,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty + if (!ret) + return 0; + +- dev_err(dev, "Unable to reguest IRQ %i\n", irq); ++ dev_err(dev, "Unable to request IRQ %i\n", irq); + + out_uart: + for (i = 0; i < devtype->nr; i++) { +diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c +index 71d17d804fdab..6fdb32b833466 100644 +--- a/drivers/tty/serial/samsung_tty.c ++++ b/drivers/tty/serial/samsung_tty.c +@@ -987,11 +987,10 @@ static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) + if ((ufstat & info->tx_fifomask) != 0 || + (ufstat & info->tx_fifofull)) + return 0; +- +- return 1; ++ return TIOCSER_TEMT; + } + +- return s3c24xx_serial_txempty_nofifo(port); ++ return s3c24xx_serial_txempty_nofifo(port) ? TIOCSER_TEMT : 0; + } + + /* no modem control lines */ +diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c +index 38a765eadbe2b..52e6ca1ba21df 100644 +--- a/drivers/tty/vt/vt.c ++++ b/drivers/tty/vt/vt.c +@@ -2469,7 +2469,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) + } + return; + case EScsiignore: +- if (c >= 20 && c <= 0x3f) ++ if (c >= 0x20 && c <= 0x3f) + return; + vc->vc_state = ESnormal; + return; +diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c +index 12e76bb62c209..19bbc38f3d35d 100644 +--- a/drivers/usb/gadget/udc/net2272.c ++++ b/drivers/usb/gadget/udc/net2272.c +@@ -2650,7 +2650,7 @@ net2272_plat_probe(struct platform_device *pdev) + goto err_req; + } + +- ret = net2272_probe_fin(dev, IRQF_TRIGGER_LOW); ++ ret = net2272_probe_fin(dev, irqflags); + if (ret) + goto err_io; + +diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c +index a7716202a8dd5..450adaca68eeb 100644 +--- a/drivers/usb/host/xhci-mem.c ++++ b/drivers/usb/host/xhci-mem.c +@@ -2533,7 +2533,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) + if (xhci_add_interrupter(xhci, ir, 0)) + goto fail; + +- xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX; ++ ir->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX; + + /* + * XXX: Might need to set the Interrupter Moderation Register to +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index 4f64b814d4aa2..61bd29dd71a2f 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -3022,9 +3022,6 @@ static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir) + return 0; + } + +- /* Update SW event ring dequeue pointer */ +- inc_deq(xhci, ir->event_ring); +- + /* Are there more items on the event ring? Caller will call us again to + * check. + */ +@@ -3038,30 +3035,26 @@ static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir) + */ + static void xhci_update_erst_dequeue(struct xhci_hcd *xhci, + struct xhci_interrupter *ir, +- union xhci_trb *event_ring_deq, + bool clear_ehb) + { + u64 temp_64; + dma_addr_t deq; + + temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); +- /* If necessary, update the HW's version of the event ring deq ptr. */ +- if (event_ring_deq != ir->event_ring->dequeue) { +- deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg, +- ir->event_ring->dequeue); +- if (deq == 0) +- xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr\n"); +- /* +- * Per 4.9.4, Software writes to the ERDP register shall +- * always advance the Event Ring Dequeue Pointer value. +- */ +- if ((temp_64 & ERST_PTR_MASK) == (deq & ERST_PTR_MASK)) +- return; ++ deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg, ++ ir->event_ring->dequeue); ++ if (deq == 0) ++ xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr\n"); ++ /* ++ * Per 4.9.4, Software writes to the ERDP register shall always advance ++ * the Event Ring Dequeue Pointer value. ++ */ ++ if ((temp_64 & ERST_PTR_MASK) == (deq & ERST_PTR_MASK) && !clear_ehb) ++ return; + +- /* Update HC event ring dequeue pointer */ +- temp_64 = ir->event_ring->deq_seg->num & ERST_DESI_MASK; +- temp_64 |= deq & ERST_PTR_MASK; +- } ++ /* Update HC event ring dequeue pointer */ ++ temp_64 = ir->event_ring->deq_seg->num & ERST_DESI_MASK; ++ temp_64 |= deq & ERST_PTR_MASK; + + /* Clear the event handler busy flag (RW1C) */ + if (clear_ehb) +@@ -3069,6 +3062,19 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci, + xhci_write_64(xhci, temp_64, &ir->ir_set->erst_dequeue); + } + ++/* Clear the interrupt pending bit for a specific interrupter. */ ++static void xhci_clear_interrupt_pending(struct xhci_hcd *xhci, ++ struct xhci_interrupter *ir) ++{ ++ if (!ir->ip_autoclear) { ++ u32 irq_pending; ++ ++ irq_pending = readl(&ir->ir_set->irq_pending); ++ irq_pending |= IMAN_IP; ++ writel(irq_pending, &ir->ir_set->irq_pending); ++ } ++} ++ + /* + * xHCI spec says we can get an interrupt, and if the HC has an error condition, + * we might get bad data out of the event ring. Section 4.10.2.7 has a list of +@@ -3077,7 +3083,6 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci, + irqreturn_t xhci_irq(struct usb_hcd *hcd) + { + struct xhci_hcd *xhci = hcd_to_xhci(hcd); +- union xhci_trb *event_ring_deq; + struct xhci_interrupter *ir; + irqreturn_t ret = IRQ_NONE; + u64 temp_64; +@@ -3118,12 +3123,8 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) + + /* This is the handler of the primary interrupter */ + ir = xhci->interrupters[0]; +- if (!hcd->msi_enabled) { +- u32 irq_pending; +- irq_pending = readl(&ir->ir_set->irq_pending); +- irq_pending |= IMAN_IP; +- writel(irq_pending, &ir->ir_set->irq_pending); +- } ++ ++ xhci_clear_interrupt_pending(xhci, ir); + + if (xhci->xhc_state & XHCI_STATE_DYING || + xhci->xhc_state & XHCI_STATE_HALTED) { +@@ -3139,24 +3140,28 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) + goto out; + } + +- event_ring_deq = ir->event_ring->dequeue; + /* FIXME this should be a delayed service routine + * that clears the EHB. + */ + while (xhci_handle_event(xhci, ir) > 0) { +- if (event_loop++ < TRBS_PER_SEGMENT / 2) +- continue; +- xhci_update_erst_dequeue(xhci, ir, event_ring_deq, false); +- event_ring_deq = ir->event_ring->dequeue; ++ /* ++ * If half a segment of events have been handled in one go then ++ * update ERDP, and force isoc trbs to interrupt more often ++ */ ++ if (event_loop++ > TRBS_PER_SEGMENT / 2) { ++ xhci_update_erst_dequeue(xhci, ir, false); + +- /* ring is half-full, force isoc trbs to interrupt more often */ +- if (xhci->isoc_bei_interval > AVOID_BEI_INTERVAL_MIN) +- xhci->isoc_bei_interval = xhci->isoc_bei_interval / 2; ++ if (ir->isoc_bei_interval > AVOID_BEI_INTERVAL_MIN) ++ ir->isoc_bei_interval = ir->isoc_bei_interval / 2; + +- event_loop = 0; ++ event_loop = 0; ++ } ++ ++ /* Update SW event ring dequeue pointer */ ++ inc_deq(xhci, ir->event_ring); + } + +- xhci_update_erst_dequeue(xhci, ir, event_ring_deq, true); ++ xhci_update_erst_dequeue(xhci, ir, true); + ret = IRQ_HANDLED; + + out: +@@ -4019,7 +4024,8 @@ static int xhci_get_isoc_frame_id(struct xhci_hcd *xhci, + } + + /* Check if we should generate event interrupt for a TD in an isoc URB */ +-static bool trb_block_event_intr(struct xhci_hcd *xhci, int num_tds, int i) ++static bool trb_block_event_intr(struct xhci_hcd *xhci, int num_tds, int i, ++ struct xhci_interrupter *ir) + { + if (xhci->hci_version < 0x100) + return false; +@@ -4030,8 +4036,8 @@ static bool trb_block_event_intr(struct xhci_hcd *xhci, int num_tds, int i) + * If AVOID_BEI is set the host handles full event rings poorly, + * generate an event at least every 8th TD to clear the event ring + */ +- if (i && xhci->quirks & XHCI_AVOID_BEI) +- return !!(i % xhci->isoc_bei_interval); ++ if (i && ir->isoc_bei_interval && xhci->quirks & XHCI_AVOID_BEI) ++ return !!(i % ir->isoc_bei_interval); + + return true; + } +@@ -4040,6 +4046,7 @@ static bool trb_block_event_intr(struct xhci_hcd *xhci, int num_tds, int i) + static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, + struct urb *urb, int slot_id, unsigned int ep_index) + { ++ struct xhci_interrupter *ir; + struct xhci_ring *ep_ring; + struct urb_priv *urb_priv; + struct xhci_td *td; +@@ -4057,6 +4064,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, + + xep = &xhci->devs[slot_id]->eps[ep_index]; + ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; ++ ir = xhci->interrupters[0]; + + num_tds = urb->number_of_packets; + if (num_tds < 1) { +@@ -4144,7 +4152,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, + td->last_trb = ep_ring->enqueue; + td->last_trb_seg = ep_ring->enq_seg; + field |= TRB_IOC; +- if (trb_block_event_intr(xhci, num_tds, i)) ++ if (trb_block_event_intr(xhci, num_tds, i, ir)) + field |= TRB_BEI; + } + /* Calculate TRB length */ +diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c +index c057c42c36f4c..0886829d53e51 100644 +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -538,6 +538,9 @@ int xhci_run(struct usb_hcd *hcd) + */ + + hcd->uses_new_polling = 1; ++ if (hcd->msi_enabled) ++ ir->ip_autoclear = true; ++ + if (!usb_hcd_is_primary_hcd(hcd)) + return xhci_run_finished(xhci); + +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index 6f82d404883f9..bf05103aa68a0 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1688,6 +1688,8 @@ struct xhci_interrupter { + struct xhci_erst erst; + struct xhci_intr_reg __iomem *ir_set; + unsigned int intr_num; ++ bool ip_autoclear; ++ u32 isoc_bei_interval; + /* For interrupter registers save and restore over suspend/resume */ + u32 s3_irq_pending; + u32 s3_irq_control; +@@ -1760,7 +1762,6 @@ struct xhci_hcd { + u8 isoc_threshold; + /* imod_interval in ns (I * 250ns) */ + u32 imod_interval; +- u32 isoc_bei_interval; + int event_ring_max; + /* 4KB min, 128MB max */ + int page_size; +diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c +index 9ab50f26db607..16494030209ea 100644 +--- a/drivers/usb/phy/phy-generic.c ++++ b/drivers/usb/phy/phy-generic.c +@@ -274,6 +274,13 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop) + return dev_err_probe(dev, PTR_ERR(nop->vbus_draw), + "could not get vbus regulator\n"); + ++ nop->vbus_draw = devm_regulator_get_exclusive(dev, "vbus"); ++ if (PTR_ERR(nop->vbus_draw) == -ENODEV) ++ nop->vbus_draw = NULL; ++ if (IS_ERR(nop->vbus_draw)) ++ return dev_err_probe(dev, PTR_ERR(nop->vbus_draw), ++ "could not get vbus regulator\n"); ++ + nop->dev = dev; + nop->phy.dev = nop->dev; + nop->phy.label = "nop-xceiv"; +diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c +index 778821bab7d93..ecfc16151d619 100644 +--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c ++++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c +@@ -151,8 +151,6 @@ static void teardown_driver(struct mlx5_vdpa_net *ndev); + + static bool mlx5_vdpa_debug; + +-#define MLX5_CVQ_MAX_ENT 16 +- + #define MLX5_LOG_VIO_FLAG(_feature) \ + do { \ + if (features & BIT_ULL(_feature)) \ +@@ -2276,9 +2274,16 @@ static void mlx5_vdpa_set_vq_num(struct vdpa_device *vdev, u16 idx, u32 num) + struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); + struct mlx5_vdpa_virtqueue *mvq; + +- if (!is_index_valid(mvdev, idx) || is_ctrl_vq_idx(mvdev, idx)) ++ if (!is_index_valid(mvdev, idx)) + return; + ++ if (is_ctrl_vq_idx(mvdev, idx)) { ++ struct mlx5_control_vq *cvq = &mvdev->cvq; ++ ++ cvq->vring.vring.num = num; ++ return; ++ } ++ + mvq = &ndev->vqs[idx]; + mvq->num_ent = num; + } +@@ -2963,7 +2968,7 @@ static int setup_cvq_vring(struct mlx5_vdpa_dev *mvdev) + u16 idx = cvq->vring.last_avail_idx; + + err = vringh_init_iotlb(&cvq->vring, mvdev->actual_features, +- MLX5_CVQ_MAX_ENT, false, ++ cvq->vring.vring.num, false, + (struct vring_desc *)(uintptr_t)cvq->desc_addr, + (struct vring_avail *)(uintptr_t)cvq->driver_addr, + (struct vring_used *)(uintptr_t)cvq->device_addr); +diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c +index be2925d0d2836..18584ce70bf07 100644 +--- a/drivers/vdpa/vdpa_sim/vdpa_sim.c ++++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c +@@ -160,7 +160,7 @@ static void vdpasim_do_reset(struct vdpasim *vdpasim, u32 flags) + } + } + +- vdpasim->running = true; ++ vdpasim->running = false; + spin_unlock(&vdpasim->iommu_lock); + + vdpasim->features = 0; +@@ -483,6 +483,7 @@ static void vdpasim_set_status(struct vdpa_device *vdpa, u8 status) + + mutex_lock(&vdpasim->mutex); + vdpasim->status = status; ++ vdpasim->running = (status & VIRTIO_CONFIG_S_DRIVER_OK) != 0; + mutex_unlock(&vdpasim->mutex); + } + +diff --git a/drivers/video/backlight/da9052_bl.c b/drivers/video/backlight/da9052_bl.c +index 1cdc8543310b4..b8ff7046510eb 100644 +--- a/drivers/video/backlight/da9052_bl.c ++++ b/drivers/video/backlight/da9052_bl.c +@@ -117,6 +117,7 @@ static int da9052_backlight_probe(struct platform_device *pdev) + wleds->led_reg = platform_get_device_id(pdev)->driver_data; + wleds->state = DA9052_WLEDS_OFF; + ++ memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; + props.max_brightness = DA9052_MAX_BRIGHTNESS; + +diff --git a/drivers/video/backlight/hx8357.c b/drivers/video/backlight/hx8357.c +index d7298376cf74d..bf18337ff0c2c 100644 +--- a/drivers/video/backlight/hx8357.c ++++ b/drivers/video/backlight/hx8357.c +@@ -609,11 +609,13 @@ static int hx8357_probe(struct spi_device *spi) + lcd->im_pins = devm_gpiod_get_array_optional(dev, "im", GPIOD_OUT_LOW); + if (IS_ERR(lcd->im_pins)) + return dev_err_probe(dev, PTR_ERR(lcd->im_pins), "failed to request im GPIOs\n"); +- if (lcd->im_pins->ndescs < HX8357_NUM_IM_PINS) +- return dev_err_probe(dev, -EINVAL, "not enough im GPIOs\n"); ++ if (lcd->im_pins) { ++ if (lcd->im_pins->ndescs < HX8357_NUM_IM_PINS) ++ return dev_err_probe(dev, -EINVAL, "not enough im GPIOs\n"); + +- for (i = 0; i < HX8357_NUM_IM_PINS; i++) +- gpiod_set_consumer_name(lcd->im_pins->desc[i], "im_pins"); ++ for (i = 0; i < HX8357_NUM_IM_PINS; i++) ++ gpiod_set_consumer_name(lcd->im_pins->desc[i], "im_pins"); ++ } + + lcdev = devm_lcd_device_register(&spi->dev, "mxsfb", &spi->dev, lcd, + &hx8357_ops); +diff --git a/drivers/video/backlight/ktz8866.c b/drivers/video/backlight/ktz8866.c +index 9c980f2571ee3..014877b5a9848 100644 +--- a/drivers/video/backlight/ktz8866.c ++++ b/drivers/video/backlight/ktz8866.c +@@ -97,20 +97,20 @@ static void ktz8866_init(struct ktz8866 *ktz) + { + unsigned int val = 0; + +- if (of_property_read_u32(ktz->client->dev.of_node, "current-num-sinks", &val)) ++ if (!of_property_read_u32(ktz->client->dev.of_node, "current-num-sinks", &val)) + ktz8866_write(ktz, BL_EN, BIT(val) - 1); + else + /* Enable all 6 current sinks if the number of current sinks isn't specified. */ + ktz8866_write(ktz, BL_EN, BIT(6) - 1); + +- if (of_property_read_u32(ktz->client->dev.of_node, "kinetic,current-ramp-delay-ms", &val)) { ++ if (!of_property_read_u32(ktz->client->dev.of_node, "kinetic,current-ramp-delay-ms", &val)) { + if (val <= 128) + ktz8866_write(ktz, BL_CFG2, BIT(7) | (ilog2(val) << 3) | PWM_HYST); + else + ktz8866_write(ktz, BL_CFG2, BIT(7) | ((5 + val / 64) << 3) | PWM_HYST); + } + +- if (of_property_read_u32(ktz->client->dev.of_node, "kinetic,led-enable-ramp-delay-ms", &val)) { ++ if (!of_property_read_u32(ktz->client->dev.of_node, "kinetic,led-enable-ramp-delay-ms", &val)) { + if (val == 0) + ktz8866_write(ktz, BL_DIMMING, 0); + else { +diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c +index a3412c936ca28..26ff4178cc161 100644 +--- a/drivers/video/backlight/lm3630a_bl.c ++++ b/drivers/video/backlight/lm3630a_bl.c +@@ -233,7 +233,7 @@ static int lm3630a_bank_a_get_brightness(struct backlight_device *bl) + if (rval < 0) + goto out_i2c_err; + brightness |= rval; +- goto out; ++ return brightness; + } + + /* disable sleep */ +@@ -244,11 +244,8 @@ static int lm3630a_bank_a_get_brightness(struct backlight_device *bl) + rval = lm3630a_read(pchip, REG_BRT_A); + if (rval < 0) + goto out_i2c_err; +- brightness = rval; ++ return rval; + +-out: +- bl->props.brightness = brightness; +- return bl->props.brightness; + out_i2c_err: + dev_err(pchip->dev, "i2c failed to access register\n"); + return 0; +@@ -310,7 +307,7 @@ static int lm3630a_bank_b_get_brightness(struct backlight_device *bl) + if (rval < 0) + goto out_i2c_err; + brightness |= rval; +- goto out; ++ return brightness; + } + + /* disable sleep */ +@@ -321,11 +318,8 @@ static int lm3630a_bank_b_get_brightness(struct backlight_device *bl) + rval = lm3630a_read(pchip, REG_BRT_B); + if (rval < 0) + goto out_i2c_err; +- brightness = rval; ++ return rval; + +-out: +- bl->props.brightness = brightness; +- return bl->props.brightness; + out_i2c_err: + dev_err(pchip->dev, "i2c failed to access register\n"); + return 0; +@@ -343,6 +337,7 @@ static int lm3630a_backlight_register(struct lm3630a_chip *pchip) + struct backlight_properties props; + const char *label; + ++ memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; + if (pdata->leda_ctrl != LM3630A_LEDA_DISABLE) { + props.brightness = pdata->leda_init_brt; +diff --git a/drivers/video/backlight/lm3639_bl.c b/drivers/video/backlight/lm3639_bl.c +index 5246c171497d6..564f62acd7211 100644 +--- a/drivers/video/backlight/lm3639_bl.c ++++ b/drivers/video/backlight/lm3639_bl.c +@@ -338,6 +338,7 @@ static int lm3639_probe(struct i2c_client *client) + } + + /* backlight */ ++ memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; + props.brightness = pdata->init_brt_led; + props.max_brightness = pdata->max_brt_led; +diff --git a/drivers/video/backlight/lp8788_bl.c b/drivers/video/backlight/lp8788_bl.c +index d1a14b0db265b..31f97230ee506 100644 +--- a/drivers/video/backlight/lp8788_bl.c ++++ b/drivers/video/backlight/lp8788_bl.c +@@ -191,6 +191,7 @@ static int lp8788_backlight_register(struct lp8788_bl *bl) + int init_brt; + char *name; + ++ memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; + props.max_brightness = MAX_BRIGHTNESS; + +diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c +index 6f58ee276ad1b..028a565250476 100644 +--- a/drivers/video/fbdev/simplefb.c ++++ b/drivers/video/fbdev/simplefb.c +@@ -470,7 +470,7 @@ static int simplefb_attach_genpds(struct simplefb_par *par, + if (err == -ENOENT) + return 0; + +- dev_info(dev, "failed to parse power-domains: %d\n", err); ++ dev_err(dev, "failed to parse power-domains: %d\n", err); + return err; + } + +diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c +index 49299b1f9ec74..6f7e5010a6735 100644 +--- a/drivers/virtio/virtio_ring.c ++++ b/drivers/virtio/virtio_ring.c +@@ -1340,7 +1340,7 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq, + sizeof(struct vring_packed_desc)); + vq->packed.vring.desc[head].id = cpu_to_le16(id); + +- if (vq->do_unmap) { ++ if (vq->use_dma_api) { + vq->packed.desc_extra[id].addr = addr; + vq->packed.desc_extra[id].len = total_sg * + sizeof(struct vring_packed_desc); +@@ -1481,7 +1481,7 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq, + desc[i].len = cpu_to_le32(sg->length); + desc[i].id = cpu_to_le16(id); + +- if (unlikely(vq->do_unmap)) { ++ if (unlikely(vq->use_dma_api)) { + vq->packed.desc_extra[curr].addr = addr; + vq->packed.desc_extra[curr].len = sg->length; + vq->packed.desc_extra[curr].flags = +@@ -1615,7 +1615,7 @@ static void detach_buf_packed(struct vring_virtqueue *vq, + vq->free_head = id; + vq->vq.num_free += state->num; + +- if (unlikely(vq->do_unmap)) { ++ if (unlikely(vq->use_dma_api)) { + curr = id; + for (i = 0; i < state->num; i++) { + vring_unmap_extra_packed(vq, +diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wdt.c +index e28ead24c520e..df68ae4acbd7e 100644 +--- a/drivers/watchdog/starfive-wdt.c ++++ b/drivers/watchdog/starfive-wdt.c +@@ -494,8 +494,13 @@ static int starfive_wdt_probe(struct platform_device *pdev) + if (ret) + goto err_exit; + +- if (!early_enable) +- pm_runtime_put_sync(&pdev->dev); ++ if (!early_enable) { ++ if (pm_runtime_enabled(&pdev->dev)) { ++ ret = pm_runtime_put_sync(&pdev->dev); ++ if (ret) ++ goto err_exit; ++ } ++ } + + return 0; + +diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c +index d9fd50df9802c..5404e03876202 100644 +--- a/drivers/watchdog/stm32_iwdg.c ++++ b/drivers/watchdog/stm32_iwdg.c +@@ -20,6 +20,8 @@ + #include + #include + ++#define DEFAULT_TIMEOUT 10 ++ + /* IWDG registers */ + #define IWDG_KR 0x00 /* Key register */ + #define IWDG_PR 0x04 /* Prescaler Register */ +@@ -248,6 +250,7 @@ static int stm32_iwdg_probe(struct platform_device *pdev) + wdd->parent = dev; + wdd->info = &stm32_iwdg_info; + wdd->ops = &stm32_iwdg_ops; ++ wdd->timeout = DEFAULT_TIMEOUT; + wdd->min_timeout = DIV_ROUND_UP((RLR_MIN + 1) * PR_MIN, wdt->rate); + wdd->max_hw_heartbeat_ms = ((RLR_MAX + 1) * wdt->data->max_prescaler * + 1000) / wdt->rate; +diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c +index 3b9f080109d7e..27553673e46bc 100644 +--- a/drivers/xen/events/events_base.c ++++ b/drivers/xen/events/events_base.c +@@ -1190,7 +1190,7 @@ int xen_pirq_from_irq(unsigned irq) + EXPORT_SYMBOL_GPL(xen_pirq_from_irq); + + static int bind_evtchn_to_irq_chip(evtchn_port_t evtchn, struct irq_chip *chip, +- struct xenbus_device *dev) ++ struct xenbus_device *dev, bool shared) + { + int ret = -ENOMEM; + struct irq_info *info; +@@ -1224,7 +1224,8 @@ static int bind_evtchn_to_irq_chip(evtchn_port_t evtchn, struct irq_chip *chip, + */ + bind_evtchn_to_cpu(info, 0, false); + } else if (!WARN_ON(info->type != IRQT_EVTCHN)) { +- info->refcnt++; ++ if (shared && !WARN_ON(info->refcnt < 0)) ++ info->refcnt++; + } + + ret = info->irq; +@@ -1237,13 +1238,13 @@ static int bind_evtchn_to_irq_chip(evtchn_port_t evtchn, struct irq_chip *chip, + + int bind_evtchn_to_irq(evtchn_port_t evtchn) + { +- return bind_evtchn_to_irq_chip(evtchn, &xen_dynamic_chip, NULL); ++ return bind_evtchn_to_irq_chip(evtchn, &xen_dynamic_chip, NULL, false); + } + EXPORT_SYMBOL_GPL(bind_evtchn_to_irq); + + int bind_evtchn_to_irq_lateeoi(evtchn_port_t evtchn) + { +- return bind_evtchn_to_irq_chip(evtchn, &xen_lateeoi_chip, NULL); ++ return bind_evtchn_to_irq_chip(evtchn, &xen_lateeoi_chip, NULL, false); + } + EXPORT_SYMBOL_GPL(bind_evtchn_to_irq_lateeoi); + +@@ -1295,7 +1296,8 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) + + static int bind_interdomain_evtchn_to_irq_chip(struct xenbus_device *dev, + evtchn_port_t remote_port, +- struct irq_chip *chip) ++ struct irq_chip *chip, ++ bool shared) + { + struct evtchn_bind_interdomain bind_interdomain; + int err; +@@ -1307,14 +1309,14 @@ static int bind_interdomain_evtchn_to_irq_chip(struct xenbus_device *dev, + &bind_interdomain); + + return err ? : bind_evtchn_to_irq_chip(bind_interdomain.local_port, +- chip, dev); ++ chip, dev, shared); + } + + int bind_interdomain_evtchn_to_irq_lateeoi(struct xenbus_device *dev, + evtchn_port_t remote_port) + { + return bind_interdomain_evtchn_to_irq_chip(dev, remote_port, +- &xen_lateeoi_chip); ++ &xen_lateeoi_chip, false); + } + EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irq_lateeoi); + +@@ -1430,7 +1432,8 @@ static int bind_evtchn_to_irqhandler_chip(evtchn_port_t evtchn, + { + int irq, retval; + +- irq = bind_evtchn_to_irq_chip(evtchn, chip, NULL); ++ irq = bind_evtchn_to_irq_chip(evtchn, chip, NULL, ++ irqflags & IRQF_SHARED); + if (irq < 0) + return irq; + retval = request_irq(irq, handler, irqflags, devname, dev_id); +@@ -1471,7 +1474,8 @@ static int bind_interdomain_evtchn_to_irqhandler_chip( + { + int irq, retval; + +- irq = bind_interdomain_evtchn_to_irq_chip(dev, remote_port, chip); ++ irq = bind_interdomain_evtchn_to_irq_chip(dev, remote_port, chip, ++ irqflags & IRQF_SHARED); + if (irq < 0) + return irq; + +diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c +index 59717628ca42b..f6a2216c2c870 100644 +--- a/drivers/xen/evtchn.c ++++ b/drivers/xen/evtchn.c +@@ -85,6 +85,7 @@ struct user_evtchn { + struct per_user_data *user; + evtchn_port_t port; + bool enabled; ++ bool unbinding; + }; + + static void evtchn_free_ring(evtchn_port_t *ring) +@@ -164,6 +165,10 @@ static irqreturn_t evtchn_interrupt(int irq, void *data) + struct per_user_data *u = evtchn->user; + unsigned int prod, cons; + ++ /* Handler might be called when tearing down the IRQ. */ ++ if (evtchn->unbinding) ++ return IRQ_HANDLED; ++ + WARN(!evtchn->enabled, + "Interrupt for port %u, but apparently not enabled; per-user %p\n", + evtchn->port, u); +@@ -421,6 +426,7 @@ static void evtchn_unbind_from_user(struct per_user_data *u, + + BUG_ON(irq < 0); + ++ evtchn->unbinding = true; + unbind_from_irqhandler(irq, evtchn); + + del_evtchn(u, evtchn); +diff --git a/fs/afs/dir.c b/fs/afs/dir.c +index 8a67fc427e748..67afe68972d5c 100644 +--- a/fs/afs/dir.c ++++ b/fs/afs/dir.c +@@ -474,16 +474,6 @@ static int afs_dir_iterate_block(struct afs_vnode *dvnode, + continue; + } + +- /* Don't expose silly rename entries to userspace. */ +- if (nlen > 6 && +- dire->u.name[0] == '.' && +- ctx->actor != afs_lookup_filldir && +- ctx->actor != afs_lookup_one_filldir && +- memcmp(dire->u.name, ".__afs", 6) == 0) { +- ctx->pos = blkoff + next * sizeof(union afs_xdr_dirent); +- continue; +- } +- + /* found the next entry */ + if (!dir_emit(ctx, dire->u.name, nlen, + ntohl(dire->u.vnode), +diff --git a/fs/afs/rotate.c b/fs/afs/rotate.c +index 700a27bc8c257..ed04bd1eeae89 100644 +--- a/fs/afs/rotate.c ++++ b/fs/afs/rotate.c +@@ -602,6 +602,8 @@ bool afs_select_fileserver(struct afs_operation *op) + goto wait_for_more_probe_results; + + alist = op->estate->addresses; ++ best_prio = -1; ++ addr_index = 0; + for (i = 0; i < alist->nr_addrs; i++) { + if (alist->addrs[i].prio > best_prio) { + addr_index = i; +@@ -609,9 +611,7 @@ bool afs_select_fileserver(struct afs_operation *op) + } + } + +- addr_index = READ_ONCE(alist->preferred); +- if (!test_bit(addr_index, &set)) +- addr_index = __ffs(set); ++ alist->preferred = addr_index; + + op->addr_index = addr_index; + set_bit(addr_index, &op->addr_tried); +@@ -656,12 +656,6 @@ bool afs_select_fileserver(struct afs_operation *op) + next_server: + trace_afs_rotate(op, afs_rotate_trace_next_server, 0); + _debug("next"); +- ASSERT(op->estate); +- alist = op->estate->addresses; +- if (op->call_responded && +- op->addr_index != READ_ONCE(alist->preferred) && +- test_bit(alist->preferred, &op->addr_tried)) +- WRITE_ONCE(alist->preferred, op->addr_index); + op->estate = NULL; + goto pick_server; + +@@ -690,14 +684,7 @@ bool afs_select_fileserver(struct afs_operation *op) + failed: + trace_afs_rotate(op, afs_rotate_trace_failed, 0); + op->flags |= AFS_OPERATION_STOP; +- if (op->estate) { +- alist = op->estate->addresses; +- if (op->call_responded && +- op->addr_index != READ_ONCE(alist->preferred) && +- test_bit(alist->preferred, &op->addr_tried)) +- WRITE_ONCE(alist->preferred, op->addr_index); +- op->estate = NULL; +- } ++ op->estate = NULL; + _leave(" = f [failed %d]", afs_op_error(op)); + return false; + } +diff --git a/fs/afs/validation.c b/fs/afs/validation.c +index 46b37f2cce7d9..32a53fc8dfb26 100644 +--- a/fs/afs/validation.c ++++ b/fs/afs/validation.c +@@ -122,6 +122,9 @@ bool afs_check_validity(const struct afs_vnode *vnode) + const struct afs_volume *volume = vnode->volume; + time64_t deadline = ktime_get_real_seconds() + 10; + ++ if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) ++ return true; ++ + if (atomic_read(&volume->cb_v_check) != atomic_read(&volume->cb_v_break) || + atomic64_read(&vnode->cb_expires_at) <= deadline || + volume->cb_expires_at <= deadline || +@@ -389,12 +392,17 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) + key_serial(key)); + + if (afs_check_validity(vnode)) +- return 0; ++ return test_bit(AFS_VNODE_DELETED, &vnode->flags) ? -ESTALE : 0; + + ret = down_write_killable(&vnode->validate_lock); + if (ret < 0) + goto error; + ++ if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { ++ ret = -ESTALE; ++ goto error_unlock; ++ } ++ + /* Validate a volume after the v_break has changed or the volume + * callback expired. We only want to do this once per volume per + * v_break change. The actual work will be done when parsing the +@@ -448,12 +456,6 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) + vnode->cb_ro_snapshot = cb_ro_snapshot; + vnode->cb_scrub = cb_scrub; + +- if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { +- _debug("file already deleted"); +- ret = -ESTALE; +- goto error_unlock; +- } +- + /* if the vnode's data version number changed then its contents are + * different */ + zap |= test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); +diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c +index 8b4bef05e2221..7761d7d93ba98 100644 +--- a/fs/btrfs/extent_io.c ++++ b/fs/btrfs/extent_io.c +@@ -2453,12 +2453,65 @@ int try_release_extent_mapping(struct page *page, gfp_t mask) + return try_release_extent_state(tree, page, mask); + } + ++struct btrfs_fiemap_entry { ++ u64 offset; ++ u64 phys; ++ u64 len; ++ u32 flags; ++}; ++ + /* +- * To cache previous fiemap extent ++ * Indicate the caller of emit_fiemap_extent() that it needs to unlock the file ++ * range from the inode's io tree, unlock the subvolume tree search path, flush ++ * the fiemap cache and relock the file range and research the subvolume tree. ++ * The value here is something negative that can't be confused with a valid ++ * errno value and different from 1 because that's also a return value from ++ * fiemap_fill_next_extent() and also it's often used to mean some btree search ++ * did not find a key, so make it some distinct negative value. ++ */ ++#define BTRFS_FIEMAP_FLUSH_CACHE (-(MAX_ERRNO + 1)) ++ ++/* ++ * Used to: ++ * ++ * - Cache the next entry to be emitted to the fiemap buffer, so that we can ++ * merge extents that are contiguous and can be grouped as a single one; + * +- * Will be used for merging fiemap extent ++ * - Store extents ready to be written to the fiemap buffer in an intermediary ++ * buffer. This intermediary buffer is to ensure that in case the fiemap ++ * buffer is memory mapped to the fiemap target file, we don't deadlock ++ * during btrfs_page_mkwrite(). This is because during fiemap we are locking ++ * an extent range in order to prevent races with delalloc flushing and ++ * ordered extent completion, which is needed in order to reliably detect ++ * delalloc in holes and prealloc extents. And this can lead to a deadlock ++ * if the fiemap buffer is memory mapped to the file we are running fiemap ++ * against (a silly, useless in practice scenario, but possible) because ++ * btrfs_page_mkwrite() will try to lock the same extent range. + */ + struct fiemap_cache { ++ /* An array of ready fiemap entries. */ ++ struct btrfs_fiemap_entry *entries; ++ /* Number of entries in the entries array. */ ++ int entries_size; ++ /* Index of the next entry in the entries array to write to. */ ++ int entries_pos; ++ /* ++ * Once the entries array is full, this indicates what's the offset for ++ * the next file extent item we must search for in the inode's subvolume ++ * tree after unlocking the extent range in the inode's io tree and ++ * releasing the search path. ++ */ ++ u64 next_search_offset; ++ /* ++ * This matches struct fiemap_extent_info::fi_mapped_extents, we use it ++ * to count ourselves emitted extents and stop instead of relying on ++ * fiemap_fill_next_extent() because we buffer ready fiemap entries at ++ * the @entries array, and we want to stop as soon as we hit the max ++ * amount of extents to map, not just to save time but also to make the ++ * logic at extent_fiemap() simpler. ++ */ ++ unsigned int extents_mapped; ++ /* Fields for the cached extent (unsubmitted, not ready, extent). */ + u64 offset; + u64 phys; + u64 len; +@@ -2466,6 +2519,28 @@ struct fiemap_cache { + bool cached; + }; + ++static int flush_fiemap_cache(struct fiemap_extent_info *fieinfo, ++ struct fiemap_cache *cache) ++{ ++ for (int i = 0; i < cache->entries_pos; i++) { ++ struct btrfs_fiemap_entry *entry = &cache->entries[i]; ++ int ret; ++ ++ ret = fiemap_fill_next_extent(fieinfo, entry->offset, ++ entry->phys, entry->len, ++ entry->flags); ++ /* ++ * Ignore 1 (reached max entries) because we keep track of that ++ * ourselves in emit_fiemap_extent(). ++ */ ++ if (ret < 0) ++ return ret; ++ } ++ cache->entries_pos = 0; ++ ++ return 0; ++} ++ + /* + * Helper to submit fiemap extent. + * +@@ -2480,8 +2555,8 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo, + struct fiemap_cache *cache, + u64 offset, u64 phys, u64 len, u32 flags) + { ++ struct btrfs_fiemap_entry *entry; + u64 cache_end; +- int ret = 0; + + /* Set at the end of extent_fiemap(). */ + ASSERT((flags & FIEMAP_EXTENT_LAST) == 0); +@@ -2494,7 +2569,9 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo, + * find an extent that starts at an offset behind the end offset of the + * previous extent we processed. This happens if fiemap is called + * without FIEMAP_FLAG_SYNC and there are ordered extents completing +- * while we call btrfs_next_leaf() (through fiemap_next_leaf_item()). ++ * after we had to unlock the file range, release the search path, emit ++ * the fiemap extents stored in the buffer (cache->entries array) and ++ * the lock the remainder of the range and re-search the btree. + * + * For example we are in leaf X processing its last item, which is the + * file extent item for file range [512K, 1M[, and after +@@ -2607,11 +2684,35 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo, + + emit: + /* Not mergeable, need to submit cached one */ +- ret = fiemap_fill_next_extent(fieinfo, cache->offset, cache->phys, +- cache->len, cache->flags); +- cache->cached = false; +- if (ret) +- return ret; ++ ++ if (cache->entries_pos == cache->entries_size) { ++ /* ++ * We will need to research for the end offset of the last ++ * stored extent and not from the current offset, because after ++ * unlocking the range and releasing the path, if there's a hole ++ * between that end offset and this current offset, a new extent ++ * may have been inserted due to a new write, so we don't want ++ * to miss it. ++ */ ++ entry = &cache->entries[cache->entries_size - 1]; ++ cache->next_search_offset = entry->offset + entry->len; ++ cache->cached = false; ++ ++ return BTRFS_FIEMAP_FLUSH_CACHE; ++ } ++ ++ entry = &cache->entries[cache->entries_pos]; ++ entry->offset = cache->offset; ++ entry->phys = cache->phys; ++ entry->len = cache->len; ++ entry->flags = cache->flags; ++ cache->entries_pos++; ++ cache->extents_mapped++; ++ ++ if (cache->extents_mapped == fieinfo->fi_extents_max) { ++ cache->cached = false; ++ return 1; ++ } + assign: + cache->cached = true; + cache->offset = offset; +@@ -2737,8 +2838,8 @@ static int fiemap_search_slot(struct btrfs_inode *inode, struct btrfs_path *path + * neighbour leaf). + * We also need the private clone because holding a read lock on an + * extent buffer of the subvolume's b+tree will make lockdep unhappy +- * when we call fiemap_fill_next_extent(), because that may cause a page +- * fault when filling the user space buffer with fiemap data. ++ * when we check if extents are shared, as backref walking may need to ++ * lock the same leaf we are processing. + */ + clone = btrfs_clone_extent_buffer(path->nodes[0]); + if (!clone) +@@ -2778,34 +2879,16 @@ static int fiemap_process_hole(struct btrfs_inode *inode, + * it beyond i_size. + */ + while (cur_offset < end && cur_offset < i_size) { +- struct extent_state *cached_state = NULL; + u64 delalloc_start; + u64 delalloc_end; + u64 prealloc_start; +- u64 lockstart; +- u64 lockend; + u64 prealloc_len = 0; + bool delalloc; + +- lockstart = round_down(cur_offset, inode->root->fs_info->sectorsize); +- lockend = round_up(end, inode->root->fs_info->sectorsize); +- +- /* +- * We are only locking for the delalloc range because that's the +- * only thing that can change here. With fiemap we have a lock +- * on the inode, so no buffered or direct writes can happen. +- * +- * However mmaps and normal page writeback will cause this to +- * change arbitrarily. We have to lock the extent lock here to +- * make sure that nobody messes with the tree while we're doing +- * btrfs_find_delalloc_in_range. +- */ +- lock_extent(&inode->io_tree, lockstart, lockend, &cached_state); + delalloc = btrfs_find_delalloc_in_range(inode, cur_offset, end, + delalloc_cached_state, + &delalloc_start, + &delalloc_end); +- unlock_extent(&inode->io_tree, lockstart, lockend, &cached_state); + if (!delalloc) + break; + +@@ -2973,6 +3056,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo, + u64 start, u64 len) + { + const u64 ino = btrfs_ino(inode); ++ struct extent_state *cached_state = NULL; + struct extent_state *delalloc_cached_state = NULL; + struct btrfs_path *path; + struct fiemap_cache cache = { 0 }; +@@ -2985,26 +3069,33 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo, + bool stopped = false; + int ret; + ++ cache.entries_size = PAGE_SIZE / sizeof(struct btrfs_fiemap_entry); ++ cache.entries = kmalloc_array(cache.entries_size, ++ sizeof(struct btrfs_fiemap_entry), ++ GFP_KERNEL); + backref_ctx = btrfs_alloc_backref_share_check_ctx(); + path = btrfs_alloc_path(); +- if (!backref_ctx || !path) { ++ if (!cache.entries || !backref_ctx || !path) { + ret = -ENOMEM; + goto out; + } + ++restart: + range_start = round_down(start, sectorsize); + range_end = round_up(start + len, sectorsize); + prev_extent_end = range_start; + ++ lock_extent(&inode->io_tree, range_start, range_end, &cached_state); ++ + ret = fiemap_find_last_extent_offset(inode, path, &last_extent_end); + if (ret < 0) +- goto out; ++ goto out_unlock; + btrfs_release_path(path); + + path->reada = READA_FORWARD; + ret = fiemap_search_slot(inode, path, range_start); + if (ret < 0) { +- goto out; ++ goto out_unlock; + } else if (ret > 0) { + /* + * No file extent item found, but we may have delalloc between +@@ -3051,7 +3142,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo, + backref_ctx, 0, 0, 0, + prev_extent_end, hole_end); + if (ret < 0) { +- goto out; ++ goto out_unlock; + } else if (ret > 0) { + /* fiemap_fill_next_extent() told us to stop. */ + stopped = true; +@@ -3107,7 +3198,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo, + extent_gen, + backref_ctx); + if (ret < 0) +- goto out; ++ goto out_unlock; + else if (ret > 0) + flags |= FIEMAP_EXTENT_SHARED; + } +@@ -3118,9 +3209,9 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo, + } + + if (ret < 0) { +- goto out; ++ goto out_unlock; + } else if (ret > 0) { +- /* fiemap_fill_next_extent() told us to stop. */ ++ /* emit_fiemap_extent() told us to stop. */ + stopped = true; + break; + } +@@ -3129,12 +3220,12 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo, + next_item: + if (fatal_signal_pending(current)) { + ret = -EINTR; +- goto out; ++ goto out_unlock; + } + + ret = fiemap_next_leaf_item(inode, path); + if (ret < 0) { +- goto out; ++ goto out_unlock; + } else if (ret > 0) { + /* No more file extent items for this inode. */ + break; +@@ -3143,22 +3234,12 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo, + } + + check_eof_delalloc: +- /* +- * Release (and free) the path before emitting any final entries to +- * fiemap_fill_next_extent() to keep lockdep happy. This is because +- * once we find no more file extent items exist, we may have a +- * non-cloned leaf, and fiemap_fill_next_extent() can trigger page +- * faults when copying data to the user space buffer. +- */ +- btrfs_free_path(path); +- path = NULL; +- + if (!stopped && prev_extent_end < range_end) { + ret = fiemap_process_hole(inode, fieinfo, &cache, + &delalloc_cached_state, backref_ctx, + 0, 0, 0, prev_extent_end, range_end - 1); + if (ret < 0) +- goto out; ++ goto out_unlock; + prev_extent_end = range_end; + } + +@@ -3166,28 +3247,16 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo, + const u64 i_size = i_size_read(&inode->vfs_inode); + + if (prev_extent_end < i_size) { +- struct extent_state *cached_state = NULL; + u64 delalloc_start; + u64 delalloc_end; +- u64 lockstart; +- u64 lockend; + bool delalloc; + +- lockstart = round_down(prev_extent_end, sectorsize); +- lockend = round_up(i_size, sectorsize); +- +- /* +- * See the comment in fiemap_process_hole as to why +- * we're doing the locking here. +- */ +- lock_extent(&inode->io_tree, lockstart, lockend, &cached_state); + delalloc = btrfs_find_delalloc_in_range(inode, + prev_extent_end, + i_size - 1, + &delalloc_cached_state, + &delalloc_start, + &delalloc_end); +- unlock_extent(&inode->io_tree, lockstart, lockend, &cached_state); + if (!delalloc) + cache.flags |= FIEMAP_EXTENT_LAST; + } else { +@@ -3195,9 +3264,39 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo, + } + } + ++out_unlock: ++ unlock_extent(&inode->io_tree, range_start, range_end, &cached_state); ++ ++ if (ret == BTRFS_FIEMAP_FLUSH_CACHE) { ++ btrfs_release_path(path); ++ ret = flush_fiemap_cache(fieinfo, &cache); ++ if (ret) ++ goto out; ++ len -= cache.next_search_offset - start; ++ start = cache.next_search_offset; ++ goto restart; ++ } else if (ret < 0) { ++ goto out; ++ } ++ ++ /* ++ * Must free the path before emitting to the fiemap buffer because we ++ * may have a non-cloned leaf and if the fiemap buffer is memory mapped ++ * to a file, a write into it (through btrfs_page_mkwrite()) may trigger ++ * waiting for an ordered extent that in order to complete needs to ++ * modify that leaf, therefore leading to a deadlock. ++ */ ++ btrfs_free_path(path); ++ path = NULL; ++ ++ ret = flush_fiemap_cache(fieinfo, &cache); ++ if (ret) ++ goto out; ++ + ret = emit_last_fiemap_cache(fieinfo, &cache); + out: + free_extent_state(delalloc_cached_state); ++ kfree(cache.entries); + btrfs_free_backref_share_ctx(backref_ctx); + btrfs_free_path(path); + return ret; +diff --git a/fs/ceph/file.c b/fs/ceph/file.c +index abe8028d95bf4..3d1cd079dbf16 100644 +--- a/fs/ceph/file.c ++++ b/fs/ceph/file.c +@@ -1138,7 +1138,12 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos, + } + + idx = 0; +- left = ret > 0 ? ret : 0; ++ if (ret <= 0) ++ left = 0; ++ else if (off + ret > i_size) ++ left = i_size - off; ++ else ++ left = ret; + while (left > 0) { + size_t plen, copied; + +@@ -1167,15 +1172,13 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos, + } + + if (ret > 0) { +- if (off > *ki_pos) { +- if (off >= i_size) { +- *retry_op = CHECK_EOF; +- ret = i_size - *ki_pos; +- *ki_pos = i_size; +- } else { +- ret = off - *ki_pos; +- *ki_pos = off; +- } ++ if (off >= i_size) { ++ *retry_op = CHECK_EOF; ++ ret = i_size - *ki_pos; ++ *ki_pos = i_size; ++ } else { ++ ret = off - *ki_pos; ++ *ki_pos = off; + } + + if (last_objver) +diff --git a/fs/erofs/fscache.c b/fs/erofs/fscache.c +index 89a7c2453aae6..122a4753ecea4 100644 +--- a/fs/erofs/fscache.c ++++ b/fs/erofs/fscache.c +@@ -3,6 +3,7 @@ + * Copyright (C) 2022, Alibaba Cloud + * Copyright (C) 2022, Bytedance Inc. All rights reserved. + */ ++#include + #include + #include "internal.h" + +@@ -12,6 +13,18 @@ static LIST_HEAD(erofs_domain_list); + static LIST_HEAD(erofs_domain_cookies_list); + static struct vfsmount *erofs_pseudo_mnt; + ++static int erofs_anon_init_fs_context(struct fs_context *fc) ++{ ++ return init_pseudo(fc, EROFS_SUPER_MAGIC) ? 0 : -ENOMEM; ++} ++ ++static struct file_system_type erofs_anon_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "pseudo_erofs", ++ .init_fs_context = erofs_anon_init_fs_context, ++ .kill_sb = kill_anon_super, ++}; ++ + struct erofs_fscache_request { + struct erofs_fscache_request *primary; + struct netfs_cache_resources cache_resources; +@@ -381,7 +394,7 @@ static int erofs_fscache_init_domain(struct super_block *sb) + goto out; + + if (!erofs_pseudo_mnt) { +- struct vfsmount *mnt = kern_mount(&erofs_fs_type); ++ struct vfsmount *mnt = kern_mount(&erofs_anon_fs_type); + if (IS_ERR(mnt)) { + err = PTR_ERR(mnt); + goto out; +diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h +index b0409badb0172..410f5af623540 100644 +--- a/fs/erofs/internal.h ++++ b/fs/erofs/internal.h +@@ -385,7 +385,6 @@ struct erofs_map_dev { + unsigned int m_deviceid; + }; + +-extern struct file_system_type erofs_fs_type; + extern const struct super_operations erofs_sops; + + extern const struct address_space_operations erofs_raw_access_aops; +diff --git a/fs/erofs/super.c b/fs/erofs/super.c +index 5f60f163bd56e..24788c230b494 100644 +--- a/fs/erofs/super.c ++++ b/fs/erofs/super.c +@@ -579,13 +579,6 @@ static const struct export_operations erofs_export_ops = { + .get_parent = erofs_get_parent, + }; + +-static int erofs_fc_fill_pseudo_super(struct super_block *sb, struct fs_context *fc) +-{ +- static const struct tree_descr empty_descr = {""}; +- +- return simple_fill_super(sb, EROFS_SUPER_MAGIC, &empty_descr); +-} +- + static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc) + { + struct inode *inode; +@@ -712,11 +705,6 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc) + return 0; + } + +-static int erofs_fc_anon_get_tree(struct fs_context *fc) +-{ +- return get_tree_nodev(fc, erofs_fc_fill_pseudo_super); +-} +- + static int erofs_fc_get_tree(struct fs_context *fc) + { + struct erofs_fs_context *ctx = fc->fs_private; +@@ -789,20 +777,10 @@ static const struct fs_context_operations erofs_context_ops = { + .free = erofs_fc_free, + }; + +-static const struct fs_context_operations erofs_anon_context_ops = { +- .get_tree = erofs_fc_anon_get_tree, +-}; +- + static int erofs_init_fs_context(struct fs_context *fc) + { + struct erofs_fs_context *ctx; + +- /* pseudo mount for anon inodes */ +- if (fc->sb_flags & SB_KERNMOUNT) { +- fc->ops = &erofs_anon_context_ops; +- return 0; +- } +- + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; +@@ -824,12 +802,6 @@ static void erofs_kill_sb(struct super_block *sb) + { + struct erofs_sb_info *sbi; + +- /* pseudo mount for anon inodes */ +- if (sb->s_flags & SB_KERNMOUNT) { +- kill_anon_super(sb); +- return; +- } +- + if (erofs_is_fscache_mode(sb)) + kill_anon_super(sb); + else +@@ -868,7 +840,7 @@ static void erofs_put_super(struct super_block *sb) + erofs_fscache_unregister_fs(sb); + } + +-struct file_system_type erofs_fs_type = { ++static struct file_system_type erofs_fs_type = { + .owner = THIS_MODULE, + .name = "erofs", + .init_fs_context = erofs_init_fs_context, +diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h +index 677a9ad45dcb7..f38bdd46e4f77 100644 +--- a/fs/ext2/ext2.h ++++ b/fs/ext2/ext2.h +@@ -674,7 +674,7 @@ struct ext2_inode_info { + struct inode vfs_inode; + struct list_head i_orphan; /* unlinked but open inodes */ + #ifdef CONFIG_QUOTA +- struct dquot *i_dquot[MAXQUOTAS]; ++ struct dquot __rcu *i_dquot[MAXQUOTAS]; + #endif + }; + +diff --git a/fs/ext2/super.c b/fs/ext2/super.c +index 01f9addc8b1f6..6d8587505cea3 100644 +--- a/fs/ext2/super.c ++++ b/fs/ext2/super.c +@@ -320,7 +320,7 @@ static ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, siz + static ssize_t ext2_quota_write(struct super_block *sb, int type, const char *data, size_t len, loff_t off); + static int ext2_quota_on(struct super_block *sb, int type, int format_id, + const struct path *path); +-static struct dquot **ext2_get_dquots(struct inode *inode) ++static struct dquot __rcu **ext2_get_dquots(struct inode *inode) + { + return EXT2_I(inode)->i_dquot; + } +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 023571f8dd1b4..4fb938ba3f359 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -1158,7 +1158,7 @@ struct ext4_inode_info { + tid_t i_datasync_tid; + + #ifdef CONFIG_QUOTA +- struct dquot *i_dquot[MAXQUOTAS]; ++ struct dquot __rcu *i_dquot[MAXQUOTAS]; + #endif + + /* Precomputed uuid+inum+igen checksum for seeding inode checksums */ +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index 0f931d0c227da..32bd83adf0bb8 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -1600,7 +1600,7 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type, + static int ext4_quota_enable(struct super_block *sb, int type, int format_id, + unsigned int flags); + +-static struct dquot **ext4_get_dquots(struct inode *inode) ++static struct dquot __rcu **ext4_get_dquots(struct inode *inode) + { + return EXT4_I(inode)->i_dquot; + } +diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c +index b0597a539fc54..9afc8d24dc369 100644 +--- a/fs/f2fs/checkpoint.c ++++ b/fs/f2fs/checkpoint.c +@@ -1587,8 +1587,9 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) + */ + if (f2fs_sb_has_encrypt(sbi) || f2fs_sb_has_verity(sbi) || + f2fs_sb_has_compression(sbi)) +- invalidate_mapping_pages(META_MAPPING(sbi), +- MAIN_BLKADDR(sbi), MAX_BLKADDR(sbi) - 1); ++ f2fs_bug_on(sbi, ++ invalidate_inode_pages2_range(META_MAPPING(sbi), ++ MAIN_BLKADDR(sbi), MAX_BLKADDR(sbi) - 1)); + + f2fs_release_ino_entry(sbi, false); + +diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c +index 531517dac0796..15f330d8fdb93 100644 +--- a/fs/f2fs/compress.c ++++ b/fs/f2fs/compress.c +@@ -1418,6 +1418,8 @@ void f2fs_compress_write_end_io(struct bio *bio, struct page *page) + struct f2fs_sb_info *sbi = bio->bi_private; + struct compress_io_ctx *cic = + (struct compress_io_ctx *)page_private(page); ++ enum count_type type = WB_DATA_TYPE(page, ++ f2fs_is_compressed_page(page)); + int i; + + if (unlikely(bio->bi_status)) +@@ -1425,7 +1427,7 @@ void f2fs_compress_write_end_io(struct bio *bio, struct page *page) + + f2fs_compress_free_page(page); + +- dec_page_count(sbi, F2FS_WB_DATA); ++ dec_page_count(sbi, type); + + if (atomic_dec_return(&cic->pending_pages)) + return; +@@ -1441,12 +1443,14 @@ void f2fs_compress_write_end_io(struct bio *bio, struct page *page) + } + + static int f2fs_write_raw_pages(struct compress_ctx *cc, +- int *submitted, ++ int *submitted_p, + struct writeback_control *wbc, + enum iostat_type io_type) + { + struct address_space *mapping = cc->inode->i_mapping; +- int _submitted, compr_blocks, ret, i; ++ struct f2fs_sb_info *sbi = F2FS_M_SB(mapping); ++ int submitted, compr_blocks, i; ++ int ret = 0; + + compr_blocks = f2fs_compressed_blocks(cc); + +@@ -1461,6 +1465,10 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc, + if (compr_blocks < 0) + return compr_blocks; + ++ /* overwrite compressed cluster w/ normal cluster */ ++ if (compr_blocks > 0) ++ f2fs_lock_op(sbi); ++ + for (i = 0; i < cc->cluster_size; i++) { + if (!cc->rpages[i]) + continue; +@@ -1485,7 +1493,7 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc, + if (!clear_page_dirty_for_io(cc->rpages[i])) + goto continue_unlock; + +- ret = f2fs_write_single_data_page(cc->rpages[i], &_submitted, ++ ret = f2fs_write_single_data_page(cc->rpages[i], &submitted, + NULL, NULL, wbc, io_type, + compr_blocks, false); + if (ret) { +@@ -1493,26 +1501,29 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc, + unlock_page(cc->rpages[i]); + ret = 0; + } else if (ret == -EAGAIN) { ++ ret = 0; + /* + * for quota file, just redirty left pages to + * avoid deadlock caused by cluster update race + * from foreground operation. + */ + if (IS_NOQUOTA(cc->inode)) +- return 0; +- ret = 0; ++ goto out; + f2fs_io_schedule_timeout(DEFAULT_IO_TIMEOUT); + goto retry_write; + } +- return ret; ++ goto out; + } + +- *submitted += _submitted; ++ *submitted_p += submitted; + } + +- f2fs_balance_fs(F2FS_M_SB(mapping), true); ++out: ++ if (compr_blocks > 0) ++ f2fs_unlock_op(sbi); + +- return 0; ++ f2fs_balance_fs(sbi, true); ++ return ret; + } + + int f2fs_write_multi_pages(struct compress_ctx *cc, +@@ -1806,16 +1817,18 @@ void f2fs_put_page_dic(struct page *page, bool in_task) + * check whether cluster blocks are contiguous, and add extent cache entry + * only if cluster blocks are logically and physically contiguous. + */ +-unsigned int f2fs_cluster_blocks_are_contiguous(struct dnode_of_data *dn) ++unsigned int f2fs_cluster_blocks_are_contiguous(struct dnode_of_data *dn, ++ unsigned int ofs_in_node) + { +- bool compressed = f2fs_data_blkaddr(dn) == COMPRESS_ADDR; ++ bool compressed = data_blkaddr(dn->inode, dn->node_page, ++ ofs_in_node) == COMPRESS_ADDR; + int i = compressed ? 1 : 0; + block_t first_blkaddr = data_blkaddr(dn->inode, dn->node_page, +- dn->ofs_in_node + i); ++ ofs_in_node + i); + + for (i += 1; i < F2FS_I(dn->inode)->i_cluster_size; i++) { + block_t blkaddr = data_blkaddr(dn->inode, dn->node_page, +- dn->ofs_in_node + i); ++ ofs_in_node + i); + + if (!__is_valid_data_blkaddr(blkaddr)) + break; +diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c +index 26e317696b338..05158f89ef32d 100644 +--- a/fs/f2fs/data.c ++++ b/fs/f2fs/data.c +@@ -48,7 +48,7 @@ void f2fs_destroy_bioset(void) + bioset_exit(&f2fs_bioset); + } + +-static bool __is_cp_guaranteed(struct page *page) ++bool f2fs_is_cp_guaranteed(struct page *page) + { + struct address_space *mapping = page->mapping; + struct inode *inode; +@@ -65,8 +65,6 @@ static bool __is_cp_guaranteed(struct page *page) + S_ISDIR(inode->i_mode)) + return true; + +- if (f2fs_is_compressed_page(page)) +- return false; + if ((S_ISREG(inode->i_mode) && IS_NOQUOTA(inode)) || + page_private_gcing(page)) + return true; +@@ -338,7 +336,7 @@ static void f2fs_write_end_io(struct bio *bio) + + bio_for_each_segment_all(bvec, bio, iter_all) { + struct page *page = bvec->bv_page; +- enum count_type type = WB_DATA_TYPE(page); ++ enum count_type type = WB_DATA_TYPE(page, false); + + if (page_private_dummy(page)) { + clear_page_private_dummy(page); +@@ -762,7 +760,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio) + wbc_account_cgroup_owner(fio->io_wbc, fio->page, PAGE_SIZE); + + inc_page_count(fio->sbi, is_read_io(fio->op) ? +- __read_io_type(page) : WB_DATA_TYPE(fio->page)); ++ __read_io_type(page) : WB_DATA_TYPE(fio->page, false)); + + if (is_read_io(bio_op(bio))) + f2fs_submit_read_bio(fio->sbi, bio, fio->type); +@@ -973,7 +971,7 @@ int f2fs_merge_page_bio(struct f2fs_io_info *fio) + if (fio->io_wbc) + wbc_account_cgroup_owner(fio->io_wbc, fio->page, PAGE_SIZE); + +- inc_page_count(fio->sbi, WB_DATA_TYPE(page)); ++ inc_page_count(fio->sbi, WB_DATA_TYPE(page, false)); + + *fio->last_block = fio->new_blkaddr; + *fio->bio = bio; +@@ -1007,11 +1005,12 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio) + enum page_type btype = PAGE_TYPE_OF_BIO(fio->type); + struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp; + struct page *bio_page; ++ enum count_type type; + + f2fs_bug_on(sbi, is_read_io(fio->op)); + + f2fs_down_write(&io->io_rwsem); +- ++next: + #ifdef CONFIG_BLK_DEV_ZONED + if (f2fs_sb_has_blkzoned(sbi) && btype < META && io->zone_pending_bio) { + wait_for_completion_io(&io->zone_wait); +@@ -1021,7 +1020,6 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio) + } + #endif + +-next: + if (fio->in_list) { + spin_lock(&io->io_lock); + if (list_empty(&io->io_list)) { +@@ -1046,7 +1044,8 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio) + /* set submitted = true as a return value */ + fio->submitted = 1; + +- inc_page_count(sbi, WB_DATA_TYPE(bio_page)); ++ type = WB_DATA_TYPE(bio_page, fio->compressed_page); ++ inc_page_count(sbi, type); + + if (io->bio && + (!io_is_mergeable(sbi, io->bio, io, fio, io->last_block_in_bio, +@@ -1059,7 +1058,8 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio) + if (F2FS_IO_ALIGNED(sbi) && + (fio->type == DATA || fio->type == NODE) && + fio->new_blkaddr & F2FS_IO_SIZE_MASK(sbi)) { +- dec_page_count(sbi, WB_DATA_TYPE(bio_page)); ++ dec_page_count(sbi, WB_DATA_TYPE(bio_page, ++ fio->compressed_page)); + fio->retry = 1; + goto skip; + } +@@ -1080,10 +1080,6 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio) + io->last_block_in_bio = fio->new_blkaddr; + + trace_f2fs_submit_page_write(fio->page, fio); +-skip: +- if (fio->in_list) +- goto next; +-out: + #ifdef CONFIG_BLK_DEV_ZONED + if (f2fs_sb_has_blkzoned(sbi) && btype < META && + is_end_zone_blkaddr(sbi, fio->new_blkaddr)) { +@@ -1096,6 +1092,10 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio) + __submit_merged_bio(io); + } + #endif ++skip: ++ if (fio->in_list) ++ goto next; ++out: + if (is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN) || + !f2fs_is_checkpoint_ready(sbi)) + __submit_merged_bio(io); +@@ -1218,7 +1218,8 @@ int f2fs_reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count) + + if (unlikely(is_inode_flag_set(dn->inode, FI_NO_ALLOC))) + return -EPERM; +- if (unlikely((err = inc_valid_block_count(sbi, dn->inode, &count)))) ++ err = inc_valid_block_count(sbi, dn->inode, &count, true); ++ if (unlikely(err)) + return err; + + trace_f2fs_reserve_new_blocks(dn->inode, dn->nid, +@@ -1475,7 +1476,7 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type) + + dn->data_blkaddr = f2fs_data_blkaddr(dn); + if (dn->data_blkaddr == NULL_ADDR) { +- err = inc_valid_block_count(sbi, dn->inode, &count); ++ err = inc_valid_block_count(sbi, dn->inode, &count, true); + if (unlikely(err)) + return err; + } +@@ -2838,7 +2839,7 @@ int f2fs_write_single_data_page(struct page *page, int *submitted, + .encrypted_page = NULL, + .submitted = 0, + .compr_blocks = compr_blocks, +- .need_lock = LOCK_RETRY, ++ .need_lock = compr_blocks ? LOCK_DONE : LOCK_RETRY, + .post_read = f2fs_post_read_required(inode) ? 1 : 0, + .io_type = io_type, + .io_wbc = wbc, +@@ -2919,6 +2920,7 @@ int f2fs_write_single_data_page(struct page *page, int *submitted, + if (err == -EAGAIN) { + err = f2fs_do_write_data_page(&fio); + if (err == -EAGAIN) { ++ f2fs_bug_on(sbi, compr_blocks); + fio.need_lock = LOCK_REQ; + err = f2fs_do_write_data_page(&fio); + } +diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c +index 042593aed1ec0..1b937f7d0414f 100644 +--- a/fs/f2fs/dir.c ++++ b/fs/f2fs/dir.c +@@ -830,13 +830,14 @@ int f2fs_do_add_link(struct inode *dir, const struct qstr *name, + return err; + } + +-int f2fs_do_tmpfile(struct inode *inode, struct inode *dir) ++int f2fs_do_tmpfile(struct inode *inode, struct inode *dir, ++ struct f2fs_filename *fname) + { + struct page *page; + int err = 0; + + f2fs_down_write(&F2FS_I(inode)->i_sem); +- page = f2fs_init_inode_metadata(inode, dir, NULL, NULL); ++ page = f2fs_init_inode_metadata(inode, dir, fname, NULL); + if (IS_ERR(page)) { + err = PTR_ERR(page); + goto fail; +diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h +index 65294e3b0bef8..5a6c35d70c7ad 100644 +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -75,6 +75,11 @@ struct f2fs_fault_info { + + extern const char *f2fs_fault_name[FAULT_MAX]; + #define IS_FAULT_SET(fi, type) ((fi)->inject_type & BIT(type)) ++ ++/* maximum retry count for injected failure */ ++#define DEFAULT_FAILURE_RETRY_COUNT 8 ++#else ++#define DEFAULT_FAILURE_RETRY_COUNT 1 + #endif + + /* +@@ -829,7 +834,7 @@ struct f2fs_inode_info { + spinlock_t i_size_lock; /* protect last_disk_size */ + + #ifdef CONFIG_QUOTA +- struct dquot *i_dquot[MAXQUOTAS]; ++ struct dquot __rcu *i_dquot[MAXQUOTAS]; + + /* quota space reservation, managed internally by quota code */ + qsize_t i_reserved_quota; +@@ -1080,7 +1085,8 @@ struct f2fs_sm_info { + * f2fs monitors the number of several block types such as on-writeback, + * dirty dentry blocks, dirty node blocks, and dirty meta blocks. + */ +-#define WB_DATA_TYPE(p) (__is_cp_guaranteed(p) ? F2FS_WB_CP_DATA : F2FS_WB_DATA) ++#define WB_DATA_TYPE(p, f) \ ++ (f || f2fs_is_cp_guaranteed(p) ? F2FS_WB_CP_DATA : F2FS_WB_DATA) + enum count_type { + F2FS_DIRTY_DENTS, + F2FS_DIRTY_DATA, +@@ -2251,7 +2257,7 @@ static inline bool __allow_reserved_blocks(struct f2fs_sb_info *sbi, + + static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool); + static inline int inc_valid_block_count(struct f2fs_sb_info *sbi, +- struct inode *inode, blkcnt_t *count) ++ struct inode *inode, blkcnt_t *count, bool partial) + { + blkcnt_t diff = 0, release = 0; + block_t avail_user_block_count; +@@ -2291,6 +2297,11 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi, + avail_user_block_count = 0; + } + if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) { ++ if (!partial) { ++ spin_unlock(&sbi->stat_lock); ++ goto enospc; ++ } ++ + diff = sbi->total_valid_block_count - avail_user_block_count; + if (diff > *count) + diff = *count; +@@ -3464,11 +3475,9 @@ bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi, + static inline void verify_blkaddr(struct f2fs_sb_info *sbi, + block_t blkaddr, int type) + { +- if (!f2fs_is_valid_blkaddr(sbi, blkaddr, type)) { ++ if (!f2fs_is_valid_blkaddr(sbi, blkaddr, type)) + f2fs_err(sbi, "invalid blkaddr: %u, type: %d, run fsck to fix.", + blkaddr, type); +- f2fs_bug_on(sbi, 1); +- } + } + + static inline bool __is_valid_data_blkaddr(block_t blkaddr) +@@ -3570,7 +3579,8 @@ int f2fs_do_add_link(struct inode *dir, const struct qstr *name, + struct inode *inode, nid_t ino, umode_t mode); + void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, + struct inode *dir, struct inode *inode); +-int f2fs_do_tmpfile(struct inode *inode, struct inode *dir); ++int f2fs_do_tmpfile(struct inode *inode, struct inode *dir, ++ struct f2fs_filename *fname); + bool f2fs_empty_dir(struct inode *dir); + + static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode) +@@ -3804,6 +3814,7 @@ void f2fs_init_ckpt_req_control(struct f2fs_sb_info *sbi); + */ + int __init f2fs_init_bioset(void); + void f2fs_destroy_bioset(void); ++bool f2fs_is_cp_guaranteed(struct page *page); + int f2fs_init_bio_entry_cache(void); + void f2fs_destroy_bio_entry_cache(void); + void f2fs_submit_read_bio(struct f2fs_sb_info *sbi, struct bio *bio, +@@ -4287,7 +4298,8 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc); + void f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool failed, + bool in_task); + void f2fs_put_page_dic(struct page *page, bool in_task); +-unsigned int f2fs_cluster_blocks_are_contiguous(struct dnode_of_data *dn); ++unsigned int f2fs_cluster_blocks_are_contiguous(struct dnode_of_data *dn, ++ unsigned int ofs_in_node); + int f2fs_init_compress_ctx(struct compress_ctx *cc); + void f2fs_destroy_compress_ctx(struct compress_ctx *cc, bool reuse); + void f2fs_init_compress_info(struct f2fs_sb_info *sbi); +@@ -4344,7 +4356,8 @@ static inline void f2fs_put_page_dic(struct page *page, bool in_task) + { + WARN_ON_ONCE(1); + } +-static inline unsigned int f2fs_cluster_blocks_are_contiguous(struct dnode_of_data *dn) { return 0; } ++static inline unsigned int f2fs_cluster_blocks_are_contiguous( ++ struct dnode_of_data *dn, unsigned int ofs_in_node) { return 0; } + static inline bool f2fs_sanity_check_cluster(struct dnode_of_data *dn) { return false; } + static inline int f2fs_init_compress_inode(struct f2fs_sb_info *sbi) { return 0; } + static inline void f2fs_destroy_compress_inode(struct f2fs_sb_info *sbi) { } +@@ -4401,15 +4414,24 @@ static inline bool f2fs_disable_compressed_file(struct inode *inode) + { + struct f2fs_inode_info *fi = F2FS_I(inode); + +- if (!f2fs_compressed_file(inode)) ++ f2fs_down_write(&F2FS_I(inode)->i_sem); ++ ++ if (!f2fs_compressed_file(inode)) { ++ f2fs_up_write(&F2FS_I(inode)->i_sem); + return true; +- if (S_ISREG(inode->i_mode) && F2FS_HAS_BLOCKS(inode)) ++ } ++ if (f2fs_is_mmap_file(inode) || ++ (S_ISREG(inode->i_mode) && F2FS_HAS_BLOCKS(inode))) { ++ f2fs_up_write(&F2FS_I(inode)->i_sem); + return false; ++ } + + fi->i_flags &= ~F2FS_COMPR_FL; + stat_dec_compr_inode(inode); + clear_inode_flag(inode, FI_COMPRESSED_FILE); + f2fs_mark_inode_dirty_sync(inode, true); ++ ++ f2fs_up_write(&F2FS_I(inode)->i_sem); + return true; + } + +@@ -4613,10 +4635,36 @@ static inline bool f2fs_is_readonly(struct f2fs_sb_info *sbi) + return f2fs_sb_has_readonly(sbi) || f2fs_readonly(sbi->sb); + } + ++static inline void f2fs_truncate_meta_inode_pages(struct f2fs_sb_info *sbi, ++ block_t blkaddr, unsigned int cnt) ++{ ++ bool need_submit = false; ++ int i = 0; ++ ++ do { ++ struct page *page; ++ ++ page = find_get_page(META_MAPPING(sbi), blkaddr + i); ++ if (page) { ++ if (PageWriteback(page)) ++ need_submit = true; ++ f2fs_put_page(page, 0); ++ } ++ } while (++i < cnt && !need_submit); ++ ++ if (need_submit) ++ f2fs_submit_merged_write_cond(sbi, sbi->meta_inode, ++ NULL, 0, DATA); ++ ++ truncate_inode_pages_range(META_MAPPING(sbi), ++ F2FS_BLK_TO_BYTES((loff_t)blkaddr), ++ F2FS_BLK_END_BYTES((loff_t)(blkaddr + cnt - 1))); ++} ++ + static inline void f2fs_invalidate_internal_cache(struct f2fs_sb_info *sbi, + block_t blkaddr) + { +- invalidate_mapping_pages(META_MAPPING(sbi), blkaddr, blkaddr); ++ f2fs_truncate_meta_inode_pages(sbi, blkaddr, 1); + f2fs_invalidate_compress_page(sbi, blkaddr); + } + +diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c +index b58ab1157b7ef..51970b345eeee 100644 +--- a/fs/f2fs/file.c ++++ b/fs/f2fs/file.c +@@ -39,6 +39,7 @@ + static vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf) + { + struct inode *inode = file_inode(vmf->vma->vm_file); ++ vm_flags_t flags = vmf->vma->vm_flags; + vm_fault_t ret; + + ret = filemap_fault(vmf); +@@ -46,7 +47,7 @@ static vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf) + f2fs_update_iostat(F2FS_I_SB(inode), inode, + APP_MAPPED_READ_IO, F2FS_BLKSIZE); + +- trace_f2fs_filemap_fault(inode, vmf->pgoff, vmf->vma->vm_flags, ret); ++ trace_f2fs_filemap_fault(inode, vmf->pgoff, flags, ret); + + return ret; + } +@@ -3588,10 +3589,10 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg) + return ret; + } + +-static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count) ++static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count, ++ unsigned int *reserved_blocks) + { + struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); +- unsigned int reserved_blocks = 0; + int cluster_size = F2FS_I(dn->inode)->i_cluster_size; + block_t blkaddr; + int i; +@@ -3614,40 +3615,53 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count) + blkcnt_t reserved; + int ret; + +- for (i = 0; i < cluster_size; i++, dn->ofs_in_node++) { +- blkaddr = f2fs_data_blkaddr(dn); ++ for (i = 0; i < cluster_size; i++) { ++ blkaddr = data_blkaddr(dn->inode, dn->node_page, ++ dn->ofs_in_node + i); + + if (i == 0) { +- if (blkaddr == COMPRESS_ADDR) +- continue; +- dn->ofs_in_node += cluster_size; +- goto next; ++ if (blkaddr != COMPRESS_ADDR) { ++ dn->ofs_in_node += cluster_size; ++ goto next; ++ } ++ continue; + } + +- if (__is_valid_data_blkaddr(blkaddr)) { ++ /* ++ * compressed cluster was not released due to it ++ * fails in release_compress_blocks(), so NEW_ADDR ++ * is a possible case. ++ */ ++ if (blkaddr == NEW_ADDR || ++ __is_valid_data_blkaddr(blkaddr)) { + compr_blocks++; + continue; + } +- +- f2fs_set_data_blkaddr(dn, NEW_ADDR); + } + + reserved = cluster_size - compr_blocks; +- ret = inc_valid_block_count(sbi, dn->inode, &reserved); +- if (ret) ++ ++ /* for the case all blocks in cluster were reserved */ ++ if (reserved == 1) ++ goto next; ++ ++ ret = inc_valid_block_count(sbi, dn->inode, &reserved, false); ++ if (unlikely(ret)) + return ret; + +- if (reserved != cluster_size - compr_blocks) +- return -ENOSPC; ++ for (i = 0; i < cluster_size; i++, dn->ofs_in_node++) { ++ if (f2fs_data_blkaddr(dn) == NULL_ADDR) ++ f2fs_set_data_blkaddr(dn, NEW_ADDR); ++ } + + f2fs_i_compr_blocks_update(dn->inode, compr_blocks, true); + +- reserved_blocks += reserved; ++ *reserved_blocks += reserved; + next: + count -= cluster_size; + } + +- return reserved_blocks; ++ return 0; + } + + static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg) +@@ -3671,9 +3685,6 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg) + if (ret) + return ret; + +- if (atomic_read(&F2FS_I(inode)->i_compr_blocks)) +- goto out; +- + f2fs_balance_fs(sbi, true); + + inode_lock(inode); +@@ -3683,6 +3694,9 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg) + goto unlock_inode; + } + ++ if (atomic_read(&F2FS_I(inode)->i_compr_blocks)) ++ goto unlock_inode; ++ + f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); + filemap_invalidate_lock(inode->i_mapping); + +@@ -3708,7 +3722,7 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg) + count = min(end_offset - dn.ofs_in_node, last_idx - page_idx); + count = round_up(count, F2FS_I(inode)->i_cluster_size); + +- ret = reserve_compress_blocks(&dn, count); ++ ret = reserve_compress_blocks(&dn, count, &reserved_blocks); + + f2fs_put_dnode(&dn); + +@@ -3716,23 +3730,21 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg) + break; + + page_idx += count; +- reserved_blocks += ret; + } + + filemap_invalidate_unlock(inode->i_mapping); + f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); + +- if (ret >= 0) { ++ if (!ret) { + clear_inode_flag(inode, FI_COMPRESS_RELEASED); + inode_set_ctime_current(inode); + f2fs_mark_inode_dirty_sync(inode, true); + } + unlock_inode: + inode_unlock(inode); +-out: + mnt_drop_write_file(filp); + +- if (ret >= 0) { ++ if (!ret) { + ret = put_user(reserved_blocks, (u64 __user *)arg); + } else if (reserved_blocks && + atomic_read(&F2FS_I(inode)->i_compr_blocks)) { +@@ -3981,16 +3993,20 @@ static int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg) + sizeof(option))) + return -EFAULT; + +- if (!f2fs_compressed_file(inode) || +- option.log_cluster_size < MIN_COMPRESS_LOG_SIZE || +- option.log_cluster_size > MAX_COMPRESS_LOG_SIZE || +- option.algorithm >= COMPRESS_MAX) ++ if (option.log_cluster_size < MIN_COMPRESS_LOG_SIZE || ++ option.log_cluster_size > MAX_COMPRESS_LOG_SIZE || ++ option.algorithm >= COMPRESS_MAX) + return -EINVAL; + + file_start_write(filp); + inode_lock(inode); + + f2fs_down_write(&F2FS_I(inode)->i_sem); ++ if (!f2fs_compressed_file(inode)) { ++ ret = -EINVAL; ++ goto out; ++ } ++ + if (f2fs_is_mmap_file(inode) || get_dirty_pages(inode)) { + ret = -EBUSY; + goto out; +diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c +index b3bb815fc6aa4..550cc811e008a 100644 +--- a/fs/f2fs/namei.c ++++ b/fs/f2fs/namei.c +@@ -852,7 +852,7 @@ static int f2fs_mknod(struct mnt_idmap *idmap, struct inode *dir, + + static int __f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir, + struct file *file, umode_t mode, bool is_whiteout, +- struct inode **new_inode) ++ struct inode **new_inode, struct f2fs_filename *fname) + { + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); + struct inode *inode; +@@ -880,7 +880,7 @@ static int __f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir, + if (err) + goto out; + +- err = f2fs_do_tmpfile(inode, dir); ++ err = f2fs_do_tmpfile(inode, dir, fname); + if (err) + goto release_out; + +@@ -931,22 +931,24 @@ static int f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir, + if (!f2fs_is_checkpoint_ready(sbi)) + return -ENOSPC; + +- err = __f2fs_tmpfile(idmap, dir, file, mode, false, NULL); ++ err = __f2fs_tmpfile(idmap, dir, file, mode, false, NULL, NULL); + + return finish_open_simple(file, err); + } + + static int f2fs_create_whiteout(struct mnt_idmap *idmap, +- struct inode *dir, struct inode **whiteout) ++ struct inode *dir, struct inode **whiteout, ++ struct f2fs_filename *fname) + { +- return __f2fs_tmpfile(idmap, dir, NULL, +- S_IFCHR | WHITEOUT_MODE, true, whiteout); ++ return __f2fs_tmpfile(idmap, dir, NULL, S_IFCHR | WHITEOUT_MODE, ++ true, whiteout, fname); + } + + int f2fs_get_tmpfile(struct mnt_idmap *idmap, struct inode *dir, + struct inode **new_inode) + { +- return __f2fs_tmpfile(idmap, dir, NULL, S_IFREG, false, new_inode); ++ return __f2fs_tmpfile(idmap, dir, NULL, S_IFREG, ++ false, new_inode, NULL); + } + + static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir, +@@ -990,7 +992,14 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir, + } + + if (flags & RENAME_WHITEOUT) { +- err = f2fs_create_whiteout(idmap, old_dir, &whiteout); ++ struct f2fs_filename fname; ++ ++ err = f2fs_setup_filename(old_dir, &old_dentry->d_name, ++ 0, &fname); ++ if (err) ++ return err; ++ ++ err = f2fs_create_whiteout(idmap, old_dir, &whiteout, &fname); + if (err) + return err; + } +diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c +index 9b546fd210100..2ea9c99e7dcb7 100644 +--- a/fs/f2fs/node.c ++++ b/fs/f2fs/node.c +@@ -852,21 +852,29 @@ int f2fs_get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode) + + if (is_inode_flag_set(dn->inode, FI_COMPRESSED_FILE) && + f2fs_sb_has_readonly(sbi)) { +- unsigned int c_len = f2fs_cluster_blocks_are_contiguous(dn); ++ unsigned int cluster_size = F2FS_I(dn->inode)->i_cluster_size; ++ unsigned int ofs_in_node = dn->ofs_in_node; ++ pgoff_t fofs = index; ++ unsigned int c_len; + block_t blkaddr; + ++ /* should align fofs and ofs_in_node to cluster_size */ ++ if (fofs % cluster_size) { ++ fofs = round_down(fofs, cluster_size); ++ ofs_in_node = round_down(ofs_in_node, cluster_size); ++ } ++ ++ c_len = f2fs_cluster_blocks_are_contiguous(dn, ofs_in_node); + if (!c_len) + goto out; + +- blkaddr = f2fs_data_blkaddr(dn); ++ blkaddr = data_blkaddr(dn->inode, dn->node_page, ofs_in_node); + if (blkaddr == COMPRESS_ADDR) + blkaddr = data_blkaddr(dn->inode, dn->node_page, +- dn->ofs_in_node + 1); ++ ofs_in_node + 1); + + f2fs_update_read_extent_tree_range_compressed(dn->inode, +- index, blkaddr, +- F2FS_I(dn->inode)->i_cluster_size, +- c_len); ++ fofs, blkaddr, cluster_size, c_len); + } + out: + return 0; +diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c +index d0f24ccbd1ac6..aad1d1a9b3d64 100644 +--- a/fs/f2fs/recovery.c ++++ b/fs/f2fs/recovery.c +@@ -611,6 +611,19 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi, + return 0; + } + ++static int f2fs_reserve_new_block_retry(struct dnode_of_data *dn) ++{ ++ int i, err = 0; ++ ++ for (i = DEFAULT_FAILURE_RETRY_COUNT; i > 0; i--) { ++ err = f2fs_reserve_new_block(dn); ++ if (!err) ++ break; ++ } ++ ++ return err; ++} ++ + static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, + struct page *page) + { +@@ -712,14 +725,8 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, + */ + if (dest == NEW_ADDR) { + f2fs_truncate_data_blocks_range(&dn, 1); +- do { +- err = f2fs_reserve_new_block(&dn); +- if (err == -ENOSPC) { +- f2fs_bug_on(sbi, 1); +- break; +- } +- } while (err && +- IS_ENABLED(CONFIG_F2FS_FAULT_INJECTION)); ++ ++ err = f2fs_reserve_new_block_retry(&dn); + if (err) + goto err; + continue; +@@ -727,16 +734,8 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, + + /* dest is valid block, try to recover from src to dest */ + if (f2fs_is_valid_blkaddr(sbi, dest, META_POR)) { +- + if (src == NULL_ADDR) { +- do { +- err = f2fs_reserve_new_block(&dn); +- if (err == -ENOSPC) { +- f2fs_bug_on(sbi, 1); +- break; +- } +- } while (err && +- IS_ENABLED(CONFIG_F2FS_FAULT_INJECTION)); ++ err = f2fs_reserve_new_block_retry(&dn); + if (err) + goto err; + } +diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c +index 4c8836ded90fc..60531f50f37fe 100644 +--- a/fs/f2fs/segment.c ++++ b/fs/f2fs/segment.c +@@ -248,7 +248,7 @@ static int __replace_atomic_write_block(struct inode *inode, pgoff_t index, + } else { + blkcnt_t count = 1; + +- err = inc_valid_block_count(sbi, inode, &count); ++ err = inc_valid_block_count(sbi, inode, &count, true); + if (err) { + f2fs_put_dnode(&dn); + return err; +@@ -3491,12 +3491,12 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, + locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr)); + locate_dirty_segment(sbi, GET_SEGNO(sbi, *new_blkaddr)); + +- if (IS_DATASEG(type)) ++ if (IS_DATASEG(curseg->seg_type)) + atomic64_inc(&sbi->allocated_data_blocks); + + up_write(&sit_i->sentry_lock); + +- if (page && IS_NODESEG(type)) { ++ if (page && IS_NODESEG(curseg->seg_type)) { + fill_node_footer_blkaddr(page, NEXT_FREE_BLKADDR(sbi, curseg)); + + f2fs_inode_chksum_set(sbi, page); +@@ -3653,8 +3653,7 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio) + } + + if (fio->post_read) +- invalidate_mapping_pages(META_MAPPING(sbi), +- fio->new_blkaddr, fio->new_blkaddr); ++ f2fs_truncate_meta_inode_pages(sbi, fio->new_blkaddr, 1); + + stat_inc_inplace_blocks(fio->sbi); + +@@ -3844,7 +3843,7 @@ void f2fs_wait_on_block_writeback_range(struct inode *inode, block_t blkaddr, + for (i = 0; i < len; i++) + f2fs_wait_on_block_writeback(inode, blkaddr + i); + +- invalidate_mapping_pages(META_MAPPING(sbi), blkaddr, blkaddr + len - 1); ++ f2fs_truncate_meta_inode_pages(sbi, blkaddr, len); + } + + static int read_compacted_summaries(struct f2fs_sb_info *sbi) +diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h +index 8129be788bd56..c77a562831493 100644 +--- a/fs/f2fs/segment.h ++++ b/fs/f2fs/segment.h +@@ -573,23 +573,22 @@ static inline bool has_curseg_enough_space(struct f2fs_sb_info *sbi, + unsigned int node_blocks, unsigned int dent_blocks) + { + +- unsigned int segno, left_blocks; ++ unsigned segno, left_blocks; + int i; + +- /* check current node segment */ ++ /* check current node sections in the worst case. */ + for (i = CURSEG_HOT_NODE; i <= CURSEG_COLD_NODE; i++) { + segno = CURSEG_I(sbi, i)->segno; +- left_blocks = f2fs_usable_blks_in_seg(sbi, segno) - +- get_seg_entry(sbi, segno)->ckpt_valid_blocks; +- ++ left_blocks = CAP_BLKS_PER_SEC(sbi) - ++ get_ckpt_valid_blocks(sbi, segno, true); + if (node_blocks > left_blocks) + return false; + } + +- /* check current data segment */ ++ /* check current data section for dentry blocks. */ + segno = CURSEG_I(sbi, CURSEG_HOT_DATA)->segno; +- left_blocks = f2fs_usable_blks_in_seg(sbi, segno) - +- get_seg_entry(sbi, segno)->ckpt_valid_blocks; ++ left_blocks = CAP_BLKS_PER_SEC(sbi) - ++ get_ckpt_valid_blocks(sbi, segno, true); + if (dent_blocks > left_blocks) + return false; + return true; +@@ -638,7 +637,7 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, + + if (free_secs > upper_secs) + return false; +- else if (free_secs <= lower_secs) ++ if (free_secs <= lower_secs) + return true; + return !curseg_space; + } +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +index d45ab0992ae59..4ba613ed3a179 100644 +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -663,7 +663,7 @@ static int f2fs_set_lz4hc_level(struct f2fs_sb_info *sbi, const char *str) + #ifdef CONFIG_F2FS_FS_ZSTD + static int f2fs_set_zstd_level(struct f2fs_sb_info *sbi, const char *str) + { +- unsigned int level; ++ int level; + int len = 4; + + if (strlen(str) == len) { +@@ -677,9 +677,15 @@ static int f2fs_set_zstd_level(struct f2fs_sb_info *sbi, const char *str) + f2fs_info(sbi, "wrong format, e.g. :"); + return -EINVAL; + } +- if (kstrtouint(str + 1, 10, &level)) ++ if (kstrtoint(str + 1, 10, &level)) + return -EINVAL; + ++ /* f2fs does not support negative compress level now */ ++ if (level < 0) { ++ f2fs_info(sbi, "do not support negative compress level: %d", level); ++ return -ERANGE; ++ } ++ + if (!f2fs_is_compress_level_valid(COMPRESS_ZSTD, level)) { + f2fs_info(sbi, "invalid zstd compress level: %d", level); + return -EINVAL; +@@ -2768,7 +2774,7 @@ int f2fs_dquot_initialize(struct inode *inode) + return dquot_initialize(inode); + } + +-static struct dquot **f2fs_get_dquots(struct inode *inode) ++static struct dquot __rcu **f2fs_get_dquots(struct inode *inode) + { + return F2FS_I(inode)->i_dquot; + } +@@ -3930,11 +3936,6 @@ static int init_blkz_info(struct f2fs_sb_info *sbi, int devi) + return 0; + + zone_sectors = bdev_zone_sectors(bdev); +- if (!is_power_of_2(zone_sectors)) { +- f2fs_err(sbi, "F2FS does not support non power of 2 zone sizes\n"); +- return -EINVAL; +- } +- + if (sbi->blocks_per_blkz && sbi->blocks_per_blkz != + SECTOR_TO_BLOCK(zone_sectors)) + return -EINVAL; +diff --git a/fs/fcntl.c b/fs/fcntl.c +index c80a6acad742f..3ff707bf2743a 100644 +--- a/fs/fcntl.c ++++ b/fs/fcntl.c +@@ -268,7 +268,7 @@ static int f_getowner_uids(struct file *filp, unsigned long arg) + } + #endif + +-static bool rw_hint_valid(enum rw_hint hint) ++static bool rw_hint_valid(u64 hint) + { + switch (hint) { + case RWH_WRITE_LIFE_NOT_SET: +@@ -288,19 +288,17 @@ static long fcntl_rw_hint(struct file *file, unsigned int cmd, + { + struct inode *inode = file_inode(file); + u64 __user *argp = (u64 __user *)arg; +- enum rw_hint hint; +- u64 h; ++ u64 hint; + + switch (cmd) { + case F_GET_RW_HINT: +- h = inode->i_write_hint; +- if (copy_to_user(argp, &h, sizeof(*argp))) ++ hint = inode->i_write_hint; ++ if (copy_to_user(argp, &hint, sizeof(*argp))) + return -EFAULT; + return 0; + case F_SET_RW_HINT: +- if (copy_from_user(&h, argp, sizeof(h))) ++ if (copy_from_user(&hint, argp, sizeof(hint))) + return -EFAULT; +- hint = (enum rw_hint) h; + if (!rw_hint_valid(hint)) + return -EINVAL; + +diff --git a/fs/fhandle.c b/fs/fhandle.c +index 18b3ba8dc8ead..57a12614addfd 100644 +--- a/fs/fhandle.c ++++ b/fs/fhandle.c +@@ -36,7 +36,7 @@ static long do_sys_name_to_handle(const struct path *path, + if (f_handle.handle_bytes > MAX_HANDLE_SZ) + return -EINVAL; + +- handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes, ++ handle = kzalloc(sizeof(struct file_handle) + f_handle.handle_bytes, + GFP_KERNEL); + if (!handle) + return -ENOMEM; +diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c +index b0cb704009963..ce9346099c72d 100644 +--- a/fs/hfsplus/wrapper.c ++++ b/fs/hfsplus/wrapper.c +@@ -30,7 +30,7 @@ struct hfsplus_wd { + * @sector: block to read or write, for blocks of HFSPLUS_SECTOR_SIZE bytes + * @buf: buffer for I/O + * @data: output pointer for location of requested data +- * @opf: request op flags ++ * @opf: I/O operation type and flags + * + * The unit of I/O is hfsplus_min_io_size(sb), which may be bigger than + * HFSPLUS_SECTOR_SIZE, and @buf must be sized accordingly. On reads +diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c +index 093c4515b22a5..228fd2e05e12f 100644 +--- a/fs/iomap/buffered-io.c ++++ b/fs/iomap/buffered-io.c +@@ -1833,16 +1833,10 @@ iomap_writepage_map(struct iomap_writepage_ctx *wpc, + if (unlikely(error)) { + /* + * Let the filesystem know what portion of the current page +- * failed to map. If the page hasn't been added to ioend, it +- * won't be affected by I/O completion and we must unlock it +- * now. ++ * failed to map. + */ + if (wpc->ops->discard_folio) + wpc->ops->discard_folio(folio, pos); +- if (!count) { +- folio_unlock(folio); +- goto done; +- } + } + + /* +@@ -1851,6 +1845,16 @@ iomap_writepage_map(struct iomap_writepage_ctx *wpc, + * all the dirty bits in the folio here. + */ + iomap_clear_range_dirty(folio, 0, folio_size(folio)); ++ ++ /* ++ * If the page hasn't been added to the ioend, it won't be affected by ++ * I/O completion and we must unlock it now. ++ */ ++ if (error && !count) { ++ folio_unlock(folio); ++ goto done; ++ } ++ + folio_start_writeback(folio); + folio_unlock(folio); + +diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h +index dd4264aa9bedd..10934f9a11be3 100644 +--- a/fs/jfs/jfs_incore.h ++++ b/fs/jfs/jfs_incore.h +@@ -92,7 +92,7 @@ struct jfs_inode_info { + } link; + } u; + #ifdef CONFIG_QUOTA +- struct dquot *i_dquot[MAXQUOTAS]; ++ struct dquot __rcu *i_dquot[MAXQUOTAS]; + #endif + u32 dev; /* will die when we get wide dev_t */ + struct inode vfs_inode; +diff --git a/fs/jfs/super.c b/fs/jfs/super.c +index 8d8e556bd6104..ff135a43b5b7b 100644 +--- a/fs/jfs/super.c ++++ b/fs/jfs/super.c +@@ -824,7 +824,7 @@ static ssize_t jfs_quota_write(struct super_block *sb, int type, + return len - towrite; + } + +-static struct dquot **jfs_get_dquots(struct inode *inode) ++static struct dquot __rcu **jfs_get_dquots(struct inode *inode) + { + return JFS_IP(inode)->i_dquot; + } +diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c +index ef817a0475ffa..3e724cb7ef01d 100644 +--- a/fs/nfs/flexfilelayout/flexfilelayout.c ++++ b/fs/nfs/flexfilelayout/flexfilelayout.c +@@ -2016,7 +2016,7 @@ static void ff_layout_cancel_io(struct pnfs_layout_segment *lseg) + for (idx = 0; idx < flseg->mirror_array_cnt; idx++) { + mirror = flseg->mirror_array[idx]; + mirror_ds = mirror->mirror_ds; +- if (!mirror_ds) ++ if (IS_ERR_OR_NULL(mirror_ds)) + continue; + ds = mirror->mirror_ds->ds; + if (!ds) +diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c +index 2d1bfee225c36..ddc1ee0319554 100644 +--- a/fs/nfs/fscache.c ++++ b/fs/nfs/fscache.c +@@ -301,11 +301,11 @@ static void nfs_netfs_issue_read(struct netfs_io_subrequest *sreq) + struct inode *inode = sreq->rreq->inode; + struct nfs_open_context *ctx = sreq->rreq->netfs_priv; + struct page *page; ++ unsigned long idx; + int err; + pgoff_t start = (sreq->start + sreq->transferred) >> PAGE_SHIFT; + pgoff_t last = ((sreq->start + sreq->len - + sreq->transferred - 1) >> PAGE_SHIFT); +- XA_STATE(xas, &sreq->rreq->mapping->i_pages, start); + + nfs_pageio_init_read(&pgio, inode, false, + &nfs_async_read_completion_ops); +@@ -316,19 +316,14 @@ static void nfs_netfs_issue_read(struct netfs_io_subrequest *sreq) + + pgio.pg_netfs = netfs; /* used in completion */ + +- xas_lock(&xas); +- xas_for_each(&xas, page, last) { ++ xa_for_each_range(&sreq->rreq->mapping->i_pages, idx, page, start, last) { + /* nfs_read_add_folio() may schedule() due to pNFS layout and other RPCs */ +- xas_pause(&xas); +- xas_unlock(&xas); + err = nfs_read_add_folio(&pgio, ctx, page_folio(page)); + if (err < 0) { + netfs->error = err; + goto out; + } +- xas_lock(&xas); + } +- xas_unlock(&xas); + out: + nfs_pageio_complete_read(&pgio); + nfs_netfs_put(netfs); +diff --git a/fs/nfs/nfs42.h b/fs/nfs/nfs42.h +index b59876b01a1e3..0282d93c8bccb 100644 +--- a/fs/nfs/nfs42.h ++++ b/fs/nfs/nfs42.h +@@ -55,11 +55,14 @@ int nfs42_proc_removexattr(struct inode *inode, const char *name); + * They would be 7 bytes long in the eventual buffer ("user.x\0"), and + * 8 bytes long XDR-encoded. + * +- * Include the trailing eof word as well. ++ * Include the trailing eof word as well and make the result a multiple ++ * of 4 bytes. + */ + static inline u32 nfs42_listxattr_xdrsize(u32 buflen) + { +- return ((buflen / (XATTR_USER_PREFIX_LEN + 2)) * 8) + 4; ++ u32 size = 8 * buflen / (XATTR_USER_PREFIX_LEN + 2) + 4; ++ ++ return (size + 3) & ~3; + } + #endif /* CONFIG_NFS_V4_2 */ + #endif /* __LINUX_FS_NFS_NFS4_2_H */ +diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c +index 23819a7565085..b2ff8c7a21494 100644 +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -10615,29 +10615,33 @@ const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = { + static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size) + { + ssize_t error, error2, error3; ++ size_t left = size; + +- error = generic_listxattr(dentry, list, size); ++ error = generic_listxattr(dentry, list, left); + if (error < 0) + return error; + if (list) { + list += error; +- size -= error; ++ left -= error; + } + +- error2 = nfs4_listxattr_nfs4_label(d_inode(dentry), list, size); ++ error2 = nfs4_listxattr_nfs4_label(d_inode(dentry), list, left); + if (error2 < 0) + return error2; + + if (list) { + list += error2; +- size -= error2; ++ left -= error2; + } + +- error3 = nfs4_listxattr_nfs4_user(d_inode(dentry), list, size); ++ error3 = nfs4_listxattr_nfs4_user(d_inode(dentry), list, left); + if (error3 < 0) + return error3; + +- return error + error2 + error3; ++ error += error2 + error3; ++ if (size && error > size) ++ return -ERANGE; ++ return error; + } + + static void nfs4_enable_swap(struct inode *inode) +diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c +index 7600100ba26f0..432612d224374 100644 +--- a/fs/nfs/nfsroot.c ++++ b/fs/nfs/nfsroot.c +@@ -175,10 +175,10 @@ static int __init root_nfs_cat(char *dest, const char *src, + size_t len = strlen(dest); + + if (len && dest[len - 1] != ',') +- if (strlcat(dest, ",", destlen) > destlen) ++ if (strlcat(dest, ",", destlen) >= destlen) + return -1; + +- if (strlcat(dest, src, destlen) > destlen) ++ if (strlcat(dest, src, destlen) >= destlen) + return -1; + return 0; + } +diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c +index afd23910f3bff..88e061bd711b7 100644 +--- a/fs/nfs/pnfs_nfs.c ++++ b/fs/nfs/pnfs_nfs.c +@@ -919,6 +919,8 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv, + dprintk("--> %s DS %s\n", __func__, ds->ds_remotestr); + + list_for_each_entry(da, &ds->ds_addrs, da_node) { ++ char servername[48]; ++ + dprintk("%s: DS %s: trying address %s\n", + __func__, ds->ds_remotestr, da->da_remotestr); + +@@ -929,6 +931,7 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv, + .dstaddr = (struct sockaddr *)&da->da_addr, + .addrlen = da->da_addrlen, + .servername = clp->cl_hostname, ++ .xprtsec = clp->cl_xprtsec, + }; + struct nfs4_add_xprt_data xprtdata = { + .clp = clp, +@@ -938,10 +941,45 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv, + .data = &xprtdata, + }; + +- if (da->da_transport != clp->cl_proto) ++ if (da->da_transport != clp->cl_proto && ++ clp->cl_proto != XPRT_TRANSPORT_TCP_TLS) + continue; ++ if (da->da_transport == XPRT_TRANSPORT_TCP && ++ mds_srv->nfs_client->cl_proto == ++ XPRT_TRANSPORT_TCP_TLS) { ++ struct sockaddr *addr = ++ (struct sockaddr *)&da->da_addr; ++ struct sockaddr_in *sin = ++ (struct sockaddr_in *)&da->da_addr; ++ struct sockaddr_in6 *sin6 = ++ (struct sockaddr_in6 *)&da->da_addr; ++ ++ /* for NFS with TLS we need to supply a correct ++ * servername of the trunked transport, not the ++ * servername of the main transport stored in ++ * clp->cl_hostname. And set the protocol to ++ * indicate to use TLS ++ */ ++ servername[0] = '\0'; ++ switch(addr->sa_family) { ++ case AF_INET: ++ snprintf(servername, sizeof(servername), ++ "%pI4", &sin->sin_addr.s_addr); ++ break; ++ case AF_INET6: ++ snprintf(servername, sizeof(servername), ++ "%pI6", &sin6->sin6_addr); ++ break; ++ default: ++ /* do not consider this address */ ++ continue; ++ } ++ xprt_args.ident = XPRT_TRANSPORT_TCP_TLS; ++ xprt_args.servername = servername; ++ } + if (da->da_addr.ss_family != clp->cl_addr.ss_family) + continue; ++ + /** + * Test this address for session trunking and + * add as an alias +@@ -953,6 +991,10 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv, + if (xprtdata.cred) + put_cred(xprtdata.cred); + } else { ++ if (da->da_transport == XPRT_TRANSPORT_TCP && ++ mds_srv->nfs_client->cl_proto == ++ XPRT_TRANSPORT_TCP_TLS) ++ da->da_transport = XPRT_TRANSPORT_TCP_TLS; + clp = nfs4_set_ds_client(mds_srv, + &da->da_addr, + da->da_addrlen, +diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h +index 82b28fdacc7e9..accf03d4765ed 100644 +--- a/fs/ocfs2/inode.h ++++ b/fs/ocfs2/inode.h +@@ -65,7 +65,7 @@ struct ocfs2_inode_info + tid_t i_sync_tid; + tid_t i_datasync_tid; + +- struct dquot *i_dquot[MAXQUOTAS]; ++ struct dquot __rcu *i_dquot[MAXQUOTAS]; + }; + + /* +diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c +index 6b906424902b4..1259fe02cd53b 100644 +--- a/fs/ocfs2/super.c ++++ b/fs/ocfs2/super.c +@@ -122,7 +122,7 @@ static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend); + static int ocfs2_enable_quotas(struct ocfs2_super *osb); + static void ocfs2_disable_quotas(struct ocfs2_super *osb); + +-static struct dquot **ocfs2_get_dquots(struct inode *inode) ++static struct dquot __rcu **ocfs2_get_dquots(struct inode *inode) + { + return OCFS2_I(inode)->i_dquot; + } +diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c +index 8586e2f5d2439..0762575a1e708 100644 +--- a/fs/overlayfs/copy_up.c ++++ b/fs/overlayfs/copy_up.c +@@ -234,11 +234,11 @@ static int ovl_verify_area(loff_t pos, loff_t pos2, loff_t len, loff_t totlen) + { + loff_t tmp; + +- if (WARN_ON_ONCE(pos != pos2)) ++ if (pos != pos2) + return -EIO; +- if (WARN_ON_ONCE(pos < 0 || len < 0 || totlen < 0)) ++ if (pos < 0 || len < 0 || totlen < 0) + return -EIO; +- if (WARN_ON_ONCE(check_add_overflow(pos, len, &tmp))) ++ if (check_add_overflow(pos, len, &tmp)) + return -EIO; + return 0; + } +diff --git a/fs/overlayfs/params.c b/fs/overlayfs/params.c +index 112b4b12f8252..36dcc530ac286 100644 +--- a/fs/overlayfs/params.c ++++ b/fs/overlayfs/params.c +@@ -280,12 +280,20 @@ static int ovl_mount_dir_check(struct fs_context *fc, const struct path *path, + { + struct ovl_fs_context *ctx = fc->fs_private; + +- if (ovl_dentry_weird(path->dentry)) +- return invalfc(fc, "filesystem on %s not supported", name); +- + if (!d_is_dir(path->dentry)) + return invalfc(fc, "%s is not a directory", name); + ++ /* ++ * Root dentries of case-insensitive capable filesystems might ++ * not have the dentry operations set, but still be incompatible ++ * with overlayfs. Check explicitly to prevent post-mount ++ * failures. ++ */ ++ if (sb_has_encoding(path->mnt->mnt_sb)) ++ return invalfc(fc, "case-insensitive capable filesystem on %s not supported", name); ++ ++ if (ovl_dentry_weird(path->dentry)) ++ return invalfc(fc, "filesystem on %s not supported", name); + + /* + * Check whether upper path is read-only here to report failures +diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c +index d0d9bfdad30cc..56815799ce798 100644 +--- a/fs/pstore/inode.c ++++ b/fs/pstore/inode.c +@@ -307,7 +307,6 @@ int pstore_put_backend_records(struct pstore_info *psi) + { + struct pstore_private *pos, *tmp; + struct dentry *root; +- int rc = 0; + + root = psinfo_lock_root(); + if (!root) +@@ -317,11 +316,8 @@ int pstore_put_backend_records(struct pstore_info *psi) + list_for_each_entry_safe(pos, tmp, &records_list, list) { + if (pos->record->psi == psi) { + list_del_init(&pos->list); +- rc = simple_unlink(d_inode(root), pos->dentry); +- if (WARN_ON(rc)) +- break; +- d_drop(pos->dentry); +- dput(pos->dentry); ++ d_invalidate(pos->dentry); ++ simple_unlink(d_inode(root), pos->dentry); + pos->dentry = NULL; + } + } +@@ -329,7 +325,7 @@ int pstore_put_backend_records(struct pstore_info *psi) + + inode_unlock(d_inode(root)); + +- return rc; ++ return 0; + } + + /* +diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c +index 1f0c754416b64..51ff554dc875a 100644 +--- a/fs/quota/dquot.c ++++ b/fs/quota/dquot.c +@@ -399,15 +399,17 @@ int dquot_mark_dquot_dirty(struct dquot *dquot) + EXPORT_SYMBOL(dquot_mark_dquot_dirty); + + /* Dirtify all the dquots - this can block when journalling */ +-static inline int mark_all_dquot_dirty(struct dquot * const *dquot) ++static inline int mark_all_dquot_dirty(struct dquot __rcu * const *dquots) + { + int ret, err, cnt; ++ struct dquot *dquot; + + ret = err = 0; + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { +- if (dquot[cnt]) ++ dquot = srcu_dereference(dquots[cnt], &dquot_srcu); ++ if (dquot) + /* Even in case of error we have to continue */ +- ret = mark_dquot_dirty(dquot[cnt]); ++ ret = mark_dquot_dirty(dquot); + if (!err) + err = ret; + } +@@ -998,14 +1000,14 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid) + } + EXPORT_SYMBOL(dqget); + +-static inline struct dquot **i_dquot(struct inode *inode) ++static inline struct dquot __rcu **i_dquot(struct inode *inode) + { + return inode->i_sb->s_op->get_dquots(inode); + } + + static int dqinit_needed(struct inode *inode, int type) + { +- struct dquot * const *dquots; ++ struct dquot __rcu * const *dquots; + int cnt; + + if (IS_NOQUOTA(inode)) +@@ -1095,14 +1097,16 @@ static void remove_dquot_ref(struct super_block *sb, int type) + */ + spin_lock(&dq_data_lock); + if (!IS_NOQUOTA(inode)) { +- struct dquot **dquots = i_dquot(inode); +- struct dquot *dquot = dquots[type]; ++ struct dquot __rcu **dquots = i_dquot(inode); ++ struct dquot *dquot = srcu_dereference_check( ++ dquots[type], &dquot_srcu, ++ lockdep_is_held(&dq_data_lock)); + + #ifdef CONFIG_QUOTA_DEBUG + if (unlikely(inode_get_rsv_space(inode) > 0)) + reserved = 1; + #endif +- dquots[type] = NULL; ++ rcu_assign_pointer(dquots[type], NULL); + if (dquot) + dqput(dquot); + } +@@ -1455,7 +1459,8 @@ static int inode_quota_active(const struct inode *inode) + static int __dquot_initialize(struct inode *inode, int type) + { + int cnt, init_needed = 0; +- struct dquot **dquots, *got[MAXQUOTAS] = {}; ++ struct dquot __rcu **dquots; ++ struct dquot *got[MAXQUOTAS] = {}; + struct super_block *sb = inode->i_sb; + qsize_t rsv; + int ret = 0; +@@ -1530,7 +1535,7 @@ static int __dquot_initialize(struct inode *inode, int type) + if (!got[cnt]) + continue; + if (!dquots[cnt]) { +- dquots[cnt] = got[cnt]; ++ rcu_assign_pointer(dquots[cnt], got[cnt]); + got[cnt] = NULL; + /* + * Make quota reservation system happy if someone +@@ -1538,12 +1543,16 @@ static int __dquot_initialize(struct inode *inode, int type) + */ + rsv = inode_get_rsv_space(inode); + if (unlikely(rsv)) { ++ struct dquot *dquot = srcu_dereference_check( ++ dquots[cnt], &dquot_srcu, ++ lockdep_is_held(&dq_data_lock)); ++ + spin_lock(&inode->i_lock); + /* Get reservation again under proper lock */ + rsv = __inode_get_rsv_space(inode); +- spin_lock(&dquots[cnt]->dq_dqb_lock); +- dquots[cnt]->dq_dqb.dqb_rsvspace += rsv; +- spin_unlock(&dquots[cnt]->dq_dqb_lock); ++ spin_lock(&dquot->dq_dqb_lock); ++ dquot->dq_dqb.dqb_rsvspace += rsv; ++ spin_unlock(&dquot->dq_dqb_lock); + spin_unlock(&inode->i_lock); + } + } +@@ -1565,7 +1574,7 @@ EXPORT_SYMBOL(dquot_initialize); + + bool dquot_initialize_needed(struct inode *inode) + { +- struct dquot **dquots; ++ struct dquot __rcu **dquots; + int i; + + if (!inode_quota_active(inode)) +@@ -1590,13 +1599,14 @@ EXPORT_SYMBOL(dquot_initialize_needed); + static void __dquot_drop(struct inode *inode) + { + int cnt; +- struct dquot **dquots = i_dquot(inode); ++ struct dquot __rcu **dquots = i_dquot(inode); + struct dquot *put[MAXQUOTAS]; + + spin_lock(&dq_data_lock); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { +- put[cnt] = dquots[cnt]; +- dquots[cnt] = NULL; ++ put[cnt] = srcu_dereference_check(dquots[cnt], &dquot_srcu, ++ lockdep_is_held(&dq_data_lock)); ++ rcu_assign_pointer(dquots[cnt], NULL); + } + spin_unlock(&dq_data_lock); + dqput_all(put); +@@ -1604,7 +1614,7 @@ static void __dquot_drop(struct inode *inode) + + void dquot_drop(struct inode *inode) + { +- struct dquot * const *dquots; ++ struct dquot __rcu * const *dquots; + int cnt; + + if (IS_NOQUOTA(inode)) +@@ -1677,7 +1687,8 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags) + int cnt, ret = 0, index; + struct dquot_warn warn[MAXQUOTAS]; + int reserve = flags & DQUOT_SPACE_RESERVE; +- struct dquot **dquots; ++ struct dquot __rcu **dquots; ++ struct dquot *dquot; + + if (!inode_quota_active(inode)) { + if (reserve) { +@@ -1697,27 +1708,26 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags) + index = srcu_read_lock(&dquot_srcu); + spin_lock(&inode->i_lock); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { +- if (!dquots[cnt]) ++ dquot = srcu_dereference(dquots[cnt], &dquot_srcu); ++ if (!dquot) + continue; + if (reserve) { +- ret = dquot_add_space(dquots[cnt], 0, number, flags, +- &warn[cnt]); ++ ret = dquot_add_space(dquot, 0, number, flags, &warn[cnt]); + } else { +- ret = dquot_add_space(dquots[cnt], number, 0, flags, +- &warn[cnt]); ++ ret = dquot_add_space(dquot, number, 0, flags, &warn[cnt]); + } + if (ret) { + /* Back out changes we already did */ + for (cnt--; cnt >= 0; cnt--) { +- if (!dquots[cnt]) ++ dquot = srcu_dereference(dquots[cnt], &dquot_srcu); ++ if (!dquot) + continue; +- spin_lock(&dquots[cnt]->dq_dqb_lock); ++ spin_lock(&dquot->dq_dqb_lock); + if (reserve) +- dquot_free_reserved_space(dquots[cnt], +- number); ++ dquot_free_reserved_space(dquot, number); + else +- dquot_decr_space(dquots[cnt], number); +- spin_unlock(&dquots[cnt]->dq_dqb_lock); ++ dquot_decr_space(dquot, number); ++ spin_unlock(&dquot->dq_dqb_lock); + } + spin_unlock(&inode->i_lock); + goto out_flush_warn; +@@ -1747,7 +1757,8 @@ int dquot_alloc_inode(struct inode *inode) + { + int cnt, ret = 0, index; + struct dquot_warn warn[MAXQUOTAS]; +- struct dquot * const *dquots; ++ struct dquot __rcu * const *dquots; ++ struct dquot *dquot; + + if (!inode_quota_active(inode)) + return 0; +@@ -1758,17 +1769,19 @@ int dquot_alloc_inode(struct inode *inode) + index = srcu_read_lock(&dquot_srcu); + spin_lock(&inode->i_lock); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { +- if (!dquots[cnt]) ++ dquot = srcu_dereference(dquots[cnt], &dquot_srcu); ++ if (!dquot) + continue; +- ret = dquot_add_inodes(dquots[cnt], 1, &warn[cnt]); ++ ret = dquot_add_inodes(dquot, 1, &warn[cnt]); + if (ret) { + for (cnt--; cnt >= 0; cnt--) { +- if (!dquots[cnt]) ++ dquot = srcu_dereference(dquots[cnt], &dquot_srcu); ++ if (!dquot) + continue; + /* Back out changes we already did */ +- spin_lock(&dquots[cnt]->dq_dqb_lock); +- dquot_decr_inodes(dquots[cnt], 1); +- spin_unlock(&dquots[cnt]->dq_dqb_lock); ++ spin_lock(&dquot->dq_dqb_lock); ++ dquot_decr_inodes(dquot, 1); ++ spin_unlock(&dquot->dq_dqb_lock); + } + goto warn_put_all; + } +@@ -1789,7 +1802,8 @@ EXPORT_SYMBOL(dquot_alloc_inode); + */ + void dquot_claim_space_nodirty(struct inode *inode, qsize_t number) + { +- struct dquot **dquots; ++ struct dquot __rcu **dquots; ++ struct dquot *dquot; + int cnt, index; + + if (!inode_quota_active(inode)) { +@@ -1805,9 +1819,8 @@ void dquot_claim_space_nodirty(struct inode *inode, qsize_t number) + spin_lock(&inode->i_lock); + /* Claim reserved quotas to allocated quotas */ + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { +- if (dquots[cnt]) { +- struct dquot *dquot = dquots[cnt]; +- ++ dquot = srcu_dereference(dquots[cnt], &dquot_srcu); ++ if (dquot) { + spin_lock(&dquot->dq_dqb_lock); + if (WARN_ON_ONCE(dquot->dq_dqb.dqb_rsvspace < number)) + number = dquot->dq_dqb.dqb_rsvspace; +@@ -1831,7 +1844,8 @@ EXPORT_SYMBOL(dquot_claim_space_nodirty); + */ + void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number) + { +- struct dquot **dquots; ++ struct dquot __rcu **dquots; ++ struct dquot *dquot; + int cnt, index; + + if (!inode_quota_active(inode)) { +@@ -1847,9 +1861,8 @@ void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number) + spin_lock(&inode->i_lock); + /* Claim reserved quotas to allocated quotas */ + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { +- if (dquots[cnt]) { +- struct dquot *dquot = dquots[cnt]; +- ++ dquot = srcu_dereference(dquots[cnt], &dquot_srcu); ++ if (dquot) { + spin_lock(&dquot->dq_dqb_lock); + if (WARN_ON_ONCE(dquot->dq_dqb.dqb_curspace < number)) + number = dquot->dq_dqb.dqb_curspace; +@@ -1875,7 +1888,8 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags) + { + unsigned int cnt; + struct dquot_warn warn[MAXQUOTAS]; +- struct dquot **dquots; ++ struct dquot __rcu **dquots; ++ struct dquot *dquot; + int reserve = flags & DQUOT_SPACE_RESERVE, index; + + if (!inode_quota_active(inode)) { +@@ -1896,17 +1910,18 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags) + int wtype; + + warn[cnt].w_type = QUOTA_NL_NOWARN; +- if (!dquots[cnt]) ++ dquot = srcu_dereference(dquots[cnt], &dquot_srcu); ++ if (!dquot) + continue; +- spin_lock(&dquots[cnt]->dq_dqb_lock); +- wtype = info_bdq_free(dquots[cnt], number); ++ spin_lock(&dquot->dq_dqb_lock); ++ wtype = info_bdq_free(dquot, number); + if (wtype != QUOTA_NL_NOWARN) +- prepare_warning(&warn[cnt], dquots[cnt], wtype); ++ prepare_warning(&warn[cnt], dquot, wtype); + if (reserve) +- dquot_free_reserved_space(dquots[cnt], number); ++ dquot_free_reserved_space(dquot, number); + else +- dquot_decr_space(dquots[cnt], number); +- spin_unlock(&dquots[cnt]->dq_dqb_lock); ++ dquot_decr_space(dquot, number); ++ spin_unlock(&dquot->dq_dqb_lock); + } + if (reserve) + *inode_reserved_space(inode) -= number; +@@ -1930,7 +1945,8 @@ void dquot_free_inode(struct inode *inode) + { + unsigned int cnt; + struct dquot_warn warn[MAXQUOTAS]; +- struct dquot * const *dquots; ++ struct dquot __rcu * const *dquots; ++ struct dquot *dquot; + int index; + + if (!inode_quota_active(inode)) +@@ -1941,16 +1957,16 @@ void dquot_free_inode(struct inode *inode) + spin_lock(&inode->i_lock); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + int wtype; +- + warn[cnt].w_type = QUOTA_NL_NOWARN; +- if (!dquots[cnt]) ++ dquot = srcu_dereference(dquots[cnt], &dquot_srcu); ++ if (!dquot) + continue; +- spin_lock(&dquots[cnt]->dq_dqb_lock); +- wtype = info_idq_free(dquots[cnt], 1); ++ spin_lock(&dquot->dq_dqb_lock); ++ wtype = info_idq_free(dquot, 1); + if (wtype != QUOTA_NL_NOWARN) +- prepare_warning(&warn[cnt], dquots[cnt], wtype); +- dquot_decr_inodes(dquots[cnt], 1); +- spin_unlock(&dquots[cnt]->dq_dqb_lock); ++ prepare_warning(&warn[cnt], dquot, wtype); ++ dquot_decr_inodes(dquot, 1); ++ spin_unlock(&dquot->dq_dqb_lock); + } + spin_unlock(&inode->i_lock); + mark_all_dquot_dirty(dquots); +@@ -1976,8 +1992,9 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to) + qsize_t cur_space; + qsize_t rsv_space = 0; + qsize_t inode_usage = 1; ++ struct dquot __rcu **dquots; + struct dquot *transfer_from[MAXQUOTAS] = {}; +- int cnt, ret = 0; ++ int cnt, index, ret = 0; + char is_valid[MAXQUOTAS] = {}; + struct dquot_warn warn_to[MAXQUOTAS]; + struct dquot_warn warn_from_inodes[MAXQUOTAS]; +@@ -2008,6 +2025,7 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to) + } + cur_space = __inode_get_bytes(inode); + rsv_space = __inode_get_rsv_space(inode); ++ dquots = i_dquot(inode); + /* + * Build the transfer_from list, check limits, and update usage in + * the target structures. +@@ -2022,7 +2040,8 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to) + if (!sb_has_quota_active(inode->i_sb, cnt)) + continue; + is_valid[cnt] = 1; +- transfer_from[cnt] = i_dquot(inode)[cnt]; ++ transfer_from[cnt] = srcu_dereference_check(dquots[cnt], ++ &dquot_srcu, lockdep_is_held(&dq_data_lock)); + ret = dquot_add_inodes(transfer_to[cnt], inode_usage, + &warn_to[cnt]); + if (ret) +@@ -2061,13 +2080,21 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to) + rsv_space); + spin_unlock(&transfer_from[cnt]->dq_dqb_lock); + } +- i_dquot(inode)[cnt] = transfer_to[cnt]; ++ rcu_assign_pointer(dquots[cnt], transfer_to[cnt]); + } + spin_unlock(&inode->i_lock); + spin_unlock(&dq_data_lock); + +- mark_all_dquot_dirty(transfer_from); +- mark_all_dquot_dirty(transfer_to); ++ /* ++ * These arrays are local and we hold dquot references so we don't need ++ * the srcu protection but still take dquot_srcu to avoid warning in ++ * mark_all_dquot_dirty(). ++ */ ++ index = srcu_read_lock(&dquot_srcu); ++ mark_all_dquot_dirty((struct dquot __rcu **)transfer_from); ++ mark_all_dquot_dirty((struct dquot __rcu **)transfer_to); ++ srcu_read_unlock(&dquot_srcu, index); ++ + flush_warnings(warn_to); + flush_warnings(warn_from_inodes); + flush_warnings(warn_from_space); +diff --git a/fs/reiserfs/reiserfs.h b/fs/reiserfs/reiserfs.h +index 725667880e626..b65549164590c 100644 +--- a/fs/reiserfs/reiserfs.h ++++ b/fs/reiserfs/reiserfs.h +@@ -97,7 +97,7 @@ struct reiserfs_inode_info { + struct rw_semaphore i_xattr_sem; + #endif + #ifdef CONFIG_QUOTA +- struct dquot *i_dquot[MAXQUOTAS]; ++ struct dquot __rcu *i_dquot[MAXQUOTAS]; + #endif + + struct inode vfs_inode; +diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c +index 67b5510beded2..7b3d5aeb2a6fe 100644 +--- a/fs/reiserfs/super.c ++++ b/fs/reiserfs/super.c +@@ -802,7 +802,7 @@ static ssize_t reiserfs_quota_write(struct super_block *, int, const char *, + static ssize_t reiserfs_quota_read(struct super_block *, int, char *, size_t, + loff_t); + +-static struct dquot **reiserfs_get_dquots(struct inode *inode) ++static struct dquot __rcu **reiserfs_get_dquots(struct inode *inode) + { + return REISERFS_I(inode)->i_dquot; + } +diff --git a/fs/select.c b/fs/select.c +index 0ee55af1a55c2..d4d881d439dcd 100644 +--- a/fs/select.c ++++ b/fs/select.c +@@ -476,7 +476,7 @@ static inline void wait_key_set(poll_table *wait, unsigned long in, + wait->_key |= POLLOUT_SET; + } + +-static int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time) ++static noinline_for_stack int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time) + { + ktime_t expire, *to = NULL; + struct poll_wqueues table; +diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c +index f391c9b803d84..98514f2f2d7b1 100644 +--- a/fs/smb/client/file.c ++++ b/fs/smb/client/file.c +@@ -2624,20 +2624,20 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) + * dirty pages if possible, but don't sleep while doing so. + */ + static void cifs_extend_writeback(struct address_space *mapping, ++ struct xa_state *xas, + long *_count, + loff_t start, + int max_pages, +- size_t max_len, +- unsigned int *_len) ++ loff_t max_len, ++ size_t *_len) + { + struct folio_batch batch; + struct folio *folio; +- unsigned int psize, nr_pages; +- size_t len = *_len; +- pgoff_t index = (start + len) / PAGE_SIZE; ++ unsigned int nr_pages; ++ pgoff_t index = (start + *_len) / PAGE_SIZE; ++ size_t len; + bool stop = true; + unsigned int i; +- XA_STATE(xas, &mapping->i_pages, index); + + folio_batch_init(&batch); + +@@ -2648,54 +2648,64 @@ static void cifs_extend_writeback(struct address_space *mapping, + */ + rcu_read_lock(); + +- xas_for_each(&xas, folio, ULONG_MAX) { ++ xas_for_each(xas, folio, ULONG_MAX) { + stop = true; +- if (xas_retry(&xas, folio)) ++ if (xas_retry(xas, folio)) + continue; + if (xa_is_value(folio)) + break; +- if (folio->index != index) ++ if (folio->index != index) { ++ xas_reset(xas); + break; ++ } ++ + if (!folio_try_get_rcu(folio)) { +- xas_reset(&xas); ++ xas_reset(xas); + continue; + } + nr_pages = folio_nr_pages(folio); +- if (nr_pages > max_pages) ++ if (nr_pages > max_pages) { ++ xas_reset(xas); + break; ++ } + + /* Has the page moved or been split? */ +- if (unlikely(folio != xas_reload(&xas))) { ++ if (unlikely(folio != xas_reload(xas))) { + folio_put(folio); ++ xas_reset(xas); + break; + } + + if (!folio_trylock(folio)) { + folio_put(folio); ++ xas_reset(xas); + break; + } +- if (!folio_test_dirty(folio) || folio_test_writeback(folio)) { ++ if (!folio_test_dirty(folio) || ++ folio_test_writeback(folio)) { + folio_unlock(folio); + folio_put(folio); ++ xas_reset(xas); + break; + } + + max_pages -= nr_pages; +- psize = folio_size(folio); +- len += psize; ++ len = folio_size(folio); + stop = false; +- if (max_pages <= 0 || len >= max_len || *_count <= 0) +- stop = true; + + index += nr_pages; ++ *_count -= nr_pages; ++ *_len += len; ++ if (max_pages <= 0 || *_len >= max_len || *_count <= 0) ++ stop = true; ++ + if (!folio_batch_add(&batch, folio)) + break; + if (stop) + break; + } + +- if (!stop) +- xas_pause(&xas); ++ xas_pause(xas); + rcu_read_unlock(); + + /* Now, if we obtained any pages, we can shift them to being +@@ -2712,16 +2722,12 @@ static void cifs_extend_writeback(struct address_space *mapping, + if (!folio_clear_dirty_for_io(folio)) + WARN_ON(1); + folio_start_writeback(folio); +- +- *_count -= folio_nr_pages(folio); + folio_unlock(folio); + } + + folio_batch_release(&batch); + cond_resched(); + } while (!stop); +- +- *_len = len; + } + + /* +@@ -2729,8 +2735,10 @@ static void cifs_extend_writeback(struct address_space *mapping, + */ + static ssize_t cifs_write_back_from_locked_folio(struct address_space *mapping, + struct writeback_control *wbc, ++ struct xa_state *xas, + struct folio *folio, +- loff_t start, loff_t end) ++ unsigned long long start, ++ unsigned long long end) + { + struct inode *inode = mapping->host; + struct TCP_Server_Info *server; +@@ -2739,17 +2747,18 @@ static ssize_t cifs_write_back_from_locked_folio(struct address_space *mapping, + struct cifs_credits credits_on_stack; + struct cifs_credits *credits = &credits_on_stack; + struct cifsFileInfo *cfile = NULL; +- unsigned int xid, wsize, len; +- loff_t i_size = i_size_read(inode); +- size_t max_len; ++ unsigned long long i_size = i_size_read(inode), max_len; ++ unsigned int xid, wsize; ++ size_t len = folio_size(folio); + long count = wbc->nr_to_write; + int rc; + + /* The folio should be locked, dirty and not undergoing writeback. */ ++ if (!folio_clear_dirty_for_io(folio)) ++ WARN_ON_ONCE(1); + folio_start_writeback(folio); + + count -= folio_nr_pages(folio); +- len = folio_size(folio); + + xid = get_xid(); + server = cifs_pick_channel(cifs_sb_master_tcon(cifs_sb)->ses); +@@ -2779,9 +2788,10 @@ static ssize_t cifs_write_back_from_locked_folio(struct address_space *mapping, + wdata->server = server; + cfile = NULL; + +- /* Find all consecutive lockable dirty pages, stopping when we find a +- * page that is not immediately lockable, is not dirty or is missing, +- * or we reach the end of the range. ++ /* Find all consecutive lockable dirty pages that have contiguous ++ * written regions, stopping when we find a page that is not ++ * immediately lockable, is not dirty or is missing, or we reach the ++ * end of the range. + */ + if (start < i_size) { + /* Trim the write to the EOF; the extra data is ignored. Also +@@ -2801,19 +2811,18 @@ static ssize_t cifs_write_back_from_locked_folio(struct address_space *mapping, + max_pages -= folio_nr_pages(folio); + + if (max_pages > 0) +- cifs_extend_writeback(mapping, &count, start, ++ cifs_extend_writeback(mapping, xas, &count, start, + max_pages, max_len, &len); + } +- len = min_t(loff_t, len, max_len); + } +- +- wdata->bytes = len; ++ len = min_t(unsigned long long, len, i_size - start); + + /* We now have a contiguous set of dirty pages, each with writeback + * set; the first page is still locked at this point, but all the rest + * have been unlocked. + */ + folio_unlock(folio); ++ wdata->bytes = len; + + if (start < i_size) { + iov_iter_xarray(&wdata->iter, ITER_SOURCE, &mapping->i_pages, +@@ -2864,102 +2873,118 @@ static ssize_t cifs_write_back_from_locked_folio(struct address_space *mapping, + /* + * write a region of pages back to the server + */ +-static int cifs_writepages_region(struct address_space *mapping, +- struct writeback_control *wbc, +- loff_t start, loff_t end, loff_t *_next) ++static ssize_t cifs_writepages_begin(struct address_space *mapping, ++ struct writeback_control *wbc, ++ struct xa_state *xas, ++ unsigned long long *_start, ++ unsigned long long end) + { +- struct folio_batch fbatch; ++ struct folio *folio; ++ unsigned long long start = *_start; ++ ssize_t ret; + int skips = 0; + +- folio_batch_init(&fbatch); +- do { +- int nr; +- pgoff_t index = start / PAGE_SIZE; ++search_again: ++ /* Find the first dirty page. */ ++ rcu_read_lock(); + +- nr = filemap_get_folios_tag(mapping, &index, end / PAGE_SIZE, +- PAGECACHE_TAG_DIRTY, &fbatch); +- if (!nr) ++ for (;;) { ++ folio = xas_find_marked(xas, end / PAGE_SIZE, PAGECACHE_TAG_DIRTY); ++ if (xas_retry(xas, folio) || xa_is_value(folio)) ++ continue; ++ if (!folio) + break; + +- for (int i = 0; i < nr; i++) { +- ssize_t ret; +- struct folio *folio = fbatch.folios[i]; ++ if (!folio_try_get_rcu(folio)) { ++ xas_reset(xas); ++ continue; ++ } + +-redo_folio: +- start = folio_pos(folio); /* May regress with THPs */ ++ if (unlikely(folio != xas_reload(xas))) { ++ folio_put(folio); ++ xas_reset(xas); ++ continue; ++ } + +- /* At this point we hold neither the i_pages lock nor the +- * page lock: the page may be truncated or invalidated +- * (changing page->mapping to NULL), or even swizzled +- * back from swapper_space to tmpfs file mapping +- */ +- if (wbc->sync_mode != WB_SYNC_NONE) { +- ret = folio_lock_killable(folio); +- if (ret < 0) +- goto write_error; +- } else { +- if (!folio_trylock(folio)) +- goto skip_write; +- } ++ xas_pause(xas); ++ break; ++ } ++ rcu_read_unlock(); ++ if (!folio) ++ return 0; + +- if (folio->mapping != mapping || +- !folio_test_dirty(folio)) { +- start += folio_size(folio); +- folio_unlock(folio); +- continue; +- } ++ start = folio_pos(folio); /* May regress with THPs */ + +- if (folio_test_writeback(folio) || +- folio_test_fscache(folio)) { +- folio_unlock(folio); +- if (wbc->sync_mode == WB_SYNC_NONE) +- goto skip_write; ++ /* At this point we hold neither the i_pages lock nor the page lock: ++ * the page may be truncated or invalidated (changing page->mapping to ++ * NULL), or even swizzled back from swapper_space to tmpfs file ++ * mapping ++ */ ++lock_again: ++ if (wbc->sync_mode != WB_SYNC_NONE) { ++ ret = folio_lock_killable(folio); ++ if (ret < 0) ++ return ret; ++ } else { ++ if (!folio_trylock(folio)) ++ goto search_again; ++ } + +- folio_wait_writeback(folio); ++ if (folio->mapping != mapping || ++ !folio_test_dirty(folio)) { ++ start += folio_size(folio); ++ folio_unlock(folio); ++ goto search_again; ++ } ++ ++ if (folio_test_writeback(folio) || ++ folio_test_fscache(folio)) { ++ folio_unlock(folio); ++ if (wbc->sync_mode != WB_SYNC_NONE) { ++ folio_wait_writeback(folio); + #ifdef CONFIG_CIFS_FSCACHE +- folio_wait_fscache(folio); ++ folio_wait_fscache(folio); + #endif +- goto redo_folio; +- } +- +- if (!folio_clear_dirty_for_io(folio)) +- /* We hold the page lock - it should've been dirty. */ +- WARN_ON(1); +- +- ret = cifs_write_back_from_locked_folio(mapping, wbc, folio, start, end); +- if (ret < 0) +- goto write_error; +- +- start += ret; +- continue; +- +-write_error: +- folio_batch_release(&fbatch); +- *_next = start; +- return ret; ++ goto lock_again; ++ } + +-skip_write: +- /* +- * Too many skipped writes, or need to reschedule? +- * Treat it as a write error without an error code. +- */ ++ start += folio_size(folio); ++ if (wbc->sync_mode == WB_SYNC_NONE) { + if (skips >= 5 || need_resched()) { + ret = 0; +- goto write_error; ++ goto out; + } +- +- /* Otherwise, just skip that folio and go on to the next */ + skips++; +- start += folio_size(folio); +- continue; + } ++ goto search_again; ++ } + +- folio_batch_release(&fbatch); +- cond_resched(); +- } while (wbc->nr_to_write > 0); ++ ret = cifs_write_back_from_locked_folio(mapping, wbc, xas, folio, start, end); ++out: ++ if (ret > 0) ++ *_start = start + ret; ++ return ret; ++} + +- *_next = start; +- return 0; ++/* ++ * Write a region of pages back to the server ++ */ ++static int cifs_writepages_region(struct address_space *mapping, ++ struct writeback_control *wbc, ++ unsigned long long *_start, ++ unsigned long long end) ++{ ++ ssize_t ret; ++ ++ XA_STATE(xas, &mapping->i_pages, *_start / PAGE_SIZE); ++ ++ do { ++ ret = cifs_writepages_begin(mapping, wbc, &xas, _start, end); ++ if (ret > 0 && wbc->nr_to_write > 0) ++ cond_resched(); ++ } while (ret > 0 && wbc->nr_to_write > 0); ++ ++ return ret > 0 ? 0 : ret; + } + + /* +@@ -2968,7 +2993,7 @@ static int cifs_writepages_region(struct address_space *mapping, + static int cifs_writepages(struct address_space *mapping, + struct writeback_control *wbc) + { +- loff_t start, next; ++ loff_t start, end; + int ret; + + /* We have to be careful as we can end up racing with setattr() +@@ -2976,28 +3001,34 @@ static int cifs_writepages(struct address_space *mapping, + * to prevent it. + */ + +- if (wbc->range_cyclic) { ++ if (wbc->range_cyclic && mapping->writeback_index) { + start = mapping->writeback_index * PAGE_SIZE; +- ret = cifs_writepages_region(mapping, wbc, start, LLONG_MAX, &next); +- if (ret == 0) { +- mapping->writeback_index = next / PAGE_SIZE; +- if (start > 0 && wbc->nr_to_write > 0) { +- ret = cifs_writepages_region(mapping, wbc, 0, +- start, &next); +- if (ret == 0) +- mapping->writeback_index = +- next / PAGE_SIZE; +- } ++ ret = cifs_writepages_region(mapping, wbc, &start, LLONG_MAX); ++ if (ret < 0) ++ goto out; ++ ++ if (wbc->nr_to_write <= 0) { ++ mapping->writeback_index = start / PAGE_SIZE; ++ goto out; + } ++ ++ start = 0; ++ end = mapping->writeback_index * PAGE_SIZE; ++ mapping->writeback_index = 0; ++ ret = cifs_writepages_region(mapping, wbc, &start, end); ++ if (ret == 0) ++ mapping->writeback_index = start / PAGE_SIZE; + } else if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) { +- ret = cifs_writepages_region(mapping, wbc, 0, LLONG_MAX, &next); ++ start = 0; ++ ret = cifs_writepages_region(mapping, wbc, &start, LLONG_MAX); + if (wbc->nr_to_write > 0 && ret == 0) +- mapping->writeback_index = next / PAGE_SIZE; ++ mapping->writeback_index = start / PAGE_SIZE; + } else { +- ret = cifs_writepages_region(mapping, wbc, +- wbc->range_start, wbc->range_end, &next); ++ start = wbc->range_start; ++ ret = cifs_writepages_region(mapping, wbc, &start, wbc->range_end); + } + ++out: + return ret; + } + +diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h +index 6ea339d5de088..81572d32db0c2 100644 +--- a/include/drm/drm_fixed.h ++++ b/include/drm/drm_fixed.h +@@ -71,7 +71,6 @@ static inline u32 dfixed_div(fixed20_12 A, fixed20_12 B) + } + + #define DRM_FIXED_POINT 32 +-#define DRM_FIXED_POINT_HALF 16 + #define DRM_FIXED_ONE (1ULL << DRM_FIXED_POINT) + #define DRM_FIXED_DECIMAL_MASK (DRM_FIXED_ONE - 1) + #define DRM_FIXED_DIGITS_MASK (~DRM_FIXED_DECIMAL_MASK) +@@ -90,12 +89,12 @@ static inline int drm_fixp2int(s64 a) + + static inline int drm_fixp2int_round(s64 a) + { +- return drm_fixp2int(a + (1 << (DRM_FIXED_POINT_HALF - 1))); ++ return drm_fixp2int(a + DRM_FIXED_ONE / 2); + } + + static inline int drm_fixp2int_ceil(s64 a) + { +- if (a > 0) ++ if (a >= 0) + return drm_fixp2int(a + DRM_FIXED_ALMOST_ONE); + else + return drm_fixp2int(a - DRM_FIXED_ALMOST_ONE); +diff --git a/include/drm/drm_kunit_helpers.h b/include/drm/drm_kunit_helpers.h +index ba483c87f0e7b..3ae19892229db 100644 +--- a/include/drm/drm_kunit_helpers.h ++++ b/include/drm/drm_kunit_helpers.h +@@ -3,6 +3,8 @@ + #ifndef DRM_KUNIT_HELPERS_H_ + #define DRM_KUNIT_HELPERS_H_ + ++#include ++ + #include + + #include +diff --git a/include/dt-bindings/clock/r8a779g0-cpg-mssr.h b/include/dt-bindings/clock/r8a779g0-cpg-mssr.h +index 754c54a6eb06a..7850cdc62e285 100644 +--- a/include/dt-bindings/clock/r8a779g0-cpg-mssr.h ++++ b/include/dt-bindings/clock/r8a779g0-cpg-mssr.h +@@ -86,5 +86,6 @@ + #define R8A779G0_CLK_CPEX 74 + #define R8A779G0_CLK_CBFUSA 75 + #define R8A779G0_CLK_R 76 ++#define R8A779G0_CLK_CP 77 + + #endif /* __DT_BINDINGS_CLOCK_R8A779G0_CPG_MSSR_H__ */ +diff --git a/include/linux/dm-io.h b/include/linux/dm-io.h +index 7595142f3fc57..7b2968612b7e6 100644 +--- a/include/linux/dm-io.h ++++ b/include/linux/dm-io.h +@@ -80,7 +80,8 @@ void dm_io_client_destroy(struct dm_io_client *client); + * error occurred doing io to the corresponding region. + */ + int dm_io(struct dm_io_request *io_req, unsigned int num_regions, +- struct dm_io_region *region, unsigned int long *sync_error_bits); ++ struct dm_io_region *region, unsigned int long *sync_error_bits, ++ unsigned short ioprio); + + #endif /* __KERNEL__ */ + #endif /* _LINUX_DM_IO_H */ +diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h +index 053137a0fe456..3f016d3c1ec4f 100644 +--- a/include/linux/f2fs_fs.h ++++ b/include/linux/f2fs_fs.h +@@ -27,6 +27,7 @@ + + #define F2FS_BYTES_TO_BLK(bytes) ((bytes) >> F2FS_BLKSIZE_BITS) + #define F2FS_BLK_TO_BYTES(blk) ((blk) << F2FS_BLKSIZE_BITS) ++#define F2FS_BLK_END_BYTES(blk) (F2FS_BLK_TO_BYTES(blk + 1) - 1) + + /* 0, 1(node nid), 2(meta nid) are reserved node id */ + #define F2FS_RESERVED_NODE_NUM 3 +diff --git a/include/linux/filter.h b/include/linux/filter.h +index 68fb6c8142fec..f537a394c42d0 100644 +--- a/include/linux/filter.h ++++ b/include/linux/filter.h +@@ -547,24 +547,27 @@ static inline bool insn_is_zext(const struct bpf_insn *insn) + __BPF_MAP(n, __BPF_DECL_ARGS, __BPF_N, u64, __ur_1, u64, __ur_2, \ + u64, __ur_3, u64, __ur_4, u64, __ur_5) + +-#define BPF_CALL_x(x, name, ...) \ ++#define BPF_CALL_x(x, attr, name, ...) \ + static __always_inline \ + u64 ____##name(__BPF_MAP(x, __BPF_DECL_ARGS, __BPF_V, __VA_ARGS__)); \ + typedef u64 (*btf_##name)(__BPF_MAP(x, __BPF_DECL_ARGS, __BPF_V, __VA_ARGS__)); \ +- u64 name(__BPF_REG(x, __BPF_DECL_REGS, __BPF_N, __VA_ARGS__)); \ +- u64 name(__BPF_REG(x, __BPF_DECL_REGS, __BPF_N, __VA_ARGS__)) \ ++ attr u64 name(__BPF_REG(x, __BPF_DECL_REGS, __BPF_N, __VA_ARGS__)); \ ++ attr u64 name(__BPF_REG(x, __BPF_DECL_REGS, __BPF_N, __VA_ARGS__)) \ + { \ + return ((btf_##name)____##name)(__BPF_MAP(x,__BPF_CAST,__BPF_N,__VA_ARGS__));\ + } \ + static __always_inline \ + u64 ____##name(__BPF_MAP(x, __BPF_DECL_ARGS, __BPF_V, __VA_ARGS__)) + +-#define BPF_CALL_0(name, ...) BPF_CALL_x(0, name, __VA_ARGS__) +-#define BPF_CALL_1(name, ...) BPF_CALL_x(1, name, __VA_ARGS__) +-#define BPF_CALL_2(name, ...) BPF_CALL_x(2, name, __VA_ARGS__) +-#define BPF_CALL_3(name, ...) BPF_CALL_x(3, name, __VA_ARGS__) +-#define BPF_CALL_4(name, ...) BPF_CALL_x(4, name, __VA_ARGS__) +-#define BPF_CALL_5(name, ...) BPF_CALL_x(5, name, __VA_ARGS__) ++#define __NOATTR ++#define BPF_CALL_0(name, ...) BPF_CALL_x(0, __NOATTR, name, __VA_ARGS__) ++#define BPF_CALL_1(name, ...) BPF_CALL_x(1, __NOATTR, name, __VA_ARGS__) ++#define BPF_CALL_2(name, ...) BPF_CALL_x(2, __NOATTR, name, __VA_ARGS__) ++#define BPF_CALL_3(name, ...) BPF_CALL_x(3, __NOATTR, name, __VA_ARGS__) ++#define BPF_CALL_4(name, ...) BPF_CALL_x(4, __NOATTR, name, __VA_ARGS__) ++#define BPF_CALL_5(name, ...) BPF_CALL_x(5, __NOATTR, name, __VA_ARGS__) ++ ++#define NOTRACE_BPF_CALL_1(name, ...) BPF_CALL_x(1, notrace, name, __VA_ARGS__) + + #define bpf_ctx_range(TYPE, MEMBER) \ + offsetof(TYPE, MEMBER) ... offsetofend(TYPE, MEMBER) - 1 +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 1fbc72c5f112c..08ecac9d7b8ba 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -2158,7 +2158,7 @@ struct super_operations { + #ifdef CONFIG_QUOTA + ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t); + ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); +- struct dquot **(*get_dquots)(struct inode *); ++ struct dquot __rcu **(*get_dquots)(struct inode *); + #endif + long (*nr_cached_objects)(struct super_block *, + struct shrink_control *); +@@ -3281,6 +3281,15 @@ extern int generic_check_addressable(unsigned, u64); + + extern void generic_set_encrypted_ci_d_ops(struct dentry *dentry); + ++static inline bool sb_has_encoding(const struct super_block *sb) ++{ ++#if IS_ENABLED(CONFIG_UNICODE) ++ return !!sb->s_encoding; ++#else ++ return false; ++#endif ++} ++ + int may_setattr(struct mnt_idmap *idmap, struct inode *inode, + unsigned int ia_valid); + int setattr_prepare(struct mnt_idmap *, struct dentry *, struct iattr *); +diff --git a/include/linux/iommu.h b/include/linux/iommu.h +index 5e27cb3a3be99..c948289f64d08 100644 +--- a/include/linux/iommu.h ++++ b/include/linux/iommu.h +@@ -487,6 +487,7 @@ struct iommu_ops { + struct module *owner; + struct iommu_domain *identity_domain; + struct iommu_domain *blocked_domain; ++ struct iommu_domain *release_domain; + struct iommu_domain *default_domain; + }; + +diff --git a/include/linux/moduleloader.h b/include/linux/moduleloader.h +index 001b2ce83832e..89b1e0ed98114 100644 +--- a/include/linux/moduleloader.h ++++ b/include/linux/moduleloader.h +@@ -115,6 +115,14 @@ int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *mod); + ++#ifdef CONFIG_MODULES ++void flush_module_init_free_work(void); ++#else ++static inline void flush_module_init_free_work(void) ++{ ++} ++#endif ++ + /* Any cleanup needed when module leaves. */ + void module_arch_cleanup(struct module *mod); + +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index 78a09af89e39b..dba428b3a87a5 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -2144,6 +2144,7 @@ struct net_device { + struct pcpu_sw_netstats __percpu *tstats; + struct pcpu_dstats __percpu *dstats; + }; ++ unsigned long state; + unsigned int flags; + unsigned short hard_header_len; + netdev_features_t features; +@@ -2189,7 +2190,6 @@ struct net_device { + * part of the usual set specified in Space.c. + */ + +- unsigned long state; + + struct list_head dev_list; + struct list_head napi_list; +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 7ab0d13672daf..213109d3c601d 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -2517,6 +2517,11 @@ static inline struct pci_dev *pcie_find_root_port(struct pci_dev *dev) + return NULL; + } + ++static inline bool pci_dev_is_disconnected(const struct pci_dev *dev) ++{ ++ return dev->error_state == pci_channel_io_perm_failure; ++} ++ + void pci_request_acs(void); + bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags); + bool pci_acs_path_enabled(struct pci_dev *start, +diff --git a/include/linux/poll.h b/include/linux/poll.h +index a9e0e1c2d1f2f..d1ea4f3714a84 100644 +--- a/include/linux/poll.h ++++ b/include/linux/poll.h +@@ -14,11 +14,7 @@ + + /* ~832 bytes of stack space used max in sys_select/sys_poll before allocating + additional memory. */ +-#ifdef __clang__ +-#define MAX_STACK_ALLOC 768 +-#else + #define MAX_STACK_ALLOC 832 +-#endif + #define FRONTEND_STACK_ALLOC 256 + #define SELECT_STACK_ALLOC FRONTEND_STACK_ALLOC + #define POLL_STACK_ALLOC FRONTEND_STACK_ALLOC +diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h +index 0746b1b0b6639..9d69e4bd6f0a8 100644 +--- a/include/linux/rcupdate.h ++++ b/include/linux/rcupdate.h +@@ -247,6 +247,37 @@ do { \ + cond_resched(); \ + } while (0) + ++/** ++ * rcu_softirq_qs_periodic - Report RCU and RCU-Tasks quiescent states ++ * @old_ts: jiffies at start of processing. ++ * ++ * This helper is for long-running softirq handlers, such as NAPI threads in ++ * networking. The caller should initialize the variable passed in as @old_ts ++ * at the beginning of the softirq handler. When invoked frequently, this macro ++ * will invoke rcu_softirq_qs() every 100 milliseconds thereafter, which will ++ * provide both RCU and RCU-Tasks quiescent states. Note that this macro ++ * modifies its old_ts argument. ++ * ++ * Because regions of code that have disabled softirq act as RCU read-side ++ * critical sections, this macro should be invoked with softirq (and ++ * preemption) enabled. ++ * ++ * The macro is not needed when CONFIG_PREEMPT_RT is defined. RT kernels would ++ * have more chance to invoke schedule() calls and provide necessary quiescent ++ * states. As a contrast, calling cond_resched() only won't achieve the same ++ * effect because cond_resched() does not provide RCU-Tasks quiescent states. ++ */ ++#define rcu_softirq_qs_periodic(old_ts) \ ++do { \ ++ if (!IS_ENABLED(CONFIG_PREEMPT_RT) && \ ++ time_after(jiffies, (old_ts) + HZ / 10)) { \ ++ preempt_disable(); \ ++ rcu_softirq_qs(); \ ++ preempt_enable(); \ ++ (old_ts) = jiffies; \ ++ } \ ++} while (0) ++ + /* + * Infrastructure to implement the synchronize_() primitives in + * TREE_RCU and rcu_barrier_() primitives in TINY_RCU. +diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h +index 2caa6b86106aa..66828dfc6e74e 100644 +--- a/include/linux/shmem_fs.h ++++ b/include/linux/shmem_fs.h +@@ -37,7 +37,7 @@ struct shmem_inode_info { + unsigned int fsflags; /* for FS_IOC_[SG]ETFLAGS */ + atomic_t stop_eviction; /* hold when working on inode */ + #ifdef CONFIG_TMPFS_QUOTA +- struct dquot *i_dquot[MAXQUOTAS]; ++ struct dquot __rcu *i_dquot[MAXQUOTAS]; + #endif + struct inode vfs_inode; + }; +diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h +index 2cc0a9606175f..515e7958c6c10 100644 +--- a/include/linux/workqueue.h ++++ b/include/linux/workqueue.h +@@ -391,6 +391,13 @@ enum { + WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */ + WQ_UNBOUND_MAX_ACTIVE = WQ_MAX_ACTIVE, + WQ_DFL_ACTIVE = WQ_MAX_ACTIVE / 2, ++ ++ /* ++ * Per-node default cap on min_active. Unless explicitly set, min_active ++ * is set to min(max_active, WQ_DFL_MIN_ACTIVE). For more details, see ++ * workqueue_struct->min_active definition. ++ */ ++ WQ_DFL_MIN_ACTIVE = 8, + }; + + /* +@@ -433,11 +440,33 @@ extern struct workqueue_struct *system_freezable_power_efficient_wq; + * alloc_workqueue - allocate a workqueue + * @fmt: printf format for the name of the workqueue + * @flags: WQ_* flags +- * @max_active: max in-flight work items per CPU, 0 for default ++ * @max_active: max in-flight work items, 0 for default + * remaining args: args for @fmt + * +- * Allocate a workqueue with the specified parameters. For detailed +- * information on WQ_* flags, please refer to ++ * For a per-cpu workqueue, @max_active limits the number of in-flight work ++ * items for each CPU. e.g. @max_active of 1 indicates that each CPU can be ++ * executing at most one work item for the workqueue. ++ * ++ * For unbound workqueues, @max_active limits the number of in-flight work items ++ * for the whole system. e.g. @max_active of 16 indicates that that there can be ++ * at most 16 work items executing for the workqueue in the whole system. ++ * ++ * As sharing the same active counter for an unbound workqueue across multiple ++ * NUMA nodes can be expensive, @max_active is distributed to each NUMA node ++ * according to the proportion of the number of online CPUs and enforced ++ * independently. ++ * ++ * Depending on online CPU distribution, a node may end up with per-node ++ * max_active which is significantly lower than @max_active, which can lead to ++ * deadlocks if the per-node concurrency limit is lower than the maximum number ++ * of interdependent work items for the workqueue. ++ * ++ * To guarantee forward progress regardless of online CPU distribution, the ++ * concurrency limit on every node is guaranteed to be equal to or greater than ++ * min_active which is set to min(@max_active, %WQ_DFL_MIN_ACTIVE). This means ++ * that the sum of per-node max_active's may be larger than @max_active. ++ * ++ * For detailed information on %WQ_* flags, please refer to + * Documentation/core-api/workqueue.rst. + * + * RETURNS: +diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h +index 56719a26a46c3..bec8c3a1ed824 100644 +--- a/include/media/videobuf2-core.h ++++ b/include/media/videobuf2-core.h +@@ -72,6 +72,10 @@ struct vb2_buffer; + * argument to other ops in this structure. + * @put_userptr: inform the allocator that a USERPTR buffer will no longer + * be used. ++ * @prepare: called every time the buffer is passed from userspace to the ++ * driver, useful for cache synchronisation, optional. ++ * @finish: called every time the buffer is passed back from the driver ++ * to the userspace, also optional. + * @attach_dmabuf: attach a shared &struct dma_buf for a hardware operation; + * used for DMABUF memory types; dev is the alloc device + * dbuf is the shared dma_buf; returns ERR_PTR() on failure; +@@ -86,10 +90,6 @@ struct vb2_buffer; + * dmabuf. + * @unmap_dmabuf: releases access control to the dmabuf - allocator is notified + * that this driver is done using the dmabuf for now. +- * @prepare: called every time the buffer is passed from userspace to the +- * driver, useful for cache synchronisation, optional. +- * @finish: called every time the buffer is passed back from the driver +- * to the userspace, also optional. + * @vaddr: return a kernel virtual address to a given memory buffer + * associated with the passed private structure or NULL if no + * such mapping exists. +@@ -484,7 +484,6 @@ struct vb2_buf_ops { + * caller. For example, for V4L2, it should match + * the types defined on &enum v4l2_buf_type. + * @io_modes: supported io methods (see &enum vb2_io_modes). +- * @alloc_devs: &struct device memory type/allocator-specific per-plane device + * @dev: device to use for the default allocation context if the driver + * doesn't fill in the @alloc_devs array. + * @dma_attrs: DMA attributes to use for the DMA. +@@ -553,6 +552,7 @@ struct vb2_buf_ops { + * VIDIOC_REQBUFS will ensure at least @min_queued_buffers + * buffers will be allocated. Note that VIDIOC_CREATE_BUFS will not + * modify the requested buffer count. ++ * @alloc_devs: &struct device memory type/allocator-specific per-plane device + */ + /* + * Private elements (won't appear at the uAPI book): +@@ -577,6 +577,9 @@ struct vb2_buf_ops { + * @waiting_for_buffers: used in poll() to check if vb2 is still waiting for + * buffers. Only set for capture queues if qbuf has not yet been + * called since poll() needs to return %EPOLLERR in that situation. ++ * @waiting_in_dqbuf: set by the core for the duration of a blocking DQBUF, when ++ * it has to wait for a buffer to become available with vb2_queue->lock ++ * released. Used to prevent destroying the queue by other threads. + * @is_multiplanar: set if buffer type is multiplanar + * @is_output: set if buffer type is output + * @copy_timestamp: set if vb2-core should set timestamps +diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h +index bdee5d649cc61..0d231024570a3 100644 +--- a/include/net/bluetooth/hci.h ++++ b/include/net/bluetooth/hci.h +@@ -393,7 +393,6 @@ enum { + HCI_LIMITED_PRIVACY, + HCI_RPA_EXPIRED, + HCI_RPA_RESOLVING, +- HCI_HS_ENABLED, + HCI_LE_ENABLED, + HCI_ADVERTISING, + HCI_ADVERTISING_CONNECTABLE, +@@ -437,7 +436,6 @@ enum { + #define HCI_NCMD_TIMEOUT msecs_to_jiffies(4000) /* 4 seconds */ + #define HCI_ACL_TX_TIMEOUT msecs_to_jiffies(45000) /* 45 seconds */ + #define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ +-#define HCI_POWER_OFF_TIMEOUT msecs_to_jiffies(5000) /* 5 seconds */ + #define HCI_LE_CONN_TIMEOUT msecs_to_jiffies(20000) /* 20 seconds */ + #define HCI_LE_AUTOCONN_TIMEOUT msecs_to_jiffies(4000) /* 4 seconds */ + +diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h +index 8f8dd91737142..d1228857b1d0f 100644 +--- a/include/net/bluetooth/hci_core.h ++++ b/include/net/bluetooth/hci_core.h +@@ -552,6 +552,7 @@ struct hci_dev { + __u32 req_status; + __u32 req_result; + struct sk_buff *req_skb; ++ struct sk_buff *req_rsp; + + void *smp_data; + void *smp_bredr_data; +diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h +index 6efbc2152146b..e2582c2425449 100644 +--- a/include/net/bluetooth/hci_sync.h ++++ b/include/net/bluetooth/hci_sync.h +@@ -42,7 +42,7 @@ int __hci_cmd_sync_status_sk(struct hci_dev *hdev, u16 opcode, u32 plen, + void hci_cmd_sync_init(struct hci_dev *hdev); + void hci_cmd_sync_clear(struct hci_dev *hdev); + void hci_cmd_sync_cancel(struct hci_dev *hdev, int err); +-void __hci_cmd_sync_cancel(struct hci_dev *hdev, int err); ++void hci_cmd_sync_cancel_sync(struct hci_dev *hdev, int err); + + int hci_cmd_sync_submit(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, + void *data, hci_cmd_sync_work_destroy_t destroy); +diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h +index cf393e72d6ed6..92d7197f9a563 100644 +--- a/include/net/bluetooth/l2cap.h ++++ b/include/net/bluetooth/l2cap.h +@@ -59,8 +59,6 @@ + #define L2CAP_WAIT_ACK_POLL_PERIOD msecs_to_jiffies(200) + #define L2CAP_WAIT_ACK_TIMEOUT msecs_to_jiffies(10000) + +-#define L2CAP_A2MP_DEFAULT_MTU 670 +- + /* L2CAP socket address */ + struct sockaddr_l2 { + sa_family_t l2_family; +@@ -109,12 +107,6 @@ struct l2cap_conninfo { + #define L2CAP_ECHO_RSP 0x09 + #define L2CAP_INFO_REQ 0x0a + #define L2CAP_INFO_RSP 0x0b +-#define L2CAP_CREATE_CHAN_REQ 0x0c +-#define L2CAP_CREATE_CHAN_RSP 0x0d +-#define L2CAP_MOVE_CHAN_REQ 0x0e +-#define L2CAP_MOVE_CHAN_RSP 0x0f +-#define L2CAP_MOVE_CHAN_CFM 0x10 +-#define L2CAP_MOVE_CHAN_CFM_RSP 0x11 + #define L2CAP_CONN_PARAM_UPDATE_REQ 0x12 + #define L2CAP_CONN_PARAM_UPDATE_RSP 0x13 + #define L2CAP_LE_CONN_REQ 0x14 +@@ -144,7 +136,6 @@ struct l2cap_conninfo { + /* L2CAP fixed channels */ + #define L2CAP_FC_SIG_BREDR 0x02 + #define L2CAP_FC_CONNLESS 0x04 +-#define L2CAP_FC_A2MP 0x08 + #define L2CAP_FC_ATT 0x10 + #define L2CAP_FC_SIG_LE 0x20 + #define L2CAP_FC_SMP_LE 0x40 +@@ -267,7 +258,6 @@ struct l2cap_conn_rsp { + /* channel identifier */ + #define L2CAP_CID_SIGNALING 0x0001 + #define L2CAP_CID_CONN_LESS 0x0002 +-#define L2CAP_CID_A2MP 0x0003 + #define L2CAP_CID_ATT 0x0004 + #define L2CAP_CID_LE_SIGNALING 0x0005 + #define L2CAP_CID_SMP 0x0006 +@@ -282,7 +272,6 @@ struct l2cap_conn_rsp { + #define L2CAP_CR_BAD_PSM 0x0002 + #define L2CAP_CR_SEC_BLOCK 0x0003 + #define L2CAP_CR_NO_MEM 0x0004 +-#define L2CAP_CR_BAD_AMP 0x0005 + #define L2CAP_CR_INVALID_SCID 0x0006 + #define L2CAP_CR_SCID_IN_USE 0x0007 + +@@ -404,29 +393,6 @@ struct l2cap_info_rsp { + __u8 data[]; + } __packed; + +-struct l2cap_create_chan_req { +- __le16 psm; +- __le16 scid; +- __u8 amp_id; +-} __packed; +- +-struct l2cap_create_chan_rsp { +- __le16 dcid; +- __le16 scid; +- __le16 result; +- __le16 status; +-} __packed; +- +-struct l2cap_move_chan_req { +- __le16 icid; +- __u8 dest_amp_id; +-} __packed; +- +-struct l2cap_move_chan_rsp { +- __le16 icid; +- __le16 result; +-} __packed; +- + #define L2CAP_MR_SUCCESS 0x0000 + #define L2CAP_MR_PEND 0x0001 + #define L2CAP_MR_BAD_ID 0x0002 +@@ -539,8 +505,6 @@ struct l2cap_seq_list { + + struct l2cap_chan { + struct l2cap_conn *conn; +- struct hci_conn *hs_hcon; +- struct hci_chan *hs_hchan; + struct kref kref; + atomic_t nesting; + +@@ -591,12 +555,6 @@ struct l2cap_chan { + unsigned long conn_state; + unsigned long flags; + +- __u8 remote_amp_id; +- __u8 local_amp_id; +- __u8 move_id; +- __u8 move_state; +- __u8 move_role; +- + __u16 next_tx_seq; + __u16 expected_ack_seq; + __u16 expected_tx_seq; +diff --git a/include/soc/qcom/qcom-spmi-pmic.h b/include/soc/qcom/qcom-spmi-pmic.h +index 17a0a8c3d6560..a62d500a6fdaf 100644 +--- a/include/soc/qcom/qcom-spmi-pmic.h ++++ b/include/soc/qcom/qcom-spmi-pmic.h +@@ -49,7 +49,7 @@ + #define PMK8350_SUBTYPE 0x2f + #define PMR735B_SUBTYPE 0x34 + #define PM6350_SUBTYPE 0x36 +-#define PM2250_SUBTYPE 0x37 ++#define PM4125_SUBTYPE 0x37 + + #define PMI8998_FAB_ID_SMIC 0x11 + #define PMI8998_FAB_ID_GF 0x30 +diff --git a/include/uapi/linux/virtio_pci.h b/include/uapi/linux/virtio_pci.h +index ef3810dee7efa..a8208492e8227 100644 +--- a/include/uapi/linux/virtio_pci.h ++++ b/include/uapi/linux/virtio_pci.h +@@ -240,7 +240,7 @@ struct virtio_pci_cfg_cap { + #define VIRTIO_ADMIN_CMD_LEGACY_DEV_CFG_READ 0x5 + #define VIRTIO_ADMIN_CMD_LEGACY_NOTIFY_INFO 0x6 + +-struct __packed virtio_admin_cmd_hdr { ++struct virtio_admin_cmd_hdr { + __le16 opcode; + /* + * 1 - SR-IOV +@@ -252,20 +252,20 @@ struct __packed virtio_admin_cmd_hdr { + __le64 group_member_id; + }; + +-struct __packed virtio_admin_cmd_status { ++struct virtio_admin_cmd_status { + __le16 status; + __le16 status_qualifier; + /* Unused, reserved for future extensions. */ + __u8 reserved2[4]; + }; + +-struct __packed virtio_admin_cmd_legacy_wr_data { ++struct virtio_admin_cmd_legacy_wr_data { + __u8 offset; /* Starting offset of the register(s) to write. */ + __u8 reserved[7]; + __u8 registers[]; + }; + +-struct __packed virtio_admin_cmd_legacy_rd_data { ++struct virtio_admin_cmd_legacy_rd_data { + __u8 offset; /* Starting offset of the register(s) to read. */ + }; + +@@ -275,7 +275,7 @@ struct __packed virtio_admin_cmd_legacy_rd_data { + + #define VIRTIO_ADMIN_CMD_MAX_NOTIFY_INFO 4 + +-struct __packed virtio_admin_cmd_notify_info_data { ++struct virtio_admin_cmd_notify_info_data { + __u8 flags; /* 0 = end of list, 1 = owner device, 2 = member device */ + __u8 bar; /* BAR of the member or the owner device */ + __u8 padding[6]; +diff --git a/init/main.c b/init/main.c +index e24b0780fdff7..9e6ab6d593bd8 100644 +--- a/init/main.c ++++ b/init/main.c +@@ -88,6 +88,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1402,11 +1403,11 @@ static void mark_readonly(void) + if (rodata_enabled) { + /* + * load_module() results in W+X mappings, which are cleaned +- * up with call_rcu(). Let's make sure that queued work is ++ * up with init_free_wq. Let's make sure that queued work is + * flushed so that we don't hit false positives looking for + * insecure pages which are W+X. + */ +- rcu_barrier(); ++ flush_module_init_free_work(); + mark_rodata_ro(); + rodata_test(); + } else +diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c +index cd9a137ad6cef..9f938874c5e13 100644 +--- a/io_uring/io_uring.c ++++ b/io_uring/io_uring.c +@@ -1176,12 +1176,11 @@ static void ctx_flush_and_put(struct io_ring_ctx *ctx, struct io_tw_state *ts) + + static unsigned int handle_tw_list(struct llist_node *node, + struct io_ring_ctx **ctx, +- struct io_tw_state *ts, +- struct llist_node *last) ++ struct io_tw_state *ts) + { + unsigned int count = 0; + +- while (node && node != last) { ++ do { + struct llist_node *next = node->next; + struct io_kiocb *req = container_of(node, struct io_kiocb, + io_task_work.node); +@@ -1205,7 +1204,7 @@ static unsigned int handle_tw_list(struct llist_node *node, + *ctx = NULL; + cond_resched(); + } +- } ++ } while (node); + + return count; + } +@@ -1224,22 +1223,6 @@ static inline struct llist_node *io_llist_xchg(struct llist_head *head, + return xchg(&head->first, new); + } + +-/** +- * io_llist_cmpxchg - possibly swap all entries in a lock-less list +- * @head: the head of lock-less list to delete all entries +- * @old: expected old value of the first entry of the list +- * @new: new entry as the head of the list +- * +- * perform a cmpxchg on the first entry of the list. +- */ +- +-static inline struct llist_node *io_llist_cmpxchg(struct llist_head *head, +- struct llist_node *old, +- struct llist_node *new) +-{ +- return cmpxchg(&head->first, old, new); +-} +- + static __cold void io_fallback_tw(struct io_uring_task *tctx, bool sync) + { + struct llist_node *node = llist_del_all(&tctx->task_list); +@@ -1274,9 +1257,7 @@ void tctx_task_work(struct callback_head *cb) + struct io_ring_ctx *ctx = NULL; + struct io_uring_task *tctx = container_of(cb, struct io_uring_task, + task_work); +- struct llist_node fake = {}; + struct llist_node *node; +- unsigned int loops = 0; + unsigned int count = 0; + + if (unlikely(current->flags & PF_EXITING)) { +@@ -1284,21 +1265,9 @@ void tctx_task_work(struct callback_head *cb) + return; + } + +- do { +- loops++; +- node = io_llist_xchg(&tctx->task_list, &fake); +- count += handle_tw_list(node, &ctx, &ts, &fake); +- +- /* skip expensive cmpxchg if there are items in the list */ +- if (READ_ONCE(tctx->task_list.first) != &fake) +- continue; +- if (ts.locked && !wq_list_empty(&ctx->submit_state.compl_reqs)) { +- io_submit_flush_completions(ctx); +- if (READ_ONCE(tctx->task_list.first) != &fake) +- continue; +- } +- node = io_llist_cmpxchg(&tctx->task_list, &fake, NULL); +- } while (node != &fake); ++ node = llist_del_all(&tctx->task_list); ++ if (node) ++ count = handle_tw_list(node, &ctx, &ts); + + ctx_flush_and_put(ctx, &ts); + +@@ -1306,7 +1275,7 @@ void tctx_task_work(struct callback_head *cb) + if (unlikely(atomic_read(&tctx->in_cancel))) + io_uring_drop_tctx_refs(current); + +- trace_io_uring_task_work_run(tctx, count, loops); ++ trace_io_uring_task_work_run(tctx, count, 1); + } + + static inline void io_req_local_work_add(struct io_kiocb *req, unsigned flags) +@@ -1420,7 +1389,20 @@ static void __cold io_move_task_work_from_local(struct io_ring_ctx *ctx) + } + } + +-static int __io_run_local_work(struct io_ring_ctx *ctx, struct io_tw_state *ts) ++static bool io_run_local_work_continue(struct io_ring_ctx *ctx, int events, ++ int min_events) ++{ ++ if (llist_empty(&ctx->work_llist)) ++ return false; ++ if (events < min_events) ++ return true; ++ if (ctx->flags & IORING_SETUP_TASKRUN_FLAG) ++ atomic_or(IORING_SQ_TASKRUN, &ctx->rings->sq_flags); ++ return false; ++} ++ ++static int __io_run_local_work(struct io_ring_ctx *ctx, struct io_tw_state *ts, ++ int min_events) + { + struct llist_node *node; + unsigned int loops = 0; +@@ -1449,18 +1431,20 @@ static int __io_run_local_work(struct io_ring_ctx *ctx, struct io_tw_state *ts) + } + loops++; + +- if (!llist_empty(&ctx->work_llist)) ++ if (io_run_local_work_continue(ctx, ret, min_events)) + goto again; + if (ts->locked) { + io_submit_flush_completions(ctx); +- if (!llist_empty(&ctx->work_llist)) ++ if (io_run_local_work_continue(ctx, ret, min_events)) + goto again; + } ++ + trace_io_uring_local_work_run(ctx, ret, loops); + return ret; + } + +-static inline int io_run_local_work_locked(struct io_ring_ctx *ctx) ++static inline int io_run_local_work_locked(struct io_ring_ctx *ctx, ++ int min_events) + { + struct io_tw_state ts = { .locked = true, }; + int ret; +@@ -1468,20 +1452,20 @@ static inline int io_run_local_work_locked(struct io_ring_ctx *ctx) + if (llist_empty(&ctx->work_llist)) + return 0; + +- ret = __io_run_local_work(ctx, &ts); ++ ret = __io_run_local_work(ctx, &ts, min_events); + /* shouldn't happen! */ + if (WARN_ON_ONCE(!ts.locked)) + mutex_lock(&ctx->uring_lock); + return ret; + } + +-static int io_run_local_work(struct io_ring_ctx *ctx) ++static int io_run_local_work(struct io_ring_ctx *ctx, int min_events) + { + struct io_tw_state ts = {}; + int ret; + + ts.locked = mutex_trylock(&ctx->uring_lock); +- ret = __io_run_local_work(ctx, &ts); ++ ret = __io_run_local_work(ctx, &ts, min_events); + if (ts.locked) + mutex_unlock(&ctx->uring_lock); + +@@ -1677,7 +1661,7 @@ static int io_iopoll_check(struct io_ring_ctx *ctx, long min) + io_task_work_pending(ctx)) { + u32 tail = ctx->cached_cq_tail; + +- (void) io_run_local_work_locked(ctx); ++ (void) io_run_local_work_locked(ctx, min); + + if (task_work_pending(current) || + wq_list_empty(&ctx->iopoll_list)) { +@@ -2520,7 +2504,7 @@ int io_run_task_work_sig(struct io_ring_ctx *ctx) + { + if (!llist_empty(&ctx->work_llist)) { + __set_current_state(TASK_RUNNING); +- if (io_run_local_work(ctx) > 0) ++ if (io_run_local_work(ctx, INT_MAX) > 0) + return 0; + } + if (io_run_task_work() > 0) +@@ -2543,7 +2527,7 @@ static bool current_pending_io(void) + static inline int io_cqring_wait_schedule(struct io_ring_ctx *ctx, + struct io_wait_queue *iowq) + { +- int io_wait, ret; ++ int ret; + + if (unlikely(READ_ONCE(ctx->check_cq))) + return 1; +@@ -2561,7 +2545,6 @@ static inline int io_cqring_wait_schedule(struct io_ring_ctx *ctx, + * can take into account that the task is waiting for IO - turns out + * to be important for low QD IO. + */ +- io_wait = current->in_iowait; + if (current_pending_io()) + current->in_iowait = 1; + ret = 0; +@@ -2569,7 +2552,7 @@ static inline int io_cqring_wait_schedule(struct io_ring_ctx *ctx, + schedule(); + else if (!schedule_hrtimeout(&iowq->timeout, HRTIMER_MODE_ABS)) + ret = -ETIME; +- current->in_iowait = io_wait; ++ current->in_iowait = 0; + return ret; + } + +@@ -2588,7 +2571,7 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events, + if (!io_allowed_run_tw(ctx)) + return -EEXIST; + if (!llist_empty(&ctx->work_llist)) +- io_run_local_work(ctx); ++ io_run_local_work(ctx, min_events); + io_run_task_work(); + io_cqring_overflow_flush(ctx); + /* if user messes with these they will just get an early return */ +@@ -2626,11 +2609,10 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events, + + trace_io_uring_cqring_wait(ctx, min_events); + do { ++ int nr_wait = (int) iowq.cq_tail - READ_ONCE(ctx->rings->cq.tail); + unsigned long check_cq; + + if (ctx->flags & IORING_SETUP_DEFER_TASKRUN) { +- int nr_wait = (int) iowq.cq_tail - READ_ONCE(ctx->rings->cq.tail); +- + atomic_set(&ctx->cq_wait_nr, nr_wait); + set_current_state(TASK_INTERRUPTIBLE); + } else { +@@ -2649,7 +2631,7 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events, + */ + io_run_task_work(); + if (!llist_empty(&ctx->work_llist)) +- io_run_local_work(ctx); ++ io_run_local_work(ctx, nr_wait); + + /* + * Non-local task_work will be run on exit to userspace, but +@@ -2720,7 +2702,7 @@ static void *__io_uaddr_map(struct page ***pages, unsigned short *npages, + struct page **page_array; + unsigned int nr_pages; + void *page_addr; +- int ret, i; ++ int ret, i, pinned; + + *npages = 0; + +@@ -2734,12 +2716,12 @@ static void *__io_uaddr_map(struct page ***pages, unsigned short *npages, + if (!page_array) + return ERR_PTR(-ENOMEM); + +- ret = pin_user_pages_fast(uaddr, nr_pages, FOLL_WRITE | FOLL_LONGTERM, +- page_array); +- if (ret != nr_pages) { +-err: +- io_pages_free(&page_array, ret > 0 ? ret : 0); +- return ret < 0 ? ERR_PTR(ret) : ERR_PTR(-EFAULT); ++ ++ pinned = pin_user_pages_fast(uaddr, nr_pages, FOLL_WRITE | FOLL_LONGTERM, ++ page_array); ++ if (pinned != nr_pages) { ++ ret = (pinned < 0) ? pinned : -EFAULT; ++ goto free_pages; + } + + page_addr = page_address(page_array[0]); +@@ -2753,7 +2735,7 @@ static void *__io_uaddr_map(struct page ***pages, unsigned short *npages, + * didn't support this feature. + */ + if (PageHighMem(page_array[i])) +- goto err; ++ goto free_pages; + + /* + * No support for discontig pages for now, should either be a +@@ -2762,13 +2744,17 @@ static void *__io_uaddr_map(struct page ***pages, unsigned short *npages, + * just fail them with EINVAL. + */ + if (page_address(page_array[i]) != page_addr) +- goto err; ++ goto free_pages; + page_addr += PAGE_SIZE; + } + + *pages = page_array; + *npages = nr_pages; + return page_to_virt(page_array[0]); ++ ++free_pages: ++ io_pages_free(&page_array, pinned > 0 ? pinned : 0); ++ return ERR_PTR(ret); + } + + static void *io_rings_map(struct io_ring_ctx *ctx, unsigned long uaddr, +@@ -3304,7 +3290,7 @@ static __cold bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx, + + if ((ctx->flags & IORING_SETUP_DEFER_TASKRUN) && + io_allowed_defer_tw_run(ctx)) +- ret |= io_run_local_work(ctx) > 0; ++ ret |= io_run_local_work(ctx, INT_MAX) > 0; + ret |= io_cancel_defer_files(ctx, task, cancel_all); + mutex_lock(&ctx->uring_lock); + ret |= io_poll_remove_all(ctx, task, cancel_all); +@@ -3666,7 +3652,7 @@ SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit, + * it should handle ownership problems if any. + */ + if (ctx->flags & IORING_SETUP_DEFER_TASKRUN) +- (void)io_run_local_work_locked(ctx); ++ (void)io_run_local_work_locked(ctx, min_complete); + } + mutex_unlock(&ctx->uring_lock); + } +diff --git a/io_uring/net.c b/io_uring/net.c +index 161622029147c..4aaeada03f1e7 100644 +--- a/io_uring/net.c ++++ b/io_uring/net.c +@@ -204,16 +204,115 @@ static int io_setup_async_msg(struct io_kiocb *req, + return -EAGAIN; + } + ++#ifdef CONFIG_COMPAT ++static int io_compat_msg_copy_hdr(struct io_kiocb *req, ++ struct io_async_msghdr *iomsg, ++ struct compat_msghdr *msg, int ddir) ++{ ++ struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); ++ struct compat_iovec __user *uiov; ++ int ret; ++ ++ if (copy_from_user(msg, sr->umsg_compat, sizeof(*msg))) ++ return -EFAULT; ++ ++ uiov = compat_ptr(msg->msg_iov); ++ if (req->flags & REQ_F_BUFFER_SELECT) { ++ compat_ssize_t clen; ++ ++ iomsg->free_iov = NULL; ++ if (msg->msg_iovlen == 0) { ++ sr->len = 0; ++ } else if (msg->msg_iovlen > 1) { ++ return -EINVAL; ++ } else { ++ if (!access_ok(uiov, sizeof(*uiov))) ++ return -EFAULT; ++ if (__get_user(clen, &uiov->iov_len)) ++ return -EFAULT; ++ if (clen < 0) ++ return -EINVAL; ++ sr->len = clen; ++ } ++ ++ return 0; ++ } ++ ++ iomsg->free_iov = iomsg->fast_iov; ++ ret = __import_iovec(ddir, (struct iovec __user *)uiov, msg->msg_iovlen, ++ UIO_FASTIOV, &iomsg->free_iov, ++ &iomsg->msg.msg_iter, true); ++ if (unlikely(ret < 0)) ++ return ret; ++ ++ return 0; ++} ++#endif ++ ++static int io_msg_copy_hdr(struct io_kiocb *req, struct io_async_msghdr *iomsg, ++ struct user_msghdr *msg, int ddir) ++{ ++ struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); ++ int ret; ++ ++ if (copy_from_user(msg, sr->umsg, sizeof(*sr->umsg))) ++ return -EFAULT; ++ ++ if (req->flags & REQ_F_BUFFER_SELECT) { ++ if (msg->msg_iovlen == 0) { ++ sr->len = iomsg->fast_iov[0].iov_len = 0; ++ iomsg->fast_iov[0].iov_base = NULL; ++ iomsg->free_iov = NULL; ++ } else if (msg->msg_iovlen > 1) { ++ return -EINVAL; ++ } else { ++ if (copy_from_user(iomsg->fast_iov, msg->msg_iov, ++ sizeof(*msg->msg_iov))) ++ return -EFAULT; ++ sr->len = iomsg->fast_iov[0].iov_len; ++ iomsg->free_iov = NULL; ++ } ++ ++ return 0; ++ } ++ ++ iomsg->free_iov = iomsg->fast_iov; ++ ret = __import_iovec(ddir, msg->msg_iov, msg->msg_iovlen, UIO_FASTIOV, ++ &iomsg->free_iov, &iomsg->msg.msg_iter, false); ++ if (unlikely(ret < 0)) ++ return ret; ++ ++ return 0; ++} ++ + static int io_sendmsg_copy_hdr(struct io_kiocb *req, + struct io_async_msghdr *iomsg) + { + struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); ++ struct user_msghdr msg; + int ret; + + iomsg->msg.msg_name = &iomsg->addr; +- iomsg->free_iov = iomsg->fast_iov; +- ret = sendmsg_copy_msghdr(&iomsg->msg, sr->umsg, sr->msg_flags, +- &iomsg->free_iov); ++ iomsg->msg.msg_iter.nr_segs = 0; ++ ++#ifdef CONFIG_COMPAT ++ if (unlikely(req->ctx->compat)) { ++ struct compat_msghdr cmsg; ++ ++ ret = io_compat_msg_copy_hdr(req, iomsg, &cmsg, ITER_SOURCE); ++ if (unlikely(ret)) ++ return ret; ++ ++ return __get_compat_msghdr(&iomsg->msg, &cmsg, NULL); ++ } ++#endif ++ ++ ret = io_msg_copy_hdr(req, iomsg, &msg, ITER_SOURCE); ++ if (unlikely(ret)) ++ return ret; ++ ++ ret = __copy_msghdr(&iomsg->msg, &msg, NULL); ++ + /* save msg_control as sys_sendmsg() overwrites it */ + sr->msg_control = iomsg->msg.msg_control_user; + return ret; +@@ -435,142 +534,77 @@ int io_send(struct io_kiocb *req, unsigned int issue_flags) + return IOU_OK; + } + +-static bool io_recvmsg_multishot_overflow(struct io_async_msghdr *iomsg) ++static int io_recvmsg_mshot_prep(struct io_kiocb *req, ++ struct io_async_msghdr *iomsg, ++ int namelen, size_t controllen) + { +- int hdr; +- +- if (iomsg->namelen < 0) +- return true; +- if (check_add_overflow((int)sizeof(struct io_uring_recvmsg_out), +- iomsg->namelen, &hdr)) +- return true; +- if (check_add_overflow(hdr, (int)iomsg->controllen, &hdr)) +- return true; ++ if ((req->flags & (REQ_F_APOLL_MULTISHOT|REQ_F_BUFFER_SELECT)) == ++ (REQ_F_APOLL_MULTISHOT|REQ_F_BUFFER_SELECT)) { ++ int hdr; ++ ++ if (unlikely(namelen < 0)) ++ return -EOVERFLOW; ++ if (check_add_overflow(sizeof(struct io_uring_recvmsg_out), ++ namelen, &hdr)) ++ return -EOVERFLOW; ++ if (check_add_overflow(hdr, controllen, &hdr)) ++ return -EOVERFLOW; ++ ++ iomsg->namelen = namelen; ++ iomsg->controllen = controllen; ++ return 0; ++ } + +- return false; ++ return 0; + } + +-static int __io_recvmsg_copy_hdr(struct io_kiocb *req, +- struct io_async_msghdr *iomsg) ++static int io_recvmsg_copy_hdr(struct io_kiocb *req, ++ struct io_async_msghdr *iomsg) + { +- struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); + struct user_msghdr msg; + int ret; + +- if (copy_from_user(&msg, sr->umsg, sizeof(*sr->umsg))) +- return -EFAULT; +- +- ret = __copy_msghdr(&iomsg->msg, &msg, &iomsg->uaddr); +- if (ret) +- return ret; +- +- if (req->flags & REQ_F_BUFFER_SELECT) { +- if (msg.msg_iovlen == 0) { +- sr->len = iomsg->fast_iov[0].iov_len = 0; +- iomsg->fast_iov[0].iov_base = NULL; +- iomsg->free_iov = NULL; +- } else if (msg.msg_iovlen > 1) { +- return -EINVAL; +- } else { +- if (copy_from_user(iomsg->fast_iov, msg.msg_iov, sizeof(*msg.msg_iov))) +- return -EFAULT; +- sr->len = iomsg->fast_iov[0].iov_len; +- iomsg->free_iov = NULL; +- } +- +- if (req->flags & REQ_F_APOLL_MULTISHOT) { +- iomsg->namelen = msg.msg_namelen; +- iomsg->controllen = msg.msg_controllen; +- if (io_recvmsg_multishot_overflow(iomsg)) +- return -EOVERFLOW; +- } +- } else { +- iomsg->free_iov = iomsg->fast_iov; +- ret = __import_iovec(ITER_DEST, msg.msg_iov, msg.msg_iovlen, UIO_FASTIOV, +- &iomsg->free_iov, &iomsg->msg.msg_iter, +- false); +- if (ret > 0) +- ret = 0; +- } +- +- return ret; +-} ++ iomsg->msg.msg_name = &iomsg->addr; ++ iomsg->msg.msg_iter.nr_segs = 0; + + #ifdef CONFIG_COMPAT +-static int __io_compat_recvmsg_copy_hdr(struct io_kiocb *req, +- struct io_async_msghdr *iomsg) +-{ +- struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); +- struct compat_msghdr msg; +- struct compat_iovec __user *uiov; +- int ret; +- +- if (copy_from_user(&msg, sr->umsg_compat, sizeof(msg))) +- return -EFAULT; +- +- ret = __get_compat_msghdr(&iomsg->msg, &msg, &iomsg->uaddr); +- if (ret) +- return ret; ++ if (unlikely(req->ctx->compat)) { ++ struct compat_msghdr cmsg; + +- uiov = compat_ptr(msg.msg_iov); +- if (req->flags & REQ_F_BUFFER_SELECT) { +- compat_ssize_t clen; +- +- iomsg->free_iov = NULL; +- if (msg.msg_iovlen == 0) { +- sr->len = 0; +- } else if (msg.msg_iovlen > 1) { +- return -EINVAL; +- } else { +- if (!access_ok(uiov, sizeof(*uiov))) +- return -EFAULT; +- if (__get_user(clen, &uiov->iov_len)) +- return -EFAULT; +- if (clen < 0) +- return -EINVAL; +- sr->len = clen; +- } ++ ret = io_compat_msg_copy_hdr(req, iomsg, &cmsg, ITER_DEST); ++ if (unlikely(ret)) ++ return ret; + +- if (req->flags & REQ_F_APOLL_MULTISHOT) { +- iomsg->namelen = msg.msg_namelen; +- iomsg->controllen = msg.msg_controllen; +- if (io_recvmsg_multishot_overflow(iomsg)) +- return -EOVERFLOW; +- } +- } else { +- iomsg->free_iov = iomsg->fast_iov; +- ret = __import_iovec(ITER_DEST, (struct iovec __user *)uiov, msg.msg_iovlen, +- UIO_FASTIOV, &iomsg->free_iov, +- &iomsg->msg.msg_iter, true); +- if (ret < 0) ++ ret = __get_compat_msghdr(&iomsg->msg, &cmsg, &iomsg->uaddr); ++ if (unlikely(ret)) + return ret; +- } + +- return 0; +-} ++ return io_recvmsg_mshot_prep(req, iomsg, cmsg.msg_namelen, ++ cmsg.msg_controllen); ++ } + #endif + +-static int io_recvmsg_copy_hdr(struct io_kiocb *req, +- struct io_async_msghdr *iomsg) +-{ +- iomsg->msg.msg_name = &iomsg->addr; +- iomsg->msg.msg_iter.nr_segs = 0; ++ ret = io_msg_copy_hdr(req, iomsg, &msg, ITER_DEST); ++ if (unlikely(ret)) ++ return ret; + +-#ifdef CONFIG_COMPAT +- if (req->ctx->compat) +- return __io_compat_recvmsg_copy_hdr(req, iomsg); +-#endif ++ ret = __copy_msghdr(&iomsg->msg, &msg, &iomsg->uaddr); ++ if (unlikely(ret)) ++ return ret; + +- return __io_recvmsg_copy_hdr(req, iomsg); ++ return io_recvmsg_mshot_prep(req, iomsg, msg.msg_namelen, ++ msg.msg_controllen); + } + + int io_recvmsg_prep_async(struct io_kiocb *req) + { ++ struct io_async_msghdr *iomsg; + int ret; + + if (!io_msg_alloc_async_prep(req)) + return -ENOMEM; +- ret = io_recvmsg_copy_hdr(req, req->async_data); ++ iomsg = req->async_data; ++ ret = io_recvmsg_copy_hdr(req, iomsg); + if (!ret) + req->flags |= REQ_F_NEED_CLEANUP; + return ret; +diff --git a/io_uring/poll.c b/io_uring/poll.c +index 7513afc7b702e..58b7556f621eb 100644 +--- a/io_uring/poll.c ++++ b/io_uring/poll.c +@@ -995,7 +995,6 @@ int io_poll_remove(struct io_kiocb *req, unsigned int issue_flags) + struct io_hash_bucket *bucket; + struct io_kiocb *preq; + int ret2, ret = 0; +- struct io_tw_state ts = { .locked = true }; + + io_ring_submit_lock(ctx, issue_flags); + preq = io_poll_find(ctx, true, &cd, &ctx->cancel_table, &bucket); +@@ -1044,7 +1043,8 @@ int io_poll_remove(struct io_kiocb *req, unsigned int issue_flags) + + req_set_fail(preq); + io_req_set_res(preq, -ECANCELED, 0); +- io_req_task_complete(preq, &ts); ++ preq->io_task_work.func = io_req_task_complete; ++ io_req_task_work_add(preq); + out: + io_ring_submit_unlock(ctx, issue_flags); + if (ret < 0) { +diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c +index 5964711891767..92aa3cf0396b8 100644 +--- a/kernel/bpf/btf.c ++++ b/kernel/bpf/btf.c +@@ -7009,6 +7009,8 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) + args = (const struct btf_param *)(t + 1); + nargs = btf_type_vlen(t); + if (nargs > MAX_BPF_FUNC_REG_ARGS) { ++ if (!is_global) ++ return -EINVAL; + bpf_log(log, "Global function %s() with %d > %d args. Buggy compiler.\n", + tname, nargs, MAX_BPF_FUNC_REG_ARGS); + return -EINVAL; +@@ -7018,6 +7020,8 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) + while (btf_type_is_modifier(t)) + t = btf_type_by_id(btf, t->type); + if (!btf_type_is_int(t) && !btf_is_any_enum(t)) { ++ if (!is_global) ++ return -EINVAL; + bpf_log(log, + "Global function %s() doesn't return scalar. Only those are supported.\n", + tname); +@@ -7058,10 +7062,6 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) + + while (btf_type_is_modifier(t)) + t = btf_type_by_id(btf, t->type); +- if (btf_type_is_int(t) || btf_is_any_enum(t)) { +- sub->args[i].arg_type = ARG_ANYTHING; +- continue; +- } + if (btf_type_is_ptr(t) && btf_get_prog_ctx_type(log, btf, t, prog_type, i)) { + sub->args[i].arg_type = ARG_PTR_TO_CTX; + continue; +@@ -7091,6 +7091,12 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog) + bpf_log(log, "arg#%d marked as non-null, but is not a pointer type\n", i); + return -EINVAL; + } ++ if (btf_type_is_int(t) || btf_is_any_enum(t)) { ++ sub->args[i].arg_type = ARG_ANYTHING; ++ continue; ++ } ++ if (!is_global) ++ return -EINVAL; + bpf_log(log, "Arg#%d type %s in %s() is not supported yet.\n", + i, btf_type_str(t), tname); + return -EINVAL; +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index ea6843be2616c..026627226ec48 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -888,7 +888,12 @@ static LIST_HEAD(pack_list); + * CONFIG_MMU=n. Use PAGE_SIZE in these cases. + */ + #ifdef PMD_SIZE +-#define BPF_PROG_PACK_SIZE (PMD_SIZE * num_possible_nodes()) ++/* PMD_SIZE is really big for some archs. It doesn't make sense to ++ * reserve too much memory in one allocation. Hardcode BPF_PROG_PACK_SIZE to ++ * 2MiB * num_possible_nodes(). On most architectures PMD_SIZE will be ++ * greater than or equal to 2MB. ++ */ ++#define BPF_PROG_PACK_SIZE (SZ_2M * num_possible_nodes()) + #else + #define BPF_PROG_PACK_SIZE PAGE_SIZE + #endif +diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c +index ef82ffc90cbe9..8f1d390bcbdeb 100644 +--- a/kernel/bpf/cpumap.c ++++ b/kernel/bpf/cpumap.c +@@ -262,6 +262,7 @@ static int cpu_map_bpf_prog_run(struct bpf_cpu_map_entry *rcpu, void **frames, + static int cpu_map_kthread_run(void *data) + { + struct bpf_cpu_map_entry *rcpu = data; ++ unsigned long last_qs = jiffies; + + complete(&rcpu->kthread_running); + set_current_state(TASK_INTERRUPTIBLE); +@@ -287,10 +288,12 @@ static int cpu_map_kthread_run(void *data) + if (__ptr_ring_empty(rcpu->queue)) { + schedule(); + sched = 1; ++ last_qs = jiffies; + } else { + __set_current_state(TASK_RUNNING); + } + } else { ++ rcu_softirq_qs_periodic(last_qs); + sched = cond_resched(); + } + +diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c +index a936c704d4e77..4e2cdbb5629f2 100644 +--- a/kernel/bpf/devmap.c ++++ b/kernel/bpf/devmap.c +@@ -130,13 +130,14 @@ static int dev_map_init_map(struct bpf_dtab *dtab, union bpf_attr *attr) + bpf_map_init_from_attr(&dtab->map, attr); + + if (attr->map_type == BPF_MAP_TYPE_DEVMAP_HASH) { +- dtab->n_buckets = roundup_pow_of_two(dtab->map.max_entries); +- +- if (!dtab->n_buckets) /* Overflow check */ ++ /* hash table size must be power of 2; roundup_pow_of_two() can ++ * overflow into UB on 32-bit arches, so check that first ++ */ ++ if (dtab->map.max_entries > 1UL << 31) + return -EINVAL; +- } + +- if (attr->map_type == BPF_MAP_TYPE_DEVMAP_HASH) { ++ dtab->n_buckets = roundup_pow_of_two(dtab->map.max_entries); ++ + dtab->dev_index_head = dev_map_create_hash(dtab->n_buckets, + dtab->map.numa_node); + if (!dtab->dev_index_head) +diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c +index 03a6a2500b6ab..3a088a5349bc0 100644 +--- a/kernel/bpf/hashtab.c ++++ b/kernel/bpf/hashtab.c +@@ -499,7 +499,13 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr) + num_possible_cpus()); + } + +- /* hash table size must be power of 2 */ ++ /* hash table size must be power of 2; roundup_pow_of_two() can overflow ++ * into UB on 32-bit arches, so check that first ++ */ ++ err = -E2BIG; ++ if (htab->map.max_entries > 1UL << 31) ++ goto free_htab; ++ + htab->n_buckets = roundup_pow_of_two(htab->map.max_entries); + + htab->elem_size = sizeof(struct htab_elem) + +@@ -509,10 +515,8 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr) + else + htab->elem_size += round_up(htab->map.value_size, 8); + +- err = -E2BIG; +- /* prevent zero size kmalloc and check for u32 overflow */ +- if (htab->n_buckets == 0 || +- htab->n_buckets > U32_MAX / sizeof(struct bucket)) ++ /* check for u32 overflow */ ++ if (htab->n_buckets > U32_MAX / sizeof(struct bucket)) + goto free_htab; + + err = bpf_map_init_elem_count(&htab->map); +diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c +index d19cd863d294e..b10092754dde3 100644 +--- a/kernel/bpf/helpers.c ++++ b/kernel/bpf/helpers.c +@@ -334,7 +334,7 @@ static inline void __bpf_spin_lock_irqsave(struct bpf_spin_lock *lock) + __this_cpu_write(irqsave_flags, flags); + } + +-notrace BPF_CALL_1(bpf_spin_lock, struct bpf_spin_lock *, lock) ++NOTRACE_BPF_CALL_1(bpf_spin_lock, struct bpf_spin_lock *, lock) + { + __bpf_spin_lock_irqsave(lock); + return 0; +@@ -357,7 +357,7 @@ static inline void __bpf_spin_unlock_irqrestore(struct bpf_spin_lock *lock) + local_irq_restore(flags); + } + +-notrace BPF_CALL_1(bpf_spin_unlock, struct bpf_spin_lock *, lock) ++NOTRACE_BPF_CALL_1(bpf_spin_unlock, struct bpf_spin_lock *, lock) + { + __bpf_spin_unlock_irqrestore(lock); + return 0; +diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c +index dff7ba5397015..c99f8e5234ac4 100644 +--- a/kernel/bpf/stackmap.c ++++ b/kernel/bpf/stackmap.c +@@ -91,11 +91,14 @@ static struct bpf_map *stack_map_alloc(union bpf_attr *attr) + } else if (value_size / 8 > sysctl_perf_event_max_stack) + return ERR_PTR(-EINVAL); + +- /* hash table size must be power of 2 */ +- n_buckets = roundup_pow_of_two(attr->max_entries); +- if (!n_buckets) ++ /* hash table size must be power of 2; roundup_pow_of_two() can overflow ++ * into UB on 32-bit arches, so check that first ++ */ ++ if (attr->max_entries > 1UL << 31) + return ERR_PTR(-E2BIG); + ++ n_buckets = roundup_pow_of_two(attr->max_entries); ++ + cost = n_buckets * sizeof(struct stack_map_bucket *) + sizeof(*smap); + smap = bpf_map_area_alloc(cost, bpf_map_attr_numa_node(attr)); + if (!smap) +diff --git a/kernel/module/main.c b/kernel/module/main.c +index 36681911c05ac..b0b99348e1a8b 100644 +--- a/kernel/module/main.c ++++ b/kernel/module/main.c +@@ -2489,6 +2489,11 @@ static void do_free_init(struct work_struct *w) + } + } + ++void flush_module_init_free_work(void) ++{ ++ flush_work(&init_free_wq); ++} ++ + #undef MODULE_PARAM_PREFIX + #define MODULE_PARAM_PREFIX "module." + /* Default value for module->async_probe_requested */ +@@ -2593,8 +2598,8 @@ static noinline int do_init_module(struct module *mod) + * Note that module_alloc() on most architectures creates W+X page + * mappings which won't be cleaned up until do_free_init() runs. Any + * code such as mark_rodata_ro() which depends on those mappings to +- * be cleaned up needs to sync with the queued work - ie +- * rcu_barrier() ++ * be cleaned up needs to sync with the queued work by invoking ++ * flush_module_init_free_work(). + */ + if (llist_add(&freeinit->node, &init_free_list)) + schedule_work(&init_free_wq); +diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h +index 6c2afee5ef620..ac2d9750e5f81 100644 +--- a/kernel/printk/internal.h ++++ b/kernel/printk/internal.h +@@ -130,6 +130,7 @@ struct printk_message { + }; + + bool other_cpu_in_panic(void); ++bool this_cpu_in_panic(void); + bool printk_get_next_message(struct printk_message *pmsg, u64 seq, + bool is_extended, bool may_supress); + +diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c +index b96077152f49d..c8093bcc01fe6 100644 +--- a/kernel/printk/nbcon.c ++++ b/kernel/printk/nbcon.c +@@ -140,39 +140,6 @@ static inline bool nbcon_state_try_cmpxchg(struct console *con, struct nbcon_sta + return atomic_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_state), &cur->atom, new->atom); + } + +-#ifdef CONFIG_64BIT +- +-#define __seq_to_nbcon_seq(seq) (seq) +-#define __nbcon_seq_to_seq(seq) (seq) +- +-#else /* CONFIG_64BIT */ +- +-#define __seq_to_nbcon_seq(seq) ((u32)seq) +- +-static inline u64 __nbcon_seq_to_seq(u32 nbcon_seq) +-{ +- u64 seq; +- u64 rb_next_seq; +- +- /* +- * The provided sequence is only the lower 32 bits of the ringbuffer +- * sequence. It needs to be expanded to 64bit. Get the next sequence +- * number from the ringbuffer and fold it. +- * +- * Having a 32bit representation in the console is sufficient. +- * If a console ever gets more than 2^31 records behind +- * the ringbuffer then this is the least of the problems. +- * +- * Also the access to the ring buffer is always safe. +- */ +- rb_next_seq = prb_next_seq(prb); +- seq = rb_next_seq - ((u32)rb_next_seq - nbcon_seq); +- +- return seq; +-} +- +-#endif /* CONFIG_64BIT */ +- + /** + * nbcon_seq_read - Read the current console sequence + * @con: Console to read the sequence of +@@ -183,7 +150,7 @@ u64 nbcon_seq_read(struct console *con) + { + unsigned long nbcon_seq = atomic_long_read(&ACCESS_PRIVATE(con, nbcon_seq)); + +- return __nbcon_seq_to_seq(nbcon_seq); ++ return __ulseq_to_u64seq(prb, nbcon_seq); + } + + /** +@@ -204,7 +171,7 @@ void nbcon_seq_force(struct console *con, u64 seq) + */ + u64 valid_seq = max_t(u64, seq, prb_first_valid_seq(prb)); + +- atomic_long_set(&ACCESS_PRIVATE(con, nbcon_seq), __seq_to_nbcon_seq(valid_seq)); ++ atomic_long_set(&ACCESS_PRIVATE(con, nbcon_seq), __u64seq_to_ulseq(valid_seq)); + + /* Clear con->seq since nbcon consoles use con->nbcon_seq instead. */ + con->seq = 0; +@@ -223,11 +190,11 @@ void nbcon_seq_force(struct console *con, u64 seq) + */ + static void nbcon_seq_try_update(struct nbcon_context *ctxt, u64 new_seq) + { +- unsigned long nbcon_seq = __seq_to_nbcon_seq(ctxt->seq); ++ unsigned long nbcon_seq = __u64seq_to_ulseq(ctxt->seq); + struct console *con = ctxt->console; + + if (atomic_long_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_seq), &nbcon_seq, +- __seq_to_nbcon_seq(new_seq))) { ++ __u64seq_to_ulseq(new_seq))) { + ctxt->seq = new_seq; + } else { + ctxt->seq = nbcon_seq_read(con); +diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c +index f2444b581e16c..72f6a564e832f 100644 +--- a/kernel/printk/printk.c ++++ b/kernel/printk/printk.c +@@ -347,6 +347,29 @@ static bool panic_in_progress(void) + return unlikely(atomic_read(&panic_cpu) != PANIC_CPU_INVALID); + } + ++/* Return true if a panic is in progress on the current CPU. */ ++bool this_cpu_in_panic(void) ++{ ++ /* ++ * We can use raw_smp_processor_id() here because it is impossible for ++ * the task to be migrated to the panic_cpu, or away from it. If ++ * panic_cpu has already been set, and we're not currently executing on ++ * that CPU, then we never will be. ++ */ ++ return unlikely(atomic_read(&panic_cpu) == raw_smp_processor_id()); ++} ++ ++/* ++ * Return true if a panic is in progress on a remote CPU. ++ * ++ * On true, the local CPU should immediately release any printing resources ++ * that may be needed by the panic CPU. ++ */ ++bool other_cpu_in_panic(void) ++{ ++ return (panic_in_progress() && !this_cpu_in_panic()); ++} ++ + /* + * This is used for debugging the mess that is the VT code by + * keeping track if we have the console semaphore held. It's +@@ -1846,10 +1869,23 @@ static bool console_waiter; + */ + static void console_lock_spinning_enable(void) + { ++ /* ++ * Do not use spinning in panic(). The panic CPU wants to keep the lock. ++ * Non-panic CPUs abandon the flush anyway. ++ * ++ * Just keep the lockdep annotation. The panic-CPU should avoid ++ * taking console_owner_lock because it might cause a deadlock. ++ * This looks like the easiest way how to prevent false lockdep ++ * reports without handling races a lockless way. ++ */ ++ if (panic_in_progress()) ++ goto lockdep; ++ + raw_spin_lock(&console_owner_lock); + console_owner = current; + raw_spin_unlock(&console_owner_lock); + ++lockdep: + /* The waiter may spin on us after setting console_owner */ + spin_acquire(&console_owner_dep_map, 0, 0, _THIS_IP_); + } +@@ -1874,6 +1910,22 @@ static int console_lock_spinning_disable_and_check(int cookie) + { + int waiter; + ++ /* ++ * Ignore spinning waiters during panic() because they might get stopped ++ * or blocked at any time, ++ * ++ * It is safe because nobody is allowed to start spinning during panic ++ * in the first place. If there has been a waiter then non panic CPUs ++ * might stay spinning. They would get stopped anyway. The panic context ++ * will never start spinning and an interrupted spin on panic CPU will ++ * never continue. ++ */ ++ if (panic_in_progress()) { ++ /* Keep lockdep happy. */ ++ spin_release(&console_owner_dep_map, _THIS_IP_); ++ return 0; ++ } ++ + raw_spin_lock(&console_owner_lock); + waiter = READ_ONCE(console_waiter); + console_owner = NULL; +@@ -2601,26 +2653,6 @@ static int console_cpu_notify(unsigned int cpu) + return 0; + } + +-/* +- * Return true if a panic is in progress on a remote CPU. +- * +- * On true, the local CPU should immediately release any printing resources +- * that may be needed by the panic CPU. +- */ +-bool other_cpu_in_panic(void) +-{ +- if (!panic_in_progress()) +- return false; +- +- /* +- * We can use raw_smp_processor_id() here because it is impossible for +- * the task to be migrated to the panic_cpu, or away from it. If +- * panic_cpu has already been set, and we're not currently executing on +- * that CPU, then we never will be. +- */ +- return atomic_read(&panic_cpu) != raw_smp_processor_id(); +-} +- + /** + * console_lock - block the console subsystem from printing + * +@@ -3761,7 +3793,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre + + might_sleep(); + +- seq = prb_next_seq(prb); ++ seq = prb_next_reserve_seq(prb); + + /* Flush the consoles so that records up to @seq are printed. */ + console_lock(); +diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c +index fde338606ce83..f5a8bb606fe50 100644 +--- a/kernel/printk/printk_ringbuffer.c ++++ b/kernel/printk/printk_ringbuffer.c +@@ -6,6 +6,7 @@ + #include + #include + #include "printk_ringbuffer.h" ++#include "internal.h" + + /** + * DOC: printk_ringbuffer overview +@@ -303,6 +304,9 @@ + * + * desc_push_tail:B / desc_reserve:D + * set descriptor reusable (state), then push descriptor tail (id) ++ * ++ * desc_update_last_finalized:A / desc_last_finalized_seq:A ++ * store finalized record, then set new highest finalized sequence number + */ + + #define DATA_SIZE(data_ring) _DATA_SIZE((data_ring)->size_bits) +@@ -1441,20 +1445,118 @@ bool prb_reserve_in_last(struct prb_reserved_entry *e, struct printk_ringbuffer + return false; + } + ++/* ++ * @last_finalized_seq value guarantees that all records up to and including ++ * this sequence number are finalized and can be read. The only exception are ++ * too old records which have already been overwritten. ++ * ++ * It is also guaranteed that @last_finalized_seq only increases. ++ * ++ * Be aware that finalized records following non-finalized records are not ++ * reported because they are not yet available to the reader. For example, ++ * a new record stored via printk() will not be available to a printer if ++ * it follows a record that has not been finalized yet. However, once that ++ * non-finalized record becomes finalized, @last_finalized_seq will be ++ * appropriately updated and the full set of finalized records will be ++ * available to the printer. And since each printk() caller will either ++ * directly print or trigger deferred printing of all available unprinted ++ * records, all printk() messages will get printed. ++ */ ++static u64 desc_last_finalized_seq(struct printk_ringbuffer *rb) ++{ ++ struct prb_desc_ring *desc_ring = &rb->desc_ring; ++ unsigned long ulseq; ++ ++ /* ++ * Guarantee the sequence number is loaded before loading the ++ * associated record in order to guarantee that the record can be ++ * seen by this CPU. This pairs with desc_update_last_finalized:A. ++ */ ++ ulseq = atomic_long_read_acquire(&desc_ring->last_finalized_seq ++ ); /* LMM(desc_last_finalized_seq:A) */ ++ ++ return __ulseq_to_u64seq(rb, ulseq); ++} ++ ++static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq, ++ struct printk_record *r, unsigned int *line_count); ++ ++/* ++ * Check if there are records directly following @last_finalized_seq that are ++ * finalized. If so, update @last_finalized_seq to the latest of these ++ * records. It is not allowed to skip over records that are not yet finalized. ++ */ ++static void desc_update_last_finalized(struct printk_ringbuffer *rb) ++{ ++ struct prb_desc_ring *desc_ring = &rb->desc_ring; ++ u64 old_seq = desc_last_finalized_seq(rb); ++ unsigned long oldval; ++ unsigned long newval; ++ u64 finalized_seq; ++ u64 try_seq; ++ ++try_again: ++ finalized_seq = old_seq; ++ try_seq = finalized_seq + 1; ++ ++ /* Try to find later finalized records. */ ++ while (_prb_read_valid(rb, &try_seq, NULL, NULL)) { ++ finalized_seq = try_seq; ++ try_seq++; ++ } ++ ++ /* No update needed if no later finalized record was found. */ ++ if (finalized_seq == old_seq) ++ return; ++ ++ oldval = __u64seq_to_ulseq(old_seq); ++ newval = __u64seq_to_ulseq(finalized_seq); ++ ++ /* ++ * Set the sequence number of a later finalized record that has been ++ * seen. ++ * ++ * Guarantee the record data is visible to other CPUs before storing ++ * its sequence number. This pairs with desc_last_finalized_seq:A. ++ * ++ * Memory barrier involvement: ++ * ++ * If desc_last_finalized_seq:A reads from ++ * desc_update_last_finalized:A, then desc_read:A reads from ++ * _prb_commit:B. ++ * ++ * Relies on: ++ * ++ * RELEASE from _prb_commit:B to desc_update_last_finalized:A ++ * matching ++ * ACQUIRE from desc_last_finalized_seq:A to desc_read:A ++ * ++ * Note: _prb_commit:B and desc_update_last_finalized:A can be ++ * different CPUs. However, the desc_update_last_finalized:A ++ * CPU (which performs the release) must have previously seen ++ * _prb_commit:B. ++ */ ++ if (!atomic_long_try_cmpxchg_release(&desc_ring->last_finalized_seq, ++ &oldval, newval)) { /* LMM(desc_update_last_finalized:A) */ ++ old_seq = __ulseq_to_u64seq(rb, oldval); ++ goto try_again; ++ } ++} ++ + /* + * Attempt to finalize a specified descriptor. If this fails, the descriptor + * is either already final or it will finalize itself when the writer commits. + */ +-static void desc_make_final(struct prb_desc_ring *desc_ring, unsigned long id) ++static void desc_make_final(struct printk_ringbuffer *rb, unsigned long id) + { ++ struct prb_desc_ring *desc_ring = &rb->desc_ring; + unsigned long prev_state_val = DESC_SV(id, desc_committed); + struct prb_desc *d = to_desc(desc_ring, id); + +- atomic_long_cmpxchg_relaxed(&d->state_var, prev_state_val, +- DESC_SV(id, desc_finalized)); /* LMM(desc_make_final:A) */ +- +- /* Best effort to remember the last finalized @id. */ +- atomic_long_set(&desc_ring->last_finalized_id, id); ++ if (atomic_long_try_cmpxchg_relaxed(&d->state_var, &prev_state_val, ++ DESC_SV(id, desc_finalized))) { /* LMM(desc_make_final:A) */ ++ desc_update_last_finalized(rb); ++ } + } + + /** +@@ -1550,7 +1652,7 @@ bool prb_reserve(struct prb_reserved_entry *e, struct printk_ringbuffer *rb, + * readers. (For seq==0 there is no previous descriptor.) + */ + if (info->seq > 0) +- desc_make_final(desc_ring, DESC_ID(id - 1)); ++ desc_make_final(rb, DESC_ID(id - 1)); + + r->text_buf = data_alloc(rb, r->text_buf_size, &d->text_blk_lpos, id); + /* If text data allocation fails, a data-less record is committed. */ +@@ -1643,7 +1745,7 @@ void prb_commit(struct prb_reserved_entry *e) + */ + head_id = atomic_long_read(&desc_ring->head_id); /* LMM(prb_commit:A) */ + if (head_id != e->id) +- desc_make_final(desc_ring, e->id); ++ desc_make_final(e->rb, e->id); + } + + /** +@@ -1663,12 +1765,9 @@ void prb_commit(struct prb_reserved_entry *e) + */ + void prb_final_commit(struct prb_reserved_entry *e) + { +- struct prb_desc_ring *desc_ring = &e->rb->desc_ring; +- + _prb_commit(e, desc_finalized); + +- /* Best effort to remember the last finalized @id. */ +- atomic_long_set(&desc_ring->last_finalized_id, e->id); ++ desc_update_last_finalized(e->rb); + } + + /* +@@ -1832,7 +1931,7 @@ static int prb_read(struct printk_ringbuffer *rb, u64 seq, + } + + /* Get the sequence number of the tail descriptor. */ +-static u64 prb_first_seq(struct printk_ringbuffer *rb) ++u64 prb_first_seq(struct printk_ringbuffer *rb) + { + struct prb_desc_ring *desc_ring = &rb->desc_ring; + enum desc_state d_state; +@@ -1875,12 +1974,123 @@ static u64 prb_first_seq(struct printk_ringbuffer *rb) + return seq; + } + ++/** ++ * prb_next_reserve_seq() - Get the sequence number after the most recently ++ * reserved record. ++ * ++ * @rb: The ringbuffer to get the sequence number from. ++ * ++ * This is the public function available to readers to see what sequence ++ * number will be assigned to the next reserved record. ++ * ++ * Note that depending on the situation, this value can be equal to or ++ * higher than the sequence number returned by prb_next_seq(). ++ * ++ * Context: Any context. ++ * Return: The sequence number that will be assigned to the next record ++ * reserved. ++ */ ++u64 prb_next_reserve_seq(struct printk_ringbuffer *rb) ++{ ++ struct prb_desc_ring *desc_ring = &rb->desc_ring; ++ unsigned long last_finalized_id; ++ atomic_long_t *state_var; ++ u64 last_finalized_seq; ++ unsigned long head_id; ++ struct prb_desc desc; ++ unsigned long diff; ++ struct prb_desc *d; ++ int err; ++ ++ /* ++ * It may not be possible to read a sequence number for @head_id. ++ * So the ID of @last_finailzed_seq is used to calculate what the ++ * sequence number of @head_id will be. ++ */ ++ ++try_again: ++ last_finalized_seq = desc_last_finalized_seq(rb); ++ ++ /* ++ * @head_id is loaded after @last_finalized_seq to ensure that ++ * it points to the record with @last_finalized_seq or newer. ++ * ++ * Memory barrier involvement: ++ * ++ * If desc_last_finalized_seq:A reads from ++ * desc_update_last_finalized:A, then ++ * prb_next_reserve_seq:A reads from desc_reserve:D. ++ * ++ * Relies on: ++ * ++ * RELEASE from desc_reserve:D to desc_update_last_finalized:A ++ * matching ++ * ACQUIRE from desc_last_finalized_seq:A to prb_next_reserve_seq:A ++ * ++ * Note: desc_reserve:D and desc_update_last_finalized:A can be ++ * different CPUs. However, the desc_update_last_finalized:A CPU ++ * (which performs the release) must have previously seen ++ * desc_read:C, which implies desc_reserve:D can be seen. ++ */ ++ head_id = atomic_long_read(&desc_ring->head_id); /* LMM(prb_next_reserve_seq:A) */ ++ ++ d = to_desc(desc_ring, last_finalized_seq); ++ state_var = &d->state_var; ++ ++ /* Extract the ID, used to specify the descriptor to read. */ ++ last_finalized_id = DESC_ID(atomic_long_read(state_var)); ++ ++ /* Ensure @last_finalized_id is correct. */ ++ err = desc_read_finalized_seq(desc_ring, last_finalized_id, last_finalized_seq, &desc); ++ ++ if (err == -EINVAL) { ++ if (last_finalized_seq == 0) { ++ /* ++ * No record has been finalized or even reserved yet. ++ * ++ * The @head_id is initialized such that the first ++ * increment will yield the first record (seq=0). ++ * Handle it separately to avoid a negative @diff ++ * below. ++ */ ++ if (head_id == DESC0_ID(desc_ring->count_bits)) ++ return 0; ++ ++ /* ++ * One or more descriptors are already reserved. Use ++ * the descriptor ID of the first one (@seq=0) for ++ * the @diff below. ++ */ ++ last_finalized_id = DESC0_ID(desc_ring->count_bits) + 1; ++ } else { ++ /* Record must have been overwritten. Try again. */ ++ goto try_again; ++ } ++ } ++ ++ /* Diff of known descriptor IDs to compute related sequence numbers. */ ++ diff = head_id - last_finalized_id; ++ ++ /* ++ * @head_id points to the most recently reserved record, but this ++ * function returns the sequence number that will be assigned to the ++ * next (not yet reserved) record. Thus +1 is needed. ++ */ ++ return (last_finalized_seq + diff + 1); ++} ++ + /* +- * Non-blocking read of a record. Updates @seq to the last finalized record +- * (which may have no data available). ++ * Non-blocking read of a record. ++ * ++ * On success @seq is updated to the record that was read and (if provided) ++ * @r and @line_count will contain the read/calculated data. ++ * ++ * On failure @seq is updated to a record that is not yet available to the ++ * reader, but it will be the next record available to the reader. + * +- * See the description of prb_read_valid() and prb_read_valid_info() +- * for details. ++ * Note: When the current CPU is in panic, this function will skip over any ++ * non-existent/non-finalized records in order to allow the panic CPU ++ * to print any and all records that have been finalized. + */ + static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq, + struct printk_record *r, unsigned int *line_count) +@@ -1899,12 +2109,32 @@ static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq, + *seq = tail_seq; + + } else if (err == -ENOENT) { +- /* Record exists, but no data available. Skip. */ ++ /* Record exists, but the data was lost. Skip. */ + (*seq)++; + + } else { +- /* Non-existent/non-finalized record. Must stop. */ +- return false; ++ /* ++ * Non-existent/non-finalized record. Must stop. ++ * ++ * For panic situations it cannot be expected that ++ * non-finalized records will become finalized. But ++ * there may be other finalized records beyond that ++ * need to be printed for a panic situation. If this ++ * is the panic CPU, skip this ++ * non-existent/non-finalized record unless it is ++ * at or beyond the head, in which case it is not ++ * possible to continue. ++ * ++ * Note that new messages printed on panic CPU are ++ * finalized when we are here. The only exception ++ * might be the last message without trailing newline. ++ * But it would have the sequence number returned ++ * by "prb_next_reserve_seq() - 1". ++ */ ++ if (this_cpu_in_panic() && ((*seq + 1) < prb_next_reserve_seq(rb))) ++ (*seq)++; ++ else ++ return false; + } + } + +@@ -1932,7 +2162,7 @@ static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq, + * On success, the reader must check r->info.seq to see which record was + * actually read. This allows the reader to detect dropped records. + * +- * Failure means @seq refers to a not yet written record. ++ * Failure means @seq refers to a record not yet available to the reader. + */ + bool prb_read_valid(struct printk_ringbuffer *rb, u64 seq, + struct printk_record *r) +@@ -1962,7 +2192,7 @@ bool prb_read_valid(struct printk_ringbuffer *rb, u64 seq, + * On success, the reader must check info->seq to see which record meta data + * was actually read. This allows the reader to detect dropped records. + * +- * Failure means @seq refers to a not yet written record. ++ * Failure means @seq refers to a record not yet available to the reader. + */ + bool prb_read_valid_info(struct printk_ringbuffer *rb, u64 seq, + struct printk_info *info, unsigned int *line_count) +@@ -2008,7 +2238,9 @@ u64 prb_first_valid_seq(struct printk_ringbuffer *rb) + * newest sequence number available to readers will be. + * + * This provides readers a sequence number to jump to if all currently +- * available records should be skipped. ++ * available records should be skipped. It is guaranteed that all records ++ * previous to the returned value have been finalized and are (or were) ++ * available to the reader. + * + * Context: Any context. + * Return: The sequence number of the next newest (not yet available) record +@@ -2016,34 +2248,19 @@ u64 prb_first_valid_seq(struct printk_ringbuffer *rb) + */ + u64 prb_next_seq(struct printk_ringbuffer *rb) + { +- struct prb_desc_ring *desc_ring = &rb->desc_ring; +- enum desc_state d_state; +- unsigned long id; + u64 seq; + +- /* Check if the cached @id still points to a valid @seq. */ +- id = atomic_long_read(&desc_ring->last_finalized_id); +- d_state = desc_read(desc_ring, id, NULL, &seq, NULL); ++ seq = desc_last_finalized_seq(rb); + +- if (d_state == desc_finalized || d_state == desc_reusable) { +- /* +- * Begin searching after the last finalized record. +- * +- * On 0, the search must begin at 0 because of hack#2 +- * of the bootstrapping phase it is not known if a +- * record at index 0 exists. +- */ +- if (seq != 0) +- seq++; +- } else { +- /* +- * The information about the last finalized sequence number +- * has gone. It should happen only when there is a flood of +- * new messages and the ringbuffer is rapidly recycled. +- * Give up and start from the beginning. +- */ +- seq = 0; +- } ++ /* ++ * Begin searching after the last finalized record. ++ * ++ * On 0, the search must begin at 0 because of hack#2 ++ * of the bootstrapping phase it is not known if a ++ * record at index 0 exists. ++ */ ++ if (seq != 0) ++ seq++; + + /* + * The information about the last finalized @seq might be inaccurate. +@@ -2085,7 +2302,7 @@ void prb_init(struct printk_ringbuffer *rb, + rb->desc_ring.infos = infos; + atomic_long_set(&rb->desc_ring.head_id, DESC0_ID(descbits)); + atomic_long_set(&rb->desc_ring.tail_id, DESC0_ID(descbits)); +- atomic_long_set(&rb->desc_ring.last_finalized_id, DESC0_ID(descbits)); ++ atomic_long_set(&rb->desc_ring.last_finalized_seq, 0); + + rb->text_data_ring.size_bits = textbits; + rb->text_data_ring.data = text_buf; +diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h +index 18cd25e489b89..cb887489d00f0 100644 +--- a/kernel/printk/printk_ringbuffer.h ++++ b/kernel/printk/printk_ringbuffer.h +@@ -75,7 +75,7 @@ struct prb_desc_ring { + struct printk_info *infos; + atomic_long_t head_id; + atomic_long_t tail_id; +- atomic_long_t last_finalized_id; ++ atomic_long_t last_finalized_seq; + }; + + /* +@@ -259,7 +259,7 @@ static struct printk_ringbuffer name = { \ + .infos = &_##name##_infos[0], \ + .head_id = ATOMIC_INIT(DESC0_ID(descbits)), \ + .tail_id = ATOMIC_INIT(DESC0_ID(descbits)), \ +- .last_finalized_id = ATOMIC_INIT(DESC0_ID(descbits)), \ ++ .last_finalized_seq = ATOMIC_INIT(0), \ + }, \ + .text_data_ring = { \ + .size_bits = (avgtextbits) + (descbits), \ +@@ -378,7 +378,41 @@ bool prb_read_valid(struct printk_ringbuffer *rb, u64 seq, + bool prb_read_valid_info(struct printk_ringbuffer *rb, u64 seq, + struct printk_info *info, unsigned int *line_count); + ++u64 prb_first_seq(struct printk_ringbuffer *rb); + u64 prb_first_valid_seq(struct printk_ringbuffer *rb); + u64 prb_next_seq(struct printk_ringbuffer *rb); ++u64 prb_next_reserve_seq(struct printk_ringbuffer *rb); ++ ++#ifdef CONFIG_64BIT ++ ++#define __u64seq_to_ulseq(u64seq) (u64seq) ++#define __ulseq_to_u64seq(rb, ulseq) (ulseq) ++ ++#else /* CONFIG_64BIT */ ++ ++#define __u64seq_to_ulseq(u64seq) ((u32)u64seq) ++ ++static inline u64 __ulseq_to_u64seq(struct printk_ringbuffer *rb, u32 ulseq) ++{ ++ u64 rb_first_seq = prb_first_seq(rb); ++ u64 seq; ++ ++ /* ++ * The provided sequence is only the lower 32 bits of the ringbuffer ++ * sequence. It needs to be expanded to 64bit. Get the first sequence ++ * number from the ringbuffer and fold it. ++ * ++ * Having a 32bit representation in the console is sufficient. ++ * If a console ever gets more than 2^31 records behind ++ * the ringbuffer then this is the least of the problems. ++ * ++ * Also the access to the ring buffer is always safe. ++ */ ++ seq = rb_first_seq - (s32)((u32)rb_first_seq - ulseq); ++ ++ return seq; ++} ++ ++#endif /* CONFIG_64BIT */ + + #endif /* _KERNEL_PRINTK_RINGBUFFER_H */ +diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c +index b2bccfd37c383..f2c10d351b597 100644 +--- a/kernel/rcu/tree.c ++++ b/kernel/rcu/tree.c +@@ -4743,13 +4743,16 @@ static void __init rcu_start_exp_gp_kworkers(void) + rcu_exp_gp_kworker = kthread_create_worker(0, gp_kworker_name); + if (IS_ERR_OR_NULL(rcu_exp_gp_kworker)) { + pr_err("Failed to create %s!\n", gp_kworker_name); ++ rcu_exp_gp_kworker = NULL; + return; + } + + rcu_exp_par_gp_kworker = kthread_create_worker(0, par_gp_kworker_name); + if (IS_ERR_OR_NULL(rcu_exp_par_gp_kworker)) { + pr_err("Failed to create %s!\n", par_gp_kworker_name); ++ rcu_exp_par_gp_kworker = NULL; + kthread_destroy_worker(rcu_exp_gp_kworker); ++ rcu_exp_gp_kworker = NULL; + return; + } + +diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h +index 2ac440bc7e10b..8107f818455da 100644 +--- a/kernel/rcu/tree_exp.h ++++ b/kernel/rcu/tree_exp.h +@@ -428,7 +428,12 @@ static void sync_rcu_exp_select_node_cpus(struct kthread_work *wp) + __sync_rcu_exp_select_node_cpus(rewp); + } + +-static inline bool rcu_gp_par_worker_started(void) ++static inline bool rcu_exp_worker_started(void) ++{ ++ return !!READ_ONCE(rcu_exp_gp_kworker); ++} ++ ++static inline bool rcu_exp_par_worker_started(void) + { + return !!READ_ONCE(rcu_exp_par_gp_kworker); + } +@@ -478,7 +483,12 @@ static void sync_rcu_exp_select_node_cpus(struct work_struct *wp) + __sync_rcu_exp_select_node_cpus(rewp); + } + +-static inline bool rcu_gp_par_worker_started(void) ++static inline bool rcu_exp_worker_started(void) ++{ ++ return !!READ_ONCE(rcu_gp_wq); ++} ++ ++static inline bool rcu_exp_par_worker_started(void) + { + return !!READ_ONCE(rcu_par_gp_wq); + } +@@ -541,7 +551,7 @@ static void sync_rcu_exp_select_cpus(void) + rnp->exp_need_flush = false; + if (!READ_ONCE(rnp->expmask)) + continue; /* Avoid early boot non-existent wq. */ +- if (!rcu_gp_par_worker_started() || ++ if (!rcu_exp_par_worker_started() || + rcu_scheduler_active != RCU_SCHEDULER_RUNNING || + rcu_is_last_leaf_node(rnp)) { + /* No worker started yet or last leaf, do direct call. */ +@@ -956,7 +966,7 @@ static void rcu_exp_print_detail_task_stall_rnp(struct rcu_node *rnp) + */ + void synchronize_rcu_expedited(void) + { +- bool boottime = (rcu_scheduler_active == RCU_SCHEDULER_INIT); ++ bool use_worker; + unsigned long flags; + struct rcu_exp_work rew; + struct rcu_node *rnp; +@@ -967,6 +977,9 @@ void synchronize_rcu_expedited(void) + lock_is_held(&rcu_sched_lock_map), + "Illegal synchronize_rcu_expedited() in RCU read-side critical section"); + ++ use_worker = (rcu_scheduler_active != RCU_SCHEDULER_INIT) && ++ rcu_exp_worker_started(); ++ + /* Is the state is such that the call is a grace period? */ + if (rcu_blocking_is_gp()) { + // Note well that this code runs with !PREEMPT && !SMP. +@@ -996,7 +1009,7 @@ void synchronize_rcu_expedited(void) + return; /* Someone else did our work for us. */ + + /* Ensure that load happens before action based on it. */ +- if (unlikely(boottime)) { ++ if (unlikely(!use_worker)) { + /* Direct call during scheduler init and early_initcalls(). */ + rcu_exp_sel_wait_wake(s); + } else { +@@ -1014,7 +1027,7 @@ void synchronize_rcu_expedited(void) + /* Let the next expedited grace period start. */ + mutex_unlock(&rcu_state.exp_mutex); + +- if (likely(!boottime)) ++ if (likely(use_worker)) + synchronize_rcu_expedited_destroy_work(&rew); + } + EXPORT_SYMBOL_GPL(synchronize_rcu_expedited); +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 533547e3c90a7..e2b4e0396af84 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -7289,7 +7289,7 @@ static int select_idle_core(struct task_struct *p, int core, struct cpumask *cpu + if (!available_idle_cpu(cpu)) { + idle = false; + if (*idle_cpu == -1) { +- if (sched_idle_cpu(cpu) && cpumask_test_cpu(cpu, p->cpus_ptr)) { ++ if (sched_idle_cpu(cpu) && cpumask_test_cpu(cpu, cpus)) { + *idle_cpu = cpu; + break; + } +@@ -7297,7 +7297,7 @@ static int select_idle_core(struct task_struct *p, int core, struct cpumask *cpu + } + break; + } +- if (*idle_cpu == -1 && cpumask_test_cpu(cpu, p->cpus_ptr)) ++ if (*idle_cpu == -1 && cpumask_test_cpu(cpu, cpus)) + *idle_cpu = cpu; + } + +@@ -7311,13 +7311,19 @@ static int select_idle_core(struct task_struct *p, int core, struct cpumask *cpu + /* + * Scan the local SMT mask for idle CPUs. + */ +-static int select_idle_smt(struct task_struct *p, int target) ++static int select_idle_smt(struct task_struct *p, struct sched_domain *sd, int target) + { + int cpu; + + for_each_cpu_and(cpu, cpu_smt_mask(target), p->cpus_ptr) { + if (cpu == target) + continue; ++ /* ++ * Check if the CPU is in the LLC scheduling domain of @target. ++ * Due to isolcpus, there is no guarantee that all the siblings are in the domain. ++ */ ++ if (!cpumask_test_cpu(cpu, sched_domain_span(sd))) ++ continue; + if (available_idle_cpu(cpu) || sched_idle_cpu(cpu)) + return cpu; + } +@@ -7341,7 +7347,7 @@ static inline int select_idle_core(struct task_struct *p, int core, struct cpuma + return __select_idle_cpu(core, p); + } + +-static inline int select_idle_smt(struct task_struct *p, int target) ++static inline int select_idle_smt(struct task_struct *p, struct sched_domain *sd, int target) + { + return -1; + } +@@ -7591,7 +7597,7 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target) + has_idle_core = test_idle_cores(target); + + if (!has_idle_core && cpus_share_cache(prev, target)) { +- i = select_idle_smt(p, prev); ++ i = select_idle_smt(p, sd, prev); + if ((unsigned int)i < nr_cpumask_bits) + return i; + } +diff --git a/kernel/time/time_test.c b/kernel/time/time_test.c +index ca058c8af6baf..3e5d422dd15cb 100644 +--- a/kernel/time/time_test.c ++++ b/kernel/time/time_test.c +@@ -73,7 +73,7 @@ static void time64_to_tm_test_date_range(struct kunit *test) + + days = div_s64(secs, 86400); + +- #define FAIL_MSG "%05ld/%02d/%02d (%2d) : %ld", \ ++ #define FAIL_MSG "%05ld/%02d/%02d (%2d) : %lld", \ + year, month, mdday, yday, days + + KUNIT_ASSERT_EQ_MSG(test, year - 1900, result.tm_year, FAIL_MSG); +diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c +index 266d02809dbb1..8aab7ed414907 100644 +--- a/kernel/time/timekeeping.c ++++ b/kernel/time/timekeeping.c +@@ -1180,13 +1180,15 @@ static int adjust_historical_crosststamp(struct system_time_snapshot *history, + } + + /* +- * cycle_between - true if test occurs chronologically between before and after ++ * timestamp_in_interval - true if ts is chronologically in [start, end] ++ * ++ * True if ts occurs chronologically at or after start, and before or at end. + */ +-static bool cycle_between(u64 before, u64 test, u64 after) ++static bool timestamp_in_interval(u64 start, u64 end, u64 ts) + { +- if (test > before && test < after) ++ if (ts >= start && ts <= end) + return true; +- if (test < before && before > after) ++ if (start > end && (ts >= start || ts <= end)) + return true; + return false; + } +@@ -1246,7 +1248,7 @@ int get_device_system_crosststamp(int (*get_time_fn) + */ + now = tk_clock_read(&tk->tkr_mono); + interval_start = tk->tkr_mono.cycle_last; +- if (!cycle_between(interval_start, cycles, now)) { ++ if (!timestamp_in_interval(interval_start, now, cycles)) { + clock_was_set_seq = tk->clock_was_set_seq; + cs_was_changed_seq = tk->cs_was_changed_seq; + cycles = interval_start; +@@ -1259,10 +1261,8 @@ int get_device_system_crosststamp(int (*get_time_fn) + tk_core.timekeeper.offs_real); + base_raw = tk->tkr_raw.base; + +- nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono, +- system_counterval.cycles); +- nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, +- system_counterval.cycles); ++ nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono, cycles); ++ nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, cycles); + } while (read_seqcount_retry(&tk_core.seq, seq)); + + xtstamp->sys_realtime = ktime_add_ns(base_real, nsec_real); +@@ -1277,13 +1277,13 @@ int get_device_system_crosststamp(int (*get_time_fn) + bool discontinuity; + + /* +- * Check that the counter value occurs after the provided ++ * Check that the counter value is not before the provided + * history reference and that the history doesn't cross a + * clocksource change + */ + if (!history_begin || +- !cycle_between(history_begin->cycles, +- system_counterval.cycles, cycles) || ++ !timestamp_in_interval(history_begin->cycles, ++ cycles, system_counterval.cycles) || + history_begin->cs_was_changed_seq != cs_was_changed_seq) + return -EINVAL; + partial_history_cycles = cycles - system_counterval.cycles; +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index 7b482a26d7419..ed8ebc9776016 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -108,7 +108,7 @@ enum { + RESCUER_NICE_LEVEL = MIN_NICE, + HIGHPRI_NICE_LEVEL = MIN_NICE, + +- WQ_NAME_LEN = 24, ++ WQ_NAME_LEN = 32, + }; + + /* +@@ -122,6 +122,9 @@ enum { + * + * L: pool->lock protected. Access with pool->lock held. + * ++ * LN: pool->lock and wq_node_nr_active->lock protected for writes. Either for ++ * reads. ++ * + * K: Only modified by worker while holding pool->lock. Can be safely read by + * self, while holding pool->lock or from IRQ context if %current is the + * kworker. +@@ -143,6 +146,9 @@ enum { + * + * WR: wq->mutex protected for writes. RCU protected for reads. + * ++ * WO: wq->mutex protected for writes. Updated with WRITE_ONCE() and can be read ++ * with READ_ONCE() without locking. ++ * + * MD: wq_mayday_lock protected. + * + * WD: Used internally by the watchdog. +@@ -240,18 +246,18 @@ struct pool_workqueue { + * pwq->inactive_works instead of pool->worklist and marked with + * WORK_STRUCT_INACTIVE. + * +- * All work items marked with WORK_STRUCT_INACTIVE do not participate +- * in pwq->nr_active and all work items in pwq->inactive_works are +- * marked with WORK_STRUCT_INACTIVE. But not all WORK_STRUCT_INACTIVE +- * work items are in pwq->inactive_works. Some of them are ready to +- * run in pool->worklist or worker->scheduled. Those work itmes are +- * only struct wq_barrier which is used for flush_work() and should +- * not participate in pwq->nr_active. For non-barrier work item, it +- * is marked with WORK_STRUCT_INACTIVE iff it is in pwq->inactive_works. ++ * All work items marked with WORK_STRUCT_INACTIVE do not participate in ++ * nr_active and all work items in pwq->inactive_works are marked with ++ * WORK_STRUCT_INACTIVE. But not all WORK_STRUCT_INACTIVE work items are ++ * in pwq->inactive_works. Some of them are ready to run in ++ * pool->worklist or worker->scheduled. Those work itmes are only struct ++ * wq_barrier which is used for flush_work() and should not participate ++ * in nr_active. For non-barrier work item, it is marked with ++ * WORK_STRUCT_INACTIVE iff it is in pwq->inactive_works. + */ + int nr_active; /* L: nr of active works */ +- int max_active; /* L: max active works */ + struct list_head inactive_works; /* L: inactive works */ ++ struct list_head pending_node; /* LN: node on wq_node_nr_active->pending_pwqs */ + struct list_head pwqs_node; /* WR: node on wq->pwqs */ + struct list_head mayday_node; /* MD: node on wq->maydays */ + +@@ -278,6 +284,26 @@ struct wq_flusher { + + struct wq_device; + ++/* ++ * Unlike in a per-cpu workqueue where max_active limits its concurrency level ++ * on each CPU, in an unbound workqueue, max_active applies to the whole system. ++ * As sharing a single nr_active across multiple sockets can be very expensive, ++ * the counting and enforcement is per NUMA node. ++ * ++ * The following struct is used to enforce per-node max_active. When a pwq wants ++ * to start executing a work item, it should increment ->nr using ++ * tryinc_node_nr_active(). If acquisition fails due to ->nr already being over ++ * ->max, the pwq is queued on ->pending_pwqs. As in-flight work items finish ++ * and decrement ->nr, node_activate_pending_pwq() activates the pending pwqs in ++ * round-robin order. ++ */ ++struct wq_node_nr_active { ++ int max; /* per-node max_active */ ++ atomic_t nr; /* per-node nr_active */ ++ raw_spinlock_t lock; /* nests inside pool locks */ ++ struct list_head pending_pwqs; /* LN: pwqs with inactive works */ ++}; ++ + /* + * The externally visible workqueue. It relays the issued work items to + * the appropriate worker_pool through its pool_workqueues. +@@ -298,10 +324,15 @@ struct workqueue_struct { + struct worker *rescuer; /* MD: rescue worker */ + + int nr_drainers; /* WQ: drain in progress */ +- int saved_max_active; /* WQ: saved pwq max_active */ ++ ++ /* See alloc_workqueue() function comment for info on min/max_active */ ++ int max_active; /* WO: max active works */ ++ int min_active; /* WO: min active works */ ++ int saved_max_active; /* WQ: saved max_active */ ++ int saved_min_active; /* WQ: saved min_active */ + + struct workqueue_attrs *unbound_attrs; /* PW: only for unbound wqs */ +- struct pool_workqueue *dfl_pwq; /* PW: only for unbound wqs */ ++ struct pool_workqueue __rcu *dfl_pwq; /* PW: only for unbound wqs */ + + #ifdef CONFIG_SYSFS + struct wq_device *wq_dev; /* I: for sysfs interface */ +@@ -323,6 +354,7 @@ struct workqueue_struct { + /* hot fields used during command issue, aligned to cacheline */ + unsigned int flags ____cacheline_aligned; /* WQ: WQ_* flags */ + struct pool_workqueue __percpu __rcu **cpu_pwq; /* I: per-cpu pwqs */ ++ struct wq_node_nr_active *node_nr_active[]; /* I: per-node nr_active */ + }; + + static struct kmem_cache *pwq_cache; +@@ -632,6 +664,36 @@ static int worker_pool_assign_id(struct worker_pool *pool) + return ret; + } + ++static struct pool_workqueue __rcu ** ++unbound_pwq_slot(struct workqueue_struct *wq, int cpu) ++{ ++ if (cpu >= 0) ++ return per_cpu_ptr(wq->cpu_pwq, cpu); ++ else ++ return &wq->dfl_pwq; ++} ++ ++/* @cpu < 0 for dfl_pwq */ ++static struct pool_workqueue *unbound_pwq(struct workqueue_struct *wq, int cpu) ++{ ++ return rcu_dereference_check(*unbound_pwq_slot(wq, cpu), ++ lockdep_is_held(&wq_pool_mutex) || ++ lockdep_is_held(&wq->mutex)); ++} ++ ++/** ++ * unbound_effective_cpumask - effective cpumask of an unbound workqueue ++ * @wq: workqueue of interest ++ * ++ * @wq->unbound_attrs->cpumask contains the cpumask requested by the user which ++ * is masked with wq_unbound_cpumask to determine the effective cpumask. The ++ * default pwq is always mapped to the pool with the current effective cpumask. ++ */ ++static struct cpumask *unbound_effective_cpumask(struct workqueue_struct *wq) ++{ ++ return unbound_pwq(wq, -1)->pool->attrs->__pod_cpumask; ++} ++ + static unsigned int work_color_to_flags(int color) + { + return color << WORK_STRUCT_COLOR_SHIFT; +@@ -1401,6 +1463,71 @@ work_func_t wq_worker_last_func(struct task_struct *task) + return worker->last_func; + } + ++/** ++ * wq_node_nr_active - Determine wq_node_nr_active to use ++ * @wq: workqueue of interest ++ * @node: NUMA node, can be %NUMA_NO_NODE ++ * ++ * Determine wq_node_nr_active to use for @wq on @node. Returns: ++ * ++ * - %NULL for per-cpu workqueues as they don't need to use shared nr_active. ++ * ++ * - node_nr_active[nr_node_ids] if @node is %NUMA_NO_NODE. ++ * ++ * - Otherwise, node_nr_active[@node]. ++ */ ++static struct wq_node_nr_active *wq_node_nr_active(struct workqueue_struct *wq, ++ int node) ++{ ++ if (!(wq->flags & WQ_UNBOUND)) ++ return NULL; ++ ++ if (node == NUMA_NO_NODE) ++ node = nr_node_ids; ++ ++ return wq->node_nr_active[node]; ++} ++ ++/** ++ * wq_update_node_max_active - Update per-node max_actives to use ++ * @wq: workqueue to update ++ * @off_cpu: CPU that's going down, -1 if a CPU is not going down ++ * ++ * Update @wq->node_nr_active[]->max. @wq must be unbound. max_active is ++ * distributed among nodes according to the proportions of numbers of online ++ * cpus. The result is always between @wq->min_active and max_active. ++ */ ++static void wq_update_node_max_active(struct workqueue_struct *wq, int off_cpu) ++{ ++ struct cpumask *effective = unbound_effective_cpumask(wq); ++ int min_active = READ_ONCE(wq->min_active); ++ int max_active = READ_ONCE(wq->max_active); ++ int total_cpus, node; ++ ++ lockdep_assert_held(&wq->mutex); ++ ++ if (off_cpu >= 0 && !cpumask_test_cpu(off_cpu, effective)) ++ off_cpu = -1; ++ ++ total_cpus = cpumask_weight_and(effective, cpu_online_mask); ++ if (off_cpu >= 0) ++ total_cpus--; ++ ++ for_each_node(node) { ++ int node_cpus; ++ ++ node_cpus = cpumask_weight_and(effective, cpumask_of_node(node)); ++ if (off_cpu >= 0 && cpu_to_node(off_cpu) == node) ++ node_cpus--; ++ ++ wq_node_nr_active(wq, node)->max = ++ clamp(DIV_ROUND_UP(max_active * node_cpus, total_cpus), ++ min_active, max_active); ++ } ++ ++ wq_node_nr_active(wq, NUMA_NO_NODE)->max = min_active; ++} ++ + /** + * get_pwq - get an extra reference on the specified pool_workqueue + * @pwq: pool_workqueue to get +@@ -1453,24 +1580,293 @@ static void put_pwq_unlocked(struct pool_workqueue *pwq) + } + } + +-static void pwq_activate_inactive_work(struct work_struct *work) ++static bool pwq_is_empty(struct pool_workqueue *pwq) + { +- struct pool_workqueue *pwq = get_work_pwq(work); ++ return !pwq->nr_active && list_empty(&pwq->inactive_works); ++} + ++static void __pwq_activate_work(struct pool_workqueue *pwq, ++ struct work_struct *work) ++{ ++ unsigned long *wdb = work_data_bits(work); ++ ++ WARN_ON_ONCE(!(*wdb & WORK_STRUCT_INACTIVE)); + trace_workqueue_activate_work(work); + if (list_empty(&pwq->pool->worklist)) + pwq->pool->watchdog_ts = jiffies; + move_linked_works(work, &pwq->pool->worklist, NULL); +- __clear_bit(WORK_STRUCT_INACTIVE_BIT, work_data_bits(work)); ++ __clear_bit(WORK_STRUCT_INACTIVE_BIT, wdb); ++} ++ ++/** ++ * pwq_activate_work - Activate a work item if inactive ++ * @pwq: pool_workqueue @work belongs to ++ * @work: work item to activate ++ * ++ * Returns %true if activated. %false if already active. ++ */ ++static bool pwq_activate_work(struct pool_workqueue *pwq, ++ struct work_struct *work) ++{ ++ struct worker_pool *pool = pwq->pool; ++ struct wq_node_nr_active *nna; ++ ++ lockdep_assert_held(&pool->lock); ++ ++ if (!(*work_data_bits(work) & WORK_STRUCT_INACTIVE)) ++ return false; ++ ++ nna = wq_node_nr_active(pwq->wq, pool->node); ++ if (nna) ++ atomic_inc(&nna->nr); ++ + pwq->nr_active++; ++ __pwq_activate_work(pwq, work); ++ return true; ++} ++ ++static bool tryinc_node_nr_active(struct wq_node_nr_active *nna) ++{ ++ int max = READ_ONCE(nna->max); ++ ++ while (true) { ++ int old, tmp; ++ ++ old = atomic_read(&nna->nr); ++ if (old >= max) ++ return false; ++ tmp = atomic_cmpxchg_relaxed(&nna->nr, old, old + 1); ++ if (tmp == old) ++ return true; ++ } ++} ++ ++/** ++ * pwq_tryinc_nr_active - Try to increment nr_active for a pwq ++ * @pwq: pool_workqueue of interest ++ * @fill: max_active may have increased, try to increase concurrency level ++ * ++ * Try to increment nr_active for @pwq. Returns %true if an nr_active count is ++ * successfully obtained. %false otherwise. ++ */ ++static bool pwq_tryinc_nr_active(struct pool_workqueue *pwq, bool fill) ++{ ++ struct workqueue_struct *wq = pwq->wq; ++ struct worker_pool *pool = pwq->pool; ++ struct wq_node_nr_active *nna = wq_node_nr_active(wq, pool->node); ++ bool obtained = false; ++ ++ lockdep_assert_held(&pool->lock); ++ ++ if (!nna) { ++ /* per-cpu workqueue, pwq->nr_active is sufficient */ ++ obtained = pwq->nr_active < READ_ONCE(wq->max_active); ++ goto out; ++ } ++ ++ /* ++ * Unbound workqueue uses per-node shared nr_active $nna. If @pwq is ++ * already waiting on $nna, pwq_dec_nr_active() will maintain the ++ * concurrency level. Don't jump the line. ++ * ++ * We need to ignore the pending test after max_active has increased as ++ * pwq_dec_nr_active() can only maintain the concurrency level but not ++ * increase it. This is indicated by @fill. ++ */ ++ if (!list_empty(&pwq->pending_node) && likely(!fill)) ++ goto out; ++ ++ obtained = tryinc_node_nr_active(nna); ++ if (obtained) ++ goto out; ++ ++ /* ++ * Lockless acquisition failed. Lock, add ourself to $nna->pending_pwqs ++ * and try again. The smp_mb() is paired with the implied memory barrier ++ * of atomic_dec_return() in pwq_dec_nr_active() to ensure that either ++ * we see the decremented $nna->nr or they see non-empty ++ * $nna->pending_pwqs. ++ */ ++ raw_spin_lock(&nna->lock); ++ ++ if (list_empty(&pwq->pending_node)) ++ list_add_tail(&pwq->pending_node, &nna->pending_pwqs); ++ else if (likely(!fill)) ++ goto out_unlock; ++ ++ smp_mb(); ++ ++ obtained = tryinc_node_nr_active(nna); ++ ++ /* ++ * If @fill, @pwq might have already been pending. Being spuriously ++ * pending in cold paths doesn't affect anything. Let's leave it be. ++ */ ++ if (obtained && likely(!fill)) ++ list_del_init(&pwq->pending_node); ++ ++out_unlock: ++ raw_spin_unlock(&nna->lock); ++out: ++ if (obtained) ++ pwq->nr_active++; ++ return obtained; ++} ++ ++/** ++ * pwq_activate_first_inactive - Activate the first inactive work item on a pwq ++ * @pwq: pool_workqueue of interest ++ * @fill: max_active may have increased, try to increase concurrency level ++ * ++ * Activate the first inactive work item of @pwq if available and allowed by ++ * max_active limit. ++ * ++ * Returns %true if an inactive work item has been activated. %false if no ++ * inactive work item is found or max_active limit is reached. ++ */ ++static bool pwq_activate_first_inactive(struct pool_workqueue *pwq, bool fill) ++{ ++ struct work_struct *work = ++ list_first_entry_or_null(&pwq->inactive_works, ++ struct work_struct, entry); ++ ++ if (work && pwq_tryinc_nr_active(pwq, fill)) { ++ __pwq_activate_work(pwq, work); ++ return true; ++ } else { ++ return false; ++ } ++} ++ ++/** ++ * node_activate_pending_pwq - Activate a pending pwq on a wq_node_nr_active ++ * @nna: wq_node_nr_active to activate a pending pwq for ++ * @caller_pool: worker_pool the caller is locking ++ * ++ * Activate a pwq in @nna->pending_pwqs. Called with @caller_pool locked. ++ * @caller_pool may be unlocked and relocked to lock other worker_pools. ++ */ ++static void node_activate_pending_pwq(struct wq_node_nr_active *nna, ++ struct worker_pool *caller_pool) ++{ ++ struct worker_pool *locked_pool = caller_pool; ++ struct pool_workqueue *pwq; ++ struct work_struct *work; ++ ++ lockdep_assert_held(&caller_pool->lock); ++ ++ raw_spin_lock(&nna->lock); ++retry: ++ pwq = list_first_entry_or_null(&nna->pending_pwqs, ++ struct pool_workqueue, pending_node); ++ if (!pwq) ++ goto out_unlock; ++ ++ /* ++ * If @pwq is for a different pool than @locked_pool, we need to lock ++ * @pwq->pool->lock. Let's trylock first. If unsuccessful, do the unlock ++ * / lock dance. For that, we also need to release @nna->lock as it's ++ * nested inside pool locks. ++ */ ++ if (pwq->pool != locked_pool) { ++ raw_spin_unlock(&locked_pool->lock); ++ locked_pool = pwq->pool; ++ if (!raw_spin_trylock(&locked_pool->lock)) { ++ raw_spin_unlock(&nna->lock); ++ raw_spin_lock(&locked_pool->lock); ++ raw_spin_lock(&nna->lock); ++ goto retry; ++ } ++ } ++ ++ /* ++ * $pwq may not have any inactive work items due to e.g. cancellations. ++ * Drop it from pending_pwqs and see if there's another one. ++ */ ++ work = list_first_entry_or_null(&pwq->inactive_works, ++ struct work_struct, entry); ++ if (!work) { ++ list_del_init(&pwq->pending_node); ++ goto retry; ++ } ++ ++ /* ++ * Acquire an nr_active count and activate the inactive work item. If ++ * $pwq still has inactive work items, rotate it to the end of the ++ * pending_pwqs so that we round-robin through them. This means that ++ * inactive work items are not activated in queueing order which is fine ++ * given that there has never been any ordering across different pwqs. ++ */ ++ if (likely(tryinc_node_nr_active(nna))) { ++ pwq->nr_active++; ++ __pwq_activate_work(pwq, work); ++ ++ if (list_empty(&pwq->inactive_works)) ++ list_del_init(&pwq->pending_node); ++ else ++ list_move_tail(&pwq->pending_node, &nna->pending_pwqs); ++ ++ /* if activating a foreign pool, make sure it's running */ ++ if (pwq->pool != caller_pool) ++ kick_pool(pwq->pool); ++ } ++ ++out_unlock: ++ raw_spin_unlock(&nna->lock); ++ if (locked_pool != caller_pool) { ++ raw_spin_unlock(&locked_pool->lock); ++ raw_spin_lock(&caller_pool->lock); ++ } + } + +-static void pwq_activate_first_inactive(struct pool_workqueue *pwq) ++/** ++ * pwq_dec_nr_active - Retire an active count ++ * @pwq: pool_workqueue of interest ++ * ++ * Decrement @pwq's nr_active and try to activate the first inactive work item. ++ * For unbound workqueues, this function may temporarily drop @pwq->pool->lock. ++ */ ++static void pwq_dec_nr_active(struct pool_workqueue *pwq) + { +- struct work_struct *work = list_first_entry(&pwq->inactive_works, +- struct work_struct, entry); ++ struct worker_pool *pool = pwq->pool; ++ struct wq_node_nr_active *nna = wq_node_nr_active(pwq->wq, pool->node); + +- pwq_activate_inactive_work(work); ++ lockdep_assert_held(&pool->lock); ++ ++ /* ++ * @pwq->nr_active should be decremented for both percpu and unbound ++ * workqueues. ++ */ ++ pwq->nr_active--; ++ ++ /* ++ * For a percpu workqueue, it's simple. Just need to kick the first ++ * inactive work item on @pwq itself. ++ */ ++ if (!nna) { ++ pwq_activate_first_inactive(pwq, false); ++ return; ++ } ++ ++ /* ++ * If @pwq is for an unbound workqueue, it's more complicated because ++ * multiple pwqs and pools may be sharing the nr_active count. When a ++ * pwq needs to wait for an nr_active count, it puts itself on ++ * $nna->pending_pwqs. The following atomic_dec_return()'s implied ++ * memory barrier is paired with smp_mb() in pwq_tryinc_nr_active() to ++ * guarantee that either we see non-empty pending_pwqs or they see ++ * decremented $nna->nr. ++ * ++ * $nna->max may change as CPUs come online/offline and @pwq->wq's ++ * max_active gets updated. However, it is guaranteed to be equal to or ++ * larger than @pwq->wq->min_active which is above zero unless freezing. ++ * This maintains the forward progress guarantee. ++ */ ++ if (atomic_dec_return(&nna->nr) >= READ_ONCE(nna->max)) ++ return; ++ ++ if (!list_empty(&nna->pending_pwqs)) ++ node_activate_pending_pwq(nna, pool); + } + + /** +@@ -1488,14 +1884,8 @@ static void pwq_dec_nr_in_flight(struct pool_workqueue *pwq, unsigned long work_ + { + int color = get_work_color(work_data); + +- if (!(work_data & WORK_STRUCT_INACTIVE)) { +- pwq->nr_active--; +- if (!list_empty(&pwq->inactive_works)) { +- /* one down, submit an inactive one */ +- if (pwq->nr_active < pwq->max_active) +- pwq_activate_first_inactive(pwq); +- } +- } ++ if (!(work_data & WORK_STRUCT_INACTIVE)) ++ pwq_dec_nr_active(pwq); + + pwq->nr_in_flight[color]--; + +@@ -1608,8 +1998,7 @@ static int try_to_grab_pending(struct work_struct *work, bool is_dwork, + * management later on and cause stall. Make sure the work + * item is activated before grabbing. + */ +- if (*work_data_bits(work) & WORK_STRUCT_INACTIVE) +- pwq_activate_inactive_work(work); ++ pwq_activate_work(pwq, work); + + list_del_init(&work->entry); + pwq_dec_nr_in_flight(pwq, *work_data_bits(work)); +@@ -1793,12 +2182,16 @@ static void __queue_work(int cpu, struct workqueue_struct *wq, + pwq->nr_in_flight[pwq->work_color]++; + work_flags = work_color_to_flags(pwq->work_color); + +- if (likely(pwq->nr_active < pwq->max_active)) { ++ /* ++ * Limit the number of concurrently active work items to max_active. ++ * @work must also queue behind existing inactive work items to maintain ++ * ordering when max_active changes. See wq_adjust_max_active(). ++ */ ++ if (list_empty(&pwq->inactive_works) && pwq_tryinc_nr_active(pwq, false)) { + if (list_empty(&pool->worklist)) + pool->watchdog_ts = jiffies; + + trace_workqueue_activate_work(work); +- pwq->nr_active++; + insert_work(pwq, work, &pool->worklist, work_flags); + kick_pool(pool); + } else { +@@ -3027,7 +3420,7 @@ static void insert_wq_barrier(struct pool_workqueue *pwq, + + barr->task = current; + +- /* The barrier work item does not participate in pwq->nr_active. */ ++ /* The barrier work item does not participate in nr_active. */ + work_flags |= WORK_STRUCT_INACTIVE; + + /* +@@ -3316,7 +3709,7 @@ void drain_workqueue(struct workqueue_struct *wq) + bool drained; + + raw_spin_lock_irq(&pwq->pool->lock); +- drained = !pwq->nr_active && list_empty(&pwq->inactive_works); ++ drained = pwq_is_empty(pwq); + raw_spin_unlock_irq(&pwq->pool->lock); + + if (drained) +@@ -3927,11 +4320,65 @@ static void wq_free_lockdep(struct workqueue_struct *wq) + } + #endif + ++static void free_node_nr_active(struct wq_node_nr_active **nna_ar) ++{ ++ int node; ++ ++ for_each_node(node) { ++ kfree(nna_ar[node]); ++ nna_ar[node] = NULL; ++ } ++ ++ kfree(nna_ar[nr_node_ids]); ++ nna_ar[nr_node_ids] = NULL; ++} ++ ++static void init_node_nr_active(struct wq_node_nr_active *nna) ++{ ++ atomic_set(&nna->nr, 0); ++ raw_spin_lock_init(&nna->lock); ++ INIT_LIST_HEAD(&nna->pending_pwqs); ++} ++ ++/* ++ * Each node's nr_active counter will be accessed mostly from its own node and ++ * should be allocated in the node. ++ */ ++static int alloc_node_nr_active(struct wq_node_nr_active **nna_ar) ++{ ++ struct wq_node_nr_active *nna; ++ int node; ++ ++ for_each_node(node) { ++ nna = kzalloc_node(sizeof(*nna), GFP_KERNEL, node); ++ if (!nna) ++ goto err_free; ++ init_node_nr_active(nna); ++ nna_ar[node] = nna; ++ } ++ ++ /* [nr_node_ids] is used as the fallback */ ++ nna = kzalloc_node(sizeof(*nna), GFP_KERNEL, NUMA_NO_NODE); ++ if (!nna) ++ goto err_free; ++ init_node_nr_active(nna); ++ nna_ar[nr_node_ids] = nna; ++ ++ return 0; ++ ++err_free: ++ free_node_nr_active(nna_ar); ++ return -ENOMEM; ++} ++ + static void rcu_free_wq(struct rcu_head *rcu) + { + struct workqueue_struct *wq = + container_of(rcu, struct workqueue_struct, rcu); + ++ if (wq->flags & WQ_UNBOUND) ++ free_node_nr_active(wq->node_nr_active); ++ + wq_free_lockdep(wq); + free_percpu(wq->cpu_pwq); + free_workqueue_attrs(wq->unbound_attrs); +@@ -4130,6 +4577,15 @@ static void pwq_release_workfn(struct kthread_work *work) + mutex_unlock(&wq_pool_mutex); + } + ++ if (!list_empty(&pwq->pending_node)) { ++ struct wq_node_nr_active *nna = ++ wq_node_nr_active(pwq->wq, pwq->pool->node); ++ ++ raw_spin_lock_irq(&nna->lock); ++ list_del_init(&pwq->pending_node); ++ raw_spin_unlock_irq(&nna->lock); ++ } ++ + call_rcu(&pwq->rcu, rcu_free_pwq); + + /* +@@ -4142,50 +4598,6 @@ static void pwq_release_workfn(struct kthread_work *work) + } + } + +-/** +- * pwq_adjust_max_active - update a pwq's max_active to the current setting +- * @pwq: target pool_workqueue +- * +- * If @pwq isn't freezing, set @pwq->max_active to the associated +- * workqueue's saved_max_active and activate inactive work items +- * accordingly. If @pwq is freezing, clear @pwq->max_active to zero. +- */ +-static void pwq_adjust_max_active(struct pool_workqueue *pwq) +-{ +- struct workqueue_struct *wq = pwq->wq; +- bool freezable = wq->flags & WQ_FREEZABLE; +- unsigned long flags; +- +- /* for @wq->saved_max_active */ +- lockdep_assert_held(&wq->mutex); +- +- /* fast exit for non-freezable wqs */ +- if (!freezable && pwq->max_active == wq->saved_max_active) +- return; +- +- /* this function can be called during early boot w/ irq disabled */ +- raw_spin_lock_irqsave(&pwq->pool->lock, flags); +- +- /* +- * During [un]freezing, the caller is responsible for ensuring that +- * this function is called at least once after @workqueue_freezing +- * is updated and visible. +- */ +- if (!freezable || !workqueue_freezing) { +- pwq->max_active = wq->saved_max_active; +- +- while (!list_empty(&pwq->inactive_works) && +- pwq->nr_active < pwq->max_active) +- pwq_activate_first_inactive(pwq); +- +- kick_pool(pwq->pool); +- } else { +- pwq->max_active = 0; +- } +- +- raw_spin_unlock_irqrestore(&pwq->pool->lock, flags); +-} +- + /* initialize newly allocated @pwq which is associated with @wq and @pool */ + static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq, + struct worker_pool *pool) +@@ -4199,6 +4611,7 @@ static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq, + pwq->flush_color = -1; + pwq->refcnt = 1; + INIT_LIST_HEAD(&pwq->inactive_works); ++ INIT_LIST_HEAD(&pwq->pending_node); + INIT_LIST_HEAD(&pwq->pwqs_node); + INIT_LIST_HEAD(&pwq->mayday_node); + kthread_init_work(&pwq->release_work, pwq_release_workfn); +@@ -4218,9 +4631,6 @@ static void link_pwq(struct pool_workqueue *pwq) + /* set the matching work_color */ + pwq->work_color = wq->work_color; + +- /* sync max_active to the current setting */ +- pwq_adjust_max_active(pwq); +- + /* link in @pwq */ + list_add_rcu(&pwq->pwqs_node, &wq->pwqs); + } +@@ -4289,10 +4699,11 @@ static void wq_calc_pod_cpumask(struct workqueue_attrs *attrs, int cpu, + "possible intersect\n"); + } + +-/* install @pwq into @wq's cpu_pwq and return the old pwq */ ++/* install @pwq into @wq and return the old pwq, @cpu < 0 for dfl_pwq */ + static struct pool_workqueue *install_unbound_pwq(struct workqueue_struct *wq, + int cpu, struct pool_workqueue *pwq) + { ++ struct pool_workqueue __rcu **slot = unbound_pwq_slot(wq, cpu); + struct pool_workqueue *old_pwq; + + lockdep_assert_held(&wq_pool_mutex); +@@ -4301,8 +4712,8 @@ static struct pool_workqueue *install_unbound_pwq(struct workqueue_struct *wq, + /* link_pwq() can handle duplicate calls */ + link_pwq(pwq); + +- old_pwq = rcu_access_pointer(*per_cpu_ptr(wq->cpu_pwq, cpu)); +- rcu_assign_pointer(*per_cpu_ptr(wq->cpu_pwq, cpu), pwq); ++ old_pwq = rcu_access_pointer(*slot); ++ rcu_assign_pointer(*slot, pwq); + return old_pwq; + } + +@@ -4402,14 +4813,14 @@ static void apply_wqattrs_commit(struct apply_wqattrs_ctx *ctx) + + copy_workqueue_attrs(ctx->wq->unbound_attrs, ctx->attrs); + +- /* save the previous pwq and install the new one */ ++ /* save the previous pwqs and install the new ones */ + for_each_possible_cpu(cpu) + ctx->pwq_tbl[cpu] = install_unbound_pwq(ctx->wq, cpu, + ctx->pwq_tbl[cpu]); ++ ctx->dfl_pwq = install_unbound_pwq(ctx->wq, -1, ctx->dfl_pwq); + +- /* @dfl_pwq might not have been used, ensure it's linked */ +- link_pwq(ctx->dfl_pwq); +- swap(ctx->wq->dfl_pwq, ctx->dfl_pwq); ++ /* update node_nr_active->max */ ++ wq_update_node_max_active(ctx->wq, -1); + + mutex_unlock(&ctx->wq->mutex); + } +@@ -4519,9 +4930,7 @@ static void wq_update_pod(struct workqueue_struct *wq, int cpu, + + /* nothing to do if the target cpumask matches the current pwq */ + wq_calc_pod_cpumask(target_attrs, cpu, off_cpu); +- pwq = rcu_dereference_protected(*per_cpu_ptr(wq->cpu_pwq, cpu), +- lockdep_is_held(&wq_pool_mutex)); +- if (wqattrs_equal(target_attrs, pwq->pool->attrs)) ++ if (wqattrs_equal(target_attrs, unbound_pwq(wq, cpu)->pool->attrs)) + return; + + /* create a new pwq */ +@@ -4539,10 +4948,11 @@ static void wq_update_pod(struct workqueue_struct *wq, int cpu, + + use_dfl_pwq: + mutex_lock(&wq->mutex); +- raw_spin_lock_irq(&wq->dfl_pwq->pool->lock); +- get_pwq(wq->dfl_pwq); +- raw_spin_unlock_irq(&wq->dfl_pwq->pool->lock); +- old_pwq = install_unbound_pwq(wq, cpu, wq->dfl_pwq); ++ pwq = unbound_pwq(wq, -1); ++ raw_spin_lock_irq(&pwq->pool->lock); ++ get_pwq(pwq); ++ raw_spin_unlock_irq(&pwq->pool->lock); ++ old_pwq = install_unbound_pwq(wq, cpu, pwq); + out_unlock: + mutex_unlock(&wq->mutex); + put_pwq_unlocked(old_pwq); +@@ -4580,10 +4990,13 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq) + + cpus_read_lock(); + if (wq->flags & __WQ_ORDERED) { ++ struct pool_workqueue *dfl_pwq; ++ + ret = apply_workqueue_attrs(wq, ordered_wq_attrs[highpri]); + /* there should only be single pwq for ordering guarantee */ +- WARN(!ret && (wq->pwqs.next != &wq->dfl_pwq->pwqs_node || +- wq->pwqs.prev != &wq->dfl_pwq->pwqs_node), ++ dfl_pwq = rcu_access_pointer(wq->dfl_pwq); ++ WARN(!ret && (wq->pwqs.next != &dfl_pwq->pwqs_node || ++ wq->pwqs.prev != &dfl_pwq->pwqs_node), + "ordering guarantee broken for workqueue %s\n", wq->name); + } else { + ret = apply_workqueue_attrs(wq, unbound_std_wq_attrs[highpri]); +@@ -4658,6 +5071,69 @@ static int init_rescuer(struct workqueue_struct *wq) + return 0; + } + ++/** ++ * wq_adjust_max_active - update a wq's max_active to the current setting ++ * @wq: target workqueue ++ * ++ * If @wq isn't freezing, set @wq->max_active to the saved_max_active and ++ * activate inactive work items accordingly. If @wq is freezing, clear ++ * @wq->max_active to zero. ++ */ ++static void wq_adjust_max_active(struct workqueue_struct *wq) ++{ ++ bool activated; ++ int new_max, new_min; ++ ++ lockdep_assert_held(&wq->mutex); ++ ++ if ((wq->flags & WQ_FREEZABLE) && workqueue_freezing) { ++ new_max = 0; ++ new_min = 0; ++ } else { ++ new_max = wq->saved_max_active; ++ new_min = wq->saved_min_active; ++ } ++ ++ if (wq->max_active == new_max && wq->min_active == new_min) ++ return; ++ ++ /* ++ * Update @wq->max/min_active and then kick inactive work items if more ++ * active work items are allowed. This doesn't break work item ordering ++ * because new work items are always queued behind existing inactive ++ * work items if there are any. ++ */ ++ WRITE_ONCE(wq->max_active, new_max); ++ WRITE_ONCE(wq->min_active, new_min); ++ ++ if (wq->flags & WQ_UNBOUND) ++ wq_update_node_max_active(wq, -1); ++ ++ if (new_max == 0) ++ return; ++ ++ /* ++ * Round-robin through pwq's activating the first inactive work item ++ * until max_active is filled. ++ */ ++ do { ++ struct pool_workqueue *pwq; ++ ++ activated = false; ++ for_each_pwq(pwq, wq) { ++ unsigned long flags; ++ ++ /* can be called during early boot w/ irq disabled */ ++ raw_spin_lock_irqsave(&pwq->pool->lock, flags); ++ if (pwq_activate_first_inactive(pwq, true)) { ++ activated = true; ++ kick_pool(pwq->pool); ++ } ++ raw_spin_unlock_irqrestore(&pwq->pool->lock, flags); ++ } ++ } while (activated); ++} ++ + __printf(1, 4) + struct workqueue_struct *alloc_workqueue(const char *fmt, + unsigned int flags, +@@ -4665,7 +5141,8 @@ struct workqueue_struct *alloc_workqueue(const char *fmt, + { + va_list args; + struct workqueue_struct *wq; +- struct pool_workqueue *pwq; ++ size_t wq_size; ++ int name_len; + + /* + * Unbound && max_active == 1 used to imply ordered, which is no longer +@@ -4681,7 +5158,12 @@ struct workqueue_struct *alloc_workqueue(const char *fmt, + flags |= WQ_UNBOUND; + + /* allocate wq and format name */ +- wq = kzalloc(sizeof(*wq), GFP_KERNEL); ++ if (flags & WQ_UNBOUND) ++ wq_size = struct_size(wq, node_nr_active, nr_node_ids + 1); ++ else ++ wq_size = sizeof(*wq); ++ ++ wq = kzalloc(wq_size, GFP_KERNEL); + if (!wq) + return NULL; + +@@ -4692,15 +5174,22 @@ struct workqueue_struct *alloc_workqueue(const char *fmt, + } + + va_start(args, max_active); +- vsnprintf(wq->name, sizeof(wq->name), fmt, args); ++ name_len = vsnprintf(wq->name, sizeof(wq->name), fmt, args); + va_end(args); + ++ if (name_len >= WQ_NAME_LEN) ++ pr_warn_once("workqueue: name exceeds WQ_NAME_LEN. Truncating to: %s\n", ++ wq->name); ++ + max_active = max_active ?: WQ_DFL_ACTIVE; + max_active = wq_clamp_max_active(max_active, flags, wq->name); + + /* init wq */ + wq->flags = flags; +- wq->saved_max_active = max_active; ++ wq->max_active = max_active; ++ wq->min_active = min(max_active, WQ_DFL_MIN_ACTIVE); ++ wq->saved_max_active = wq->max_active; ++ wq->saved_min_active = wq->min_active; + mutex_init(&wq->mutex); + atomic_set(&wq->nr_pwqs_to_flush, 0); + INIT_LIST_HEAD(&wq->pwqs); +@@ -4711,8 +5200,13 @@ struct workqueue_struct *alloc_workqueue(const char *fmt, + wq_init_lockdep(wq); + INIT_LIST_HEAD(&wq->list); + ++ if (flags & WQ_UNBOUND) { ++ if (alloc_node_nr_active(wq->node_nr_active) < 0) ++ goto err_unreg_lockdep; ++ } ++ + if (alloc_and_link_pwqs(wq) < 0) +- goto err_unreg_lockdep; ++ goto err_free_node_nr_active; + + if (wq_online && init_rescuer(wq) < 0) + goto err_destroy; +@@ -4728,8 +5222,7 @@ struct workqueue_struct *alloc_workqueue(const char *fmt, + mutex_lock(&wq_pool_mutex); + + mutex_lock(&wq->mutex); +- for_each_pwq(pwq, wq) +- pwq_adjust_max_active(pwq); ++ wq_adjust_max_active(wq); + mutex_unlock(&wq->mutex); + + list_add_tail_rcu(&wq->list, &workqueues); +@@ -4738,6 +5231,9 @@ struct workqueue_struct *alloc_workqueue(const char *fmt, + + return wq; + ++err_free_node_nr_active: ++ if (wq->flags & WQ_UNBOUND) ++ free_node_nr_active(wq->node_nr_active); + err_unreg_lockdep: + wq_unregister_lockdep(wq); + wq_free_lockdep(wq); +@@ -4759,9 +5255,9 @@ static bool pwq_busy(struct pool_workqueue *pwq) + if (pwq->nr_in_flight[i]) + return true; + +- if ((pwq != pwq->wq->dfl_pwq) && (pwq->refcnt > 1)) ++ if ((pwq != rcu_access_pointer(pwq->wq->dfl_pwq)) && (pwq->refcnt > 1)) + return true; +- if (pwq->nr_active || !list_empty(&pwq->inactive_works)) ++ if (!pwq_is_empty(pwq)) + return true; + + return false; +@@ -4843,13 +5339,12 @@ void destroy_workqueue(struct workqueue_struct *wq) + rcu_read_lock(); + + for_each_possible_cpu(cpu) { +- pwq = rcu_access_pointer(*per_cpu_ptr(wq->cpu_pwq, cpu)); +- RCU_INIT_POINTER(*per_cpu_ptr(wq->cpu_pwq, cpu), NULL); +- put_pwq_unlocked(pwq); ++ put_pwq_unlocked(unbound_pwq(wq, cpu)); ++ RCU_INIT_POINTER(*unbound_pwq_slot(wq, cpu), NULL); + } + +- put_pwq_unlocked(wq->dfl_pwq); +- wq->dfl_pwq = NULL; ++ put_pwq_unlocked(unbound_pwq(wq, -1)); ++ RCU_INIT_POINTER(*unbound_pwq_slot(wq, -1), NULL); + + rcu_read_unlock(); + } +@@ -4860,15 +5355,14 @@ EXPORT_SYMBOL_GPL(destroy_workqueue); + * @wq: target workqueue + * @max_active: new max_active value. + * +- * Set max_active of @wq to @max_active. ++ * Set max_active of @wq to @max_active. See the alloc_workqueue() function ++ * comment. + * + * CONTEXT: + * Don't call from IRQ context. + */ + void workqueue_set_max_active(struct workqueue_struct *wq, int max_active) + { +- struct pool_workqueue *pwq; +- + /* disallow meddling with max_active for ordered workqueues */ + if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT)) + return; +@@ -4879,9 +5373,10 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active) + + wq->flags &= ~__WQ_ORDERED; + wq->saved_max_active = max_active; ++ if (wq->flags & WQ_UNBOUND) ++ wq->saved_min_active = min(wq->saved_min_active, max_active); + +- for_each_pwq(pwq, wq) +- pwq_adjust_max_active(pwq); ++ wq_adjust_max_active(wq); + + mutex_unlock(&wq->mutex); + } +@@ -5128,8 +5623,8 @@ static void show_pwq(struct pool_workqueue *pwq) + pr_info(" pwq %d:", pool->id); + pr_cont_pool_info(pool); + +- pr_cont(" active=%d/%d refcnt=%d%s\n", +- pwq->nr_active, pwq->max_active, pwq->refcnt, ++ pr_cont(" active=%d refcnt=%d%s\n", ++ pwq->nr_active, pwq->refcnt, + !list_empty(&pwq->mayday_node) ? " MAYDAY" : ""); + + hash_for_each(pool->busy_hash, bkt, worker, hentry) { +@@ -5203,7 +5698,7 @@ void show_one_workqueue(struct workqueue_struct *wq) + unsigned long flags; + + for_each_pwq(pwq, wq) { +- if (pwq->nr_active || !list_empty(&pwq->inactive_works)) { ++ if (!pwq_is_empty(pwq)) { + idle = false; + break; + } +@@ -5215,7 +5710,7 @@ void show_one_workqueue(struct workqueue_struct *wq) + + for_each_pwq(pwq, wq) { + raw_spin_lock_irqsave(&pwq->pool->lock, flags); +- if (pwq->nr_active || !list_empty(&pwq->inactive_works)) { ++ if (!pwq_is_empty(pwq)) { + /* + * Defer printing to avoid deadlocks in console + * drivers that queue work while holding locks +@@ -5562,6 +6057,10 @@ int workqueue_online_cpu(unsigned int cpu) + + for_each_cpu(tcpu, pt->pod_cpus[pt->cpu_pod[cpu]]) + wq_update_pod(wq, tcpu, cpu, true); ++ ++ mutex_lock(&wq->mutex); ++ wq_update_node_max_active(wq, -1); ++ mutex_unlock(&wq->mutex); + } + } + +@@ -5590,6 +6089,10 @@ int workqueue_offline_cpu(unsigned int cpu) + + for_each_cpu(tcpu, pt->pod_cpus[pt->cpu_pod[cpu]]) + wq_update_pod(wq, tcpu, cpu, false); ++ ++ mutex_lock(&wq->mutex); ++ wq_update_node_max_active(wq, cpu); ++ mutex_unlock(&wq->mutex); + } + } + mutex_unlock(&wq_pool_mutex); +@@ -5677,7 +6180,6 @@ EXPORT_SYMBOL_GPL(work_on_cpu_safe_key); + void freeze_workqueues_begin(void) + { + struct workqueue_struct *wq; +- struct pool_workqueue *pwq; + + mutex_lock(&wq_pool_mutex); + +@@ -5686,8 +6188,7 @@ void freeze_workqueues_begin(void) + + list_for_each_entry(wq, &workqueues, list) { + mutex_lock(&wq->mutex); +- for_each_pwq(pwq, wq) +- pwq_adjust_max_active(pwq); ++ wq_adjust_max_active(wq); + mutex_unlock(&wq->mutex); + } + +@@ -5752,7 +6253,6 @@ bool freeze_workqueues_busy(void) + void thaw_workqueues(void) + { + struct workqueue_struct *wq; +- struct pool_workqueue *pwq; + + mutex_lock(&wq_pool_mutex); + +@@ -5764,8 +6264,7 @@ void thaw_workqueues(void) + /* restore max_active and repopulate worklist */ + list_for_each_entry(wq, &workqueues, list) { + mutex_lock(&wq->mutex); +- for_each_pwq(pwq, wq) +- pwq_adjust_max_active(pwq); ++ wq_adjust_max_active(wq); + mutex_unlock(&wq->mutex); + } + +@@ -6874,8 +7373,12 @@ void __init workqueue_init_topology(void) + * combinations to apply per-pod sharing. + */ + list_for_each_entry(wq, &workqueues, list) { +- for_each_online_cpu(cpu) { ++ for_each_online_cpu(cpu) + wq_update_pod(wq, cpu, cpu, true); ++ if (wq->flags & WQ_UNBOUND) { ++ mutex_lock(&wq->mutex); ++ wq_update_node_max_active(wq, -1); ++ mutex_unlock(&wq->mutex); + } + } + +diff --git a/lib/cmdline_kunit.c b/lib/cmdline_kunit.c +index d4572dbc91453..705b82736be08 100644 +--- a/lib/cmdline_kunit.c ++++ b/lib/cmdline_kunit.c +@@ -124,7 +124,7 @@ static void cmdline_do_one_range_test(struct kunit *test, const char *in, + n, e[0], r[0]); + + p = memchr_inv(&r[1], 0, sizeof(r) - sizeof(r[0])); +- KUNIT_EXPECT_PTR_EQ_MSG(test, p, NULL, "in test %u at %u out of bound", n, p - r); ++ KUNIT_EXPECT_PTR_EQ_MSG(test, p, NULL, "in test %u at %td out of bound", n, p - r); + } + + static void cmdline_test_range(struct kunit *test) +diff --git a/lib/kunit/device.c b/lib/kunit/device.c +index 644a38a1f5b1c..9ea399049749e 100644 +--- a/lib/kunit/device.c ++++ b/lib/kunit/device.c +@@ -10,6 +10,7 @@ + */ + + #include ++#include + + #include + #include +@@ -133,6 +134,9 @@ static struct kunit_device *kunit_device_register_internal(struct kunit *test, + return ERR_PTR(err); + } + ++ kunit_dev->dev.dma_mask = &kunit_dev->dev.coherent_dma_mask; ++ kunit_dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); ++ + kunit_add_action(test, device_unregister_wrapper, &kunit_dev->dev); + + return kunit_dev; +diff --git a/lib/kunit/executor_test.c b/lib/kunit/executor_test.c +index 22d4ee86dbedd..3f7f967e3688e 100644 +--- a/lib/kunit/executor_test.c ++++ b/lib/kunit/executor_test.c +@@ -129,7 +129,7 @@ static void parse_filter_attr_test(struct kunit *test) + GFP_KERNEL); + for (j = 0; j < filter_count; j++) { + parsed_filters[j] = kunit_next_attr_filter(&filter, &err); +- KUNIT_ASSERT_EQ_MSG(test, err, 0, "failed to parse filter '%s'", filters[j]); ++ KUNIT_ASSERT_EQ_MSG(test, err, 0, "failed to parse filter from '%s'", filters); + } + + KUNIT_EXPECT_STREQ(test, kunit_attr_filter_name(parsed_filters[0]), "speed"); +diff --git a/lib/memcpy_kunit.c b/lib/memcpy_kunit.c +index 440aee705ccca..30e00ef0bf2e0 100644 +--- a/lib/memcpy_kunit.c ++++ b/lib/memcpy_kunit.c +@@ -32,7 +32,7 @@ struct some_bytes { + BUILD_BUG_ON(sizeof(instance.data) != 32); \ + for (size_t i = 0; i < sizeof(instance.data); i++) { \ + KUNIT_ASSERT_EQ_MSG(test, instance.data[i], v, \ +- "line %d: '%s' not initialized to 0x%02x @ %d (saw 0x%02x)\n", \ ++ "line %d: '%s' not initialized to 0x%02x @ %zu (saw 0x%02x)\n", \ + __LINE__, #instance, v, i, instance.data[i]); \ + } \ + } while (0) +@@ -41,7 +41,7 @@ struct some_bytes { + BUILD_BUG_ON(sizeof(one) != sizeof(two)); \ + for (size_t i = 0; i < sizeof(one); i++) { \ + KUNIT_EXPECT_EQ_MSG(test, one.data[i], two.data[i], \ +- "line %d: %s.data[%d] (0x%02x) != %s.data[%d] (0x%02x)\n", \ ++ "line %d: %s.data[%zu] (0x%02x) != %s.data[%zu] (0x%02x)\n", \ + __LINE__, #one, i, one.data[i], #two, i, two.data[i]); \ + } \ + kunit_info(test, "ok: " TEST_OP "() " name "\n"); \ +diff --git a/lib/stackdepot.c b/lib/stackdepot.c +index 4a7055a63d9f8..c1ec2b4b6dabf 100644 +--- a/lib/stackdepot.c ++++ b/lib/stackdepot.c +@@ -45,15 +45,16 @@ + #define DEPOT_POOL_INDEX_BITS (DEPOT_HANDLE_BITS - DEPOT_OFFSET_BITS - \ + STACK_DEPOT_EXTRA_BITS) + #define DEPOT_POOLS_CAP 8192 ++/* The pool_index is offset by 1 so the first record does not have a 0 handle. */ + #define DEPOT_MAX_POOLS \ +- (((1LL << (DEPOT_POOL_INDEX_BITS)) < DEPOT_POOLS_CAP) ? \ +- (1LL << (DEPOT_POOL_INDEX_BITS)) : DEPOT_POOLS_CAP) ++ (((1LL << (DEPOT_POOL_INDEX_BITS)) - 1 < DEPOT_POOLS_CAP) ? \ ++ (1LL << (DEPOT_POOL_INDEX_BITS)) - 1 : DEPOT_POOLS_CAP) + + /* Compact structure that stores a reference to a stack. */ + union handle_parts { + depot_stack_handle_t handle; + struct { +- u32 pool_index : DEPOT_POOL_INDEX_BITS; ++ u32 pool_index : DEPOT_POOL_INDEX_BITS; /* pool_index is offset by 1 */ + u32 offset : DEPOT_OFFSET_BITS; + u32 extra : STACK_DEPOT_EXTRA_BITS; + }; +@@ -372,7 +373,7 @@ static struct stack_record *depot_pop_free_pool(void **prealloc, size_t size) + stack = current_pool + pool_offset; + + /* Pre-initialize handle once. */ +- stack->handle.pool_index = pool_index; ++ stack->handle.pool_index = pool_index + 1; + stack->handle.offset = pool_offset >> DEPOT_STACK_ALIGN; + stack->handle.extra = 0; + INIT_LIST_HEAD(&stack->hash_list); +@@ -483,18 +484,19 @@ static struct stack_record *depot_fetch_stack(depot_stack_handle_t handle) + const int pools_num_cached = READ_ONCE(pools_num); + union handle_parts parts = { .handle = handle }; + void *pool; ++ u32 pool_index = parts.pool_index - 1; + size_t offset = parts.offset << DEPOT_STACK_ALIGN; + struct stack_record *stack; + + lockdep_assert_not_held(&pool_lock); + +- if (parts.pool_index > pools_num_cached) { ++ if (pool_index >= pools_num_cached) { + WARN(1, "pool index %d out of bounds (%d) for stack id %08x\n", +- parts.pool_index, pools_num_cached, handle); ++ pool_index, pools_num_cached, handle); + return NULL; + } + +- pool = stack_pools[parts.pool_index]; ++ pool = stack_pools[pool_index]; + if (WARN_ON(!pool)) + return NULL; + +diff --git a/lib/test_blackhole_dev.c b/lib/test_blackhole_dev.c +index 4c40580a99a36..f247089d63c08 100644 +--- a/lib/test_blackhole_dev.c ++++ b/lib/test_blackhole_dev.c +@@ -29,7 +29,6 @@ static int __init test_blackholedev_init(void) + { + struct ipv6hdr *ip6h; + struct sk_buff *skb; +- struct ethhdr *ethh; + struct udphdr *uh; + int data_len; + int ret; +@@ -61,7 +60,7 @@ static int __init test_blackholedev_init(void) + ip6h->saddr = in6addr_loopback; + ip6h->daddr = in6addr_loopback; + /* Ether */ +- ethh = (struct ethhdr *)skb_push(skb, sizeof(struct ethhdr)); ++ skb_push(skb, sizeof(struct ethhdr)); + skb_set_mac_header(skb, 0); + + skb->protocol = htons(ETH_P_IPV6); +diff --git a/mm/shmem.c b/mm/shmem.c +index d7c84ff621860..791a6dc163244 100644 +--- a/mm/shmem.c ++++ b/mm/shmem.c +@@ -311,7 +311,7 @@ static void shmem_disable_quotas(struct super_block *sb) + dquot_quota_off(sb, type); + } + +-static struct dquot **shmem_get_dquots(struct inode *inode) ++static struct dquot __rcu **shmem_get_dquots(struct inode *inode) + { + return SHMEM_I(inode)->i_dquot; + } +diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig +index da7cac0a1b716..6b2b65a667008 100644 +--- a/net/bluetooth/Kconfig ++++ b/net/bluetooth/Kconfig +@@ -62,14 +62,6 @@ source "net/bluetooth/cmtp/Kconfig" + + source "net/bluetooth/hidp/Kconfig" + +-config BT_HS +- bool "Bluetooth High Speed (HS) features" +- depends on BT_BREDR +- help +- Bluetooth High Speed includes support for off-loading +- Bluetooth connections via 802.11 (wifi) physical layer +- available with Bluetooth version 3.0 or later. +- + config BT_LE + bool "Bluetooth Low Energy (LE) features" + depends on BT +diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile +index 141ac1fda0bfa..628d448d78be3 100644 +--- a/net/bluetooth/Makefile ++++ b/net/bluetooth/Makefile +@@ -21,7 +21,6 @@ bluetooth-$(CONFIG_DEV_COREDUMP) += coredump.o + + bluetooth-$(CONFIG_BT_BREDR) += sco.o + bluetooth-$(CONFIG_BT_LE) += iso.o +-bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o + bluetooth-$(CONFIG_BT_LEDS) += leds.o + bluetooth-$(CONFIG_BT_MSFTEXT) += msft.o + bluetooth-$(CONFIG_BT_AOSPEXT) += aosp.o +diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c +deleted file mode 100644 +index e7adb8a98cf90..0000000000000 +--- a/net/bluetooth/a2mp.c ++++ /dev/null +@@ -1,1054 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0-only +-/* +- Copyright (c) 2010,2011 Code Aurora Forum. All rights reserved. +- Copyright (c) 2011,2012 Intel Corp. +- +-*/ +- +-#include +-#include +-#include +- +-#include "hci_request.h" +-#include "a2mp.h" +-#include "amp.h" +- +-#define A2MP_FEAT_EXT 0x8000 +- +-/* Global AMP Manager list */ +-static LIST_HEAD(amp_mgr_list); +-static DEFINE_MUTEX(amp_mgr_list_lock); +- +-/* A2MP build & send command helper functions */ +-static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data) +-{ +- struct a2mp_cmd *cmd; +- int plen; +- +- plen = sizeof(*cmd) + len; +- cmd = kzalloc(plen, GFP_KERNEL); +- if (!cmd) +- return NULL; +- +- cmd->code = code; +- cmd->ident = ident; +- cmd->len = cpu_to_le16(len); +- +- memcpy(cmd->data, data, len); +- +- return cmd; +-} +- +-static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data) +-{ +- struct l2cap_chan *chan = mgr->a2mp_chan; +- struct a2mp_cmd *cmd; +- u16 total_len = len + sizeof(*cmd); +- struct kvec iv; +- struct msghdr msg; +- +- cmd = __a2mp_build(code, ident, len, data); +- if (!cmd) +- return; +- +- iv.iov_base = cmd; +- iv.iov_len = total_len; +- +- memset(&msg, 0, sizeof(msg)); +- +- iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iv, 1, total_len); +- +- l2cap_chan_send(chan, &msg, total_len); +- +- kfree(cmd); +-} +- +-static u8 __next_ident(struct amp_mgr *mgr) +-{ +- if (++mgr->ident == 0) +- mgr->ident = 1; +- +- return mgr->ident; +-} +- +-static struct amp_mgr *amp_mgr_lookup_by_state(u8 state) +-{ +- struct amp_mgr *mgr; +- +- mutex_lock(&_mgr_list_lock); +- list_for_each_entry(mgr, &_mgr_list, list) { +- if (test_and_clear_bit(state, &mgr->state)) { +- amp_mgr_get(mgr); +- mutex_unlock(&_mgr_list_lock); +- return mgr; +- } +- } +- mutex_unlock(&_mgr_list_lock); +- +- return NULL; +-} +- +-/* hci_dev_list shall be locked */ +-static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl) +-{ +- struct hci_dev *hdev; +- int i = 1; +- +- cl[0].id = AMP_ID_BREDR; +- cl[0].type = AMP_TYPE_BREDR; +- cl[0].status = AMP_STATUS_BLUETOOTH_ONLY; +- +- list_for_each_entry(hdev, &hci_dev_list, list) { +- if (hdev->dev_type == HCI_AMP) { +- cl[i].id = hdev->id; +- cl[i].type = hdev->amp_type; +- if (test_bit(HCI_UP, &hdev->flags)) +- cl[i].status = hdev->amp_status; +- else +- cl[i].status = AMP_STATUS_POWERED_DOWN; +- i++; +- } +- } +-} +- +-/* Processing A2MP messages */ +-static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb, +- struct a2mp_cmd *hdr) +-{ +- struct a2mp_cmd_rej *rej = (void *) skb->data; +- +- if (le16_to_cpu(hdr->len) < sizeof(*rej)) +- return -EINVAL; +- +- BT_DBG("ident %u reason %d", hdr->ident, le16_to_cpu(rej->reason)); +- +- skb_pull(skb, sizeof(*rej)); +- +- return 0; +-} +- +-static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb, +- struct a2mp_cmd *hdr) +-{ +- struct a2mp_discov_req *req = (void *) skb->data; +- u16 len = le16_to_cpu(hdr->len); +- struct a2mp_discov_rsp *rsp; +- u16 ext_feat; +- u8 num_ctrl; +- struct hci_dev *hdev; +- +- if (len < sizeof(*req)) +- return -EINVAL; +- +- skb_pull(skb, sizeof(*req)); +- +- ext_feat = le16_to_cpu(req->ext_feat); +- +- BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(req->mtu), ext_feat); +- +- /* check that packet is not broken for now */ +- while (ext_feat & A2MP_FEAT_EXT) { +- if (len < sizeof(ext_feat)) +- return -EINVAL; +- +- ext_feat = get_unaligned_le16(skb->data); +- BT_DBG("efm 0x%4.4x", ext_feat); +- len -= sizeof(ext_feat); +- skb_pull(skb, sizeof(ext_feat)); +- } +- +- read_lock(&hci_dev_list_lock); +- +- /* at minimum the BR/EDR needs to be listed */ +- num_ctrl = 1; +- +- list_for_each_entry(hdev, &hci_dev_list, list) { +- if (hdev->dev_type == HCI_AMP) +- num_ctrl++; +- } +- +- len = struct_size(rsp, cl, num_ctrl); +- rsp = kmalloc(len, GFP_ATOMIC); +- if (!rsp) { +- read_unlock(&hci_dev_list_lock); +- return -ENOMEM; +- } +- +- rsp->mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU); +- rsp->ext_feat = 0; +- +- __a2mp_add_cl(mgr, rsp->cl); +- +- read_unlock(&hci_dev_list_lock); +- +- a2mp_send(mgr, A2MP_DISCOVER_RSP, hdr->ident, len, rsp); +- +- kfree(rsp); +- return 0; +-} +- +-static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb, +- struct a2mp_cmd *hdr) +-{ +- struct a2mp_discov_rsp *rsp = (void *) skb->data; +- u16 len = le16_to_cpu(hdr->len); +- struct a2mp_cl *cl; +- u16 ext_feat; +- bool found = false; +- +- if (len < sizeof(*rsp)) +- return -EINVAL; +- +- len -= sizeof(*rsp); +- skb_pull(skb, sizeof(*rsp)); +- +- ext_feat = le16_to_cpu(rsp->ext_feat); +- +- BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(rsp->mtu), ext_feat); +- +- /* check that packet is not broken for now */ +- while (ext_feat & A2MP_FEAT_EXT) { +- if (len < sizeof(ext_feat)) +- return -EINVAL; +- +- ext_feat = get_unaligned_le16(skb->data); +- BT_DBG("efm 0x%4.4x", ext_feat); +- len -= sizeof(ext_feat); +- skb_pull(skb, sizeof(ext_feat)); +- } +- +- cl = (void *) skb->data; +- while (len >= sizeof(*cl)) { +- BT_DBG("Remote AMP id %u type %u status %u", cl->id, cl->type, +- cl->status); +- +- if (cl->id != AMP_ID_BREDR && cl->type != AMP_TYPE_BREDR) { +- struct a2mp_info_req req; +- +- found = true; +- +- memset(&req, 0, sizeof(req)); +- +- req.id = cl->id; +- a2mp_send(mgr, A2MP_GETINFO_REQ, __next_ident(mgr), +- sizeof(req), &req); +- } +- +- len -= sizeof(*cl); +- cl = skb_pull(skb, sizeof(*cl)); +- } +- +- /* Fall back to L2CAP init sequence */ +- if (!found) { +- struct l2cap_conn *conn = mgr->l2cap_conn; +- struct l2cap_chan *chan; +- +- mutex_lock(&conn->chan_lock); +- +- list_for_each_entry(chan, &conn->chan_l, list) { +- +- BT_DBG("chan %p state %s", chan, +- state_to_string(chan->state)); +- +- if (chan->scid == L2CAP_CID_A2MP) +- continue; +- +- l2cap_chan_lock(chan); +- +- if (chan->state == BT_CONNECT) +- l2cap_send_conn_req(chan); +- +- l2cap_chan_unlock(chan); +- } +- +- mutex_unlock(&conn->chan_lock); +- } +- +- return 0; +-} +- +-static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb, +- struct a2mp_cmd *hdr) +-{ +- struct a2mp_cl *cl = (void *) skb->data; +- +- while (skb->len >= sizeof(*cl)) { +- BT_DBG("Controller id %u type %u status %u", cl->id, cl->type, +- cl->status); +- cl = skb_pull(skb, sizeof(*cl)); +- } +- +- /* TODO send A2MP_CHANGE_RSP */ +- +- return 0; +-} +- +-static void read_local_amp_info_complete(struct hci_dev *hdev, u8 status, +- u16 opcode) +-{ +- BT_DBG("%s status 0x%2.2x", hdev->name, status); +- +- a2mp_send_getinfo_rsp(hdev); +-} +- +-static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb, +- struct a2mp_cmd *hdr) +-{ +- struct a2mp_info_req *req = (void *) skb->data; +- struct hci_dev *hdev; +- struct hci_request hreq; +- int err = 0; +- +- if (le16_to_cpu(hdr->len) < sizeof(*req)) +- return -EINVAL; +- +- BT_DBG("id %u", req->id); +- +- hdev = hci_dev_get(req->id); +- if (!hdev || hdev->dev_type != HCI_AMP) { +- struct a2mp_info_rsp rsp; +- +- memset(&rsp, 0, sizeof(rsp)); +- +- rsp.id = req->id; +- rsp.status = A2MP_STATUS_INVALID_CTRL_ID; +- +- a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp), +- &rsp); +- +- goto done; +- } +- +- set_bit(READ_LOC_AMP_INFO, &mgr->state); +- hci_req_init(&hreq, hdev); +- hci_req_add(&hreq, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL); +- err = hci_req_run(&hreq, read_local_amp_info_complete); +- if (err < 0) +- a2mp_send_getinfo_rsp(hdev); +- +-done: +- if (hdev) +- hci_dev_put(hdev); +- +- skb_pull(skb, sizeof(*req)); +- return 0; +-} +- +-static int a2mp_getinfo_rsp(struct amp_mgr *mgr, struct sk_buff *skb, +- struct a2mp_cmd *hdr) +-{ +- struct a2mp_info_rsp *rsp = (struct a2mp_info_rsp *) skb->data; +- struct a2mp_amp_assoc_req req; +- struct amp_ctrl *ctrl; +- +- if (le16_to_cpu(hdr->len) < sizeof(*rsp)) +- return -EINVAL; +- +- BT_DBG("id %u status 0x%2.2x", rsp->id, rsp->status); +- +- if (rsp->status) +- return -EINVAL; +- +- ctrl = amp_ctrl_add(mgr, rsp->id); +- if (!ctrl) +- return -ENOMEM; +- +- memset(&req, 0, sizeof(req)); +- +- req.id = rsp->id; +- a2mp_send(mgr, A2MP_GETAMPASSOC_REQ, __next_ident(mgr), sizeof(req), +- &req); +- +- skb_pull(skb, sizeof(*rsp)); +- return 0; +-} +- +-static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb, +- struct a2mp_cmd *hdr) +-{ +- struct a2mp_amp_assoc_req *req = (void *) skb->data; +- struct hci_dev *hdev; +- struct amp_mgr *tmp; +- +- if (le16_to_cpu(hdr->len) < sizeof(*req)) +- return -EINVAL; +- +- BT_DBG("id %u", req->id); +- +- /* Make sure that other request is not processed */ +- tmp = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC); +- +- hdev = hci_dev_get(req->id); +- if (!hdev || hdev->amp_type == AMP_TYPE_BREDR || tmp) { +- struct a2mp_amp_assoc_rsp rsp; +- +- memset(&rsp, 0, sizeof(rsp)); +- rsp.id = req->id; +- +- if (tmp) { +- rsp.status = A2MP_STATUS_COLLISION_OCCURED; +- amp_mgr_put(tmp); +- } else { +- rsp.status = A2MP_STATUS_INVALID_CTRL_ID; +- } +- +- a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp), +- &rsp); +- +- goto done; +- } +- +- amp_read_loc_assoc(hdev, mgr); +- +-done: +- if (hdev) +- hci_dev_put(hdev); +- +- skb_pull(skb, sizeof(*req)); +- return 0; +-} +- +-static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb, +- struct a2mp_cmd *hdr) +-{ +- struct a2mp_amp_assoc_rsp *rsp = (void *) skb->data; +- u16 len = le16_to_cpu(hdr->len); +- struct hci_dev *hdev; +- struct amp_ctrl *ctrl; +- struct hci_conn *hcon; +- size_t assoc_len; +- +- if (len < sizeof(*rsp)) +- return -EINVAL; +- +- assoc_len = len - sizeof(*rsp); +- +- BT_DBG("id %u status 0x%2.2x assoc len %zu", rsp->id, rsp->status, +- assoc_len); +- +- if (rsp->status) +- return -EINVAL; +- +- /* Save remote ASSOC data */ +- ctrl = amp_ctrl_lookup(mgr, rsp->id); +- if (ctrl) { +- u8 *assoc; +- +- assoc = kmemdup(rsp->amp_assoc, assoc_len, GFP_KERNEL); +- if (!assoc) { +- amp_ctrl_put(ctrl); +- return -ENOMEM; +- } +- +- ctrl->assoc = assoc; +- ctrl->assoc_len = assoc_len; +- ctrl->assoc_rem_len = assoc_len; +- ctrl->assoc_len_so_far = 0; +- +- amp_ctrl_put(ctrl); +- } +- +- /* Create Phys Link */ +- hdev = hci_dev_get(rsp->id); +- if (!hdev) +- return -EINVAL; +- +- hcon = phylink_add(hdev, mgr, rsp->id, true); +- if (!hcon) +- goto done; +- +- BT_DBG("Created hcon %p: loc:%u -> rem:%u", hcon, hdev->id, rsp->id); +- +- mgr->bredr_chan->remote_amp_id = rsp->id; +- +- amp_create_phylink(hdev, mgr, hcon); +- +-done: +- hci_dev_put(hdev); +- skb_pull(skb, len); +- return 0; +-} +- +-static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, +- struct a2mp_cmd *hdr) +-{ +- struct a2mp_physlink_req *req = (void *) skb->data; +- struct a2mp_physlink_rsp rsp; +- struct hci_dev *hdev; +- struct hci_conn *hcon; +- struct amp_ctrl *ctrl; +- +- if (le16_to_cpu(hdr->len) < sizeof(*req)) +- return -EINVAL; +- +- BT_DBG("local_id %u, remote_id %u", req->local_id, req->remote_id); +- +- memset(&rsp, 0, sizeof(rsp)); +- +- rsp.local_id = req->remote_id; +- rsp.remote_id = req->local_id; +- +- hdev = hci_dev_get(req->remote_id); +- if (!hdev || hdev->amp_type == AMP_TYPE_BREDR) { +- rsp.status = A2MP_STATUS_INVALID_CTRL_ID; +- goto send_rsp; +- } +- +- ctrl = amp_ctrl_lookup(mgr, rsp.remote_id); +- if (!ctrl) { +- ctrl = amp_ctrl_add(mgr, rsp.remote_id); +- if (ctrl) { +- amp_ctrl_get(ctrl); +- } else { +- rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION; +- goto send_rsp; +- } +- } +- +- if (ctrl) { +- size_t assoc_len = le16_to_cpu(hdr->len) - sizeof(*req); +- u8 *assoc; +- +- assoc = kmemdup(req->amp_assoc, assoc_len, GFP_KERNEL); +- if (!assoc) { +- amp_ctrl_put(ctrl); +- hci_dev_put(hdev); +- return -ENOMEM; +- } +- +- ctrl->assoc = assoc; +- ctrl->assoc_len = assoc_len; +- ctrl->assoc_rem_len = assoc_len; +- ctrl->assoc_len_so_far = 0; +- +- amp_ctrl_put(ctrl); +- } +- +- hcon = phylink_add(hdev, mgr, req->local_id, false); +- if (hcon) { +- amp_accept_phylink(hdev, mgr, hcon); +- rsp.status = A2MP_STATUS_SUCCESS; +- } else { +- rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION; +- } +- +-send_rsp: +- if (hdev) +- hci_dev_put(hdev); +- +- /* Reply error now and success after HCI Write Remote AMP Assoc +- command complete with success status +- */ +- if (rsp.status != A2MP_STATUS_SUCCESS) { +- a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident, +- sizeof(rsp), &rsp); +- } else { +- set_bit(WRITE_REMOTE_AMP_ASSOC, &mgr->state); +- mgr->ident = hdr->ident; +- } +- +- skb_pull(skb, le16_to_cpu(hdr->len)); +- return 0; +-} +- +-static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, +- struct a2mp_cmd *hdr) +-{ +- struct a2mp_physlink_req *req = (void *) skb->data; +- struct a2mp_physlink_rsp rsp; +- struct hci_dev *hdev; +- struct hci_conn *hcon; +- +- if (le16_to_cpu(hdr->len) < sizeof(*req)) +- return -EINVAL; +- +- BT_DBG("local_id %u remote_id %u", req->local_id, req->remote_id); +- +- memset(&rsp, 0, sizeof(rsp)); +- +- rsp.local_id = req->remote_id; +- rsp.remote_id = req->local_id; +- rsp.status = A2MP_STATUS_SUCCESS; +- +- hdev = hci_dev_get(req->remote_id); +- if (!hdev) { +- rsp.status = A2MP_STATUS_INVALID_CTRL_ID; +- goto send_rsp; +- } +- +- hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, +- &mgr->l2cap_conn->hcon->dst); +- if (!hcon) { +- bt_dev_err(hdev, "no phys link exist"); +- rsp.status = A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS; +- goto clean; +- } +- +- /* TODO Disconnect Phys Link here */ +- +-clean: +- hci_dev_put(hdev); +- +-send_rsp: +- a2mp_send(mgr, A2MP_DISCONNPHYSLINK_RSP, hdr->ident, sizeof(rsp), &rsp); +- +- skb_pull(skb, sizeof(*req)); +- return 0; +-} +- +-static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb, +- struct a2mp_cmd *hdr) +-{ +- BT_DBG("ident %u code 0x%2.2x", hdr->ident, hdr->code); +- +- skb_pull(skb, le16_to_cpu(hdr->len)); +- return 0; +-} +- +-/* Handle A2MP signalling */ +-static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) +-{ +- struct a2mp_cmd *hdr; +- struct amp_mgr *mgr = chan->data; +- int err = 0; +- +- amp_mgr_get(mgr); +- +- while (skb->len >= sizeof(*hdr)) { +- u16 len; +- +- hdr = (void *) skb->data; +- len = le16_to_cpu(hdr->len); +- +- BT_DBG("code 0x%2.2x id %u len %u", hdr->code, hdr->ident, len); +- +- skb_pull(skb, sizeof(*hdr)); +- +- if (len > skb->len || !hdr->ident) { +- err = -EINVAL; +- break; +- } +- +- mgr->ident = hdr->ident; +- +- switch (hdr->code) { +- case A2MP_COMMAND_REJ: +- a2mp_command_rej(mgr, skb, hdr); +- break; +- +- case A2MP_DISCOVER_REQ: +- err = a2mp_discover_req(mgr, skb, hdr); +- break; +- +- case A2MP_CHANGE_NOTIFY: +- err = a2mp_change_notify(mgr, skb, hdr); +- break; +- +- case A2MP_GETINFO_REQ: +- err = a2mp_getinfo_req(mgr, skb, hdr); +- break; +- +- case A2MP_GETAMPASSOC_REQ: +- err = a2mp_getampassoc_req(mgr, skb, hdr); +- break; +- +- case A2MP_CREATEPHYSLINK_REQ: +- err = a2mp_createphyslink_req(mgr, skb, hdr); +- break; +- +- case A2MP_DISCONNPHYSLINK_REQ: +- err = a2mp_discphyslink_req(mgr, skb, hdr); +- break; +- +- case A2MP_DISCOVER_RSP: +- err = a2mp_discover_rsp(mgr, skb, hdr); +- break; +- +- case A2MP_GETINFO_RSP: +- err = a2mp_getinfo_rsp(mgr, skb, hdr); +- break; +- +- case A2MP_GETAMPASSOC_RSP: +- err = a2mp_getampassoc_rsp(mgr, skb, hdr); +- break; +- +- case A2MP_CHANGE_RSP: +- case A2MP_CREATEPHYSLINK_RSP: +- case A2MP_DISCONNPHYSLINK_RSP: +- err = a2mp_cmd_rsp(mgr, skb, hdr); +- break; +- +- default: +- BT_ERR("Unknown A2MP sig cmd 0x%2.2x", hdr->code); +- err = -EINVAL; +- break; +- } +- } +- +- if (err) { +- struct a2mp_cmd_rej rej; +- +- memset(&rej, 0, sizeof(rej)); +- +- rej.reason = cpu_to_le16(0); +- hdr = (void *) skb->data; +- +- BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err); +- +- a2mp_send(mgr, A2MP_COMMAND_REJ, hdr->ident, sizeof(rej), +- &rej); +- } +- +- /* Always free skb and return success error code to prevent +- from sending L2CAP Disconnect over A2MP channel */ +- kfree_skb(skb); +- +- amp_mgr_put(mgr); +- +- return 0; +-} +- +-static void a2mp_chan_close_cb(struct l2cap_chan *chan) +-{ +- l2cap_chan_put(chan); +-} +- +-static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state, +- int err) +-{ +- struct amp_mgr *mgr = chan->data; +- +- if (!mgr) +- return; +- +- BT_DBG("chan %p state %s", chan, state_to_string(state)); +- +- chan->state = state; +- +- switch (state) { +- case BT_CLOSED: +- if (mgr) +- amp_mgr_put(mgr); +- break; +- } +-} +- +-static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan, +- unsigned long hdr_len, +- unsigned long len, int nb) +-{ +- struct sk_buff *skb; +- +- skb = bt_skb_alloc(hdr_len + len, GFP_KERNEL); +- if (!skb) +- return ERR_PTR(-ENOMEM); +- +- return skb; +-} +- +-static const struct l2cap_ops a2mp_chan_ops = { +- .name = "L2CAP A2MP channel", +- .recv = a2mp_chan_recv_cb, +- .close = a2mp_chan_close_cb, +- .state_change = a2mp_chan_state_change_cb, +- .alloc_skb = a2mp_chan_alloc_skb_cb, +- +- /* Not implemented for A2MP */ +- .new_connection = l2cap_chan_no_new_connection, +- .teardown = l2cap_chan_no_teardown, +- .ready = l2cap_chan_no_ready, +- .defer = l2cap_chan_no_defer, +- .resume = l2cap_chan_no_resume, +- .set_shutdown = l2cap_chan_no_set_shutdown, +- .get_sndtimeo = l2cap_chan_no_get_sndtimeo, +-}; +- +-static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked) +-{ +- struct l2cap_chan *chan; +- int err; +- +- chan = l2cap_chan_create(); +- if (!chan) +- return NULL; +- +- BT_DBG("chan %p", chan); +- +- chan->chan_type = L2CAP_CHAN_FIXED; +- chan->scid = L2CAP_CID_A2MP; +- chan->dcid = L2CAP_CID_A2MP; +- chan->omtu = L2CAP_A2MP_DEFAULT_MTU; +- chan->imtu = L2CAP_A2MP_DEFAULT_MTU; +- chan->flush_to = L2CAP_DEFAULT_FLUSH_TO; +- +- chan->ops = &a2mp_chan_ops; +- +- l2cap_chan_set_defaults(chan); +- chan->remote_max_tx = chan->max_tx; +- chan->remote_tx_win = chan->tx_win; +- +- chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO; +- chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO; +- +- skb_queue_head_init(&chan->tx_q); +- +- chan->mode = L2CAP_MODE_ERTM; +- +- err = l2cap_ertm_init(chan); +- if (err < 0) { +- l2cap_chan_del(chan, 0); +- return NULL; +- } +- +- chan->conf_state = 0; +- +- if (locked) +- __l2cap_chan_add(conn, chan); +- else +- l2cap_chan_add(conn, chan); +- +- chan->remote_mps = chan->omtu; +- chan->mps = chan->omtu; +- +- chan->state = BT_CONNECTED; +- +- return chan; +-} +- +-/* AMP Manager functions */ +-struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr) +-{ +- BT_DBG("mgr %p orig refcnt %d", mgr, kref_read(&mgr->kref)); +- +- kref_get(&mgr->kref); +- +- return mgr; +-} +- +-static void amp_mgr_destroy(struct kref *kref) +-{ +- struct amp_mgr *mgr = container_of(kref, struct amp_mgr, kref); +- +- BT_DBG("mgr %p", mgr); +- +- mutex_lock(&_mgr_list_lock); +- list_del(&mgr->list); +- mutex_unlock(&_mgr_list_lock); +- +- amp_ctrl_list_flush(mgr); +- kfree(mgr); +-} +- +-int amp_mgr_put(struct amp_mgr *mgr) +-{ +- BT_DBG("mgr %p orig refcnt %d", mgr, kref_read(&mgr->kref)); +- +- return kref_put(&mgr->kref, &_mgr_destroy); +-} +- +-static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn, bool locked) +-{ +- struct amp_mgr *mgr; +- struct l2cap_chan *chan; +- +- mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); +- if (!mgr) +- return NULL; +- +- BT_DBG("conn %p mgr %p", conn, mgr); +- +- mgr->l2cap_conn = conn; +- +- chan = a2mp_chan_open(conn, locked); +- if (!chan) { +- kfree(mgr); +- return NULL; +- } +- +- mgr->a2mp_chan = chan; +- chan->data = mgr; +- +- conn->hcon->amp_mgr = mgr; +- +- kref_init(&mgr->kref); +- +- /* Remote AMP ctrl list initialization */ +- INIT_LIST_HEAD(&mgr->amp_ctrls); +- mutex_init(&mgr->amp_ctrls_lock); +- +- mutex_lock(&_mgr_list_lock); +- list_add(&mgr->list, &_mgr_list); +- mutex_unlock(&_mgr_list_lock); +- +- return mgr; +-} +- +-struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, +- struct sk_buff *skb) +-{ +- struct amp_mgr *mgr; +- +- if (conn->hcon->type != ACL_LINK) +- return NULL; +- +- mgr = amp_mgr_create(conn, false); +- if (!mgr) { +- BT_ERR("Could not create AMP manager"); +- return NULL; +- } +- +- BT_DBG("mgr: %p chan %p", mgr, mgr->a2mp_chan); +- +- return mgr->a2mp_chan; +-} +- +-void a2mp_send_getinfo_rsp(struct hci_dev *hdev) +-{ +- struct amp_mgr *mgr; +- struct a2mp_info_rsp rsp; +- +- mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_INFO); +- if (!mgr) +- return; +- +- BT_DBG("%s mgr %p", hdev->name, mgr); +- +- memset(&rsp, 0, sizeof(rsp)); +- +- rsp.id = hdev->id; +- rsp.status = A2MP_STATUS_INVALID_CTRL_ID; +- +- if (hdev->amp_type != AMP_TYPE_BREDR) { +- rsp.status = 0; +- rsp.total_bw = cpu_to_le32(hdev->amp_total_bw); +- rsp.max_bw = cpu_to_le32(hdev->amp_max_bw); +- rsp.min_latency = cpu_to_le32(hdev->amp_min_latency); +- rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap); +- rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size); +- } +- +- a2mp_send(mgr, A2MP_GETINFO_RSP, mgr->ident, sizeof(rsp), &rsp); +- amp_mgr_put(mgr); +-} +- +-void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status) +-{ +- struct amp_mgr *mgr; +- struct amp_assoc *loc_assoc = &hdev->loc_assoc; +- struct a2mp_amp_assoc_rsp *rsp; +- size_t len; +- +- mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC); +- if (!mgr) +- return; +- +- BT_DBG("%s mgr %p", hdev->name, mgr); +- +- len = sizeof(struct a2mp_amp_assoc_rsp) + loc_assoc->len; +- rsp = kzalloc(len, GFP_KERNEL); +- if (!rsp) { +- amp_mgr_put(mgr); +- return; +- } +- +- rsp->id = hdev->id; +- +- if (status) { +- rsp->status = A2MP_STATUS_INVALID_CTRL_ID; +- } else { +- rsp->status = A2MP_STATUS_SUCCESS; +- memcpy(rsp->amp_assoc, loc_assoc->data, loc_assoc->len); +- } +- +- a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, mgr->ident, len, rsp); +- amp_mgr_put(mgr); +- kfree(rsp); +-} +- +-void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status) +-{ +- struct amp_mgr *mgr; +- struct amp_assoc *loc_assoc = &hdev->loc_assoc; +- struct a2mp_physlink_req *req; +- struct l2cap_chan *bredr_chan; +- size_t len; +- +- mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC_FINAL); +- if (!mgr) +- return; +- +- len = sizeof(*req) + loc_assoc->len; +- +- BT_DBG("%s mgr %p assoc_len %zu", hdev->name, mgr, len); +- +- req = kzalloc(len, GFP_KERNEL); +- if (!req) { +- amp_mgr_put(mgr); +- return; +- } +- +- bredr_chan = mgr->bredr_chan; +- if (!bredr_chan) +- goto clean; +- +- req->local_id = hdev->id; +- req->remote_id = bredr_chan->remote_amp_id; +- memcpy(req->amp_assoc, loc_assoc->data, loc_assoc->len); +- +- a2mp_send(mgr, A2MP_CREATEPHYSLINK_REQ, __next_ident(mgr), len, req); +- +-clean: +- amp_mgr_put(mgr); +- kfree(req); +-} +- +-void a2mp_send_create_phy_link_rsp(struct hci_dev *hdev, u8 status) +-{ +- struct amp_mgr *mgr; +- struct a2mp_physlink_rsp rsp; +- struct hci_conn *hs_hcon; +- +- mgr = amp_mgr_lookup_by_state(WRITE_REMOTE_AMP_ASSOC); +- if (!mgr) +- return; +- +- memset(&rsp, 0, sizeof(rsp)); +- +- hs_hcon = hci_conn_hash_lookup_state(hdev, AMP_LINK, BT_CONNECT); +- if (!hs_hcon) { +- rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION; +- } else { +- rsp.remote_id = hs_hcon->remote_id; +- rsp.status = A2MP_STATUS_SUCCESS; +- } +- +- BT_DBG("%s mgr %p hs_hcon %p status %u", hdev->name, mgr, hs_hcon, +- status); +- +- rsp.local_id = hdev->id; +- a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, mgr->ident, sizeof(rsp), &rsp); +- amp_mgr_put(mgr); +-} +- +-void a2mp_discover_amp(struct l2cap_chan *chan) +-{ +- struct l2cap_conn *conn = chan->conn; +- struct amp_mgr *mgr = conn->hcon->amp_mgr; +- struct a2mp_discov_req req; +- +- BT_DBG("chan %p conn %p mgr %p", chan, conn, mgr); +- +- if (!mgr) { +- mgr = amp_mgr_create(conn, true); +- if (!mgr) +- return; +- } +- +- mgr->bredr_chan = chan; +- +- memset(&req, 0, sizeof(req)); +- +- req.mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU); +- req.ext_feat = 0; +- a2mp_send(mgr, A2MP_DISCOVER_REQ, 1, sizeof(req), &req); +-} +diff --git a/net/bluetooth/a2mp.h b/net/bluetooth/a2mp.h +deleted file mode 100644 +index 2fd253a61a2a1..0000000000000 +--- a/net/bluetooth/a2mp.h ++++ /dev/null +@@ -1,154 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-only */ +-/* +- Copyright (c) 2010,2011 Code Aurora Forum. All rights reserved. +- Copyright (c) 2011,2012 Intel Corp. +- +-*/ +- +-#ifndef __A2MP_H +-#define __A2MP_H +- +-#include +- +-enum amp_mgr_state { +- READ_LOC_AMP_INFO, +- READ_LOC_AMP_ASSOC, +- READ_LOC_AMP_ASSOC_FINAL, +- WRITE_REMOTE_AMP_ASSOC, +-}; +- +-struct amp_mgr { +- struct list_head list; +- struct l2cap_conn *l2cap_conn; +- struct l2cap_chan *a2mp_chan; +- struct l2cap_chan *bredr_chan; +- struct kref kref; +- __u8 ident; +- __u8 handle; +- unsigned long state; +- unsigned long flags; +- +- struct list_head amp_ctrls; +- struct mutex amp_ctrls_lock; +-}; +- +-struct a2mp_cmd { +- __u8 code; +- __u8 ident; +- __le16 len; +- __u8 data[]; +-} __packed; +- +-/* A2MP command codes */ +-#define A2MP_COMMAND_REJ 0x01 +-struct a2mp_cmd_rej { +- __le16 reason; +- __u8 data[]; +-} __packed; +- +-#define A2MP_DISCOVER_REQ 0x02 +-struct a2mp_discov_req { +- __le16 mtu; +- __le16 ext_feat; +-} __packed; +- +-struct a2mp_cl { +- __u8 id; +- __u8 type; +- __u8 status; +-} __packed; +- +-#define A2MP_DISCOVER_RSP 0x03 +-struct a2mp_discov_rsp { +- __le16 mtu; +- __le16 ext_feat; +- struct a2mp_cl cl[]; +-} __packed; +- +-#define A2MP_CHANGE_NOTIFY 0x04 +-#define A2MP_CHANGE_RSP 0x05 +- +-#define A2MP_GETINFO_REQ 0x06 +-struct a2mp_info_req { +- __u8 id; +-} __packed; +- +-#define A2MP_GETINFO_RSP 0x07 +-struct a2mp_info_rsp { +- __u8 id; +- __u8 status; +- __le32 total_bw; +- __le32 max_bw; +- __le32 min_latency; +- __le16 pal_cap; +- __le16 assoc_size; +-} __packed; +- +-#define A2MP_GETAMPASSOC_REQ 0x08 +-struct a2mp_amp_assoc_req { +- __u8 id; +-} __packed; +- +-#define A2MP_GETAMPASSOC_RSP 0x09 +-struct a2mp_amp_assoc_rsp { +- __u8 id; +- __u8 status; +- __u8 amp_assoc[]; +-} __packed; +- +-#define A2MP_CREATEPHYSLINK_REQ 0x0A +-#define A2MP_DISCONNPHYSLINK_REQ 0x0C +-struct a2mp_physlink_req { +- __u8 local_id; +- __u8 remote_id; +- __u8 amp_assoc[]; +-} __packed; +- +-#define A2MP_CREATEPHYSLINK_RSP 0x0B +-#define A2MP_DISCONNPHYSLINK_RSP 0x0D +-struct a2mp_physlink_rsp { +- __u8 local_id; +- __u8 remote_id; +- __u8 status; +-} __packed; +- +-/* A2MP response status */ +-#define A2MP_STATUS_SUCCESS 0x00 +-#define A2MP_STATUS_INVALID_CTRL_ID 0x01 +-#define A2MP_STATUS_UNABLE_START_LINK_CREATION 0x02 +-#define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS 0x02 +-#define A2MP_STATUS_COLLISION_OCCURED 0x03 +-#define A2MP_STATUS_DISCONN_REQ_RECVD 0x04 +-#define A2MP_STATUS_PHYS_LINK_EXISTS 0x05 +-#define A2MP_STATUS_SECURITY_VIOLATION 0x06 +- +-struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr); +- +-#if IS_ENABLED(CONFIG_BT_HS) +-int amp_mgr_put(struct amp_mgr *mgr); +-struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, +- struct sk_buff *skb); +-void a2mp_discover_amp(struct l2cap_chan *chan); +-#else +-static inline int amp_mgr_put(struct amp_mgr *mgr) +-{ +- return 0; +-} +- +-static inline struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, +- struct sk_buff *skb) +-{ +- return NULL; +-} +- +-static inline void a2mp_discover_amp(struct l2cap_chan *chan) +-{ +-} +-#endif +- +-void a2mp_send_getinfo_rsp(struct hci_dev *hdev); +-void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status); +-void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status); +-void a2mp_send_create_phy_link_rsp(struct hci_dev *hdev, u8 status); +- +-#endif /* __A2MP_H */ +diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c +index b93464ac3517f..67604ccec2f42 100644 +--- a/net/bluetooth/af_bluetooth.c ++++ b/net/bluetooth/af_bluetooth.c +@@ -309,14 +309,11 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, + if (flags & MSG_OOB) + return -EOPNOTSUPP; + +- lock_sock(sk); +- + skb = skb_recv_datagram(sk, flags, &err); + if (!skb) { + if (sk->sk_shutdown & RCV_SHUTDOWN) + err = 0; + +- release_sock(sk); + return err; + } + +@@ -346,8 +343,6 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, + + skb_free_datagram(sk, skb); + +- release_sock(sk); +- + if (flags & MSG_TRUNC) + copied = skblen; + +@@ -570,10 +565,11 @@ int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) + if (sk->sk_state == BT_LISTEN) + return -EINVAL; + +- lock_sock(sk); ++ spin_lock(&sk->sk_receive_queue.lock); + skb = skb_peek(&sk->sk_receive_queue); + amount = skb ? skb->len : 0; +- release_sock(sk); ++ spin_unlock(&sk->sk_receive_queue.lock); ++ + err = put_user(amount, (int __user *)arg); + break; + +diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c +deleted file mode 100644 +index 5d698f19868c5..0000000000000 +--- a/net/bluetooth/amp.c ++++ /dev/null +@@ -1,590 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0-only +-/* +- Copyright (c) 2011,2012 Intel Corp. +- +-*/ +- +-#include +-#include +-#include +-#include +- +-#include "hci_request.h" +-#include "a2mp.h" +-#include "amp.h" +- +-/* Remote AMP Controllers interface */ +-void amp_ctrl_get(struct amp_ctrl *ctrl) +-{ +- BT_DBG("ctrl %p orig refcnt %d", ctrl, +- kref_read(&ctrl->kref)); +- +- kref_get(&ctrl->kref); +-} +- +-static void amp_ctrl_destroy(struct kref *kref) +-{ +- struct amp_ctrl *ctrl = container_of(kref, struct amp_ctrl, kref); +- +- BT_DBG("ctrl %p", ctrl); +- +- kfree(ctrl->assoc); +- kfree(ctrl); +-} +- +-int amp_ctrl_put(struct amp_ctrl *ctrl) +-{ +- BT_DBG("ctrl %p orig refcnt %d", ctrl, +- kref_read(&ctrl->kref)); +- +- return kref_put(&ctrl->kref, &_ctrl_destroy); +-} +- +-struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr, u8 id) +-{ +- struct amp_ctrl *ctrl; +- +- ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); +- if (!ctrl) +- return NULL; +- +- kref_init(&ctrl->kref); +- ctrl->id = id; +- +- mutex_lock(&mgr->amp_ctrls_lock); +- list_add(&ctrl->list, &mgr->amp_ctrls); +- mutex_unlock(&mgr->amp_ctrls_lock); +- +- BT_DBG("mgr %p ctrl %p", mgr, ctrl); +- +- return ctrl; +-} +- +-void amp_ctrl_list_flush(struct amp_mgr *mgr) +-{ +- struct amp_ctrl *ctrl, *n; +- +- BT_DBG("mgr %p", mgr); +- +- mutex_lock(&mgr->amp_ctrls_lock); +- list_for_each_entry_safe(ctrl, n, &mgr->amp_ctrls, list) { +- list_del(&ctrl->list); +- amp_ctrl_put(ctrl); +- } +- mutex_unlock(&mgr->amp_ctrls_lock); +-} +- +-struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id) +-{ +- struct amp_ctrl *ctrl; +- +- BT_DBG("mgr %p id %u", mgr, id); +- +- mutex_lock(&mgr->amp_ctrls_lock); +- list_for_each_entry(ctrl, &mgr->amp_ctrls, list) { +- if (ctrl->id == id) { +- amp_ctrl_get(ctrl); +- mutex_unlock(&mgr->amp_ctrls_lock); +- return ctrl; +- } +- } +- mutex_unlock(&mgr->amp_ctrls_lock); +- +- return NULL; +-} +- +-/* Physical Link interface */ +-static u8 __next_handle(struct amp_mgr *mgr) +-{ +- if (++mgr->handle == 0) +- mgr->handle = 1; +- +- return mgr->handle; +-} +- +-struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, +- u8 remote_id, bool out) +-{ +- bdaddr_t *dst = &mgr->l2cap_conn->hcon->dst; +- struct hci_conn *hcon; +- u8 role = out ? HCI_ROLE_MASTER : HCI_ROLE_SLAVE; +- +- hcon = hci_conn_add(hdev, AMP_LINK, dst, role, __next_handle(mgr)); +- if (!hcon) +- return NULL; +- +- BT_DBG("hcon %p dst %pMR", hcon, dst); +- +- hcon->state = BT_CONNECT; +- hcon->attempt++; +- hcon->remote_id = remote_id; +- hcon->amp_mgr = amp_mgr_get(mgr); +- +- return hcon; +-} +- +-/* AMP crypto key generation interface */ +-static int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output) +-{ +- struct crypto_shash *tfm; +- struct shash_desc *shash; +- int ret; +- +- if (!ksize) +- return -EINVAL; +- +- tfm = crypto_alloc_shash("hmac(sha256)", 0, 0); +- if (IS_ERR(tfm)) { +- BT_DBG("crypto_alloc_ahash failed: err %ld", PTR_ERR(tfm)); +- return PTR_ERR(tfm); +- } +- +- ret = crypto_shash_setkey(tfm, key, ksize); +- if (ret) { +- BT_DBG("crypto_ahash_setkey failed: err %d", ret); +- goto failed; +- } +- +- shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm), +- GFP_KERNEL); +- if (!shash) { +- ret = -ENOMEM; +- goto failed; +- } +- +- shash->tfm = tfm; +- +- ret = crypto_shash_digest(shash, plaintext, psize, output); +- +- kfree(shash); +- +-failed: +- crypto_free_shash(tfm); +- return ret; +-} +- +-int phylink_gen_key(struct hci_conn *conn, u8 *data, u8 *len, u8 *type) +-{ +- struct hci_dev *hdev = conn->hdev; +- struct link_key *key; +- u8 keybuf[HCI_AMP_LINK_KEY_SIZE]; +- u8 gamp_key[HCI_AMP_LINK_KEY_SIZE]; +- int err; +- +- if (!hci_conn_check_link_mode(conn)) +- return -EACCES; +- +- BT_DBG("conn %p key_type %d", conn, conn->key_type); +- +- /* Legacy key */ +- if (conn->key_type < 3) { +- bt_dev_err(hdev, "legacy key type %u", conn->key_type); +- return -EACCES; +- } +- +- *type = conn->key_type; +- *len = HCI_AMP_LINK_KEY_SIZE; +- +- key = hci_find_link_key(hdev, &conn->dst); +- if (!key) { +- BT_DBG("No Link key for conn %p dst %pMR", conn, &conn->dst); +- return -EACCES; +- } +- +- /* BR/EDR Link Key concatenated together with itself */ +- memcpy(&keybuf[0], key->val, HCI_LINK_KEY_SIZE); +- memcpy(&keybuf[HCI_LINK_KEY_SIZE], key->val, HCI_LINK_KEY_SIZE); +- +- /* Derive Generic AMP Link Key (gamp) */ +- err = hmac_sha256(keybuf, HCI_AMP_LINK_KEY_SIZE, "gamp", 4, gamp_key); +- if (err) { +- bt_dev_err(hdev, "could not derive Generic AMP Key: err %d", err); +- return err; +- } +- +- if (conn->key_type == HCI_LK_DEBUG_COMBINATION) { +- BT_DBG("Use Generic AMP Key (gamp)"); +- memcpy(data, gamp_key, HCI_AMP_LINK_KEY_SIZE); +- return err; +- } +- +- /* Derive Dedicated AMP Link Key: "802b" is 802.11 PAL keyID */ +- return hmac_sha256(gamp_key, HCI_AMP_LINK_KEY_SIZE, "802b", 4, data); +-} +- +-static void read_local_amp_assoc_complete(struct hci_dev *hdev, u8 status, +- u16 opcode, struct sk_buff *skb) +-{ +- struct hci_rp_read_local_amp_assoc *rp = (void *)skb->data; +- struct amp_assoc *assoc = &hdev->loc_assoc; +- size_t rem_len, frag_len; +- +- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); +- +- if (rp->status) +- goto send_rsp; +- +- frag_len = skb->len - sizeof(*rp); +- rem_len = __le16_to_cpu(rp->rem_len); +- +- if (rem_len > frag_len) { +- BT_DBG("frag_len %zu rem_len %zu", frag_len, rem_len); +- +- memcpy(assoc->data + assoc->offset, rp->frag, frag_len); +- assoc->offset += frag_len; +- +- /* Read other fragments */ +- amp_read_loc_assoc_frag(hdev, rp->phy_handle); +- +- return; +- } +- +- memcpy(assoc->data + assoc->offset, rp->frag, rem_len); +- assoc->len = assoc->offset + rem_len; +- assoc->offset = 0; +- +-send_rsp: +- /* Send A2MP Rsp when all fragments are received */ +- a2mp_send_getampassoc_rsp(hdev, rp->status); +- a2mp_send_create_phy_link_req(hdev, rp->status); +-} +- +-void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle) +-{ +- struct hci_cp_read_local_amp_assoc cp; +- struct amp_assoc *loc_assoc = &hdev->loc_assoc; +- struct hci_request req; +- int err; +- +- BT_DBG("%s handle %u", hdev->name, phy_handle); +- +- cp.phy_handle = phy_handle; +- cp.max_len = cpu_to_le16(hdev->amp_assoc_size); +- cp.len_so_far = cpu_to_le16(loc_assoc->offset); +- +- hci_req_init(&req, hdev); +- hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); +- err = hci_req_run_skb(&req, read_local_amp_assoc_complete); +- if (err < 0) +- a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID); +-} +- +-void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr) +-{ +- struct hci_cp_read_local_amp_assoc cp; +- struct hci_request req; +- int err; +- +- memset(&hdev->loc_assoc, 0, sizeof(struct amp_assoc)); +- memset(&cp, 0, sizeof(cp)); +- +- cp.max_len = cpu_to_le16(hdev->amp_assoc_size); +- +- set_bit(READ_LOC_AMP_ASSOC, &mgr->state); +- hci_req_init(&req, hdev); +- hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); +- err = hci_req_run_skb(&req, read_local_amp_assoc_complete); +- if (err < 0) +- a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID); +-} +- +-void amp_read_loc_assoc_final_data(struct hci_dev *hdev, +- struct hci_conn *hcon) +-{ +- struct hci_cp_read_local_amp_assoc cp; +- struct amp_mgr *mgr = hcon->amp_mgr; +- struct hci_request req; +- int err; +- +- if (!mgr) +- return; +- +- cp.phy_handle = hcon->handle; +- cp.len_so_far = cpu_to_le16(0); +- cp.max_len = cpu_to_le16(hdev->amp_assoc_size); +- +- set_bit(READ_LOC_AMP_ASSOC_FINAL, &mgr->state); +- +- /* Read Local AMP Assoc final link information data */ +- hci_req_init(&req, hdev); +- hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); +- err = hci_req_run_skb(&req, read_local_amp_assoc_complete); +- if (err < 0) +- a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID); +-} +- +-static void write_remote_amp_assoc_complete(struct hci_dev *hdev, u8 status, +- u16 opcode, struct sk_buff *skb) +-{ +- struct hci_rp_write_remote_amp_assoc *rp = (void *)skb->data; +- +- BT_DBG("%s status 0x%2.2x phy_handle 0x%2.2x", +- hdev->name, rp->status, rp->phy_handle); +- +- if (rp->status) +- return; +- +- amp_write_rem_assoc_continue(hdev, rp->phy_handle); +-} +- +-/* Write AMP Assoc data fragments, returns true with last fragment written*/ +-static bool amp_write_rem_assoc_frag(struct hci_dev *hdev, +- struct hci_conn *hcon) +-{ +- struct hci_cp_write_remote_amp_assoc *cp; +- struct amp_mgr *mgr = hcon->amp_mgr; +- struct amp_ctrl *ctrl; +- struct hci_request req; +- u16 frag_len, len; +- +- ctrl = amp_ctrl_lookup(mgr, hcon->remote_id); +- if (!ctrl) +- return false; +- +- if (!ctrl->assoc_rem_len) { +- BT_DBG("all fragments are written"); +- ctrl->assoc_rem_len = ctrl->assoc_len; +- ctrl->assoc_len_so_far = 0; +- +- amp_ctrl_put(ctrl); +- return true; +- } +- +- frag_len = min_t(u16, 248, ctrl->assoc_rem_len); +- len = frag_len + sizeof(*cp); +- +- cp = kzalloc(len, GFP_KERNEL); +- if (!cp) { +- amp_ctrl_put(ctrl); +- return false; +- } +- +- BT_DBG("hcon %p ctrl %p frag_len %u assoc_len %u rem_len %u", +- hcon, ctrl, frag_len, ctrl->assoc_len, ctrl->assoc_rem_len); +- +- cp->phy_handle = hcon->handle; +- cp->len_so_far = cpu_to_le16(ctrl->assoc_len_so_far); +- cp->rem_len = cpu_to_le16(ctrl->assoc_rem_len); +- memcpy(cp->frag, ctrl->assoc, frag_len); +- +- ctrl->assoc_len_so_far += frag_len; +- ctrl->assoc_rem_len -= frag_len; +- +- amp_ctrl_put(ctrl); +- +- hci_req_init(&req, hdev); +- hci_req_add(&req, HCI_OP_WRITE_REMOTE_AMP_ASSOC, len, cp); +- hci_req_run_skb(&req, write_remote_amp_assoc_complete); +- +- kfree(cp); +- +- return false; +-} +- +-void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle) +-{ +- struct hci_conn *hcon; +- +- BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle); +- +- hcon = hci_conn_hash_lookup_handle(hdev, handle); +- if (!hcon) +- return; +- +- /* Send A2MP create phylink rsp when all fragments are written */ +- if (amp_write_rem_assoc_frag(hdev, hcon)) +- a2mp_send_create_phy_link_rsp(hdev, 0); +-} +- +-void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle) +-{ +- struct hci_conn *hcon; +- +- BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle); +- +- hcon = hci_conn_hash_lookup_handle(hdev, handle); +- if (!hcon) +- return; +- +- BT_DBG("%s phy handle 0x%2.2x hcon %p", hdev->name, handle, hcon); +- +- amp_write_rem_assoc_frag(hdev, hcon); +-} +- +-static void create_phylink_complete(struct hci_dev *hdev, u8 status, +- u16 opcode) +-{ +- struct hci_cp_create_phy_link *cp; +- +- BT_DBG("%s status 0x%2.2x", hdev->name, status); +- +- cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK); +- if (!cp) +- return; +- +- hci_dev_lock(hdev); +- +- if (status) { +- struct hci_conn *hcon; +- +- hcon = hci_conn_hash_lookup_handle(hdev, cp->phy_handle); +- if (hcon) +- hci_conn_del(hcon); +- } else { +- amp_write_remote_assoc(hdev, cp->phy_handle); +- } +- +- hci_dev_unlock(hdev); +-} +- +-void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, +- struct hci_conn *hcon) +-{ +- struct hci_cp_create_phy_link cp; +- struct hci_request req; +- +- cp.phy_handle = hcon->handle; +- +- BT_DBG("%s hcon %p phy handle 0x%2.2x", hdev->name, hcon, +- hcon->handle); +- +- if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len, +- &cp.key_type)) { +- BT_DBG("Cannot create link key"); +- return; +- } +- +- hci_req_init(&req, hdev); +- hci_req_add(&req, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp); +- hci_req_run(&req, create_phylink_complete); +-} +- +-static void accept_phylink_complete(struct hci_dev *hdev, u8 status, +- u16 opcode) +-{ +- struct hci_cp_accept_phy_link *cp; +- +- BT_DBG("%s status 0x%2.2x", hdev->name, status); +- +- if (status) +- return; +- +- cp = hci_sent_cmd_data(hdev, HCI_OP_ACCEPT_PHY_LINK); +- if (!cp) +- return; +- +- amp_write_remote_assoc(hdev, cp->phy_handle); +-} +- +-void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, +- struct hci_conn *hcon) +-{ +- struct hci_cp_accept_phy_link cp; +- struct hci_request req; +- +- cp.phy_handle = hcon->handle; +- +- BT_DBG("%s hcon %p phy handle 0x%2.2x", hdev->name, hcon, +- hcon->handle); +- +- if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len, +- &cp.key_type)) { +- BT_DBG("Cannot create link key"); +- return; +- } +- +- hci_req_init(&req, hdev); +- hci_req_add(&req, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp); +- hci_req_run(&req, accept_phylink_complete); +-} +- +-void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon) +-{ +- struct hci_dev *bredr_hdev = hci_dev_hold(bredr_hcon->hdev); +- struct amp_mgr *mgr = hs_hcon->amp_mgr; +- struct l2cap_chan *bredr_chan; +- +- BT_DBG("bredr_hcon %p hs_hcon %p mgr %p", bredr_hcon, hs_hcon, mgr); +- +- if (!bredr_hdev || !mgr || !mgr->bredr_chan) +- return; +- +- bredr_chan = mgr->bredr_chan; +- +- l2cap_chan_lock(bredr_chan); +- +- set_bit(FLAG_EFS_ENABLE, &bredr_chan->flags); +- bredr_chan->remote_amp_id = hs_hcon->remote_id; +- bredr_chan->local_amp_id = hs_hcon->hdev->id; +- bredr_chan->hs_hcon = hs_hcon; +- bredr_chan->conn->mtu = hs_hcon->hdev->block_mtu; +- +- __l2cap_physical_cfm(bredr_chan, 0); +- +- l2cap_chan_unlock(bredr_chan); +- +- hci_dev_put(bredr_hdev); +-} +- +-void amp_create_logical_link(struct l2cap_chan *chan) +-{ +- struct hci_conn *hs_hcon = chan->hs_hcon; +- struct hci_cp_create_accept_logical_link cp; +- struct hci_dev *hdev; +- +- BT_DBG("chan %p hs_hcon %p dst %pMR", chan, hs_hcon, +- &chan->conn->hcon->dst); +- +- if (!hs_hcon) +- return; +- +- hdev = hci_dev_hold(chan->hs_hcon->hdev); +- if (!hdev) +- return; +- +- cp.phy_handle = hs_hcon->handle; +- +- cp.tx_flow_spec.id = chan->local_id; +- cp.tx_flow_spec.stype = chan->local_stype; +- cp.tx_flow_spec.msdu = cpu_to_le16(chan->local_msdu); +- cp.tx_flow_spec.sdu_itime = cpu_to_le32(chan->local_sdu_itime); +- cp.tx_flow_spec.acc_lat = cpu_to_le32(chan->local_acc_lat); +- cp.tx_flow_spec.flush_to = cpu_to_le32(chan->local_flush_to); +- +- cp.rx_flow_spec.id = chan->remote_id; +- cp.rx_flow_spec.stype = chan->remote_stype; +- cp.rx_flow_spec.msdu = cpu_to_le16(chan->remote_msdu); +- cp.rx_flow_spec.sdu_itime = cpu_to_le32(chan->remote_sdu_itime); +- cp.rx_flow_spec.acc_lat = cpu_to_le32(chan->remote_acc_lat); +- cp.rx_flow_spec.flush_to = cpu_to_le32(chan->remote_flush_to); +- +- if (hs_hcon->out) +- hci_send_cmd(hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp), +- &cp); +- else +- hci_send_cmd(hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp), +- &cp); +- +- hci_dev_put(hdev); +-} +- +-void amp_disconnect_logical_link(struct hci_chan *hchan) +-{ +- struct hci_conn *hcon = hchan->conn; +- struct hci_cp_disconn_logical_link cp; +- +- if (hcon->state != BT_CONNECTED) { +- BT_DBG("hchan %p not connected", hchan); +- return; +- } +- +- cp.log_handle = cpu_to_le16(hchan->handle); +- hci_send_cmd(hcon->hdev, HCI_OP_DISCONN_LOGICAL_LINK, sizeof(cp), &cp); +-} +- +-void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason) +-{ +- BT_DBG("hchan %p", hchan); +- +- hci_chan_del(hchan); +-} +diff --git a/net/bluetooth/amp.h b/net/bluetooth/amp.h +deleted file mode 100644 +index 97c87abd129f6..0000000000000 +--- a/net/bluetooth/amp.h ++++ /dev/null +@@ -1,60 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-only */ +-/* +- Copyright (c) 2011,2012 Intel Corp. +- +-*/ +- +-#ifndef __AMP_H +-#define __AMP_H +- +-struct amp_ctrl { +- struct list_head list; +- struct kref kref; +- __u8 id; +- __u16 assoc_len_so_far; +- __u16 assoc_rem_len; +- __u16 assoc_len; +- __u8 *assoc; +-}; +- +-int amp_ctrl_put(struct amp_ctrl *ctrl); +-void amp_ctrl_get(struct amp_ctrl *ctrl); +-struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr, u8 id); +-struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id); +-void amp_ctrl_list_flush(struct amp_mgr *mgr); +- +-struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, +- u8 remote_id, bool out); +- +-int phylink_gen_key(struct hci_conn *hcon, u8 *data, u8 *len, u8 *type); +- +-void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle); +-void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr); +-void amp_read_loc_assoc_final_data(struct hci_dev *hdev, +- struct hci_conn *hcon); +-void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, +- struct hci_conn *hcon); +-void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, +- struct hci_conn *hcon); +- +-#if IS_ENABLED(CONFIG_BT_HS) +-void amp_create_logical_link(struct l2cap_chan *chan); +-void amp_disconnect_logical_link(struct hci_chan *hchan); +-#else +-static inline void amp_create_logical_link(struct l2cap_chan *chan) +-{ +-} +- +-static inline void amp_disconnect_logical_link(struct hci_chan *hchan) +-{ +-} +-#endif +- +-void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle); +-void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle); +-void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon); +-void amp_create_logical_link(struct l2cap_chan *chan); +-void amp_disconnect_logical_link(struct hci_chan *hchan); +-void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason); +- +-#endif /* __AMP_H */ +diff --git a/net/bluetooth/eir.c b/net/bluetooth/eir.c +index 9214189279e80..1bc51e2b05a34 100644 +--- a/net/bluetooth/eir.c ++++ b/net/bluetooth/eir.c +@@ -13,48 +13,33 @@ + + #define PNP_INFO_SVCLASS_ID 0x1200 + +-static u8 eir_append_name(u8 *eir, u16 eir_len, u8 type, u8 *data, u8 data_len) +-{ +- u8 name[HCI_MAX_SHORT_NAME_LENGTH + 1]; +- +- /* If data is already NULL terminated just pass it directly */ +- if (data[data_len - 1] == '\0') +- return eir_append_data(eir, eir_len, type, data, data_len); +- +- memcpy(name, data, HCI_MAX_SHORT_NAME_LENGTH); +- name[HCI_MAX_SHORT_NAME_LENGTH] = '\0'; +- +- return eir_append_data(eir, eir_len, type, name, sizeof(name)); +-} +- + u8 eir_append_local_name(struct hci_dev *hdev, u8 *ptr, u8 ad_len) + { + size_t short_len; + size_t complete_len; + +- /* no space left for name (+ NULL + type + len) */ +- if ((max_adv_len(hdev) - ad_len) < HCI_MAX_SHORT_NAME_LENGTH + 3) ++ /* no space left for name (+ type + len) */ ++ if ((max_adv_len(hdev) - ad_len) < HCI_MAX_SHORT_NAME_LENGTH + 2) + return ad_len; + + /* use complete name if present and fits */ + complete_len = strnlen(hdev->dev_name, sizeof(hdev->dev_name)); + if (complete_len && complete_len <= HCI_MAX_SHORT_NAME_LENGTH) +- return eir_append_name(ptr, ad_len, EIR_NAME_COMPLETE, +- hdev->dev_name, complete_len + 1); ++ return eir_append_data(ptr, ad_len, EIR_NAME_COMPLETE, ++ hdev->dev_name, complete_len); + + /* use short name if present */ + short_len = strnlen(hdev->short_name, sizeof(hdev->short_name)); + if (short_len) +- return eir_append_name(ptr, ad_len, EIR_NAME_SHORT, ++ return eir_append_data(ptr, ad_len, EIR_NAME_SHORT, + hdev->short_name, +- short_len == HCI_MAX_SHORT_NAME_LENGTH ? +- short_len : short_len + 1); ++ short_len); + + /* use shortened full name if present, we already know that name + * is longer then HCI_MAX_SHORT_NAME_LENGTH + */ + if (complete_len) +- return eir_append_name(ptr, ad_len, EIR_NAME_SHORT, ++ return eir_append_data(ptr, ad_len, EIR_NAME_SHORT, + hdev->dev_name, + HCI_MAX_SHORT_NAME_LENGTH); + +diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c +index a41d2693f4d8c..ba330114d38f7 100644 +--- a/net/bluetooth/hci_conn.c ++++ b/net/bluetooth/hci_conn.c +@@ -36,7 +36,6 @@ + + #include "hci_request.h" + #include "smp.h" +-#include "a2mp.h" + #include "eir.h" + + struct sco_param { +@@ -1175,9 +1174,6 @@ void hci_conn_del(struct hci_conn *conn) + } + } + +- if (conn->amp_mgr) +- amp_mgr_put(conn->amp_mgr); +- + skb_queue_purge(&conn->data_q); + + /* Remove the connection from the list and cleanup its remaining +@@ -3014,7 +3010,7 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason) + case HCI_EV_LE_CONN_COMPLETE: + case HCI_EV_LE_ENHANCED_CONN_COMPLETE: + case HCI_EVT_LE_CIS_ESTABLISHED: +- hci_cmd_sync_cancel(hdev, -ECANCELED); ++ hci_cmd_sync_cancel(hdev, ECANCELED); + break; + } + } +diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c +index 2821a42cefdc6..7d5334b529834 100644 +--- a/net/bluetooth/hci_core.c ++++ b/net/bluetooth/hci_core.c +@@ -908,7 +908,7 @@ int hci_get_dev_info(void __user *arg) + else + flags = hdev->flags; + +- strcpy(di.name, hdev->name); ++ strscpy(di.name, hdev->name, sizeof(di.name)); + di.bdaddr = hdev->bdaddr; + di.type = (hdev->bus & 0x0f) | ((hdev->dev_type & 0x03) << 4); + di.flags = flags; +@@ -1491,11 +1491,12 @@ static void hci_cmd_timeout(struct work_struct *work) + struct hci_dev *hdev = container_of(work, struct hci_dev, + cmd_timer.work); + +- if (hdev->sent_cmd) { +- struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data; +- u16 opcode = __le16_to_cpu(sent->opcode); ++ if (hdev->req_skb) { ++ u16 opcode = hci_skb_opcode(hdev->req_skb); + + bt_dev_err(hdev, "command 0x%4.4x tx timeout", opcode); ++ ++ hci_cmd_sync_cancel_sync(hdev, ETIMEDOUT); + } else { + bt_dev_err(hdev, "command tx timeout"); + } +@@ -2795,6 +2796,7 @@ void hci_release_dev(struct hci_dev *hdev) + ida_destroy(&hdev->unset_handle_ida); + ida_simple_remove(&hci_index_ida, hdev->id); + kfree_skb(hdev->sent_cmd); ++ kfree_skb(hdev->req_skb); + kfree_skb(hdev->recv_event); + kfree(hdev); + } +@@ -2826,6 +2828,23 @@ int hci_unregister_suspend_notifier(struct hci_dev *hdev) + return ret; + } + ++/* Cancel ongoing command synchronously: ++ * ++ * - Cancel command timer ++ * - Reset command counter ++ * - Cancel command request ++ */ ++static void hci_cancel_cmd_sync(struct hci_dev *hdev, int err) ++{ ++ bt_dev_dbg(hdev, "err 0x%2.2x", err); ++ ++ cancel_delayed_work_sync(&hdev->cmd_timer); ++ cancel_delayed_work_sync(&hdev->ncmd_timer); ++ atomic_set(&hdev->cmd_cnt, 1); ++ ++ hci_cmd_sync_cancel_sync(hdev, -err); ++} ++ + /* Suspend HCI device */ + int hci_suspend_dev(struct hci_dev *hdev) + { +@@ -2843,7 +2862,7 @@ int hci_suspend_dev(struct hci_dev *hdev) + return 0; + + /* Cancel potentially blocking sync operation before suspend */ +- __hci_cmd_sync_cancel(hdev, -EHOSTDOWN); ++ hci_cancel_cmd_sync(hdev, -EHOSTDOWN); + + hci_req_sync_lock(hdev); + ret = hci_suspend_sync(hdev); +@@ -3107,21 +3126,33 @@ int __hci_cmd_send(struct hci_dev *hdev, u16 opcode, u32 plen, + EXPORT_SYMBOL(__hci_cmd_send); + + /* Get data from the previously sent command */ +-void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode) ++static void *hci_cmd_data(struct sk_buff *skb, __u16 opcode) + { + struct hci_command_hdr *hdr; + +- if (!hdev->sent_cmd) ++ if (!skb || skb->len < HCI_COMMAND_HDR_SIZE) + return NULL; + +- hdr = (void *) hdev->sent_cmd->data; ++ hdr = (void *)skb->data; + + if (hdr->opcode != cpu_to_le16(opcode)) + return NULL; + +- BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode); ++ return skb->data + HCI_COMMAND_HDR_SIZE; ++} ++ ++/* Get data from the previously sent command */ ++void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode) ++{ ++ void *data; + +- return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE; ++ /* Check if opcode matches last sent command */ ++ data = hci_cmd_data(hdev->sent_cmd, opcode); ++ if (!data) ++ /* Check if opcode matches last request */ ++ data = hci_cmd_data(hdev->req_skb, opcode); ++ ++ return data; + } + + /* Get data from last received event */ +@@ -4022,17 +4053,19 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status, + if (!status && !hci_req_is_complete(hdev)) + return; + ++ skb = hdev->req_skb; ++ + /* If this was the last command in a request the complete +- * callback would be found in hdev->sent_cmd instead of the ++ * callback would be found in hdev->req_skb instead of the + * command queue (hdev->cmd_q). + */ +- if (bt_cb(hdev->sent_cmd)->hci.req_flags & HCI_REQ_SKB) { +- *req_complete_skb = bt_cb(hdev->sent_cmd)->hci.req_complete_skb; ++ if (skb && bt_cb(skb)->hci.req_flags & HCI_REQ_SKB) { ++ *req_complete_skb = bt_cb(skb)->hci.req_complete_skb; + return; + } + +- if (bt_cb(hdev->sent_cmd)->hci.req_complete) { +- *req_complete = bt_cb(hdev->sent_cmd)->hci.req_complete; ++ if (skb && bt_cb(skb)->hci.req_complete) { ++ *req_complete = bt_cb(skb)->hci.req_complete; + return; + } + +@@ -4128,6 +4161,36 @@ static void hci_rx_work(struct work_struct *work) + } + } + ++static void hci_send_cmd_sync(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ int err; ++ ++ bt_dev_dbg(hdev, "skb %p", skb); ++ ++ kfree_skb(hdev->sent_cmd); ++ ++ hdev->sent_cmd = skb_clone(skb, GFP_KERNEL); ++ if (!hdev->sent_cmd) { ++ skb_queue_head(&hdev->cmd_q, skb); ++ queue_work(hdev->workqueue, &hdev->cmd_work); ++ return; ++ } ++ ++ err = hci_send_frame(hdev, skb); ++ if (err < 0) { ++ hci_cmd_sync_cancel_sync(hdev, err); ++ return; ++ } ++ ++ if (hci_req_status_pend(hdev) && ++ !hci_dev_test_and_set_flag(hdev, HCI_CMD_PENDING)) { ++ kfree_skb(hdev->req_skb); ++ hdev->req_skb = skb_clone(hdev->sent_cmd, GFP_KERNEL); ++ } ++ ++ atomic_dec(&hdev->cmd_cnt); ++} ++ + static void hci_cmd_work(struct work_struct *work) + { + struct hci_dev *hdev = container_of(work, struct hci_dev, cmd_work); +@@ -4142,30 +4205,15 @@ static void hci_cmd_work(struct work_struct *work) + if (!skb) + return; + +- kfree_skb(hdev->sent_cmd); +- +- hdev->sent_cmd = skb_clone(skb, GFP_KERNEL); +- if (hdev->sent_cmd) { +- int res; +- if (hci_req_status_pend(hdev)) +- hci_dev_set_flag(hdev, HCI_CMD_PENDING); +- atomic_dec(&hdev->cmd_cnt); ++ hci_send_cmd_sync(hdev, skb); + +- res = hci_send_frame(hdev, skb); +- if (res < 0) +- __hci_cmd_sync_cancel(hdev, -res); +- +- rcu_read_lock(); +- if (test_bit(HCI_RESET, &hdev->flags) || +- hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE)) +- cancel_delayed_work(&hdev->cmd_timer); +- else +- queue_delayed_work(hdev->workqueue, &hdev->cmd_timer, +- HCI_CMD_TIMEOUT); +- rcu_read_unlock(); +- } else { +- skb_queue_head(&hdev->cmd_q, skb); +- queue_work(hdev->workqueue, &hdev->cmd_work); +- } ++ rcu_read_lock(); ++ if (test_bit(HCI_RESET, &hdev->flags) || ++ hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE)) ++ cancel_delayed_work(&hdev->cmd_timer); ++ else ++ queue_delayed_work(hdev->workqueue, &hdev->cmd_timer, ++ HCI_CMD_TIMEOUT); ++ rcu_read_unlock(); + } + } +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index 2a5f5a7d2412b..6275b14b56927 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -36,8 +36,6 @@ + #include "hci_request.h" + #include "hci_debugfs.h" + #include "hci_codec.h" +-#include "a2mp.h" +-#include "amp.h" + #include "smp.h" + #include "msft.h" + #include "eir.h" +@@ -2526,9 +2524,7 @@ static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn, + * Only those in BT_CONFIG or BT_CONNECTED states can be + * considered connected. + */ +- if (conn && +- (conn->state == BT_CONFIG || conn->state == BT_CONNECTED) && +- !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) ++ if (conn && (conn->state == BT_CONFIG || conn->state == BT_CONNECTED)) + mgmt_device_connected(hdev, conn, name, name_len); + + if (discov->state == DISCOVERY_STOPPED) +@@ -3556,8 +3552,6 @@ static void hci_remote_name_evt(struct hci_dev *hdev, void *data, + + bt_dev_dbg(hdev, "status 0x%2.2x", ev->status); + +- hci_conn_check_pending(hdev); +- + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); +@@ -3762,8 +3756,9 @@ static void hci_remote_features_evt(struct hci_dev *hdev, void *data, + bacpy(&cp.bdaddr, &conn->dst); + cp.pscan_rep_mode = 0x02; + hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); +- } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) ++ } else { + mgmt_device_connected(hdev, conn, NULL, 0); ++ } + + if (!hci_outgoing_auth_needed(hdev, conn)) { + conn->state = BT_CONNECTED; +@@ -3936,6 +3931,11 @@ static u8 hci_cc_le_setup_iso_path(struct hci_dev *hdev, void *data, + * last. + */ + hci_connect_cfm(conn, rp->status); ++ ++ /* Notify device connected in case it is a BIG Sync */ ++ if (!rp->status && test_bit(HCI_CONN_BIG_SYNC, &conn->flags)) ++ mgmt_device_connected(hdev, conn, NULL, 0); ++ + break; + } + +@@ -4381,7 +4381,7 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, void *data, + * (since for this kind of commands there will not be a command + * complete event). + */ +- if (ev->status || (hdev->sent_cmd && !hci_skb_event(hdev->sent_cmd))) { ++ if (ev->status || (hdev->req_skb && !hci_skb_event(hdev->req_skb))) { + hci_req_cmd_complete(hdev, *opcode, ev->status, req_complete, + req_complete_skb); + if (hci_dev_test_flag(hdev, HCI_CMD_PENDING)) { +@@ -5010,8 +5010,9 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev, void *data, + bacpy(&cp.bdaddr, &conn->dst); + cp.pscan_rep_mode = 0x02; + hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); +- } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) ++ } else { + mgmt_device_connected(hdev, conn, NULL, 0); ++ } + + if (!hci_outgoing_auth_needed(hdev, conn)) { + conn->state = BT_CONNECTED; +@@ -5984,8 +5985,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, + goto unlock; + } + +- if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) +- mgmt_device_connected(hdev, conn, NULL, 0); ++ mgmt_device_connected(hdev, conn, NULL, 0); + + conn->sec_level = BT_SECURITY_LOW; + conn->state = BT_CONFIG; +@@ -7214,6 +7214,9 @@ static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data, + /* Notify iso layer */ + hci_connect_cfm(pa_sync, 0x00); + ++ /* Notify MGMT layer */ ++ mgmt_device_connected(hdev, pa_sync, NULL, 0); ++ + unlock: + hci_dev_unlock(hdev); + } +@@ -7324,10 +7327,10 @@ static void hci_le_meta_evt(struct hci_dev *hdev, void *data, + bt_dev_dbg(hdev, "subevent 0x%2.2x", ev->subevent); + + /* Only match event if command OGF is for LE */ +- if (hdev->sent_cmd && +- hci_opcode_ogf(hci_skb_opcode(hdev->sent_cmd)) == 0x08 && +- hci_skb_event(hdev->sent_cmd) == ev->subevent) { +- *opcode = hci_skb_opcode(hdev->sent_cmd); ++ if (hdev->req_skb && ++ hci_opcode_ogf(hci_skb_opcode(hdev->req_skb)) == 0x08 && ++ hci_skb_event(hdev->req_skb) == ev->subevent) { ++ *opcode = hci_skb_opcode(hdev->req_skb); + hci_req_cmd_complete(hdev, *opcode, 0x00, req_complete, + req_complete_skb); + } +@@ -7714,10 +7717,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) + } + + /* Only match event if command OGF is not for LE */ +- if (hdev->sent_cmd && +- hci_opcode_ogf(hci_skb_opcode(hdev->sent_cmd)) != 0x08 && +- hci_skb_event(hdev->sent_cmd) == event) { +- hci_req_cmd_complete(hdev, hci_skb_opcode(hdev->sent_cmd), ++ if (hdev->req_skb && ++ hci_opcode_ogf(hci_skb_opcode(hdev->req_skb)) != 0x08 && ++ hci_skb_event(hdev->req_skb) == event) { ++ hci_req_cmd_complete(hdev, hci_skb_opcode(hdev->req_skb), + status, &req_complete, &req_complete_skb); + req_evt = event; + } +diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c +index 6e023b0104b03..00e02138003ec 100644 +--- a/net/bluetooth/hci_request.c ++++ b/net/bluetooth/hci_request.c +@@ -895,7 +895,7 @@ void hci_request_setup(struct hci_dev *hdev) + + void hci_request_cancel_all(struct hci_dev *hdev) + { +- __hci_cmd_sync_cancel(hdev, ENODEV); ++ hci_cmd_sync_cancel_sync(hdev, ENODEV); + + cancel_interleave_scan(hdev); + } +diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c +index 5716345a26dfb..684a6ac02b80d 100644 +--- a/net/bluetooth/hci_sync.c ++++ b/net/bluetooth/hci_sync.c +@@ -32,6 +32,10 @@ static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode, + hdev->req_result = result; + hdev->req_status = HCI_REQ_DONE; + ++ /* Free the request command so it is not used as response */ ++ kfree_skb(hdev->req_skb); ++ hdev->req_skb = NULL; ++ + if (skb) { + struct sock *sk = hci_skb_sk(skb); + +@@ -39,7 +43,7 @@ static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode, + if (sk) + sock_put(sk); + +- hdev->req_skb = skb_get(skb); ++ hdev->req_rsp = skb_get(skb); + } + + wake_up_interruptible(&hdev->req_wait_q); +@@ -187,8 +191,8 @@ struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen, + + hdev->req_status = 0; + hdev->req_result = 0; +- skb = hdev->req_skb; +- hdev->req_skb = NULL; ++ skb = hdev->req_rsp; ++ hdev->req_rsp = NULL; + + bt_dev_dbg(hdev, "end: err %d", err); + +@@ -584,7 +588,7 @@ void hci_cmd_sync_clear(struct hci_dev *hdev) + mutex_unlock(&hdev->cmd_sync_work_lock); + } + +-void __hci_cmd_sync_cancel(struct hci_dev *hdev, int err) ++void hci_cmd_sync_cancel(struct hci_dev *hdev, int err) + { + bt_dev_dbg(hdev, "err 0x%2.2x", err); + +@@ -592,15 +596,17 @@ void __hci_cmd_sync_cancel(struct hci_dev *hdev, int err) + hdev->req_result = err; + hdev->req_status = HCI_REQ_CANCELED; + +- cancel_delayed_work_sync(&hdev->cmd_timer); +- cancel_delayed_work_sync(&hdev->ncmd_timer); +- atomic_set(&hdev->cmd_cnt, 1); +- +- wake_up_interruptible(&hdev->req_wait_q); ++ queue_work(hdev->workqueue, &hdev->cmd_sync_cancel_work); + } + } ++EXPORT_SYMBOL(hci_cmd_sync_cancel); + +-void hci_cmd_sync_cancel(struct hci_dev *hdev, int err) ++/* Cancel ongoing command request synchronously: ++ * ++ * - Set result and mark status to HCI_REQ_CANCELED ++ * - Wakeup command sync thread ++ */ ++void hci_cmd_sync_cancel_sync(struct hci_dev *hdev, int err) + { + bt_dev_dbg(hdev, "err 0x%2.2x", err); + +@@ -608,10 +614,10 @@ void hci_cmd_sync_cancel(struct hci_dev *hdev, int err) + hdev->req_result = err; + hdev->req_status = HCI_REQ_CANCELED; + +- queue_work(hdev->workqueue, &hdev->cmd_sync_cancel_work); ++ wake_up_interruptible(&hdev->req_wait_q); + } + } +-EXPORT_SYMBOL(hci_cmd_sync_cancel); ++EXPORT_SYMBOL(hci_cmd_sync_cancel_sync); + + /* Submit HCI command to be run in as cmd_sync_work: + * +@@ -4834,6 +4840,11 @@ int hci_dev_open_sync(struct hci_dev *hdev) + hdev->sent_cmd = NULL; + } + ++ if (hdev->req_skb) { ++ kfree_skb(hdev->req_skb); ++ hdev->req_skb = NULL; ++ } ++ + clear_bit(HCI_RUNNING, &hdev->flags); + hci_sock_dev_event(hdev, HCI_DEV_CLOSE); + +@@ -4994,6 +5005,12 @@ int hci_dev_close_sync(struct hci_dev *hdev) + hdev->sent_cmd = NULL; + } + ++ /* Drop last request */ ++ if (hdev->req_skb) { ++ kfree_skb(hdev->req_skb); ++ hdev->req_skb = NULL; ++ } ++ + clear_bit(HCI_RUNNING, &hdev->flags); + hci_sock_dev_event(hdev, HCI_DEV_CLOSE); + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 656f49b299d20..ab5a9d42fae71 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -39,8 +39,6 @@ + #include + + #include "smp.h" +-#include "a2mp.h" +-#include "amp.h" + + #define LE_FLOWCTL_MAX_CREDITS 65535 + +@@ -167,24 +165,6 @@ static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, + return NULL; + } + +-static struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, +- u8 ident) +-{ +- struct l2cap_chan *c; +- +- mutex_lock(&conn->chan_lock); +- c = __l2cap_get_chan_by_ident(conn, ident); +- if (c) { +- /* Only lock if chan reference is not 0 */ +- c = l2cap_chan_hold_unless_zero(c); +- if (c) +- l2cap_chan_lock(c); +- } +- mutex_unlock(&conn->chan_lock); +- +- return c; +-} +- + static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src, + u8 src_type) + { +@@ -651,7 +631,6 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) + chan->ops->teardown(chan, err); + + if (conn) { +- struct amp_mgr *mgr = conn->hcon->amp_mgr; + /* Delete from channel list */ + list_del(&chan->list); + +@@ -666,16 +645,6 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) + if (chan->chan_type != L2CAP_CHAN_FIXED || + test_bit(FLAG_HOLD_HCI_CONN, &chan->flags)) + hci_conn_drop(conn->hcon); +- +- if (mgr && mgr->bredr_chan == chan) +- mgr->bredr_chan = NULL; +- } +- +- if (chan->hs_hchan) { +- struct hci_chan *hs_hchan = chan->hs_hchan; +- +- BT_DBG("chan %p disconnect hs_hchan %p", chan, hs_hchan); +- amp_disconnect_logical_link(hs_hchan); + } + + if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state)) +@@ -977,12 +946,6 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, + hci_send_acl(conn->hchan, skb, flags); + } + +-static bool __chan_is_moving(struct l2cap_chan *chan) +-{ +- return chan->move_state != L2CAP_MOVE_STABLE && +- chan->move_state != L2CAP_MOVE_WAIT_PREPARE; +-} +- + static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) + { + struct hci_conn *hcon = chan->conn->hcon; +@@ -991,15 +954,6 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) + BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len, + skb->priority); + +- if (chan->hs_hcon && !__chan_is_moving(chan)) { +- if (chan->hs_hchan) +- hci_send_acl(chan->hs_hchan, skb, ACL_COMPLETE); +- else +- kfree_skb(skb); +- +- return; +- } +- + /* Use NO_FLUSH for LE links (where this is the only option) or + * if the BR/EDR link supports it and flushing has not been + * explicitly requested (through FLAG_FLUSHABLE). +@@ -1180,9 +1134,6 @@ static void l2cap_send_sframe(struct l2cap_chan *chan, + if (!control->sframe) + return; + +- if (__chan_is_moving(chan)) +- return; +- + if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state) && + !control->poll) + control->final = 1; +@@ -1237,40 +1188,6 @@ static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) + return !test_bit(CONF_CONNECT_PEND, &chan->conf_state); + } + +-static bool __amp_capable(struct l2cap_chan *chan) +-{ +- struct l2cap_conn *conn = chan->conn; +- struct hci_dev *hdev; +- bool amp_available = false; +- +- if (!(conn->local_fixed_chan & L2CAP_FC_A2MP)) +- return false; +- +- if (!(conn->remote_fixed_chan & L2CAP_FC_A2MP)) +- return false; +- +- read_lock(&hci_dev_list_lock); +- list_for_each_entry(hdev, &hci_dev_list, list) { +- if (hdev->amp_type != AMP_TYPE_BREDR && +- test_bit(HCI_UP, &hdev->flags)) { +- amp_available = true; +- break; +- } +- } +- read_unlock(&hci_dev_list_lock); +- +- if (chan->chan_policy == BT_CHANNEL_POLICY_AMP_PREFERRED) +- return amp_available; +- +- return false; +-} +- +-static bool l2cap_check_efs(struct l2cap_chan *chan) +-{ +- /* Check EFS parameters */ +- return true; +-} +- + void l2cap_send_conn_req(struct l2cap_chan *chan) + { + struct l2cap_conn *conn = chan->conn; +@@ -1286,76 +1203,6 @@ void l2cap_send_conn_req(struct l2cap_chan *chan) + l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); + } + +-static void l2cap_send_create_chan_req(struct l2cap_chan *chan, u8 amp_id) +-{ +- struct l2cap_create_chan_req req; +- req.scid = cpu_to_le16(chan->scid); +- req.psm = chan->psm; +- req.amp_id = amp_id; +- +- chan->ident = l2cap_get_ident(chan->conn); +- +- l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_REQ, +- sizeof(req), &req); +-} +- +-static void l2cap_move_setup(struct l2cap_chan *chan) +-{ +- struct sk_buff *skb; +- +- BT_DBG("chan %p", chan); +- +- if (chan->mode != L2CAP_MODE_ERTM) +- return; +- +- __clear_retrans_timer(chan); +- __clear_monitor_timer(chan); +- __clear_ack_timer(chan); +- +- chan->retry_count = 0; +- skb_queue_walk(&chan->tx_q, skb) { +- if (bt_cb(skb)->l2cap.retries) +- bt_cb(skb)->l2cap.retries = 1; +- else +- break; +- } +- +- chan->expected_tx_seq = chan->buffer_seq; +- +- clear_bit(CONN_REJ_ACT, &chan->conn_state); +- clear_bit(CONN_SREJ_ACT, &chan->conn_state); +- l2cap_seq_list_clear(&chan->retrans_list); +- l2cap_seq_list_clear(&chan->srej_list); +- skb_queue_purge(&chan->srej_q); +- +- chan->tx_state = L2CAP_TX_STATE_XMIT; +- chan->rx_state = L2CAP_RX_STATE_MOVE; +- +- set_bit(CONN_REMOTE_BUSY, &chan->conn_state); +-} +- +-static void l2cap_move_done(struct l2cap_chan *chan) +-{ +- u8 move_role = chan->move_role; +- BT_DBG("chan %p", chan); +- +- chan->move_state = L2CAP_MOVE_STABLE; +- chan->move_role = L2CAP_MOVE_ROLE_NONE; +- +- if (chan->mode != L2CAP_MODE_ERTM) +- return; +- +- switch (move_role) { +- case L2CAP_MOVE_ROLE_INITIATOR: +- l2cap_tx(chan, NULL, NULL, L2CAP_EV_EXPLICIT_POLL); +- chan->rx_state = L2CAP_RX_STATE_WAIT_F; +- break; +- case L2CAP_MOVE_ROLE_RESPONDER: +- chan->rx_state = L2CAP_RX_STATE_WAIT_P; +- break; +- } +-} +- + static void l2cap_chan_ready(struct l2cap_chan *chan) + { + /* The channel may have already been flagged as connected in +@@ -1505,10 +1352,7 @@ static void l2cap_le_start(struct l2cap_chan *chan) + + static void l2cap_start_connection(struct l2cap_chan *chan) + { +- if (__amp_capable(chan)) { +- BT_DBG("chan %p AMP capable: discover AMPs", chan); +- a2mp_discover_amp(chan); +- } else if (chan->conn->hcon->type == LE_LINK) { ++ if (chan->conn->hcon->type == LE_LINK) { + l2cap_le_start(chan); + } else { + l2cap_send_conn_req(chan); +@@ -1611,11 +1455,6 @@ static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err) + __clear_ack_timer(chan); + } + +- if (chan->scid == L2CAP_CID_A2MP) { +- l2cap_state_change(chan, BT_DISCONN); +- return; +- } +- + req.dcid = cpu_to_le16(chan->dcid); + req.scid = cpu_to_le16(chan->scid); + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_DISCONN_REQ, +@@ -1754,11 +1593,6 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) + + l2cap_chan_lock(chan); + +- if (chan->scid == L2CAP_CID_A2MP) { +- l2cap_chan_unlock(chan); +- continue; +- } +- + if (hcon->type == LE_LINK) { + l2cap_le_start(chan); + } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { +@@ -2067,9 +1901,6 @@ static void l2cap_streaming_send(struct l2cap_chan *chan, + + BT_DBG("chan %p, skbs %p", chan, skbs); + +- if (__chan_is_moving(chan)) +- return; +- + skb_queue_splice_tail_init(skbs, &chan->tx_q); + + while (!skb_queue_empty(&chan->tx_q)) { +@@ -2112,9 +1943,6 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) + if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) + return 0; + +- if (__chan_is_moving(chan)) +- return 0; +- + while (chan->tx_send_head && + chan->unacked_frames < chan->remote_tx_win && + chan->tx_state == L2CAP_TX_STATE_XMIT) { +@@ -2180,9 +2008,6 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan) + if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) + return; + +- if (__chan_is_moving(chan)) +- return; +- + while (chan->retrans_list.head != L2CAP_SEQ_LIST_CLEAR) { + seq = l2cap_seq_list_pop(&chan->retrans_list); + +@@ -2522,8 +2347,7 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan, + pdu_len = chan->conn->mtu; + + /* Constrain PDU size for BR/EDR connections */ +- if (!chan->hs_hcon) +- pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD); ++ pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD); + + /* Adjust for largest possible L2CAP overhead. */ + if (chan->fcs) +@@ -3287,11 +3111,6 @@ int l2cap_ertm_init(struct l2cap_chan *chan) + + skb_queue_head_init(&chan->tx_q); + +- chan->local_amp_id = AMP_ID_BREDR; +- chan->move_id = AMP_ID_BREDR; +- chan->move_state = L2CAP_MOVE_STABLE; +- chan->move_role = L2CAP_MOVE_ROLE_NONE; +- + if (chan->mode != L2CAP_MODE_ERTM) + return 0; + +@@ -3326,52 +3145,19 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) + + static inline bool __l2cap_ews_supported(struct l2cap_conn *conn) + { +- return ((conn->local_fixed_chan & L2CAP_FC_A2MP) && +- (conn->feat_mask & L2CAP_FEAT_EXT_WINDOW)); ++ return (conn->feat_mask & L2CAP_FEAT_EXT_WINDOW); + } + + static inline bool __l2cap_efs_supported(struct l2cap_conn *conn) + { +- return ((conn->local_fixed_chan & L2CAP_FC_A2MP) && +- (conn->feat_mask & L2CAP_FEAT_EXT_FLOW)); ++ return (conn->feat_mask & L2CAP_FEAT_EXT_FLOW); + } + + static void __l2cap_set_ertm_timeouts(struct l2cap_chan *chan, + struct l2cap_conf_rfc *rfc) + { +- if (chan->local_amp_id != AMP_ID_BREDR && chan->hs_hcon) { +- u64 ertm_to = chan->hs_hcon->hdev->amp_be_flush_to; +- +- /* Class 1 devices have must have ERTM timeouts +- * exceeding the Link Supervision Timeout. The +- * default Link Supervision Timeout for AMP +- * controllers is 10 seconds. +- * +- * Class 1 devices use 0xffffffff for their +- * best-effort flush timeout, so the clamping logic +- * will result in a timeout that meets the above +- * requirement. ERTM timeouts are 16-bit values, so +- * the maximum timeout is 65.535 seconds. +- */ +- +- /* Convert timeout to milliseconds and round */ +- ertm_to = DIV_ROUND_UP_ULL(ertm_to, 1000); +- +- /* This is the recommended formula for class 2 devices +- * that start ERTM timers when packets are sent to the +- * controller. +- */ +- ertm_to = 3 * ertm_to + 500; +- +- if (ertm_to > 0xffff) +- ertm_to = 0xffff; +- +- rfc->retrans_timeout = cpu_to_le16((u16) ertm_to); +- rfc->monitor_timeout = rfc->retrans_timeout; +- } else { +- rfc->retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); +- rfc->monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); +- } ++ rfc->retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); ++ rfc->monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); + } + + static inline void l2cap_txwin_setup(struct l2cap_chan *chan) +@@ -3623,13 +3409,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data + case L2CAP_CONF_EWS: + if (olen != 2) + break; +- if (!(chan->conn->local_fixed_chan & L2CAP_FC_A2MP)) +- return -ECONNREFUSED; +- set_bit(FLAG_EXT_CTRL, &chan->flags); +- set_bit(CONF_EWS_RECV, &chan->conf_state); +- chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW; +- chan->remote_tx_win = val; +- break; ++ return -ECONNREFUSED; + + default: + if (hint) +@@ -4027,11 +3807,7 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan) + rsp.dcid = cpu_to_le16(chan->scid); + rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); + rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); +- +- if (chan->hs_hcon) +- rsp_code = L2CAP_CREATE_CHAN_RSP; +- else +- rsp_code = L2CAP_CONN_RSP; ++ rsp_code = L2CAP_CONN_RSP; + + BT_DBG("chan %p rsp_code %u", chan, rsp_code); + +@@ -4190,7 +3966,6 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, + chan->dst_type = bdaddr_dst_type(conn->hcon); + chan->psm = psm; + chan->dcid = scid; +- chan->local_amp_id = amp_id; + + __l2cap_chan_add(conn, chan); + +@@ -4516,10 +4291,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, + /* check compatibility */ + + /* Send rsp for BR/EDR channel */ +- if (!chan->hs_hcon) +- l2cap_send_efs_conf_rsp(chan, rsp, cmd->ident, flags); +- else +- chan->ident = cmd->ident; ++ l2cap_send_efs_conf_rsp(chan, rsp, cmd->ident, flags); + } + + unlock: +@@ -4571,15 +4343,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, + goto done; + } + +- if (!chan->hs_hcon) { +- l2cap_send_efs_conf_rsp(chan, buf, cmd->ident, +- 0); +- } else { +- if (l2cap_check_efs(chan)) { +- amp_create_logical_link(chan); +- chan->ident = cmd->ident; +- } +- } ++ l2cap_send_efs_conf_rsp(chan, buf, cmd->ident, 0); + } + goto done; + +@@ -4750,9 +4514,6 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, + if (!disable_ertm) + feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING + | L2CAP_FEAT_FCS; +- if (conn->local_fixed_chan & L2CAP_FC_A2MP) +- feat_mask |= L2CAP_FEAT_EXT_FLOW +- | L2CAP_FEAT_EXT_WINDOW; + + put_unaligned_le32(feat_mask, rsp->data); + l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(buf), +@@ -4841,751 +4602,6 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, + return 0; + } + +-static int l2cap_create_channel_req(struct l2cap_conn *conn, +- struct l2cap_cmd_hdr *cmd, +- u16 cmd_len, void *data) +-{ +- struct l2cap_create_chan_req *req = data; +- struct l2cap_create_chan_rsp rsp; +- struct l2cap_chan *chan; +- struct hci_dev *hdev; +- u16 psm, scid; +- +- if (cmd_len != sizeof(*req)) +- return -EPROTO; +- +- if (!(conn->local_fixed_chan & L2CAP_FC_A2MP)) +- return -EINVAL; +- +- psm = le16_to_cpu(req->psm); +- scid = le16_to_cpu(req->scid); +- +- BT_DBG("psm 0x%2.2x, scid 0x%4.4x, amp_id %d", psm, scid, req->amp_id); +- +- /* For controller id 0 make BR/EDR connection */ +- if (req->amp_id == AMP_ID_BREDR) { +- l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP, +- req->amp_id); +- return 0; +- } +- +- /* Validate AMP controller id */ +- hdev = hci_dev_get(req->amp_id); +- if (!hdev) +- goto error; +- +- if (hdev->dev_type != HCI_AMP || !test_bit(HCI_UP, &hdev->flags)) { +- hci_dev_put(hdev); +- goto error; +- } +- +- chan = l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP, +- req->amp_id); +- if (chan) { +- struct amp_mgr *mgr = conn->hcon->amp_mgr; +- struct hci_conn *hs_hcon; +- +- hs_hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, +- &conn->hcon->dst); +- if (!hs_hcon) { +- hci_dev_put(hdev); +- cmd_reject_invalid_cid(conn, cmd->ident, chan->scid, +- chan->dcid); +- return 0; +- } +- +- BT_DBG("mgr %p bredr_chan %p hs_hcon %p", mgr, chan, hs_hcon); +- +- mgr->bredr_chan = chan; +- chan->hs_hcon = hs_hcon; +- chan->fcs = L2CAP_FCS_NONE; +- conn->mtu = hdev->block_mtu; +- } +- +- hci_dev_put(hdev); +- +- return 0; +- +-error: +- rsp.dcid = 0; +- rsp.scid = cpu_to_le16(scid); +- rsp.result = cpu_to_le16(L2CAP_CR_BAD_AMP); +- rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); +- +- l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP, +- sizeof(rsp), &rsp); +- +- return 0; +-} +- +-static void l2cap_send_move_chan_req(struct l2cap_chan *chan, u8 dest_amp_id) +-{ +- struct l2cap_move_chan_req req; +- u8 ident; +- +- BT_DBG("chan %p, dest_amp_id %d", chan, dest_amp_id); +- +- ident = l2cap_get_ident(chan->conn); +- chan->ident = ident; +- +- req.icid = cpu_to_le16(chan->scid); +- req.dest_amp_id = dest_amp_id; +- +- l2cap_send_cmd(chan->conn, ident, L2CAP_MOVE_CHAN_REQ, sizeof(req), +- &req); +- +- __set_chan_timer(chan, L2CAP_MOVE_TIMEOUT); +-} +- +-static void l2cap_send_move_chan_rsp(struct l2cap_chan *chan, u16 result) +-{ +- struct l2cap_move_chan_rsp rsp; +- +- BT_DBG("chan %p, result 0x%4.4x", chan, result); +- +- rsp.icid = cpu_to_le16(chan->dcid); +- rsp.result = cpu_to_le16(result); +- +- l2cap_send_cmd(chan->conn, chan->ident, L2CAP_MOVE_CHAN_RSP, +- sizeof(rsp), &rsp); +-} +- +-static void l2cap_send_move_chan_cfm(struct l2cap_chan *chan, u16 result) +-{ +- struct l2cap_move_chan_cfm cfm; +- +- BT_DBG("chan %p, result 0x%4.4x", chan, result); +- +- chan->ident = l2cap_get_ident(chan->conn); +- +- cfm.icid = cpu_to_le16(chan->scid); +- cfm.result = cpu_to_le16(result); +- +- l2cap_send_cmd(chan->conn, chan->ident, L2CAP_MOVE_CHAN_CFM, +- sizeof(cfm), &cfm); +- +- __set_chan_timer(chan, L2CAP_MOVE_TIMEOUT); +-} +- +-static void l2cap_send_move_chan_cfm_icid(struct l2cap_conn *conn, u16 icid) +-{ +- struct l2cap_move_chan_cfm cfm; +- +- BT_DBG("conn %p, icid 0x%4.4x", conn, icid); +- +- cfm.icid = cpu_to_le16(icid); +- cfm.result = cpu_to_le16(L2CAP_MC_UNCONFIRMED); +- +- l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_MOVE_CHAN_CFM, +- sizeof(cfm), &cfm); +-} +- +-static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident, +- u16 icid) +-{ +- struct l2cap_move_chan_cfm_rsp rsp; +- +- BT_DBG("icid 0x%4.4x", icid); +- +- rsp.icid = cpu_to_le16(icid); +- l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp); +-} +- +-static void __release_logical_link(struct l2cap_chan *chan) +-{ +- chan->hs_hchan = NULL; +- chan->hs_hcon = NULL; +- +- /* Placeholder - release the logical link */ +-} +- +-static void l2cap_logical_fail(struct l2cap_chan *chan) +-{ +- /* Logical link setup failed */ +- if (chan->state != BT_CONNECTED) { +- /* Create channel failure, disconnect */ +- l2cap_send_disconn_req(chan, ECONNRESET); +- return; +- } +- +- switch (chan->move_role) { +- case L2CAP_MOVE_ROLE_RESPONDER: +- l2cap_move_done(chan); +- l2cap_send_move_chan_rsp(chan, L2CAP_MR_NOT_SUPP); +- break; +- case L2CAP_MOVE_ROLE_INITIATOR: +- if (chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_COMP || +- chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_CFM) { +- /* Remote has only sent pending or +- * success responses, clean up +- */ +- l2cap_move_done(chan); +- } +- +- /* Other amp move states imply that the move +- * has already aborted +- */ +- l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); +- break; +- } +-} +- +-static void l2cap_logical_finish_create(struct l2cap_chan *chan, +- struct hci_chan *hchan) +-{ +- struct l2cap_conf_rsp rsp; +- +- chan->hs_hchan = hchan; +- chan->hs_hcon->l2cap_data = chan->conn; +- +- l2cap_send_efs_conf_rsp(chan, &rsp, chan->ident, 0); +- +- if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) { +- int err; +- +- set_default_fcs(chan); +- +- err = l2cap_ertm_init(chan); +- if (err < 0) +- l2cap_send_disconn_req(chan, -err); +- else +- l2cap_chan_ready(chan); +- } +-} +- +-static void l2cap_logical_finish_move(struct l2cap_chan *chan, +- struct hci_chan *hchan) +-{ +- chan->hs_hcon = hchan->conn; +- chan->hs_hcon->l2cap_data = chan->conn; +- +- BT_DBG("move_state %d", chan->move_state); +- +- switch (chan->move_state) { +- case L2CAP_MOVE_WAIT_LOGICAL_COMP: +- /* Move confirm will be sent after a success +- * response is received +- */ +- chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS; +- break; +- case L2CAP_MOVE_WAIT_LOGICAL_CFM: +- if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { +- chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY; +- } else if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) { +- chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP; +- l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED); +- } else if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) { +- chan->move_state = L2CAP_MOVE_WAIT_CONFIRM; +- l2cap_send_move_chan_rsp(chan, L2CAP_MR_SUCCESS); +- } +- break; +- default: +- /* Move was not in expected state, free the channel */ +- __release_logical_link(chan); +- +- chan->move_state = L2CAP_MOVE_STABLE; +- } +-} +- +-/* Call with chan locked */ +-void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan, +- u8 status) +-{ +- BT_DBG("chan %p, hchan %p, status %d", chan, hchan, status); +- +- if (status) { +- l2cap_logical_fail(chan); +- __release_logical_link(chan); +- return; +- } +- +- if (chan->state != BT_CONNECTED) { +- /* Ignore logical link if channel is on BR/EDR */ +- if (chan->local_amp_id != AMP_ID_BREDR) +- l2cap_logical_finish_create(chan, hchan); +- } else { +- l2cap_logical_finish_move(chan, hchan); +- } +-} +- +-void l2cap_move_start(struct l2cap_chan *chan) +-{ +- BT_DBG("chan %p", chan); +- +- if (chan->local_amp_id == AMP_ID_BREDR) { +- if (chan->chan_policy != BT_CHANNEL_POLICY_AMP_PREFERRED) +- return; +- chan->move_role = L2CAP_MOVE_ROLE_INITIATOR; +- chan->move_state = L2CAP_MOVE_WAIT_PREPARE; +- /* Placeholder - start physical link setup */ +- } else { +- chan->move_role = L2CAP_MOVE_ROLE_INITIATOR; +- chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS; +- chan->move_id = 0; +- l2cap_move_setup(chan); +- l2cap_send_move_chan_req(chan, 0); +- } +-} +- +-static void l2cap_do_create(struct l2cap_chan *chan, int result, +- u8 local_amp_id, u8 remote_amp_id) +-{ +- BT_DBG("chan %p state %s %u -> %u", chan, state_to_string(chan->state), +- local_amp_id, remote_amp_id); +- +- chan->fcs = L2CAP_FCS_NONE; +- +- /* Outgoing channel on AMP */ +- if (chan->state == BT_CONNECT) { +- if (result == L2CAP_CR_SUCCESS) { +- chan->local_amp_id = local_amp_id; +- l2cap_send_create_chan_req(chan, remote_amp_id); +- } else { +- /* Revert to BR/EDR connect */ +- l2cap_send_conn_req(chan); +- } +- +- return; +- } +- +- /* Incoming channel on AMP */ +- if (__l2cap_no_conn_pending(chan)) { +- struct l2cap_conn_rsp rsp; +- char buf[128]; +- rsp.scid = cpu_to_le16(chan->dcid); +- rsp.dcid = cpu_to_le16(chan->scid); +- +- if (result == L2CAP_CR_SUCCESS) { +- /* Send successful response */ +- rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); +- rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); +- } else { +- /* Send negative response */ +- rsp.result = cpu_to_le16(L2CAP_CR_NO_MEM); +- rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); +- } +- +- l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_RSP, +- sizeof(rsp), &rsp); +- +- if (result == L2CAP_CR_SUCCESS) { +- l2cap_state_change(chan, BT_CONFIG); +- set_bit(CONF_REQ_SENT, &chan->conf_state); +- l2cap_send_cmd(chan->conn, l2cap_get_ident(chan->conn), +- L2CAP_CONF_REQ, +- l2cap_build_conf_req(chan, buf, sizeof(buf)), buf); +- chan->num_conf_req++; +- } +- } +-} +- +-static void l2cap_do_move_initiate(struct l2cap_chan *chan, u8 local_amp_id, +- u8 remote_amp_id) +-{ +- l2cap_move_setup(chan); +- chan->move_id = local_amp_id; +- chan->move_state = L2CAP_MOVE_WAIT_RSP; +- +- l2cap_send_move_chan_req(chan, remote_amp_id); +-} +- +-static void l2cap_do_move_respond(struct l2cap_chan *chan, int result) +-{ +- struct hci_chan *hchan = NULL; +- +- /* Placeholder - get hci_chan for logical link */ +- +- if (hchan) { +- if (hchan->state == BT_CONNECTED) { +- /* Logical link is ready to go */ +- chan->hs_hcon = hchan->conn; +- chan->hs_hcon->l2cap_data = chan->conn; +- chan->move_state = L2CAP_MOVE_WAIT_CONFIRM; +- l2cap_send_move_chan_rsp(chan, L2CAP_MR_SUCCESS); +- +- l2cap_logical_cfm(chan, hchan, L2CAP_MR_SUCCESS); +- } else { +- /* Wait for logical link to be ready */ +- chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM; +- } +- } else { +- /* Logical link not available */ +- l2cap_send_move_chan_rsp(chan, L2CAP_MR_NOT_ALLOWED); +- } +-} +- +-static void l2cap_do_move_cancel(struct l2cap_chan *chan, int result) +-{ +- if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) { +- u8 rsp_result; +- if (result == -EINVAL) +- rsp_result = L2CAP_MR_BAD_ID; +- else +- rsp_result = L2CAP_MR_NOT_ALLOWED; +- +- l2cap_send_move_chan_rsp(chan, rsp_result); +- } +- +- chan->move_role = L2CAP_MOVE_ROLE_NONE; +- chan->move_state = L2CAP_MOVE_STABLE; +- +- /* Restart data transmission */ +- l2cap_ertm_send(chan); +-} +- +-/* Invoke with locked chan */ +-void __l2cap_physical_cfm(struct l2cap_chan *chan, int result) +-{ +- u8 local_amp_id = chan->local_amp_id; +- u8 remote_amp_id = chan->remote_amp_id; +- +- BT_DBG("chan %p, result %d, local_amp_id %d, remote_amp_id %d", +- chan, result, local_amp_id, remote_amp_id); +- +- if (chan->state == BT_DISCONN || chan->state == BT_CLOSED) +- return; +- +- if (chan->state != BT_CONNECTED) { +- l2cap_do_create(chan, result, local_amp_id, remote_amp_id); +- } else if (result != L2CAP_MR_SUCCESS) { +- l2cap_do_move_cancel(chan, result); +- } else { +- switch (chan->move_role) { +- case L2CAP_MOVE_ROLE_INITIATOR: +- l2cap_do_move_initiate(chan, local_amp_id, +- remote_amp_id); +- break; +- case L2CAP_MOVE_ROLE_RESPONDER: +- l2cap_do_move_respond(chan, result); +- break; +- default: +- l2cap_do_move_cancel(chan, result); +- break; +- } +- } +-} +- +-static inline int l2cap_move_channel_req(struct l2cap_conn *conn, +- struct l2cap_cmd_hdr *cmd, +- u16 cmd_len, void *data) +-{ +- struct l2cap_move_chan_req *req = data; +- struct l2cap_move_chan_rsp rsp; +- struct l2cap_chan *chan; +- u16 icid = 0; +- u16 result = L2CAP_MR_NOT_ALLOWED; +- +- if (cmd_len != sizeof(*req)) +- return -EPROTO; +- +- icid = le16_to_cpu(req->icid); +- +- BT_DBG("icid 0x%4.4x, dest_amp_id %d", icid, req->dest_amp_id); +- +- if (!(conn->local_fixed_chan & L2CAP_FC_A2MP)) +- return -EINVAL; +- +- chan = l2cap_get_chan_by_dcid(conn, icid); +- if (!chan) { +- rsp.icid = cpu_to_le16(icid); +- rsp.result = cpu_to_le16(L2CAP_MR_NOT_ALLOWED); +- l2cap_send_cmd(conn, cmd->ident, L2CAP_MOVE_CHAN_RSP, +- sizeof(rsp), &rsp); +- return 0; +- } +- +- chan->ident = cmd->ident; +- +- if (chan->scid < L2CAP_CID_DYN_START || +- chan->chan_policy == BT_CHANNEL_POLICY_BREDR_ONLY || +- (chan->mode != L2CAP_MODE_ERTM && +- chan->mode != L2CAP_MODE_STREAMING)) { +- result = L2CAP_MR_NOT_ALLOWED; +- goto send_move_response; +- } +- +- if (chan->local_amp_id == req->dest_amp_id) { +- result = L2CAP_MR_SAME_ID; +- goto send_move_response; +- } +- +- if (req->dest_amp_id != AMP_ID_BREDR) { +- struct hci_dev *hdev; +- hdev = hci_dev_get(req->dest_amp_id); +- if (!hdev || hdev->dev_type != HCI_AMP || +- !test_bit(HCI_UP, &hdev->flags)) { +- if (hdev) +- hci_dev_put(hdev); +- +- result = L2CAP_MR_BAD_ID; +- goto send_move_response; +- } +- hci_dev_put(hdev); +- } +- +- /* Detect a move collision. Only send a collision response +- * if this side has "lost", otherwise proceed with the move. +- * The winner has the larger bd_addr. +- */ +- if ((__chan_is_moving(chan) || +- chan->move_role != L2CAP_MOVE_ROLE_NONE) && +- bacmp(&conn->hcon->src, &conn->hcon->dst) > 0) { +- result = L2CAP_MR_COLLISION; +- goto send_move_response; +- } +- +- chan->move_role = L2CAP_MOVE_ROLE_RESPONDER; +- l2cap_move_setup(chan); +- chan->move_id = req->dest_amp_id; +- +- if (req->dest_amp_id == AMP_ID_BREDR) { +- /* Moving to BR/EDR */ +- if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { +- chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY; +- result = L2CAP_MR_PEND; +- } else { +- chan->move_state = L2CAP_MOVE_WAIT_CONFIRM; +- result = L2CAP_MR_SUCCESS; +- } +- } else { +- chan->move_state = L2CAP_MOVE_WAIT_PREPARE; +- /* Placeholder - uncomment when amp functions are available */ +- /*amp_accept_physical(chan, req->dest_amp_id);*/ +- result = L2CAP_MR_PEND; +- } +- +-send_move_response: +- l2cap_send_move_chan_rsp(chan, result); +- +- l2cap_chan_unlock(chan); +- l2cap_chan_put(chan); +- +- return 0; +-} +- +-static void l2cap_move_continue(struct l2cap_conn *conn, u16 icid, u16 result) +-{ +- struct l2cap_chan *chan; +- struct hci_chan *hchan = NULL; +- +- chan = l2cap_get_chan_by_scid(conn, icid); +- if (!chan) { +- l2cap_send_move_chan_cfm_icid(conn, icid); +- return; +- } +- +- __clear_chan_timer(chan); +- if (result == L2CAP_MR_PEND) +- __set_chan_timer(chan, L2CAP_MOVE_ERTX_TIMEOUT); +- +- switch (chan->move_state) { +- case L2CAP_MOVE_WAIT_LOGICAL_COMP: +- /* Move confirm will be sent when logical link +- * is complete. +- */ +- chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM; +- break; +- case L2CAP_MOVE_WAIT_RSP_SUCCESS: +- if (result == L2CAP_MR_PEND) { +- break; +- } else if (test_bit(CONN_LOCAL_BUSY, +- &chan->conn_state)) { +- chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY; +- } else { +- /* Logical link is up or moving to BR/EDR, +- * proceed with move +- */ +- chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP; +- l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED); +- } +- break; +- case L2CAP_MOVE_WAIT_RSP: +- /* Moving to AMP */ +- if (result == L2CAP_MR_SUCCESS) { +- /* Remote is ready, send confirm immediately +- * after logical link is ready +- */ +- chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM; +- } else { +- /* Both logical link and move success +- * are required to confirm +- */ +- chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_COMP; +- } +- +- /* Placeholder - get hci_chan for logical link */ +- if (!hchan) { +- /* Logical link not available */ +- l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); +- break; +- } +- +- /* If the logical link is not yet connected, do not +- * send confirmation. +- */ +- if (hchan->state != BT_CONNECTED) +- break; +- +- /* Logical link is already ready to go */ +- +- chan->hs_hcon = hchan->conn; +- chan->hs_hcon->l2cap_data = chan->conn; +- +- if (result == L2CAP_MR_SUCCESS) { +- /* Can confirm now */ +- l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED); +- } else { +- /* Now only need move success +- * to confirm +- */ +- chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS; +- } +- +- l2cap_logical_cfm(chan, hchan, L2CAP_MR_SUCCESS); +- break; +- default: +- /* Any other amp move state means the move failed. */ +- chan->move_id = chan->local_amp_id; +- l2cap_move_done(chan); +- l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); +- } +- +- l2cap_chan_unlock(chan); +- l2cap_chan_put(chan); +-} +- +-static void l2cap_move_fail(struct l2cap_conn *conn, u8 ident, u16 icid, +- u16 result) +-{ +- struct l2cap_chan *chan; +- +- chan = l2cap_get_chan_by_ident(conn, ident); +- if (!chan) { +- /* Could not locate channel, icid is best guess */ +- l2cap_send_move_chan_cfm_icid(conn, icid); +- return; +- } +- +- __clear_chan_timer(chan); +- +- if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) { +- if (result == L2CAP_MR_COLLISION) { +- chan->move_role = L2CAP_MOVE_ROLE_RESPONDER; +- } else { +- /* Cleanup - cancel move */ +- chan->move_id = chan->local_amp_id; +- l2cap_move_done(chan); +- } +- } +- +- l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED); +- +- l2cap_chan_unlock(chan); +- l2cap_chan_put(chan); +-} +- +-static int l2cap_move_channel_rsp(struct l2cap_conn *conn, +- struct l2cap_cmd_hdr *cmd, +- u16 cmd_len, void *data) +-{ +- struct l2cap_move_chan_rsp *rsp = data; +- u16 icid, result; +- +- if (cmd_len != sizeof(*rsp)) +- return -EPROTO; +- +- icid = le16_to_cpu(rsp->icid); +- result = le16_to_cpu(rsp->result); +- +- BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); +- +- if (result == L2CAP_MR_SUCCESS || result == L2CAP_MR_PEND) +- l2cap_move_continue(conn, icid, result); +- else +- l2cap_move_fail(conn, cmd->ident, icid, result); +- +- return 0; +-} +- +-static int l2cap_move_channel_confirm(struct l2cap_conn *conn, +- struct l2cap_cmd_hdr *cmd, +- u16 cmd_len, void *data) +-{ +- struct l2cap_move_chan_cfm *cfm = data; +- struct l2cap_chan *chan; +- u16 icid, result; +- +- if (cmd_len != sizeof(*cfm)) +- return -EPROTO; +- +- icid = le16_to_cpu(cfm->icid); +- result = le16_to_cpu(cfm->result); +- +- BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); +- +- chan = l2cap_get_chan_by_dcid(conn, icid); +- if (!chan) { +- /* Spec requires a response even if the icid was not found */ +- l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid); +- return 0; +- } +- +- if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM) { +- if (result == L2CAP_MC_CONFIRMED) { +- chan->local_amp_id = chan->move_id; +- if (chan->local_amp_id == AMP_ID_BREDR) +- __release_logical_link(chan); +- } else { +- chan->move_id = chan->local_amp_id; +- } +- +- l2cap_move_done(chan); +- } +- +- l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid); +- +- l2cap_chan_unlock(chan); +- l2cap_chan_put(chan); +- +- return 0; +-} +- +-static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn, +- struct l2cap_cmd_hdr *cmd, +- u16 cmd_len, void *data) +-{ +- struct l2cap_move_chan_cfm_rsp *rsp = data; +- struct l2cap_chan *chan; +- u16 icid; +- +- if (cmd_len != sizeof(*rsp)) +- return -EPROTO; +- +- icid = le16_to_cpu(rsp->icid); +- +- BT_DBG("icid 0x%4.4x", icid); +- +- chan = l2cap_get_chan_by_scid(conn, icid); +- if (!chan) +- return 0; +- +- __clear_chan_timer(chan); +- +- if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM_RSP) { +- chan->local_amp_id = chan->move_id; +- +- if (chan->local_amp_id == AMP_ID_BREDR && chan->hs_hchan) +- __release_logical_link(chan); +- +- l2cap_move_done(chan); +- } +- +- l2cap_chan_unlock(chan); +- l2cap_chan_put(chan); +- +- return 0; +-} +- + static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, + struct l2cap_cmd_hdr *cmd, + u16 cmd_len, u8 *data) +@@ -5745,7 +4761,6 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, + break; + + case L2CAP_CONN_RSP: +- case L2CAP_CREATE_CHAN_RSP: + l2cap_connect_create_rsp(conn, cmd, cmd_len, data); + break; + +@@ -5780,26 +4795,6 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, + l2cap_information_rsp(conn, cmd, cmd_len, data); + break; + +- case L2CAP_CREATE_CHAN_REQ: +- err = l2cap_create_channel_req(conn, cmd, cmd_len, data); +- break; +- +- case L2CAP_MOVE_CHAN_REQ: +- err = l2cap_move_channel_req(conn, cmd, cmd_len, data); +- break; +- +- case L2CAP_MOVE_CHAN_RSP: +- l2cap_move_channel_rsp(conn, cmd, cmd_len, data); +- break; +- +- case L2CAP_MOVE_CHAN_CFM: +- err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data); +- break; +- +- case L2CAP_MOVE_CHAN_CFM_RSP: +- l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data); +- break; +- + default: + BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code); + err = -EINVAL; +@@ -7051,8 +6046,8 @@ static int l2cap_rx_state_recv(struct l2cap_chan *chan, + if (control->final) { + clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); + +- if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state) && +- !__chan_is_moving(chan)) { ++ if (!test_and_clear_bit(CONN_REJ_ACT, ++ &chan->conn_state)) { + control->final = 0; + l2cap_retransmit_all(chan, control); + } +@@ -7245,11 +6240,7 @@ static int l2cap_finish_move(struct l2cap_chan *chan) + BT_DBG("chan %p", chan); + + chan->rx_state = L2CAP_RX_STATE_RECV; +- +- if (chan->hs_hcon) +- chan->conn->mtu = chan->hs_hcon->hdev->block_mtu; +- else +- chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu; ++ chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu; + + return l2cap_resegment(chan); + } +@@ -7316,11 +6307,7 @@ static int l2cap_rx_state_wait_f(struct l2cap_chan *chan, + */ + chan->next_tx_seq = control->reqseq; + chan->unacked_frames = 0; +- +- if (chan->hs_hcon) +- chan->conn->mtu = chan->hs_hcon->hdev->block_mtu; +- else +- chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu; ++ chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu; + + err = l2cap_resegment(chan); + +@@ -7672,21 +6659,10 @@ static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid, + + chan = l2cap_get_chan_by_scid(conn, cid); + if (!chan) { +- if (cid == L2CAP_CID_A2MP) { +- chan = a2mp_channel_create(conn, skb); +- if (!chan) { +- kfree_skb(skb); +- return; +- } +- +- l2cap_chan_hold(chan); +- l2cap_chan_lock(chan); +- } else { +- BT_DBG("unknown cid 0x%4.4x", cid); +- /* Drop packet and return */ +- kfree_skb(skb); +- return; +- } ++ BT_DBG("unknown cid 0x%4.4x", cid); ++ /* Drop packet and return */ ++ kfree_skb(skb); ++ return; + } + + BT_DBG("chan %p, len %d", chan, skb->len); +@@ -7887,10 +6863,6 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) + + conn->local_fixed_chan = L2CAP_FC_SIG_BREDR | L2CAP_FC_CONNLESS; + +- if (hcon->type == ACL_LINK && +- hci_dev_test_flag(hcon->hdev, HCI_HS_ENABLED)) +- conn->local_fixed_chan |= L2CAP_FC_A2MP; +- + if (hci_dev_test_flag(hcon->hdev, HCI_LE_ENABLED) && + (bredr_sc_enabled(hcon->hdev) || + hci_dev_test_flag(hcon->hdev, HCI_FORCE_BREDR_SMP))) +@@ -8355,11 +7327,6 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) + BT_DBG("chan %p scid 0x%4.4x state %s", chan, chan->scid, + state_to_string(chan->state)); + +- if (chan->scid == L2CAP_CID_A2MP) { +- l2cap_chan_unlock(chan); +- continue; +- } +- + if (!status && encrypt) + chan->sec_level = hcon->sec_level; + +diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c +index e50d3d102078e..ee7a41d6994fc 100644 +--- a/net/bluetooth/l2cap_sock.c ++++ b/net/bluetooth/l2cap_sock.c +@@ -1027,23 +1027,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, + break; + } + +- if (opt > BT_CHANNEL_POLICY_AMP_PREFERRED) { +- err = -EINVAL; +- break; +- } +- +- if (chan->mode != L2CAP_MODE_ERTM && +- chan->mode != L2CAP_MODE_STREAMING) { +- err = -EOPNOTSUPP; +- break; +- } +- +- chan->chan_policy = (u8) opt; +- +- if (sk->sk_state == BT_CONNECTED && +- chan->move_role == L2CAP_MOVE_ROLE_NONE) +- l2cap_move_start(chan); +- ++ err = -EOPNOTSUPP; + break; + + case BT_SNDMTU: +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index ee3b4aad8bd8d..640d6d54ac6ba 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -835,8 +835,6 @@ static u32 get_supported_settings(struct hci_dev *hdev) + + if (lmp_ssp_capable(hdev)) { + settings |= MGMT_SETTING_SSP; +- if (IS_ENABLED(CONFIG_BT_HS)) +- settings |= MGMT_SETTING_HS; + } + + if (lmp_sc_capable(hdev)) +@@ -901,9 +899,6 @@ static u32 get_current_settings(struct hci_dev *hdev) + if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) + settings |= MGMT_SETTING_SSP; + +- if (hci_dev_test_flag(hdev, HCI_HS_ENABLED)) +- settings |= MGMT_SETTING_HS; +- + if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) + settings |= MGMT_SETTING_ADVERTISING; + +@@ -1409,7 +1404,7 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data, + + /* Cancel potentially blocking sync operation before power off */ + if (cp->val == 0x00) { +- __hci_cmd_sync_cancel(hdev, -EHOSTDOWN); ++ hci_cmd_sync_cancel_sync(hdev, -EHOSTDOWN); + err = hci_cmd_sync_queue(hdev, set_powered_sync, cmd, + mgmt_set_powered_complete); + } else { +@@ -1930,7 +1925,6 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err) + + if (enable && hci_dev_test_and_clear_flag(hdev, + HCI_SSP_ENABLED)) { +- hci_dev_clear_flag(hdev, HCI_HS_ENABLED); + new_settings(hdev, NULL); + } + +@@ -1943,12 +1937,6 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err) + changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED); + } else { + changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED); +- +- if (!changed) +- changed = hci_dev_test_and_clear_flag(hdev, +- HCI_HS_ENABLED); +- else +- hci_dev_clear_flag(hdev, HCI_HS_ENABLED); + } + + mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); +@@ -2012,11 +2000,6 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) + } else { + changed = hci_dev_test_and_clear_flag(hdev, + HCI_SSP_ENABLED); +- if (!changed) +- changed = hci_dev_test_and_clear_flag(hdev, +- HCI_HS_ENABLED); +- else +- hci_dev_clear_flag(hdev, HCI_HS_ENABLED); + } + + err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev); +@@ -2062,63 +2045,10 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) + + static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) + { +- struct mgmt_mode *cp = data; +- bool changed; +- u8 status; +- int err; +- + bt_dev_dbg(hdev, "sock %p", sk); + +- if (!IS_ENABLED(CONFIG_BT_HS)) +- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, ++ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, + MGMT_STATUS_NOT_SUPPORTED); +- +- status = mgmt_bredr_support(hdev); +- if (status) +- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status); +- +- if (!lmp_ssp_capable(hdev)) +- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, +- MGMT_STATUS_NOT_SUPPORTED); +- +- if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) +- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, +- MGMT_STATUS_REJECTED); +- +- if (cp->val != 0x00 && cp->val != 0x01) +- return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, +- MGMT_STATUS_INVALID_PARAMS); +- +- hci_dev_lock(hdev); +- +- if (pending_find(MGMT_OP_SET_SSP, hdev)) { +- err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, +- MGMT_STATUS_BUSY); +- goto unlock; +- } +- +- if (cp->val) { +- changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED); +- } else { +- if (hdev_is_powered(hdev)) { +- err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, +- MGMT_STATUS_REJECTED); +- goto unlock; +- } +- +- changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED); +- } +- +- err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev); +- if (err < 0) +- goto unlock; +- +- if (changed) +- err = new_settings(hdev, sk); +- +-unlock: +- hci_dev_unlock(hdev); +- return err; + } + + static void set_le_complete(struct hci_dev *hdev, void *data, int err) +@@ -3188,6 +3118,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, + static u8 link_to_bdaddr(u8 link_type, u8 addr_type) + { + switch (link_type) { ++ case ISO_LINK: + case LE_LINK: + switch (addr_type) { + case ADDR_LE_DEV_PUBLIC: +@@ -6766,7 +6697,6 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) + hci_dev_clear_flag(hdev, HCI_SSP_ENABLED); + hci_dev_clear_flag(hdev, HCI_LINK_SECURITY); + hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE); +- hci_dev_clear_flag(hdev, HCI_HS_ENABLED); + } + + hci_dev_change_flag(hdev, HCI_BREDR_ENABLED); +@@ -8470,7 +8400,7 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev, + + static u8 calculate_name_len(struct hci_dev *hdev) + { +- u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3]; ++ u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 2]; /* len + type + name */ + + return eir_append_local_name(hdev, buf, 0); + } +@@ -9681,6 +9611,9 @@ void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn, + u16 eir_len = 0; + u32 flags = 0; + ++ if (test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) ++ return; ++ + /* allocate buff for LE or BR/EDR adv */ + if (conn->le_adv_data_len > 0) + skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_CONNECTED, +@@ -9766,14 +9699,6 @@ void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, + struct mgmt_ev_device_disconnected ev; + struct sock *sk = NULL; + +- /* The connection is still in hci_conn_hash so test for 1 +- * instead of 0 to know if this is the last one. +- */ +- if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) { +- cancel_delayed_work(&hdev->power_off); +- queue_work(hdev->req_workqueue, &hdev->power_off.work); +- } +- + if (!mgmt_connected) + return; + +@@ -9830,14 +9755,6 @@ void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, + { + struct mgmt_ev_connect_failed ev; + +- /* The connection is still in hci_conn_hash so test for 1 +- * instead of 0 to know if this is the last one. +- */ +- if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) { +- cancel_delayed_work(&hdev->power_off); +- queue_work(hdev->req_workqueue, &hdev->power_off.work); +- } +- + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = link_to_bdaddr(link_type, addr_type); + ev.status = mgmt_status(status); +diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c +index 630e3023273b2..9612c5d1b13f6 100644 +--- a/net/bluetooth/msft.c ++++ b/net/bluetooth/msft.c +@@ -875,6 +875,7 @@ static int msft_add_address_filter_sync(struct hci_dev *hdev, void *data) + remove = true; + goto done; + } ++ + cp->sub_opcode = MSFT_OP_LE_MONITOR_ADVERTISEMENT; + cp->rssi_high = address_filter->rssi_high; + cp->rssi_low = address_filter->rssi_low; +@@ -887,6 +888,8 @@ static int msft_add_address_filter_sync(struct hci_dev *hdev, void *data) + + skb = __hci_cmd_sync(hdev, hdev->msft_opcode, size, cp, + HCI_CMD_TIMEOUT); ++ kfree(cp); ++ + if (IS_ERR(skb)) { + bt_dev_err(hdev, "Failed to enable address %pMR filter", + &address_filter->bdaddr); +diff --git a/net/core/dev.c b/net/core/dev.c +index 76e6438f4858e..c9b8412f1c9d3 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -2261,7 +2261,7 @@ void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) + rcu_read_lock(); + again: + list_for_each_entry_rcu(ptype, ptype_list, list) { +- if (ptype->ignore_outgoing) ++ if (READ_ONCE(ptype->ignore_outgoing)) + continue; + + /* Never send packets back to the socket +@@ -6708,6 +6708,8 @@ static int napi_threaded_poll(void *data) + void *have; + + while (!napi_thread_wait(napi)) { ++ unsigned long last_qs = jiffies; ++ + for (;;) { + bool repoll = false; + +@@ -6732,6 +6734,7 @@ static int napi_threaded_poll(void *data) + if (!repoll) + break; + ++ rcu_softirq_qs_periodic(last_qs); + cond_resched(); + } + } +@@ -11631,11 +11634,12 @@ static void __init net_dev_struct_check(void) + + /* TXRX read-mostly hotpath */ + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, lstats); ++ CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, state); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, flags); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, hard_header_len); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, features); + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, ip6_ptr); +- CACHELINE_ASSERT_GROUP_SIZE(struct net_device, net_device_read_txrx, 38); ++ CACHELINE_ASSERT_GROUP_SIZE(struct net_device, net_device_read_txrx, 46); + + /* RX read-mostly hotpath */ + CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, ptype_specific); +diff --git a/net/core/gso_test.c b/net/core/gso_test.c +index 4c2e77bd12f4b..358c44680d917 100644 +--- a/net/core/gso_test.c ++++ b/net/core/gso_test.c +@@ -225,7 +225,7 @@ static void gso_test_func(struct kunit *test) + + segs = skb_segment(skb, features); + if (IS_ERR(segs)) { +- KUNIT_FAIL(test, "segs error %lld", PTR_ERR(segs)); ++ KUNIT_FAIL(test, "segs error %pe", segs); + goto free_gso_skb; + } else if (!segs) { + KUNIT_FAIL(test, "no segments"); +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index edbbef563d4d9..71dee435d549d 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -6736,6 +6736,14 @@ static struct skb_ext *skb_ext_maybe_cow(struct skb_ext *old, + for (i = 0; i < sp->len; i++) + xfrm_state_hold(sp->xvec[i]); + } ++#endif ++#ifdef CONFIG_MCTP_FLOWS ++ if (old_active & (1 << SKB_EXT_MCTP)) { ++ struct mctp_flow *flow = skb_ext_get_ptr(old, SKB_EXT_MCTP); ++ ++ if (flow->key) ++ refcount_inc(&flow->key->refs); ++ } + #endif + __skb_ext_put(old); + return new; +diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c +index b1e29e18d1d60..c53b731f2d672 100644 +--- a/net/core/sock_diag.c ++++ b/net/core/sock_diag.c +@@ -193,7 +193,7 @@ int sock_diag_register(const struct sock_diag_handler *hndl) + if (sock_diag_handlers[hndl->family]) + err = -EBUSY; + else +- sock_diag_handlers[hndl->family] = hndl; ++ WRITE_ONCE(sock_diag_handlers[hndl->family], hndl); + mutex_unlock(&sock_diag_table_mutex); + + return err; +@@ -209,7 +209,7 @@ void sock_diag_unregister(const struct sock_diag_handler *hnld) + + mutex_lock(&sock_diag_table_mutex); + BUG_ON(sock_diag_handlers[family] != hnld); +- sock_diag_handlers[family] = NULL; ++ WRITE_ONCE(sock_diag_handlers[family], NULL); + mutex_unlock(&sock_diag_table_mutex); + } + EXPORT_SYMBOL_GPL(sock_diag_unregister); +@@ -227,7 +227,7 @@ static int __sock_diag_cmd(struct sk_buff *skb, struct nlmsghdr *nlh) + return -EINVAL; + req->sdiag_family = array_index_nospec(req->sdiag_family, AF_MAX); + +- if (sock_diag_handlers[req->sdiag_family] == NULL) ++ if (READ_ONCE(sock_diag_handlers[req->sdiag_family]) == NULL) + sock_load_diag_module(req->sdiag_family, 0); + + mutex_lock(&sock_diag_table_mutex); +@@ -286,12 +286,12 @@ static int sock_diag_bind(struct net *net, int group) + switch (group) { + case SKNLGRP_INET_TCP_DESTROY: + case SKNLGRP_INET_UDP_DESTROY: +- if (!sock_diag_handlers[AF_INET]) ++ if (!READ_ONCE(sock_diag_handlers[AF_INET])) + sock_load_diag_module(AF_INET, 0); + break; + case SKNLGRP_INET6_TCP_DESTROY: + case SKNLGRP_INET6_UDP_DESTROY: +- if (!sock_diag_handlers[AF_INET6]) ++ if (!READ_ONCE(sock_diag_handlers[AF_INET6])) + sock_load_diag_module(AF_INET6, 0); + break; + } +diff --git a/net/devlink/netlink.c b/net/devlink/netlink.c +index 499885c8b9cae..593605c1b1ef4 100644 +--- a/net/devlink/netlink.c ++++ b/net/devlink/netlink.c +@@ -193,12 +193,13 @@ devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs, + devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]); + + devlinks_xa_for_each_registered_get(net, index, devlink) { +- devl_dev_lock(devlink, dev_lock); +- if (devl_is_registered(devlink) && +- strcmp(devlink->dev->bus->name, busname) == 0 && +- strcmp(dev_name(devlink->dev), devname) == 0) +- return devlink; +- devl_dev_unlock(devlink, dev_lock); ++ if (strcmp(devlink->dev->bus->name, busname) == 0 && ++ strcmp(dev_name(devlink->dev), devname) == 0) { ++ devl_dev_lock(devlink, dev_lock); ++ if (devl_is_registered(devlink)) ++ return devlink; ++ devl_dev_unlock(devlink, dev_lock); ++ } + devlink_put(devlink); + } + +diff --git a/net/devlink/netlink_gen.c b/net/devlink/netlink_gen.c +index c81cf2dd154f3..f9786d51f68f9 100644 +--- a/net/devlink/netlink_gen.c ++++ b/net/devlink/netlink_gen.c +@@ -198,7 +198,7 @@ static const struct nla_policy devlink_eswitch_set_nl_policy[DEVLINK_ATTR_ESWITC + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_ESWITCH_MODE] = NLA_POLICY_MAX(NLA_U16, 1), +- [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = NLA_POLICY_MAX(NLA_U16, 3), ++ [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = NLA_POLICY_MAX(NLA_U8, 3), + [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = NLA_POLICY_MAX(NLA_U8, 1), + }; + +diff --git a/net/devlink/port.c b/net/devlink/port.c +index 4b2d46ccfe484..118d130d2afd5 100644 +--- a/net/devlink/port.c ++++ b/net/devlink/port.c +@@ -889,7 +889,7 @@ int devlink_nl_port_new_doit(struct sk_buff *skb, struct genl_info *info) + err = -ENOMEM; + goto err_out_port_del; + } +- err = devlink_nl_port_fill(msg, devlink_port, DEVLINK_CMD_NEW, ++ err = devlink_nl_port_fill(msg, devlink_port, DEVLINK_CMD_PORT_NEW, + info->snd_portid, info->snd_seq, 0, NULL); + if (WARN_ON_ONCE(err)) + goto err_out_msg_free; +diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c +index 6d14d935ee828..26329db09210b 100644 +--- a/net/hsr/hsr_framereg.c ++++ b/net/hsr/hsr_framereg.c +@@ -228,6 +228,10 @@ struct hsr_node *hsr_get_node(struct hsr_port *port, struct list_head *node_db, + */ + if (ethhdr->h_proto == htons(ETH_P_PRP) || + ethhdr->h_proto == htons(ETH_P_HSR)) { ++ /* Check if skb contains hsr_ethhdr */ ++ if (skb->mac_len < sizeof(struct hsr_ethhdr)) ++ return NULL; ++ + /* Use the existing sequence_nr from the tag as starting point + * for filtering duplicate frames. + */ +diff --git a/net/hsr/hsr_main.c b/net/hsr/hsr_main.c +index cb83c8feb7465..9756e657bab97 100644 +--- a/net/hsr/hsr_main.c ++++ b/net/hsr/hsr_main.c +@@ -148,14 +148,21 @@ static struct notifier_block hsr_nb = { + + static int __init hsr_init(void) + { +- int res; ++ int err; + + BUILD_BUG_ON(sizeof(struct hsr_tag) != HSR_HLEN); + +- register_netdevice_notifier(&hsr_nb); +- res = hsr_netlink_init(); ++ err = register_netdevice_notifier(&hsr_nb); ++ if (err) ++ return err; ++ ++ err = hsr_netlink_init(); ++ if (err) { ++ unregister_netdevice_notifier(&hsr_nb); ++ return err; ++ } + +- return res; ++ return 0; + } + + static void __exit hsr_exit(void) +diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c +index 8e6b6aa0579e1..9804e9608a5a0 100644 +--- a/net/ipv4/inet_diag.c ++++ b/net/ipv4/inet_diag.c +@@ -57,7 +57,7 @@ static const struct inet_diag_handler *inet_diag_lock_handler(int proto) + return ERR_PTR(-ENOENT); + } + +- if (!inet_diag_table[proto]) ++ if (!READ_ONCE(inet_diag_table[proto])) + sock_load_diag_module(AF_INET, proto); + + mutex_lock(&inet_diag_table_mutex); +@@ -1503,7 +1503,7 @@ int inet_diag_register(const struct inet_diag_handler *h) + mutex_lock(&inet_diag_table_mutex); + err = -EEXIST; + if (!inet_diag_table[type]) { +- inet_diag_table[type] = h; ++ WRITE_ONCE(inet_diag_table[type], h); + err = 0; + } + mutex_unlock(&inet_diag_table_mutex); +@@ -1520,7 +1520,7 @@ void inet_diag_unregister(const struct inet_diag_handler *h) + return; + + mutex_lock(&inet_diag_table_mutex); +- inet_diag_table[type] = NULL; ++ WRITE_ONCE(inet_diag_table[type], NULL); + mutex_unlock(&inet_diag_table_mutex); + } + EXPORT_SYMBOL_GPL(inet_diag_unregister); +diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c +index 308ff34002ea6..4e470f18487f6 100644 +--- a/net/ipv4/inet_hashtables.c ++++ b/net/ipv4/inet_hashtables.c +@@ -1136,7 +1136,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, + sock_prot_inuse_add(net, sk->sk_prot, -1); + + spin_lock(lock); +- sk_nulls_del_node_init_rcu(sk); ++ __sk_nulls_del_node_init_rcu(sk); + spin_unlock(lock); + + sk->sk_hash = 0; +diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c +index 5befa4de5b241..e8de45d34d56a 100644 +--- a/net/ipv4/inet_timewait_sock.c ++++ b/net/ipv4/inet_timewait_sock.c +@@ -263,12 +263,12 @@ void __inet_twsk_schedule(struct inet_timewait_sock *tw, int timeo, bool rearm) + } + EXPORT_SYMBOL_GPL(__inet_twsk_schedule); + ++/* Remove all non full sockets (TIME_WAIT and NEW_SYN_RECV) for dead netns */ + void inet_twsk_purge(struct inet_hashinfo *hashinfo, int family) + { +- struct inet_timewait_sock *tw; +- struct sock *sk; + struct hlist_nulls_node *node; + unsigned int slot; ++ struct sock *sk; + + for (slot = 0; slot <= hashinfo->ehash_mask; slot++) { + struct inet_ehash_bucket *head = &hashinfo->ehash[slot]; +@@ -277,38 +277,35 @@ void inet_twsk_purge(struct inet_hashinfo *hashinfo, int family) + rcu_read_lock(); + restart: + sk_nulls_for_each_rcu(sk, node, &head->chain) { +- if (sk->sk_state != TCP_TIME_WAIT) { +- /* A kernel listener socket might not hold refcnt for net, +- * so reqsk_timer_handler() could be fired after net is +- * freed. Userspace listener and reqsk never exist here. +- */ +- if (unlikely(sk->sk_state == TCP_NEW_SYN_RECV && +- hashinfo->pernet)) { +- struct request_sock *req = inet_reqsk(sk); +- +- inet_csk_reqsk_queue_drop_and_put(req->rsk_listener, req); +- } ++ int state = inet_sk_state_load(sk); + ++ if ((1 << state) & ~(TCPF_TIME_WAIT | ++ TCPF_NEW_SYN_RECV)) + continue; +- } + +- tw = inet_twsk(sk); +- if ((tw->tw_family != family) || +- refcount_read(&twsk_net(tw)->ns.count)) ++ if (sk->sk_family != family || ++ refcount_read(&sock_net(sk)->ns.count)) + continue; + +- if (unlikely(!refcount_inc_not_zero(&tw->tw_refcnt))) ++ if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt))) + continue; + +- if (unlikely((tw->tw_family != family) || +- refcount_read(&twsk_net(tw)->ns.count))) { +- inet_twsk_put(tw); ++ if (unlikely(sk->sk_family != family || ++ refcount_read(&sock_net(sk)->ns.count))) { ++ sock_gen_put(sk); + goto restart; + } + + rcu_read_unlock(); + local_bh_disable(); +- inet_twsk_deschedule_put(tw); ++ if (state == TCP_TIME_WAIT) { ++ inet_twsk_deschedule_put(inet_twsk(sk)); ++ } else { ++ struct request_sock *req = inet_reqsk(sk); ++ ++ inet_csk_reqsk_queue_drop_and_put(req->rsk_listener, ++ req); ++ } + local_bh_enable(); + goto restart_rcu; + } +diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c +index 1b6981de3f295..7af36e4f1647d 100644 +--- a/net/ipv4/ip_tunnel.c ++++ b/net/ipv4/ip_tunnel.c +@@ -378,7 +378,7 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb, + bool log_ecn_error) + { + const struct iphdr *iph = ip_hdr(skb); +- int err; ++ int nh, err; + + #ifdef CONFIG_NET_IPGRE_BROADCAST + if (ipv4_is_multicast(iph->daddr)) { +@@ -404,8 +404,21 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb, + tunnel->i_seqno = ntohl(tpi->seq) + 1; + } + ++ /* Save offset of outer header relative to skb->head, ++ * because we are going to reset the network header to the inner header ++ * and might change skb->head. ++ */ ++ nh = skb_network_header(skb) - skb->head; ++ + skb_set_network_header(skb, (tunnel->dev->type == ARPHRD_ETHER) ? ETH_HLEN : 0); + ++ if (!pskb_inet_may_pull(skb)) { ++ DEV_STATS_INC(tunnel->dev, rx_length_errors); ++ DEV_STATS_INC(tunnel->dev, rx_errors); ++ goto drop; ++ } ++ iph = (struct iphdr *)(skb->head + nh); ++ + err = IP_ECN_decapsulate(iph, skb); + if (unlikely(err)) { + if (log_ecn_error) +diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c +index 3622298365105..b53c36c473a5b 100644 +--- a/net/ipv4/ipmr.c ++++ b/net/ipv4/ipmr.c +@@ -1603,9 +1603,11 @@ int ip_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval, + + if (copy_from_sockptr(&olr, optlen, sizeof(int))) + return -EFAULT; +- olr = min_t(unsigned int, olr, sizeof(int)); + if (olr < 0) + return -EINVAL; ++ ++ olr = min_t(unsigned int, olr, sizeof(int)); ++ + if (copy_to_sockptr(optlen, &olr, sizeof(int))) + return -EFAULT; + if (copy_to_sockptr(optval, &val, olr)) +diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c +index aea89326c6979..288f1846b3518 100644 +--- a/net/ipv4/raw.c ++++ b/net/ipv4/raw.c +@@ -350,6 +350,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, + goto error; + skb_reserve(skb, hlen); + ++ skb->protocol = htons(ETH_P_IP); + skb->priority = READ_ONCE(sk->sk_priority); + skb->mark = sockc->mark; + skb->tstamp = sockc->transmit_time; +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index c82dc42f57c65..a4f4185923144 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -4010,11 +4010,11 @@ int do_tcp_getsockopt(struct sock *sk, int level, + if (copy_from_sockptr(&len, optlen, sizeof(int))) + return -EFAULT; + +- len = min_t(unsigned int, len, sizeof(int)); +- + if (len < 0) + return -EINVAL; + ++ len = min_t(unsigned int, len, sizeof(int)); ++ + switch (optname) { + case TCP_MAXSEG: + val = tp->mss_cache; +diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c +index 9e85f2a0bddd4..0ecc7311dc6ce 100644 +--- a/net/ipv4/tcp_minisocks.c ++++ b/net/ipv4/tcp_minisocks.c +@@ -398,10 +398,6 @@ void tcp_twsk_purge(struct list_head *net_exit_list, int family) + /* Even if tw_refcount == 1, we must clean up kernel reqsk */ + inet_twsk_purge(net->ipv4.tcp_death_row.hashinfo, family); + } else if (!purged_once) { +- /* The last refcount is decremented in tcp_sk_exit_batch() */ +- if (refcount_read(&net->ipv4.tcp_death_row.tw_refcount) == 1) +- continue; +- + inet_twsk_purge(&tcp_hashinfo, family); + purged_once = true; + } +diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c +index e474b201900f9..17231c0f88302 100644 +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -2792,11 +2792,11 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname, + if (get_user(len, optlen)) + return -EFAULT; + +- len = min_t(unsigned int, len, sizeof(int)); +- + if (len < 0) + return -EINVAL; + ++ len = min_t(unsigned int, len, sizeof(int)); ++ + switch (optname) { + case UDP_CORK: + val = udp_test_bit(CORK, sk); +diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c +index 7523c4baef35e..52c04f0ac4981 100644 +--- a/net/ipv6/fib6_rules.c ++++ b/net/ipv6/fib6_rules.c +@@ -449,6 +449,11 @@ static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule) + + nla_total_size(16); /* src */ + } + ++static void fib6_rule_flush_cache(struct fib_rules_ops *ops) ++{ ++ rt_genid_bump_ipv6(ops->fro_net); ++} ++ + static const struct fib_rules_ops __net_initconst fib6_rules_ops_template = { + .family = AF_INET6, + .rule_size = sizeof(struct fib6_rule), +@@ -461,6 +466,7 @@ static const struct fib_rules_ops __net_initconst fib6_rules_ops_template = { + .compare = fib6_rule_compare, + .fill = fib6_rule_fill, + .nlmsg_payload = fib6_rule_nlmsg_payload, ++ .flush_cache = fib6_rule_flush_cache, + .nlgroup = RTNLGRP_IPV6_RULE, + .owner = THIS_MODULE, + .fro_net = &init_net, +diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c +index bc6e0a0bad3c1..76ee1615ff2a0 100644 +--- a/net/ipv6/mcast.c ++++ b/net/ipv6/mcast.c +@@ -2719,7 +2719,6 @@ void ipv6_mc_down(struct inet6_dev *idev) + /* Should stop work after group drop. or we will + * start work again in mld_ifc_event() + */ +- synchronize_net(); + mld_query_stop_work(idev); + mld_report_stop_work(idev); + +diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c +index 1184d40167b86..eda933c097926 100644 +--- a/net/kcm/kcmsock.c ++++ b/net/kcm/kcmsock.c +@@ -1152,10 +1152,11 @@ static int kcm_getsockopt(struct socket *sock, int level, int optname, + if (get_user(len, optlen)) + return -EFAULT; + +- len = min_t(unsigned int, len, sizeof(int)); + if (len < 0) + return -EINVAL; + ++ len = min_t(unsigned int, len, sizeof(int)); ++ + switch (optname) { + case KCM_RECV_DISABLE: + val = kcm->rx_disabled; +diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c +index f011af6601c9c..6146e4e67bbb5 100644 +--- a/net/l2tp/l2tp_ppp.c ++++ b/net/l2tp/l2tp_ppp.c +@@ -1356,11 +1356,11 @@ static int pppol2tp_getsockopt(struct socket *sock, int level, int optname, + if (get_user(len, optlen)) + return -EFAULT; + +- len = min_t(unsigned int, len, sizeof(int)); +- + if (len < 0) + return -EINVAL; + ++ len = min_t(unsigned int, len, sizeof(int)); ++ + err = -ENOTCONN; + if (!sk->sk_user_data) + goto end; +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index 2022a26eb8811..20d863370796d 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -7523,10 +7523,10 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, + if (err) + goto err_clear; + +- if (req->link_id > 0) ++ if (req->link_id >= 0) + link = sdata_dereference(sdata->link[req->link_id], sdata); + else +- link = sdata_dereference(sdata->link[0], sdata); ++ link = &sdata->deflink; + + if (WARN_ON(!link)) { + err = -ENOLINK; +diff --git a/net/mctp/route.c b/net/mctp/route.c +index ceee44ea09d97..01c530dbc1a65 100644 +--- a/net/mctp/route.c ++++ b/net/mctp/route.c +@@ -843,6 +843,9 @@ static int mctp_do_fragment_route(struct mctp_route *rt, struct sk_buff *skb, + /* copy message payload */ + skb_copy_bits(skb, pos, skb_transport_header(skb2), size); + ++ /* we need to copy the extensions, for MCTP flow data */ ++ skb_ext_copy(skb2, skb); ++ + /* do route */ + rc = rt->output(rt, skb2); + if (rc) +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 1683dc196b592..6873c9815cd31 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -1211,7 +1211,7 @@ static int nf_tables_updtable(struct nft_ctx *ctx) + if (flags & ~NFT_TABLE_F_MASK) + return -EOPNOTSUPP; + +- if (flags == ctx->table->flags) ++ if (flags == (ctx->table->flags & NFT_TABLE_F_MASK)) + return 0; + + if ((nft_table_has_owner(ctx->table) && +@@ -2619,19 +2619,6 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy, + } + } + +- if (nla[NFTA_CHAIN_COUNTERS]) { +- if (!nft_is_base_chain(chain)) { +- err = -EOPNOTSUPP; +- goto err_hooks; +- } +- +- stats = nft_stats_alloc(nla[NFTA_CHAIN_COUNTERS]); +- if (IS_ERR(stats)) { +- err = PTR_ERR(stats); +- goto err_hooks; +- } +- } +- + if (!(table->flags & NFT_TABLE_F_DORMANT) && + nft_is_base_chain(chain) && + !list_empty(&hook.list)) { +@@ -2646,6 +2633,20 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy, + } + + unregister = true; ++ ++ if (nla[NFTA_CHAIN_COUNTERS]) { ++ if (!nft_is_base_chain(chain)) { ++ err = -EOPNOTSUPP; ++ goto err_hooks; ++ } ++ ++ stats = nft_stats_alloc(nla[NFTA_CHAIN_COUNTERS]); ++ if (IS_ERR(stats)) { ++ err = PTR_ERR(stats); ++ goto err_hooks; ++ } ++ } ++ + err = -ENOMEM; + trans = nft_trans_alloc(ctx, NFT_MSG_NEWCHAIN, + sizeof(struct nft_trans_chain)); +diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c +index aa1d9e93a9a04..b3b282de802de 100644 +--- a/net/netfilter/nft_set_pipapo.c ++++ b/net/netfilter/nft_set_pipapo.c +@@ -2244,8 +2244,6 @@ static void nft_pipapo_destroy(const struct nft_ctx *ctx, + if (m) { + rcu_barrier(); + +- nft_set_pipapo_match_destroy(ctx, set, m); +- + for_each_possible_cpu(cpu) + pipapo_free_scratch(m, cpu); + free_percpu(m->scratch); +@@ -2257,8 +2255,7 @@ static void nft_pipapo_destroy(const struct nft_ctx *ctx, + if (priv->clone) { + m = priv->clone; + +- if (priv->dirty) +- nft_set_pipapo_match_destroy(ctx, set, m); ++ nft_set_pipapo_match_destroy(ctx, set, m); + + for_each_possible_cpu(cpu) + pipapo_free_scratch(priv->clone, cpu); +diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c +index c9bbc26866907..e6a8701a38dbe 100644 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -3998,7 +3998,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval, + if (val < 0 || val > 1) + return -EINVAL; + +- po->prot_hook.ignore_outgoing = !!val; ++ WRITE_ONCE(po->prot_hook.ignore_outgoing, !!val); + return 0; + } + case PACKET_TX_HAS_OFF: +@@ -4129,7 +4129,7 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, + 0); + break; + case PACKET_IGNORE_OUTGOING: +- val = po->prot_hook.ignore_outgoing; ++ val = READ_ONCE(po->prot_hook.ignore_outgoing); + break; + case PACKET_ROLLOVER_STATS: + if (!po->rollover) +diff --git a/net/rds/send.c b/net/rds/send.c +index 2899def23865f..09a2801106549 100644 +--- a/net/rds/send.c ++++ b/net/rds/send.c +@@ -103,13 +103,12 @@ EXPORT_SYMBOL_GPL(rds_send_path_reset); + + static int acquire_in_xmit(struct rds_conn_path *cp) + { +- return test_and_set_bit(RDS_IN_XMIT, &cp->cp_flags) == 0; ++ return test_and_set_bit_lock(RDS_IN_XMIT, &cp->cp_flags) == 0; + } + + static void release_in_xmit(struct rds_conn_path *cp) + { +- clear_bit(RDS_IN_XMIT, &cp->cp_flags); +- smp_mb__after_atomic(); ++ clear_bit_unlock(RDS_IN_XMIT, &cp->cp_flags); + /* + * We don't use wait_on_bit()/wake_up_bit() because our waking is in a + * hot path and finding waiters is very rare. We don't want to walk +diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c +index 31a8252bd09c9..ad99409c6325e 100644 +--- a/net/sched/sch_taprio.c ++++ b/net/sched/sch_taprio.c +@@ -1008,7 +1008,8 @@ static const struct nla_policy entry_policy[TCA_TAPRIO_SCHED_ENTRY_MAX + 1] = { + }; + + static const struct nla_policy taprio_tc_policy[TCA_TAPRIO_TC_ENTRY_MAX + 1] = { +- [TCA_TAPRIO_TC_ENTRY_INDEX] = { .type = NLA_U32 }, ++ [TCA_TAPRIO_TC_ENTRY_INDEX] = NLA_POLICY_MAX(NLA_U32, ++ TC_QOPT_MAX_QUEUE), + [TCA_TAPRIO_TC_ENTRY_MAX_SDU] = { .type = NLA_U32 }, + [TCA_TAPRIO_TC_ENTRY_FP] = NLA_POLICY_RANGE(NLA_U32, + TC_FP_EXPRESS, +diff --git a/net/sunrpc/addr.c b/net/sunrpc/addr.c +index d435bffc61999..97ff11973c493 100644 +--- a/net/sunrpc/addr.c ++++ b/net/sunrpc/addr.c +@@ -284,10 +284,10 @@ char *rpc_sockaddr2uaddr(const struct sockaddr *sap, gfp_t gfp_flags) + } + + if (snprintf(portbuf, sizeof(portbuf), +- ".%u.%u", port >> 8, port & 0xff) > (int)sizeof(portbuf)) ++ ".%u.%u", port >> 8, port & 0xff) >= (int)sizeof(portbuf)) + return NULL; + +- if (strlcat(addrbuf, portbuf, sizeof(addrbuf)) > sizeof(addrbuf)) ++ if (strlcat(addrbuf, portbuf, sizeof(addrbuf)) >= sizeof(addrbuf)) + return NULL; + + return kstrdup(addrbuf, gfp_flags); +diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c +index 64cff717c3d9b..3366505bc669a 100644 +--- a/net/sunrpc/auth_gss/gss_krb5_mech.c ++++ b/net/sunrpc/auth_gss/gss_krb5_mech.c +@@ -398,6 +398,7 @@ gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx, + u64 seq_send64; + int keylen; + u32 time32; ++ int ret; + + p = simple_get_bytes(p, end, &ctx->flags, sizeof(ctx->flags)); + if (IS_ERR(p)) +@@ -450,8 +451,16 @@ gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx, + } + ctx->mech_used.len = gss_kerberos_mech.gm_oid.len; + +- return gss_krb5_import_ctx_v2(ctx, gfp_mask); ++ ret = gss_krb5_import_ctx_v2(ctx, gfp_mask); ++ if (ret) { ++ p = ERR_PTR(ret); ++ goto out_free; ++ } + ++ return 0; ++ ++out_free: ++ kfree(ctx->mech_used.data); + out_err: + return PTR_ERR(p); + } +diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.c b/net/sunrpc/auth_gss/gss_rpc_xdr.c +index d79f12c2550ac..cb32ab9a83952 100644 +--- a/net/sunrpc/auth_gss/gss_rpc_xdr.c ++++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c +@@ -250,8 +250,8 @@ static int gssx_dec_option_array(struct xdr_stream *xdr, + + creds = kzalloc(sizeof(struct svc_cred), GFP_KERNEL); + if (!creds) { +- kfree(oa->data); +- return -ENOMEM; ++ err = -ENOMEM; ++ goto free_oa; + } + + oa->data[0].option.data = CREDS_VALUE; +@@ -265,29 +265,40 @@ static int gssx_dec_option_array(struct xdr_stream *xdr, + + /* option buffer */ + p = xdr_inline_decode(xdr, 4); +- if (unlikely(p == NULL)) +- return -ENOSPC; ++ if (unlikely(p == NULL)) { ++ err = -ENOSPC; ++ goto free_creds; ++ } + + length = be32_to_cpup(p); + p = xdr_inline_decode(xdr, length); +- if (unlikely(p == NULL)) +- return -ENOSPC; ++ if (unlikely(p == NULL)) { ++ err = -ENOSPC; ++ goto free_creds; ++ } + + if (length == sizeof(CREDS_VALUE) && + memcmp(p, CREDS_VALUE, sizeof(CREDS_VALUE)) == 0) { + /* We have creds here. parse them */ + err = gssx_dec_linux_creds(xdr, creds); + if (err) +- return err; ++ goto free_creds; + oa->data[0].value.len = 1; /* presence */ + } else { + /* consume uninteresting buffer */ + err = gssx_dec_buffer(xdr, &dummy); + if (err) +- return err; ++ goto free_creds; + } + } + return 0; ++ ++free_creds: ++ kfree(creds); ++free_oa: ++ kfree(oa->data); ++ oa->data = NULL; ++ return err; + } + + static int gssx_dec_status(struct xdr_stream *xdr, +diff --git a/net/unix/garbage.c b/net/unix/garbage.c +index 2a81880dac7b7..027c86e804f8a 100644 +--- a/net/unix/garbage.c ++++ b/net/unix/garbage.c +@@ -198,7 +198,7 @@ void wait_for_unix_gc(void) + if (READ_ONCE(unix_tot_inflight) > UNIX_INFLIGHT_TRIGGER_GC && + !READ_ONCE(gc_in_progress)) + unix_gc(); +- wait_event(unix_gc_wait, gc_in_progress == false); ++ wait_event(unix_gc_wait, !READ_ONCE(gc_in_progress)); + } + + /* The external entry point: unix_gc() */ +diff --git a/net/wireless/scan.c b/net/wireless/scan.c +index 389a52c29bfc7..f138f88be9048 100644 +--- a/net/wireless/scan.c ++++ b/net/wireless/scan.c +@@ -2602,9 +2602,9 @@ cfg80211_defrag_mle(const struct element *mle, const u8 *ie, size_t ielen, + } + + static u8 +-cfg80211_tbtt_info_for_mld_ap(const u8 *ie, size_t ielen, u8 mld_id, u8 link_id, +- const struct ieee80211_neighbor_ap_info **ap_info, +- const u8 **tbtt_info) ++cfg80211_rnr_info_for_mld_ap(const u8 *ie, size_t ielen, u8 mld_id, u8 link_id, ++ const struct ieee80211_neighbor_ap_info **ap_info, ++ u8 *param_ch_count) + { + const struct ieee80211_neighbor_ap_info *info; + const struct element *rnr; +@@ -2661,7 +2661,9 @@ cfg80211_tbtt_info_for_mld_ap(const u8 *ie, size_t ielen, u8 mld_id, u8 link_id, + if (mld_id == mld_params->mld_id && + link_id == lid) { + *ap_info = info; +- *tbtt_info = pos; ++ *param_ch_count = ++ le16_get_bits(mld_params->params, ++ IEEE80211_RNR_MLD_PARAMS_BSS_CHANGE_COUNT); + + return use_for; + } +@@ -2674,6 +2676,103 @@ cfg80211_tbtt_info_for_mld_ap(const u8 *ie, size_t ielen, u8 mld_id, u8 link_id, + return 0; + } + ++static struct element * ++cfg80211_gen_reporter_rnr(struct cfg80211_bss *source_bss, bool is_mbssid, ++ bool same_mld, u8 link_id, u8 bss_change_count, ++ gfp_t gfp) ++{ ++ const struct cfg80211_bss_ies *ies; ++ struct ieee80211_neighbor_ap_info ap_info; ++ struct ieee80211_tbtt_info_ge_11 tbtt_info; ++ u32 short_ssid; ++ const struct element *elem; ++ struct element *res; ++ ++ /* ++ * We only generate the RNR to permit ML lookups. For that we do not ++ * need an entry for the corresponding transmitting BSS, lets just skip ++ * it even though it would be easy to add. ++ */ ++ if (!same_mld) ++ return NULL; ++ ++ /* We could use tx_data->ies if we change cfg80211_calc_short_ssid */ ++ rcu_read_lock(); ++ ies = rcu_dereference(source_bss->ies); ++ ++ ap_info.tbtt_info_len = offsetofend(typeof(tbtt_info), mld_params); ++ ap_info.tbtt_info_hdr = ++ u8_encode_bits(IEEE80211_TBTT_INFO_TYPE_TBTT, ++ IEEE80211_AP_INFO_TBTT_HDR_TYPE) | ++ u8_encode_bits(0, IEEE80211_AP_INFO_TBTT_HDR_COUNT); ++ ++ ap_info.channel = ieee80211_frequency_to_channel(source_bss->channel->center_freq); ++ ++ /* operating class */ ++ elem = cfg80211_find_elem(WLAN_EID_SUPPORTED_REGULATORY_CLASSES, ++ ies->data, ies->len); ++ if (elem && elem->datalen >= 1) { ++ ap_info.op_class = elem->data[0]; ++ } else { ++ struct cfg80211_chan_def chandef; ++ ++ /* The AP is not providing us with anything to work with. So ++ * make up a somewhat reasonable operating class, but don't ++ * bother with it too much as no one will ever use the ++ * information. ++ */ ++ cfg80211_chandef_create(&chandef, source_bss->channel, ++ NL80211_CHAN_NO_HT); ++ ++ if (!ieee80211_chandef_to_operating_class(&chandef, ++ &ap_info.op_class)) ++ goto out_unlock; ++ } ++ ++ /* Just set TBTT offset and PSD 20 to invalid/unknown */ ++ tbtt_info.tbtt_offset = 255; ++ tbtt_info.psd_20 = IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED; ++ ++ memcpy(tbtt_info.bssid, source_bss->bssid, ETH_ALEN); ++ if (cfg80211_calc_short_ssid(ies, &elem, &short_ssid)) ++ goto out_unlock; ++ ++ rcu_read_unlock(); ++ ++ tbtt_info.short_ssid = cpu_to_le32(short_ssid); ++ ++ tbtt_info.bss_params = IEEE80211_RNR_TBTT_PARAMS_SAME_SSID; ++ ++ if (is_mbssid) { ++ tbtt_info.bss_params |= IEEE80211_RNR_TBTT_PARAMS_MULTI_BSSID; ++ tbtt_info.bss_params |= IEEE80211_RNR_TBTT_PARAMS_TRANSMITTED_BSSID; ++ } ++ ++ tbtt_info.mld_params.mld_id = 0; ++ tbtt_info.mld_params.params = ++ le16_encode_bits(link_id, IEEE80211_RNR_MLD_PARAMS_LINK_ID) | ++ le16_encode_bits(bss_change_count, ++ IEEE80211_RNR_MLD_PARAMS_BSS_CHANGE_COUNT); ++ ++ res = kzalloc(struct_size(res, data, ++ sizeof(ap_info) + ap_info.tbtt_info_len), ++ gfp); ++ if (!res) ++ return NULL; ++ ++ /* Copy the data */ ++ res->id = WLAN_EID_REDUCED_NEIGHBOR_REPORT; ++ res->datalen = sizeof(ap_info) + ap_info.tbtt_info_len; ++ memcpy(res->data, &ap_info, sizeof(ap_info)); ++ memcpy(res->data + sizeof(ap_info), &tbtt_info, ap_info.tbtt_info_len); ++ ++ return res; ++ ++out_unlock: ++ rcu_read_unlock(); ++ return NULL; ++} ++ + static void + cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, + struct cfg80211_inform_single_bss_data *tx_data, +@@ -2687,13 +2786,14 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, + .source_bss = source_bss, + .bss_source = BSS_SOURCE_STA_PROFILE, + }; ++ struct element *reporter_rnr = NULL; + struct ieee80211_multi_link_elem *ml_elem; + struct cfg80211_mle *mle; + u16 control; + u8 ml_common_len; +- u8 *new_ie; ++ u8 *new_ie = NULL; + struct cfg80211_bss *bss; +- int mld_id; ++ u8 mld_id, reporter_link_id, bss_change_count; + u16 seen_links = 0; + const u8 *pos; + u8 i; +@@ -2715,8 +2815,14 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, + + ml_common_len = ml_elem->variable[0]; + +- /* length + MLD MAC address + link ID info + BSS Params Change Count */ +- pos = ml_elem->variable + 1 + 6 + 1 + 1; ++ /* length + MLD MAC address */ ++ pos = ml_elem->variable + 1 + 6; ++ ++ reporter_link_id = pos[0]; ++ pos += 1; ++ ++ bss_change_count = pos[0]; ++ pos += 1; + + if (u16_get_bits(control, IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY)) + pos += 2; +@@ -2747,17 +2853,28 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, + if (!mle) + return; + ++ /* No point in doing anything if there is no per-STA profile */ ++ if (!mle->sta_prof[0]) ++ goto out; ++ + new_ie = kmalloc(IEEE80211_MAX_DATA_LEN, gfp); + if (!new_ie) + goto out; + ++ reporter_rnr = cfg80211_gen_reporter_rnr(source_bss, ++ u16_get_bits(control, ++ IEEE80211_MLC_BASIC_PRES_MLD_ID), ++ mld_id == 0, reporter_link_id, ++ bss_change_count, ++ gfp); ++ + for (i = 0; i < ARRAY_SIZE(mle->sta_prof) && mle->sta_prof[i]; i++) { + const struct ieee80211_neighbor_ap_info *ap_info; + enum nl80211_band band; + u32 freq; + const u8 *profile; +- const u8 *tbtt_info; + ssize_t profile_len; ++ u8 param_ch_count; + u8 link_id, use_for; + + if (!ieee80211_mle_basic_sta_prof_size_ok((u8 *)mle->sta_prof[i], +@@ -2800,10 +2917,11 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, + profile_len -= 2; + + /* Find in RNR to look up channel information */ +- use_for = cfg80211_tbtt_info_for_mld_ap(tx_data->ie, +- tx_data->ielen, +- mld_id, link_id, +- &ap_info, &tbtt_info); ++ use_for = cfg80211_rnr_info_for_mld_ap(tx_data->ie, ++ tx_data->ielen, ++ mld_id, link_id, ++ &ap_info, ++ ¶m_ch_count); + if (!use_for) + continue; + +@@ -2846,7 +2964,8 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, + continue; + + /* Copy the Basic Multi-Link element including the common +- * information, and then fix up the link ID. ++ * information, and then fix up the link ID and BSS param ++ * change count. + * Note that the ML element length has been verified and we + * also checked that it contains the link ID. + */ +@@ -2857,10 +2976,21 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, + sizeof(*ml_elem) + ml_common_len); + + new_ie[data.ielen + sizeof(*ml_elem) + 1 + ETH_ALEN] = link_id; ++ new_ie[data.ielen + sizeof(*ml_elem) + 1 + ETH_ALEN + 1] = ++ param_ch_count; + + data.ielen += sizeof(*ml_elem) + ml_common_len; + +- /* TODO: Add an RNR containing only the reporting AP */ ++ if (reporter_rnr && (use_for & NL80211_BSS_USE_FOR_NORMAL)) { ++ if (data.ielen + sizeof(struct element) + ++ reporter_rnr->datalen > IEEE80211_MAX_DATA_LEN) ++ continue; ++ ++ memcpy(new_ie + data.ielen, reporter_rnr, ++ sizeof(struct element) + reporter_rnr->datalen); ++ data.ielen += sizeof(struct element) + ++ reporter_rnr->datalen; ++ } + + bss = cfg80211_inform_single_bss_data(wiphy, &data, gfp); + if (!bss) +@@ -2869,6 +2999,7 @@ cfg80211_parse_ml_elem_sta_data(struct wiphy *wiphy, + } + + out: ++ kfree(reporter_rnr); + kfree(new_ie); + kfree(mle); + } +diff --git a/net/wireless/tests/scan.c b/net/wireless/tests/scan.c +index 77854161cd22b..f9ea44aee9952 100644 +--- a/net/wireless/tests/scan.c ++++ b/net/wireless/tests/scan.c +@@ -2,7 +2,7 @@ + /* + * KUnit tests for inform_bss functions + * +- * Copyright (C) 2023 Intel Corporation ++ * Copyright (C) 2023-2024 Intel Corporation + */ + #include + #include +@@ -406,9 +406,27 @@ static struct inform_bss_ml_sta_case { + const char *desc; + int mld_id; + bool sta_prof_vendor_elems; ++ bool include_oper_class; + } inform_bss_ml_sta_cases[] = { +- { .desc = "no_mld_id", .mld_id = 0, .sta_prof_vendor_elems = false }, +- { .desc = "mld_id_eq_1", .mld_id = 1, .sta_prof_vendor_elems = true }, ++ { ++ .desc = "zero_mld_id", ++ .mld_id = 0, ++ .sta_prof_vendor_elems = false, ++ }, { ++ .desc = "zero_mld_id_with_oper_class", ++ .mld_id = 0, ++ .sta_prof_vendor_elems = false, ++ .include_oper_class = true, ++ }, { ++ .desc = "mld_id_eq_1", ++ .mld_id = 1, ++ .sta_prof_vendor_elems = true, ++ }, { ++ .desc = "mld_id_eq_1_with_oper_class", ++ .mld_id = 1, ++ .sta_prof_vendor_elems = true, ++ .include_oper_class = true, ++ }, + }; + KUNIT_ARRAY_PARAM_DESC(inform_bss_ml_sta, inform_bss_ml_sta_cases, desc) + +@@ -515,6 +533,12 @@ static void test_inform_bss_ml_sta(struct kunit *test) + skb_put_u8(input, 4); + skb_put_data(input, "TEST", 4); + ++ if (params->include_oper_class) { ++ skb_put_u8(input, WLAN_EID_SUPPORTED_REGULATORY_CLASSES); ++ skb_put_u8(input, 1); ++ skb_put_u8(input, 81); ++ } ++ + skb_put_u8(input, WLAN_EID_REDUCED_NEIGHBOR_REPORT); + skb_put_u8(input, sizeof(rnr)); + skb_put_data(input, &rnr, sizeof(rnr)); +@@ -582,15 +606,21 @@ static void test_inform_bss_ml_sta(struct kunit *test) + KUNIT_EXPECT_EQ(test, ies->tsf, tsf + le64_to_cpu(sta_prof.tsf_offset)); + /* Resulting length should be: + * SSID (inherited) + RNR (inherited) + vendor element(s) + ++ * operating class (if requested) + ++ * generated RNR (if MLD ID == 0) + + * MLE common info + MLE header and control + */ + if (params->sta_prof_vendor_elems) + KUNIT_EXPECT_EQ(test, ies->len, + 6 + 2 + sizeof(rnr) + 2 + 160 + 2 + 165 + ++ (params->include_oper_class ? 3 : 0) + ++ (!params->mld_id ? 22 : 0) + + mle_basic_common_info.var_len + 5); + else + KUNIT_EXPECT_EQ(test, ies->len, + 6 + 2 + sizeof(rnr) + 2 + 155 + ++ (params->include_oper_class ? 3 : 0) + ++ (!params->mld_id ? 22 : 0) + + mle_basic_common_info.var_len + 5); + rcu_read_unlock(); + +diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c +index f7a7c7798c3b2..d18d51412cc00 100644 +--- a/net/x25/af_x25.c ++++ b/net/x25/af_x25.c +@@ -460,12 +460,12 @@ static int x25_getsockopt(struct socket *sock, int level, int optname, + if (get_user(len, optlen)) + goto out; + +- len = min_t(unsigned int, len, sizeof(int)); +- + rc = -EINVAL; + if (len < 0) + goto out; + ++ len = min_t(unsigned int, len, sizeof(int)); ++ + rc = -EFAULT; + if (put_user(len, optlen)) + goto out; +diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c +index 653e51ae39648..6346690d5c699 100644 +--- a/net/xfrm/xfrm_device.c ++++ b/net/xfrm/xfrm_device.c +@@ -407,7 +407,8 @@ bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x) + struct xfrm_dst *xdst = (struct xfrm_dst *)dst; + struct net_device *dev = x->xso.dev; + +- if (!x->type_offload) ++ if (!x->type_offload || ++ (x->xso.type == XFRM_DEV_OFFLOAD_UNSPECIFIED && x->encap)) + return false; + + if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET || +diff --git a/scripts/coccinelle/api/device_attr_show.cocci b/scripts/coccinelle/api/device_attr_show.cocci +index 550d1d2fc02a9..dfcf9304195f3 100644 +--- a/scripts/coccinelle/api/device_attr_show.cocci ++++ b/scripts/coccinelle/api/device_attr_show.cocci +@@ -28,7 +28,7 @@ ssize_t show(struct device *dev, struct device_attribute *attr, char *buf) + + @rp depends on patch@ + identifier show, dev, attr, buf; +-expression BUF, SZ, FORMAT, STR; ++expression BUF, SZ, FORMAT; + @@ + + ssize_t show(struct device *dev, struct device_attribute *attr, char *buf) +diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l +index cc386e4436834..2c2b3e6f248ca 100644 +--- a/scripts/kconfig/lexer.l ++++ b/scripts/kconfig/lexer.l +@@ -302,8 +302,11 @@ static char *expand_token(const char *in, size_t n) + new_string(); + append_string(in, n); + +- /* get the whole line because we do not know the end of token. */ +- while ((c = input()) != EOF) { ++ /* ++ * get the whole line because we do not know the end of token. ++ * input() returns 0 (not EOF!) when it reachs the end of file. ++ */ ++ while ((c = input()) != 0) { + if (c == '\n') { + unput(c); + break; +diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c +index 18320a248aa7d..78dcb0ea15582 100644 +--- a/sound/core/seq/seq_midi.c ++++ b/sound/core/seq/seq_midi.c +@@ -113,6 +113,12 @@ static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, i + return 0; + } + ++/* callback for snd_seq_dump_var_event(), bridging to dump_midi() */ ++static int __dump_midi(void *ptr, void *buf, int count) ++{ ++ return dump_midi(ptr, buf, count); ++} ++ + static int event_process_midi(struct snd_seq_event *ev, int direct, + void *private_data, int atomic, int hop) + { +@@ -132,7 +138,7 @@ static int event_process_midi(struct snd_seq_event *ev, int direct, + pr_debug("ALSA: seq_midi: invalid sysex event flags = 0x%x\n", ev->flags); + return 0; + } +- snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream); ++ snd_seq_dump_var_event(ev, __dump_midi, substream); + snd_midi_event_reset_decode(msynth->parser); + } else { + if (msynth->parser == NULL) +diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c +index 1b9260108e482..1678737f11be7 100644 +--- a/sound/core/seq/seq_virmidi.c ++++ b/sound/core/seq/seq_virmidi.c +@@ -62,6 +62,13 @@ static void snd_virmidi_init_event(struct snd_virmidi *vmidi, + /* + * decode input event and put to read buffer of each opened file + */ ++ ++/* callback for snd_seq_dump_var_event(), bridging to snd_rawmidi_receive() */ ++static int dump_to_rawmidi(void *ptr, void *buf, int count) ++{ ++ return snd_rawmidi_receive(ptr, buf, count); ++} ++ + static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, + struct snd_seq_event *ev, + bool atomic) +@@ -80,7 +87,7 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, + if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { + if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) + continue; +- snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)snd_rawmidi_receive, vmidi->substream); ++ snd_seq_dump_var_event(ev, dump_to_rawmidi, vmidi->substream); + snd_midi_event_reset_decode(vmidi->parser); + } else { + len = snd_midi_event_decode(vmidi->parser, msg, sizeof(msg), ev); +diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c +index e436d4dab317f..86ddaff915de1 100644 +--- a/sound/pci/hda/cs35l41_hda_property.c ++++ b/sound/pci/hda/cs35l41_hda_property.c +@@ -210,6 +210,7 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde + struct spi_device *spi; + bool dsd_found; + int ret; ++ int i; + + for (cfg = cs35l41_config_table; cfg->ssid; cfg++) { + if (!strcasecmp(cfg->ssid, cs35l41->acpi_subsystem_id)) +@@ -295,16 +296,6 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde + cs35l41->index = id == 0x40 ? 0 : 1; + } + +- if (cfg->num_amps == 3) +- /* 3 amps means a center channel, so no duplicate channels */ +- cs35l41->channel_index = 0; +- else +- /* +- * if 4 amps, there are duplicate channels, so they need different indexes +- * if 2 amps, no duplicate channels, channel_index would be 0 +- */ +- cs35l41->channel_index = cs35l41->index / 2; +- + cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset", + cs35l41->index, GPIOD_OUT_LOW, + "cs35l41-reset"); +@@ -312,6 +303,11 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde + + hw_cfg->spk_pos = cfg->channel[cs35l41->index]; + ++ cs35l41->channel_index = 0; ++ for (i = 0; i < cs35l41->index; i++) ++ if (cfg->channel[i] == hw_cfg->spk_pos) ++ cs35l41->channel_index++; ++ + if (cfg->boost_type == INTERNAL) { + hw_cfg->bst_type = CS35L41_INT_BOOST; + hw_cfg->bst_ind = cfg->boost_ind_nanohenry; +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index a1facdb98d9a0..1dc5eb92ddcad 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -6696,6 +6696,60 @@ static void alc285_fixup_hp_spectre_x360(struct hda_codec *codec, + } + } + ++static void alc285_fixup_hp_envy_x360(struct hda_codec *codec, ++ const struct hda_fixup *fix, ++ int action) ++{ ++ static const struct coef_fw coefs[] = { ++ WRITE_COEF(0x08, 0x6a0c), WRITE_COEF(0x0d, 0xa023), ++ WRITE_COEF(0x10, 0x0320), WRITE_COEF(0x1a, 0x8c03), ++ WRITE_COEF(0x25, 0x1800), WRITE_COEF(0x26, 0x003a), ++ WRITE_COEF(0x28, 0x1dfe), WRITE_COEF(0x29, 0xb014), ++ WRITE_COEF(0x2b, 0x1dfe), WRITE_COEF(0x37, 0xfe15), ++ WRITE_COEF(0x38, 0x7909), WRITE_COEF(0x45, 0xd489), ++ WRITE_COEF(0x46, 0x00f4), WRITE_COEF(0x4a, 0x21e0), ++ WRITE_COEF(0x66, 0x03f0), WRITE_COEF(0x67, 0x1000), ++ WRITE_COEF(0x6e, 0x1005), { } ++ }; ++ ++ static const struct hda_pintbl pincfgs[] = { ++ { 0x12, 0xb7a60130 }, /* Internal microphone*/ ++ { 0x14, 0x90170150 }, /* B&O soundbar speakers */ ++ { 0x17, 0x90170153 }, /* Side speakers */ ++ { 0x19, 0x03a11040 }, /* Headset microphone */ ++ { } ++ }; ++ ++ switch (action) { ++ case HDA_FIXUP_ACT_PRE_PROBE: ++ snd_hda_apply_pincfgs(codec, pincfgs); ++ ++ /* Fixes volume control problem for side speakers */ ++ alc295_fixup_disable_dac3(codec, fix, action); ++ ++ /* Fixes no sound from headset speaker */ ++ snd_hda_codec_amp_stereo(codec, 0x21, HDA_OUTPUT, 0, -1, 0); ++ ++ /* Auto-enable headset mic when plugged */ ++ snd_hda_jack_set_gating_jack(codec, 0x19, 0x21); ++ ++ /* Headset mic volume enhancement */ ++ snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREF50); ++ break; ++ case HDA_FIXUP_ACT_INIT: ++ alc_process_coef_fw(codec, coefs); ++ break; ++ case HDA_FIXUP_ACT_BUILD: ++ rename_ctl(codec, "Bass Speaker Playback Volume", ++ "B&O-Tuned Playback Volume"); ++ rename_ctl(codec, "Front Playback Switch", ++ "B&O Soundbar Playback Switch"); ++ rename_ctl(codec, "Bass Speaker Playback Switch", ++ "Side Speaker Playback Switch"); ++ break; ++ } ++} ++ + /* for hda_fixup_thinkpad_acpi() */ + #include "thinkpad_helper.c" + +@@ -7297,6 +7351,7 @@ enum { + ALC280_FIXUP_HP_9480M, + ALC245_FIXUP_HP_X360_AMP, + ALC285_FIXUP_HP_SPECTRE_X360_EB1, ++ ALC285_FIXUP_HP_ENVY_X360, + ALC288_FIXUP_DELL_HEADSET_MODE, + ALC288_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC288_FIXUP_DELL_XPS_13, +@@ -9273,6 +9328,12 @@ static const struct hda_fixup alc269_fixups[] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_hp_spectre_x360_eb1 + }, ++ [ALC285_FIXUP_HP_ENVY_X360] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = alc285_fixup_hp_envy_x360, ++ .chained = true, ++ .chain_id = ALC285_FIXUP_HP_GPIO_AMP_INIT, ++ }, + [ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_ideapad_s740_coef, +@@ -9861,6 +9922,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3), + SND_PCI_QUIRK(0x103c, 0x8519, "HP Spectre x360 15-df0xxx", ALC285_FIXUP_HP_SPECTRE_X360), + SND_PCI_QUIRK(0x103c, 0x8537, "HP ProBook 440 G6", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), ++ SND_PCI_QUIRK(0x103c, 0x85de, "HP Envy x360 13-ar0xxx", ALC285_FIXUP_HP_ENVY_X360), + SND_PCI_QUIRK(0x103c, 0x860f, "HP ZBook 15 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT), + SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT), + SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED), +@@ -10559,6 +10621,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { + {.id = ALC295_FIXUP_HP_OMEN, .name = "alc295-hp-omen"}, + {.id = ALC285_FIXUP_HP_SPECTRE_X360, .name = "alc285-hp-spectre-x360"}, + {.id = ALC285_FIXUP_HP_SPECTRE_X360_EB1, .name = "alc285-hp-spectre-x360-eb1"}, ++ {.id = ALC285_FIXUP_HP_ENVY_X360, .name = "alc285-hp-envy-x360"}, + {.id = ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP, .name = "alc287-ideapad-bass-spk-amp"}, + {.id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN, .name = "alc287-yoga9-bass-spk-pin"}, + {.id = ALC623_FIXUP_LENOVO_THINKSTATION_P340, .name = "alc623-lenovo-thinkstation-p340"}, +diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c +index 1bfb00102a77a..7aef93126ed0c 100644 +--- a/sound/pci/hda/tas2781_hda_i2c.c ++++ b/sound/pci/hda/tas2781_hda_i2c.c +@@ -160,11 +160,13 @@ static void tas2781_hda_playback_hook(struct device *dev, int action) + pm_runtime_get_sync(dev); + mutex_lock(&tas_hda->priv->codec_lock); + tasdevice_tuning_switch(tas_hda->priv, 0); ++ tas_hda->priv->playback_started = true; + mutex_unlock(&tas_hda->priv->codec_lock); + break; + case HDA_GEN_PCM_ACT_CLOSE: + mutex_lock(&tas_hda->priv->codec_lock); + tasdevice_tuning_switch(tas_hda->priv, 1); ++ tas_hda->priv->playback_started = false; + mutex_unlock(&tas_hda->priv->codec_lock); + + pm_runtime_mark_last_busy(dev); +@@ -666,6 +668,7 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) + tasdevice_save_calibration(tas_priv); + + tasdevice_tuning_switch(tas_hda->priv, 0); ++ tas_hda->priv->playback_started = true; + + out: + mutex_unlock(&tas_hda->priv->codec_lock); +@@ -832,23 +835,19 @@ static void tas2781_hda_i2c_remove(struct i2c_client *clt) + static int tas2781_runtime_suspend(struct device *dev) + { + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); +- int i; + + dev_dbg(tas_hda->dev, "Runtime Suspend\n"); + + mutex_lock(&tas_hda->priv->codec_lock); + ++ /* The driver powers up the amplifiers at module load time. ++ * Stop the playback if it's unused. ++ */ + if (tas_hda->priv->playback_started) { + tasdevice_tuning_switch(tas_hda->priv, 1); + tas_hda->priv->playback_started = false; + } + +- for (i = 0; i < tas_hda->priv->ndev; i++) { +- tas_hda->priv->tasdevice[i].cur_book = -1; +- tas_hda->priv->tasdevice[i].cur_prog = -1; +- tas_hda->priv->tasdevice[i].cur_conf = -1; +- } +- + mutex_unlock(&tas_hda->priv->codec_lock); + + return 0; +@@ -877,16 +876,16 @@ static int tas2781_runtime_resume(struct device *dev) + static int tas2781_system_suspend(struct device *dev) + { + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); +- int ret; + + dev_dbg(tas_hda->priv->dev, "System Suspend\n"); + +- ret = pm_runtime_force_suspend(dev); +- if (ret) +- return ret; ++ mutex_lock(&tas_hda->priv->codec_lock); + + /* Shutdown chip before system suspend */ +- tasdevice_tuning_switch(tas_hda->priv, 1); ++ if (tas_hda->priv->playback_started) ++ tasdevice_tuning_switch(tas_hda->priv, 1); ++ ++ mutex_unlock(&tas_hda->priv->codec_lock); + + /* + * Reset GPIO may be shared, so cannot reset here. +@@ -898,13 +897,9 @@ static int tas2781_system_suspend(struct device *dev) + static int tas2781_system_resume(struct device *dev) + { + struct tas2781_hda *tas_hda = dev_get_drvdata(dev); +- int i, ret; +- +- dev_info(tas_hda->priv->dev, "System Resume\n"); ++ int i; + +- ret = pm_runtime_force_resume(dev); +- if (ret) +- return ret; ++ dev_dbg(tas_hda->priv->dev, "System Resume\n"); + + mutex_lock(&tas_hda->priv->codec_lock); + +@@ -920,6 +915,10 @@ static int tas2781_system_resume(struct device *dev) + * calibrated data inside algo. + */ + tasdevice_apply_calibration(tas_hda->priv); ++ ++ if (tas_hda->priv->playback_started) ++ tasdevice_tuning_switch(tas_hda->priv, 0); ++ + mutex_unlock(&tas_hda->priv->codec_lock); + + return 0; +diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c +index 20b94814a0462..b86f65d420054 100644 +--- a/sound/soc/amd/acp/acp-sof-mach.c ++++ b/sound/soc/amd/acp/acp-sof-mach.c +@@ -126,16 +126,14 @@ static int acp_sof_probe(struct platform_device *pdev) + if (dmi_id && dmi_id->driver_data) + acp_card_drvdata->tdm_mode = dmi_id->driver_data; + +- acp_sofdsp_dai_links_create(card); ++ ret = acp_sofdsp_dai_links_create(card); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, "Failed to create DAI links\n"); + + ret = devm_snd_soc_register_card(&pdev->dev, card); +- if (ret) { +- dev_err(&pdev->dev, +- "devm_snd_soc_register_card(%s) failed: %d\n", +- card->name, ret); +- return ret; +- } +- ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to register card(%s)\n", card->name); + return 0; + } + +diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c +index 420bbf588efea..e100cc9f5c192 100644 +--- a/sound/soc/codecs/tlv320adc3xxx.c ++++ b/sound/soc/codecs/tlv320adc3xxx.c +@@ -1429,7 +1429,7 @@ static int adc3xxx_i2c_probe(struct i2c_client *i2c) + return ret; + } + +-static void __exit adc3xxx_i2c_remove(struct i2c_client *client) ++static void adc3xxx_i2c_remove(struct i2c_client *client) + { + struct adc3xxx *adc3xxx = i2c_get_clientdata(client); + +@@ -1452,7 +1452,7 @@ static struct i2c_driver adc3xxx_i2c_driver = { + .of_match_table = tlv320adc3xxx_of_match, + }, + .probe = adc3xxx_i2c_probe, +- .remove = __exit_p(adc3xxx_i2c_remove), ++ .remove = adc3xxx_i2c_remove, + .id_table = adc3xxx_i2c_id, + }; + +diff --git a/sound/soc/intel/boards/sof_ssp_common.h b/sound/soc/intel/boards/sof_ssp_common.h +index 6d827103479b5..d24888bc99fde 100644 +--- a/sound/soc/intel/boards/sof_ssp_common.h ++++ b/sound/soc/intel/boards/sof_ssp_common.h +@@ -67,6 +67,14 @@ enum sof_ssp_codec { + + enum sof_ssp_codec sof_ssp_detect_codec_type(struct device *dev); + enum sof_ssp_codec sof_ssp_detect_amp_type(struct device *dev); ++ ++#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SOF_SSP_COMMON) + const char *sof_ssp_get_codec_name(enum sof_ssp_codec codec_type); ++#else ++static inline const char *sof_ssp_get_codec_name(enum sof_ssp_codec codec_type) ++{ ++ return NULL; ++} ++#endif + + #endif /* __SOF_SSP_COMMON_H */ +diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c +index 7109b81cc3d0a..5d1419ed7a62d 100644 +--- a/sound/soc/meson/aiu.c ++++ b/sound/soc/meson/aiu.c +@@ -212,11 +212,12 @@ static const char * const aiu_spdif_ids[] = { + static int aiu_clk_get(struct device *dev) + { + struct aiu *aiu = dev_get_drvdata(dev); ++ struct clk *pclk; + int ret; + +- aiu->pclk = devm_clk_get(dev, "pclk"); +- if (IS_ERR(aiu->pclk)) +- return dev_err_probe(dev, PTR_ERR(aiu->pclk), "Can't get the aiu pclk\n"); ++ pclk = devm_clk_get_enabled(dev, "pclk"); ++ if (IS_ERR(pclk)) ++ return dev_err_probe(dev, PTR_ERR(pclk), "Can't get the aiu pclk\n"); + + aiu->spdif_mclk = devm_clk_get(dev, "spdif_mclk"); + if (IS_ERR(aiu->spdif_mclk)) +@@ -233,18 +234,6 @@ static int aiu_clk_get(struct device *dev) + if (ret) + return dev_err_probe(dev, ret, "Can't get the spdif clocks\n"); + +- ret = clk_prepare_enable(aiu->pclk); +- if (ret) { +- dev_err(dev, "peripheral clock enable failed\n"); +- return ret; +- } +- +- ret = devm_add_action_or_reset(dev, +- (void(*)(void *))clk_disable_unprepare, +- aiu->pclk); +- if (ret) +- dev_err(dev, "failed to add reset action on pclk"); +- + return ret; + } + +diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h +index 393b6c2307e49..0f94c8bf60818 100644 +--- a/sound/soc/meson/aiu.h ++++ b/sound/soc/meson/aiu.h +@@ -33,7 +33,6 @@ struct aiu_platform_data { + }; + + struct aiu { +- struct clk *pclk; + struct clk *spdif_mclk; + struct aiu_interface i2s; + struct aiu_interface spdif; +diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c +index 1c3d433cefd23..2cedbce738373 100644 +--- a/sound/soc/meson/axg-tdm-interface.c ++++ b/sound/soc/meson/axg-tdm-interface.c +@@ -12,6 +12,9 @@ + + #include "axg-tdm.h" + ++/* Maximum bit clock frequency according the datasheets */ ++#define MAX_SCLK 100000000 /* Hz */ ++ + enum { + TDM_IFACE_PAD, + TDM_IFACE_LOOPBACK, +@@ -153,19 +156,27 @@ static int axg_tdm_iface_startup(struct snd_pcm_substream *substream, + return -EINVAL; + } + +- /* Apply component wide rate symmetry */ + if (snd_soc_component_active(dai->component)) { ++ /* Apply component wide rate symmetry */ + ret = snd_pcm_hw_constraint_single(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, + iface->rate); +- if (ret < 0) { +- dev_err(dai->dev, +- "can't set iface rate constraint\n"); +- return ret; +- } ++ ++ } else { ++ /* Limit rate according to the slot number and width */ ++ unsigned int max_rate = ++ MAX_SCLK / (iface->slots * iface->slot_width); ++ ret = snd_pcm_hw_constraint_minmax(substream->runtime, ++ SNDRV_PCM_HW_PARAM_RATE, ++ 0, max_rate); + } + +- return 0; ++ if (ret < 0) ++ dev_err(dai->dev, "can't set iface rate constraint\n"); ++ else ++ ret = 0; ++ ++ return ret; + } + + static int axg_tdm_iface_set_stream(struct snd_pcm_substream *substream, +@@ -264,8 +275,8 @@ static int axg_tdm_iface_set_sclk(struct snd_soc_dai *dai, + srate = iface->slots * iface->slot_width * params_rate(params); + + if (!iface->mclk_rate) { +- /* If no specific mclk is requested, default to bit clock * 4 */ +- clk_set_rate(iface->mclk, 4 * srate); ++ /* If no specific mclk is requested, default to bit clock * 2 */ ++ clk_set_rate(iface->mclk, 2 * srate); + } else { + /* Check if we can actually get the bit clock from mclk */ + if (iface->mclk_rate % srate) { +diff --git a/sound/soc/meson/t9015.c b/sound/soc/meson/t9015.c +index 9c6b4dac68932..571f65788c592 100644 +--- a/sound/soc/meson/t9015.c ++++ b/sound/soc/meson/t9015.c +@@ -48,7 +48,6 @@ + #define POWER_CFG 0x10 + + struct t9015 { +- struct clk *pclk; + struct regulator *avdd; + }; + +@@ -249,6 +248,7 @@ static int t9015_probe(struct platform_device *pdev) + struct t9015 *priv; + void __iomem *regs; + struct regmap *regmap; ++ struct clk *pclk; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); +@@ -256,26 +256,14 @@ static int t9015_probe(struct platform_device *pdev) + return -ENOMEM; + platform_set_drvdata(pdev, priv); + +- priv->pclk = devm_clk_get(dev, "pclk"); +- if (IS_ERR(priv->pclk)) +- return dev_err_probe(dev, PTR_ERR(priv->pclk), "failed to get core clock\n"); ++ pclk = devm_clk_get_enabled(dev, "pclk"); ++ if (IS_ERR(pclk)) ++ return dev_err_probe(dev, PTR_ERR(pclk), "failed to get core clock\n"); + + priv->avdd = devm_regulator_get(dev, "AVDD"); + if (IS_ERR(priv->avdd)) + return dev_err_probe(dev, PTR_ERR(priv->avdd), "failed to AVDD\n"); + +- ret = clk_prepare_enable(priv->pclk); +- if (ret) { +- dev_err(dev, "core clock enable failed\n"); +- return ret; +- } +- +- ret = devm_add_action_or_reset(dev, +- (void(*)(void *))clk_disable_unprepare, +- priv->pclk); +- if (ret) +- return ret; +- + ret = device_reset(dev); + if (ret) { + dev_err(dev, "reset failed\n"); +diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c +index 860e66ec85e8a..9fa020ef7eab9 100644 +--- a/sound/soc/rockchip/rockchip_i2s_tdm.c ++++ b/sound/soc/rockchip/rockchip_i2s_tdm.c +@@ -25,8 +25,6 @@ + #define DEFAULT_MCLK_FS 256 + #define CH_GRP_MAX 4 /* The max channel 8 / 2 */ + #define MULTIPLEX_CH_MAX 10 +-#define CLK_PPM_MIN -1000 +-#define CLK_PPM_MAX 1000 + + #define TRCM_TXRX 0 + #define TRCM_TX 1 +@@ -53,20 +51,6 @@ struct rk_i2s_tdm_dev { + struct clk *hclk; + struct clk *mclk_tx; + struct clk *mclk_rx; +- /* The mclk_tx_src is parent of mclk_tx */ +- struct clk *mclk_tx_src; +- /* The mclk_rx_src is parent of mclk_rx */ +- struct clk *mclk_rx_src; +- /* +- * The mclk_root0 and mclk_root1 are root parent and supplies for +- * the different FS. +- * +- * e.g: +- * mclk_root0 is VPLL0, used for FS=48000Hz +- * mclk_root1 is VPLL1, used for FS=44100Hz +- */ +- struct clk *mclk_root0; +- struct clk *mclk_root1; + struct regmap *regmap; + struct regmap *grf; + struct snd_dmaengine_dai_dma_data capture_dma_data; +@@ -76,19 +60,11 @@ struct rk_i2s_tdm_dev { + const struct rk_i2s_soc_data *soc_data; + bool is_master_mode; + bool io_multiplex; +- bool mclk_calibrate; + bool tdm_mode; +- unsigned int mclk_rx_freq; +- unsigned int mclk_tx_freq; +- unsigned int mclk_root0_freq; +- unsigned int mclk_root1_freq; +- unsigned int mclk_root0_initial_freq; +- unsigned int mclk_root1_initial_freq; + unsigned int frame_width; + unsigned int clk_trcm; + unsigned int i2s_sdis[CH_GRP_MAX]; + unsigned int i2s_sdos[CH_GRP_MAX]; +- int clk_ppm; + int refcount; + spinlock_t lock; /* xfer lock */ + bool has_playback; +@@ -114,12 +90,6 @@ static void i2s_tdm_disable_unprepare_mclk(struct rk_i2s_tdm_dev *i2s_tdm) + { + clk_disable_unprepare(i2s_tdm->mclk_tx); + clk_disable_unprepare(i2s_tdm->mclk_rx); +- if (i2s_tdm->mclk_calibrate) { +- clk_disable_unprepare(i2s_tdm->mclk_tx_src); +- clk_disable_unprepare(i2s_tdm->mclk_rx_src); +- clk_disable_unprepare(i2s_tdm->mclk_root0); +- clk_disable_unprepare(i2s_tdm->mclk_root1); +- } + } + + /** +@@ -142,29 +112,9 @@ static int i2s_tdm_prepare_enable_mclk(struct rk_i2s_tdm_dev *i2s_tdm) + ret = clk_prepare_enable(i2s_tdm->mclk_rx); + if (ret) + goto err_mclk_rx; +- if (i2s_tdm->mclk_calibrate) { +- ret = clk_prepare_enable(i2s_tdm->mclk_tx_src); +- if (ret) +- goto err_mclk_rx; +- ret = clk_prepare_enable(i2s_tdm->mclk_rx_src); +- if (ret) +- goto err_mclk_rx_src; +- ret = clk_prepare_enable(i2s_tdm->mclk_root0); +- if (ret) +- goto err_mclk_root0; +- ret = clk_prepare_enable(i2s_tdm->mclk_root1); +- if (ret) +- goto err_mclk_root1; +- } + + return 0; + +-err_mclk_root1: +- clk_disable_unprepare(i2s_tdm->mclk_root0); +-err_mclk_root0: +- clk_disable_unprepare(i2s_tdm->mclk_rx_src); +-err_mclk_rx_src: +- clk_disable_unprepare(i2s_tdm->mclk_tx_src); + err_mclk_rx: + clk_disable_unprepare(i2s_tdm->mclk_tx); + err_mclk_tx: +@@ -564,159 +514,6 @@ static void rockchip_i2s_tdm_xfer_resume(struct snd_pcm_substream *substream, + I2S_XFER_RXS_START); + } + +-static int rockchip_i2s_tdm_clk_set_rate(struct rk_i2s_tdm_dev *i2s_tdm, +- struct clk *clk, unsigned long rate, +- int ppm) +-{ +- unsigned long rate_target; +- int delta, ret; +- +- if (ppm == i2s_tdm->clk_ppm) +- return 0; +- +- if (ppm < 0) +- delta = -1; +- else +- delta = 1; +- +- delta *= (int)div64_u64((u64)rate * (u64)abs(ppm) + 500000, +- 1000000); +- +- rate_target = rate + delta; +- +- if (!rate_target) +- return -EINVAL; +- +- ret = clk_set_rate(clk, rate_target); +- if (ret) +- return ret; +- +- i2s_tdm->clk_ppm = ppm; +- +- return 0; +-} +- +-static int rockchip_i2s_tdm_calibrate_mclk(struct rk_i2s_tdm_dev *i2s_tdm, +- struct snd_pcm_substream *substream, +- unsigned int lrck_freq) +-{ +- struct clk *mclk_root; +- struct clk *mclk_parent; +- unsigned int mclk_root_freq; +- unsigned int mclk_root_initial_freq; +- unsigned int mclk_parent_freq; +- unsigned int div, delta; +- u64 ppm; +- int ret; +- +- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) +- mclk_parent = i2s_tdm->mclk_tx_src; +- else +- mclk_parent = i2s_tdm->mclk_rx_src; +- +- switch (lrck_freq) { +- case 8000: +- case 16000: +- case 24000: +- case 32000: +- case 48000: +- case 64000: +- case 96000: +- case 192000: +- mclk_root = i2s_tdm->mclk_root0; +- mclk_root_freq = i2s_tdm->mclk_root0_freq; +- mclk_root_initial_freq = i2s_tdm->mclk_root0_initial_freq; +- mclk_parent_freq = DEFAULT_MCLK_FS * 192000; +- break; +- case 11025: +- case 22050: +- case 44100: +- case 88200: +- case 176400: +- mclk_root = i2s_tdm->mclk_root1; +- mclk_root_freq = i2s_tdm->mclk_root1_freq; +- mclk_root_initial_freq = i2s_tdm->mclk_root1_initial_freq; +- mclk_parent_freq = DEFAULT_MCLK_FS * 176400; +- break; +- default: +- dev_err(i2s_tdm->dev, "Invalid LRCK frequency: %u Hz\n", +- lrck_freq); +- return -EINVAL; +- } +- +- ret = clk_set_parent(mclk_parent, mclk_root); +- if (ret) +- return ret; +- +- ret = rockchip_i2s_tdm_clk_set_rate(i2s_tdm, mclk_root, +- mclk_root_freq, 0); +- if (ret) +- return ret; +- +- delta = abs(mclk_root_freq % mclk_parent_freq - mclk_parent_freq); +- ppm = div64_u64((uint64_t)delta * 1000000, (uint64_t)mclk_root_freq); +- +- if (ppm) { +- div = DIV_ROUND_CLOSEST(mclk_root_initial_freq, mclk_parent_freq); +- if (!div) +- return -EINVAL; +- +- mclk_root_freq = mclk_parent_freq * round_up(div, 2); +- +- ret = clk_set_rate(mclk_root, mclk_root_freq); +- if (ret) +- return ret; +- +- i2s_tdm->mclk_root0_freq = clk_get_rate(i2s_tdm->mclk_root0); +- i2s_tdm->mclk_root1_freq = clk_get_rate(i2s_tdm->mclk_root1); +- } +- +- return clk_set_rate(mclk_parent, mclk_parent_freq); +-} +- +-static int rockchip_i2s_tdm_set_mclk(struct rk_i2s_tdm_dev *i2s_tdm, +- struct snd_pcm_substream *substream, +- struct clk **mclk) +-{ +- unsigned int mclk_freq; +- int ret; +- +- if (i2s_tdm->clk_trcm) { +- if (i2s_tdm->mclk_tx_freq != i2s_tdm->mclk_rx_freq) { +- dev_err(i2s_tdm->dev, +- "clk_trcm, tx: %d and rx: %d should be the same\n", +- i2s_tdm->mclk_tx_freq, +- i2s_tdm->mclk_rx_freq); +- return -EINVAL; +- } +- +- ret = clk_set_rate(i2s_tdm->mclk_tx, i2s_tdm->mclk_tx_freq); +- if (ret) +- return ret; +- +- ret = clk_set_rate(i2s_tdm->mclk_rx, i2s_tdm->mclk_rx_freq); +- if (ret) +- return ret; +- +- /* mclk_rx is also ok. */ +- *mclk = i2s_tdm->mclk_tx; +- } else { +- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { +- *mclk = i2s_tdm->mclk_tx; +- mclk_freq = i2s_tdm->mclk_tx_freq; +- } else { +- *mclk = i2s_tdm->mclk_rx; +- mclk_freq = i2s_tdm->mclk_rx_freq; +- } +- +- ret = clk_set_rate(*mclk, mclk_freq); +- if (ret) +- return ret; +- } +- +- return 0; +-} +- + static int rockchip_i2s_ch_to_io(unsigned int ch, bool substream_capture) + { + if (substream_capture) { +@@ -853,19 +650,17 @@ static int rockchip_i2s_tdm_hw_params(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) + { + struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai); +- struct clk *mclk; +- int ret = 0; + unsigned int val = 0; + unsigned int mclk_rate, bclk_rate, div_bclk = 4, div_lrck = 64; ++ int err; + + if (i2s_tdm->is_master_mode) { +- if (i2s_tdm->mclk_calibrate) +- rockchip_i2s_tdm_calibrate_mclk(i2s_tdm, substream, +- params_rate(params)); ++ struct clk *mclk = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ i2s_tdm->mclk_tx : i2s_tdm->mclk_rx; + +- ret = rockchip_i2s_tdm_set_mclk(i2s_tdm, substream, &mclk); +- if (ret) +- return ret; ++ err = clk_set_rate(mclk, DEFAULT_MCLK_FS * params_rate(params)); ++ if (err) ++ return err; + + mclk_rate = clk_get_rate(mclk); + bclk_rate = i2s_tdm->frame_width * params_rate(params); +@@ -973,96 +768,6 @@ static int rockchip_i2s_tdm_trigger(struct snd_pcm_substream *substream, + return 0; + } + +-static int rockchip_i2s_tdm_set_sysclk(struct snd_soc_dai *cpu_dai, int stream, +- unsigned int freq, int dir) +-{ +- struct rk_i2s_tdm_dev *i2s_tdm = to_info(cpu_dai); +- +- /* Put set mclk rate into rockchip_i2s_tdm_set_mclk() */ +- if (i2s_tdm->clk_trcm) { +- i2s_tdm->mclk_tx_freq = freq; +- i2s_tdm->mclk_rx_freq = freq; +- } else { +- if (stream == SNDRV_PCM_STREAM_PLAYBACK) +- i2s_tdm->mclk_tx_freq = freq; +- else +- i2s_tdm->mclk_rx_freq = freq; +- } +- +- dev_dbg(i2s_tdm->dev, "The target mclk_%s freq is: %d\n", +- stream ? "rx" : "tx", freq); +- +- return 0; +-} +- +-static int rockchip_i2s_tdm_clk_compensation_info(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_info *uinfo) +-{ +- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; +- uinfo->count = 1; +- uinfo->value.integer.min = CLK_PPM_MIN; +- uinfo->value.integer.max = CLK_PPM_MAX; +- uinfo->value.integer.step = 1; +- +- return 0; +-} +- +-static int rockchip_i2s_tdm_clk_compensation_get(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_value *ucontrol) +-{ +- struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); +- struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai); +- +- ucontrol->value.integer.value[0] = i2s_tdm->clk_ppm; +- +- return 0; +-} +- +-static int rockchip_i2s_tdm_clk_compensation_put(struct snd_kcontrol *kcontrol, +- struct snd_ctl_elem_value *ucontrol) +-{ +- struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); +- struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai); +- int ret = 0, ppm = 0; +- int changed = 0; +- unsigned long old_rate; +- +- if (ucontrol->value.integer.value[0] < CLK_PPM_MIN || +- ucontrol->value.integer.value[0] > CLK_PPM_MAX) +- return -EINVAL; +- +- ppm = ucontrol->value.integer.value[0]; +- +- old_rate = clk_get_rate(i2s_tdm->mclk_root0); +- ret = rockchip_i2s_tdm_clk_set_rate(i2s_tdm, i2s_tdm->mclk_root0, +- i2s_tdm->mclk_root0_freq, ppm); +- if (ret) +- return ret; +- if (old_rate != clk_get_rate(i2s_tdm->mclk_root0)) +- changed = 1; +- +- if (clk_is_match(i2s_tdm->mclk_root0, i2s_tdm->mclk_root1)) +- return changed; +- +- old_rate = clk_get_rate(i2s_tdm->mclk_root1); +- ret = rockchip_i2s_tdm_clk_set_rate(i2s_tdm, i2s_tdm->mclk_root1, +- i2s_tdm->mclk_root1_freq, ppm); +- if (ret) +- return ret; +- if (old_rate != clk_get_rate(i2s_tdm->mclk_root1)) +- changed = 1; +- +- return changed; +-} +- +-static struct snd_kcontrol_new rockchip_i2s_tdm_compensation_control = { +- .iface = SNDRV_CTL_ELEM_IFACE_PCM, +- .name = "PCM Clock Compensation in PPM", +- .info = rockchip_i2s_tdm_clk_compensation_info, +- .get = rockchip_i2s_tdm_clk_compensation_get, +- .put = rockchip_i2s_tdm_clk_compensation_put, +-}; +- + static int rockchip_i2s_tdm_dai_probe(struct snd_soc_dai *dai) + { + struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai); +@@ -1072,9 +777,6 @@ static int rockchip_i2s_tdm_dai_probe(struct snd_soc_dai *dai) + if (i2s_tdm->has_playback) + snd_soc_dai_dma_data_set_playback(dai, &i2s_tdm->playback_dma_data); + +- if (i2s_tdm->mclk_calibrate) +- snd_soc_add_dai_controls(dai, &rockchip_i2s_tdm_compensation_control, 1); +- + return 0; + } + +@@ -1115,7 +817,6 @@ static const struct snd_soc_dai_ops rockchip_i2s_tdm_dai_ops = { + .probe = rockchip_i2s_tdm_dai_probe, + .hw_params = rockchip_i2s_tdm_hw_params, + .set_bclk_ratio = rockchip_i2s_tdm_set_bclk_ratio, +- .set_sysclk = rockchip_i2s_tdm_set_sysclk, + .set_fmt = rockchip_i2s_tdm_set_fmt, + .set_tdm_slot = rockchip_dai_tdm_slot, + .trigger = rockchip_i2s_tdm_trigger, +@@ -1444,35 +1145,6 @@ static void rockchip_i2s_tdm_path_config(struct rk_i2s_tdm_dev *i2s_tdm, + rockchip_i2s_tdm_tx_path_config(i2s_tdm, num); + } + +-static int rockchip_i2s_tdm_get_calibrate_mclks(struct rk_i2s_tdm_dev *i2s_tdm) +-{ +- int num_mclks = 0; +- +- i2s_tdm->mclk_tx_src = devm_clk_get(i2s_tdm->dev, "mclk_tx_src"); +- if (!IS_ERR(i2s_tdm->mclk_tx_src)) +- num_mclks++; +- +- i2s_tdm->mclk_rx_src = devm_clk_get(i2s_tdm->dev, "mclk_rx_src"); +- if (!IS_ERR(i2s_tdm->mclk_rx_src)) +- num_mclks++; +- +- i2s_tdm->mclk_root0 = devm_clk_get(i2s_tdm->dev, "mclk_root0"); +- if (!IS_ERR(i2s_tdm->mclk_root0)) +- num_mclks++; +- +- i2s_tdm->mclk_root1 = devm_clk_get(i2s_tdm->dev, "mclk_root1"); +- if (!IS_ERR(i2s_tdm->mclk_root1)) +- num_mclks++; +- +- if (num_mclks < 4 && num_mclks != 0) +- return -ENOENT; +- +- if (num_mclks == 4) +- i2s_tdm->mclk_calibrate = 1; +- +- return 0; +-} +- + static int rockchip_i2s_tdm_path_prepare(struct rk_i2s_tdm_dev *i2s_tdm, + struct device_node *np, + bool is_rx_path) +@@ -1610,11 +1282,6 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev) + i2s_tdm->io_multiplex = + of_property_read_bool(node, "rockchip,io-multiplex"); + +- ret = rockchip_i2s_tdm_get_calibrate_mclks(i2s_tdm); +- if (ret) +- return dev_err_probe(i2s_tdm->dev, ret, +- "mclk-calibrate clocks missing"); +- + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(regs)) { + return dev_err_probe(i2s_tdm->dev, PTR_ERR(regs), +@@ -1667,13 +1334,6 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev) + goto err_disable_hclk; + } + +- if (i2s_tdm->mclk_calibrate) { +- i2s_tdm->mclk_root0_initial_freq = clk_get_rate(i2s_tdm->mclk_root0); +- i2s_tdm->mclk_root1_initial_freq = clk_get_rate(i2s_tdm->mclk_root1); +- i2s_tdm->mclk_root0_freq = i2s_tdm->mclk_root0_initial_freq; +- i2s_tdm->mclk_root1_freq = i2s_tdm->mclk_root1_initial_freq; +- } +- + pm_runtime_enable(&pdev->dev); + + regmap_update_bits(i2s_tdm->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK, +diff --git a/sound/soc/sh/rz-ssi.c b/sound/soc/sh/rz-ssi.c +index 14cf1a41fb0d1..9d103646973ad 100644 +--- a/sound/soc/sh/rz-ssi.c ++++ b/sound/soc/sh/rz-ssi.c +@@ -1015,7 +1015,7 @@ static int rz_ssi_probe(struct platform_device *pdev) + dev_name(&pdev->dev), ssi); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, +- "irq request error (dma_tx)\n"); ++ "irq request error (dma_rt)\n"); + } else { + if (ssi->irq_tx < 0) + return ssi->irq_tx; +diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c +index e05eb7a86dd44..aad904839b817 100644 +--- a/sound/soc/sof/amd/acp-loader.c ++++ b/sound/soc/sof/amd/acp-loader.c +@@ -173,7 +173,7 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev) + + adata = sdev->pdata->hw_pdata; + +- if (adata->signed_fw_image) ++ if (adata->quirks && adata->quirks->signed_fw_image) + size_fw = adata->fw_bin_size - ACP_FIRMWARE_SIGNATURE; + else + size_fw = adata->fw_bin_size; +@@ -267,29 +267,49 @@ int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev) + { + struct snd_sof_pdata *plat_data = sdev->pdata; + struct acp_dev_data *adata = plat_data->hw_pdata; ++ const char *fw_filename; + int ret; + +- ret = request_firmware(&sdev->basefw.fw, adata->fw_code_bin, sdev->dev); ++ fw_filename = kasprintf(GFP_KERNEL, "%s/%s", ++ plat_data->fw_filename_prefix, ++ adata->fw_code_bin); ++ if (!fw_filename) ++ return -ENOMEM; ++ ++ ret = request_firmware(&sdev->basefw.fw, fw_filename, sdev->dev); + if (ret < 0) { ++ kfree(fw_filename); + dev_err(sdev->dev, "sof signed firmware code bin is missing\n"); + return ret; + } else { +- dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_code_bin); ++ dev_dbg(sdev->dev, "request_firmware %s successful\n", fw_filename); + } ++ kfree(fw_filename); ++ + ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_IRAM, 0, +- (void *)sdev->basefw.fw->data, sdev->basefw.fw->size); ++ (void *)sdev->basefw.fw->data, ++ sdev->basefw.fw->size); ++ ++ fw_filename = kasprintf(GFP_KERNEL, "%s/%s", ++ plat_data->fw_filename_prefix, ++ adata->fw_data_bin); ++ if (!fw_filename) ++ return -ENOMEM; + +- ret = request_firmware(&adata->fw_dbin, adata->fw_data_bin, sdev->dev); ++ ret = request_firmware(&adata->fw_dbin, fw_filename, sdev->dev); + if (ret < 0) { ++ kfree(fw_filename); + dev_err(sdev->dev, "sof signed firmware data bin is missing\n"); + return ret; + + } else { +- dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_data_bin); ++ dev_dbg(sdev->dev, "request_firmware %s successful\n", fw_filename); + } ++ kfree(fw_filename); + + ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0, +- (void *)adata->fw_dbin->data, adata->fw_dbin->size); ++ (void *)adata->fw_dbin->data, ++ adata->fw_dbin->size); + return ret; + } + EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, SND_SOC_SOF_AMD_COMMON); +diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c +index 07632ae6ccf5e..4db8cdc91daae 100644 +--- a/sound/soc/sof/amd/acp.c ++++ b/sound/soc/sof/amd/acp.c +@@ -20,12 +20,15 @@ + #include "acp.h" + #include "acp-dsp-offset.h" + +-#define SECURED_FIRMWARE 1 +- + static bool enable_fw_debug; + module_param(enable_fw_debug, bool, 0444); + MODULE_PARM_DESC(enable_fw_debug, "Enable Firmware debug"); + ++static struct acp_quirk_entry quirk_valve_galileo = { ++ .signed_fw_image = true, ++ .skip_iram_dram_size_mod = true, ++}; ++ + const struct dmi_system_id acp_sof_quirk_table[] = { + { + /* Valve Jupiter device */ +@@ -34,7 +37,7 @@ const struct dmi_system_id acp_sof_quirk_table[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Sephiroth"), + }, +- .driver_data = (void *)SECURED_FIRMWARE, ++ .driver_data = &quirk_valve_galileo, + }, + {} + }; +@@ -255,7 +258,7 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, + } + } + +- if (adata->signed_fw_image) ++ if (adata->quirks && adata->quirks->signed_fw_image) + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_INCLUDE_HDR, ACP_SHA_HEADER); + + snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr); +@@ -279,7 +282,7 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr, + } + + /* psp_send_cmd only required for vangogh platform (rev - 5) */ +- if (desc->rev == 5) { ++ if (desc->rev == 5 && !(adata->quirks && adata->quirks->skip_iram_dram_size_mod)) { + /* Modify IRAM and DRAM size */ + ret = psp_send_cmd(adata, MBOX_ACP_IRAM_DRAM_FENCE_COMMAND | IRAM_DRAM_FENCE_2); + if (ret) +@@ -493,7 +496,6 @@ EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON); + int amd_sof_acp_probe(struct snd_sof_dev *sdev) + { + struct pci_dev *pci = to_pci_dev(sdev->dev); +- struct snd_sof_pdata *plat_data = sdev->pdata; + struct acp_dev_data *adata; + const struct sof_amd_acp_desc *chip; + const struct dmi_system_id *dmi_id; +@@ -557,20 +559,29 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) + sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size; + sdev->debug_box.size = BOX_SIZE_1024; + +- adata->signed_fw_image = false; + dmi_id = dmi_first_match(acp_sof_quirk_table); +- if (dmi_id && dmi_id->driver_data) { +- adata->fw_code_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-code.bin", +- plat_data->fw_filename_prefix, +- chip->name); +- adata->fw_data_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-data.bin", +- plat_data->fw_filename_prefix, +- chip->name); +- adata->signed_fw_image = dmi_id->driver_data; +- +- dev_dbg(sdev->dev, "fw_code_bin:%s, fw_data_bin:%s\n", adata->fw_code_bin, +- adata->fw_data_bin); ++ if (dmi_id) { ++ adata->quirks = dmi_id->driver_data; ++ ++ if (adata->quirks->signed_fw_image) { ++ adata->fw_code_bin = devm_kasprintf(sdev->dev, GFP_KERNEL, ++ "sof-%s-code.bin", ++ chip->name); ++ if (!adata->fw_code_bin) { ++ ret = -ENOMEM; ++ goto free_ipc_irq; ++ } ++ ++ adata->fw_data_bin = devm_kasprintf(sdev->dev, GFP_KERNEL, ++ "sof-%s-data.bin", ++ chip->name); ++ if (!adata->fw_data_bin) { ++ ret = -ENOMEM; ++ goto free_ipc_irq; ++ } ++ } + } ++ + adata->enable_fw_debug = enable_fw_debug; + acp_memory_init(sdev); + +diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h +index c645aee216fd0..7d4a8b6b3cc67 100644 +--- a/sound/soc/sof/amd/acp.h ++++ b/sound/soc/sof/amd/acp.h +@@ -193,6 +193,11 @@ struct sof_amd_acp_desc { + u32 probe_reg_offset; + }; + ++struct acp_quirk_entry { ++ bool signed_fw_image; ++ bool skip_iram_dram_size_mod; ++}; ++ + /* Common device data struct for ACP devices */ + struct acp_dev_data { + struct snd_sof_dev *dev; +@@ -213,7 +218,7 @@ struct acp_dev_data { + u8 *data_buf; + dma_addr_t sram_dma_addr; + u8 *sram_data_buf; +- bool signed_fw_image; ++ struct acp_quirk_entry *quirks; + struct dma_descriptor dscr_info[ACP_MAX_DESC]; + struct acp_dsp_stream stream_buf[ACP_MAX_STREAM]; + struct acp_dsp_stream *dtrace_stream; +diff --git a/sound/soc/sof/amd/vangogh.c b/sound/soc/sof/amd/vangogh.c +index de15d21aa6d98..bc6ffdb5471a5 100644 +--- a/sound/soc/sof/amd/vangogh.c ++++ b/sound/soc/sof/amd/vangogh.c +@@ -143,6 +143,7 @@ EXPORT_SYMBOL_NS(sof_vangogh_ops, SND_SOC_SOF_AMD_COMMON); + int sof_vangogh_ops_init(struct snd_sof_dev *sdev) + { + const struct dmi_system_id *dmi_id; ++ struct acp_quirk_entry *quirks; + + /* common defaults */ + memcpy(&sof_vangogh_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops)); +@@ -151,8 +152,12 @@ int sof_vangogh_ops_init(struct snd_sof_dev *sdev) + sof_vangogh_ops.num_drv = ARRAY_SIZE(vangogh_sof_dai); + + dmi_id = dmi_first_match(acp_sof_quirk_table); +- if (dmi_id && dmi_id->driver_data) +- sof_vangogh_ops.load_firmware = acp_sof_load_signed_firmware; ++ if (dmi_id) { ++ quirks = dmi_id->driver_data; ++ ++ if (quirks->signed_fw_image) ++ sof_vangogh_ops.load_firmware = acp_sof_load_signed_firmware; ++ } + + return 0; + } +diff --git a/sound/soc/sof/fw-file-profile.c b/sound/soc/sof/fw-file-profile.c +index 138a1ca2c4a85..b56b14232444c 100644 +--- a/sound/soc/sof/fw-file-profile.c ++++ b/sound/soc/sof/fw-file-profile.c +@@ -89,6 +89,12 @@ static int sof_test_topology_file(struct device *dev, + return ret; + } + ++static bool sof_platform_uses_generic_loader(struct snd_sof_dev *sdev) ++{ ++ return (sdev->pdata->desc->ops->load_firmware == snd_sof_load_firmware_raw || ++ sdev->pdata->desc->ops->load_firmware == snd_sof_load_firmware_memcpy); ++} ++ + static int + sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev, + enum sof_ipc_type ipc_type, +@@ -130,7 +136,8 @@ sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev, + * For default path and firmware name do a verification before + * continuing further. + */ +- if (base_profile->fw_path || base_profile->fw_name) { ++ if ((base_profile->fw_path || base_profile->fw_name) && ++ sof_platform_uses_generic_loader(sdev)) { + ret = sof_test_firmware_file(dev, out_profile, &ipc_type); + if (ret) + return ret; +@@ -181,7 +188,8 @@ sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev, + out_profile->ipc_type = ipc_type; + + /* Test only default firmware file */ +- if (!base_profile->fw_path && !base_profile->fw_name) ++ if ((!base_profile->fw_path && !base_profile->fw_name) && ++ sof_platform_uses_generic_loader(sdev)) + ret = sof_test_firmware_file(dev, out_profile, NULL); + + if (!ret) +@@ -267,7 +275,11 @@ static void sof_print_profile_info(struct snd_sof_dev *sdev, + + dev_info(dev, "Firmware paths/files for ipc type %d:\n", profile->ipc_type); + +- dev_info(dev, " Firmware file: %s/%s\n", profile->fw_path, profile->fw_name); ++ /* The firmware path is only valid when generic loader is used */ ++ if (sof_platform_uses_generic_loader(sdev)) ++ dev_info(dev, " Firmware file: %s/%s\n", ++ profile->fw_path, profile->fw_name); ++ + if (profile->fw_lib_path) + dev_info(dev, " Firmware lib path: %s\n", profile->fw_lib_path); + dev_info(dev, " Topology file: %s/%s\n", profile->tplg_path, profile->tplg_name); +diff --git a/sound/soc/sof/ipc3-loader.c b/sound/soc/sof/ipc3-loader.c +index 28218766d2114..6e3ef06721106 100644 +--- a/sound/soc/sof/ipc3-loader.c ++++ b/sound/soc/sof/ipc3-loader.c +@@ -148,6 +148,8 @@ static size_t sof_ipc3_fw_parse_ext_man(struct snd_sof_dev *sdev) + + head = (struct sof_ext_man_header *)fw->data; + remaining = head->full_size - head->header_size; ++ if (remaining < 0 || remaining > sdev->basefw.fw->size) ++ return -EINVAL; + ext_man_size = ipc3_fw_ext_man_size(sdev, fw); + + /* Assert firmware starts with extended manifest */ +diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c +index 6de605a601e5f..bd114be537d7a 100644 +--- a/sound/usb/mixer_scarlett2.c ++++ b/sound/usb/mixer_scarlett2.c +@@ -173,7 +173,12 @@ + + /* some gui mixers can't handle negative ctl values */ + #define SCARLETT2_VOLUME_BIAS 127 +-#define SCARLETT2_GAIN_BIAS 70 ++ ++/* maximum preamp input gain and value ++ * values are from 0 to 70, preamp gain is from 0 to 69 dB ++ */ ++#define SCARLETT2_MAX_GAIN_VALUE 70 ++#define SCARLETT2_MAX_GAIN_DB 69 + + /* mixer range from -80dB to +6dB in 0.5dB steps */ + #define SCARLETT2_MIXER_MIN_DB -80 +@@ -284,14 +289,22 @@ static const char *const scarlett2_dim_mute_names[SCARLETT2_DIM_MUTE_COUNT] = { + "Mute Playback Switch", "Dim Playback Switch" + }; + +-/* Autogain Status Values */ +-enum { +- SCARLETT2_AUTOGAIN_STATUS_STOPPED, +- SCARLETT2_AUTOGAIN_STATUS_RUNNING, +- SCARLETT2_AUTOGAIN_STATUS_FAILED, +- SCARLETT2_AUTOGAIN_STATUS_CANCELLED, +- SCARLETT2_AUTOGAIN_STATUS_UNKNOWN, +- SCARLETT2_AUTOGAIN_STATUS_COUNT ++/* The autogain_status is set based on the autogain_switch and ++ * raw_autogain_status values. ++ * ++ * If autogain_switch is set, autogain_status is set to 0 (Running). ++ * The other status values are from the raw_autogain_status value + 1. ++ */ ++static const char *const scarlett2_autogain_status_texts[] = { ++ "Running", ++ "Success", ++ "SuccessDRover", ++ "WarnMinGainLimit", ++ "FailDRunder", ++ "FailMaxGainLimit", ++ "FailClipped", ++ "Cancelled", ++ "Invalid" + }; + + /* Power Status Values */ +@@ -415,7 +428,7 @@ enum { + SCARLETT2_CONFIG_INPUT_SELECT_SWITCH, + SCARLETT2_CONFIG_INPUT_LINK_SWITCH, + SCARLETT2_CONFIG_POWER_EXT, +- SCARLETT2_CONFIG_POWER_STATUS, ++ SCARLETT2_CONFIG_POWER_LOW, + SCARLETT2_CONFIG_PCM_INPUT_SWITCH, + SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN, + SCARLETT2_CONFIG_COUNT +@@ -723,8 +736,8 @@ static const struct scarlett2_config_set scarlett2_config_set_gen4_4i4 = { + [SCARLETT2_CONFIG_POWER_EXT] = { + .offset = 0x168 }, + +- [SCARLETT2_CONFIG_POWER_STATUS] = { +- .offset = 0x66 } ++ [SCARLETT2_CONFIG_POWER_LOW] = { ++ .offset = 0x16d } + } + }; + +@@ -2835,9 +2848,9 @@ static int scarlett2_autogain_is_running(struct scarlett2_data *private) + { + int i; + ++ /* autogain_status[] is 0 if autogain is running */ + for (i = 0; i < private->info->gain_input_count; i++) +- if (private->autogain_status[i] == +- SCARLETT2_AUTOGAIN_STATUS_RUNNING) ++ if (!private->autogain_status[i]) + return 1; + + return 0; +@@ -2867,25 +2880,25 @@ static int scarlett2_update_autogain(struct usb_mixer_interface *mixer) + return err; + + /* Translate autogain_switch and raw_autogain_status into +- * autogain_status ++ * autogain_status. ++ * ++ * When autogain_switch[] is set, the status is the first ++ * element in scarlett2_autogain_status_texts[] (Running). The ++ * subsequent elements correspond to the status value from the ++ * device (raw_autogain_status[]) + 1. The last element is ++ * "Invalid", in case the device reports a status outside the ++ * range of scarlett2_autogain_status_texts[]. + */ + for (i = 0; i < info->gain_input_count; i++) + if (private->autogain_switch[i]) ++ private->autogain_status[i] = 0; ++ else if (raw_autogain_status[i] < ++ ARRAY_SIZE(scarlett2_autogain_status_texts) - 1) + private->autogain_status[i] = +- SCARLETT2_AUTOGAIN_STATUS_RUNNING; +- else if (raw_autogain_status[i] == 0) +- private->autogain_status[i] = +- SCARLETT2_AUTOGAIN_STATUS_STOPPED; +- else if (raw_autogain_status[i] >= 2 && +- raw_autogain_status[i] <= 5) +- private->autogain_status[i] = +- SCARLETT2_AUTOGAIN_STATUS_FAILED; +- else if (raw_autogain_status[i] == 6) +- private->autogain_status[i] = +- SCARLETT2_AUTOGAIN_STATUS_CANCELLED; ++ raw_autogain_status[i] + 1; + else + private->autogain_status[i] = +- SCARLETT2_AUTOGAIN_STATUS_UNKNOWN; ++ ARRAY_SIZE(scarlett2_autogain_status_texts) - 1; + + return 0; + } +@@ -3111,12 +3124,10 @@ static int scarlett2_autogain_switch_ctl_put( + static int scarlett2_autogain_status_ctl_info( + struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) + { +- static const char *const values[SCARLETT2_AUTOGAIN_STATUS_COUNT] = { +- "Stopped", "Running", "Failed", "Cancelled", "Unknown" +- }; +- + return snd_ctl_enum_info( +- uinfo, 1, SCARLETT2_AUTOGAIN_STATUS_COUNT, values); ++ uinfo, 1, ++ ARRAY_SIZE(scarlett2_autogain_status_texts), ++ scarlett2_autogain_status_texts); + } + + static const struct snd_kcontrol_new scarlett2_autogain_switch_ctl = { +@@ -3458,7 +3469,7 @@ static int scarlett2_input_gain_ctl_info(struct snd_kcontrol *kctl, + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = elem->channels; + uinfo->value.integer.min = 0; +- uinfo->value.integer.max = SCARLETT2_GAIN_BIAS; ++ uinfo->value.integer.max = SCARLETT2_MAX_GAIN_VALUE; + uinfo->value.integer.step = 1; + + unlock: +@@ -3535,7 +3546,7 @@ static int scarlett2_input_gain_ctl_put(struct snd_kcontrol *kctl, + } + + static const DECLARE_TLV_DB_MINMAX( +- db_scale_scarlett2_gain, -SCARLETT2_GAIN_BIAS * 100, 0 ++ db_scale_scarlett2_gain, 0, SCARLETT2_MAX_GAIN_DB * 100 + ); + + static const struct snd_kcontrol_new scarlett2_input_gain_ctl = { +@@ -6294,8 +6305,7 @@ static int scarlett2_update_power_status(struct usb_mixer_interface *mixer) + { + struct scarlett2_data *private = mixer->private_data; + int err; +- u8 power_ext; +- u8 power_status; ++ u8 power_ext, power_low; + + private->power_status_updated = 0; + +@@ -6304,12 +6314,12 @@ static int scarlett2_update_power_status(struct usb_mixer_interface *mixer) + if (err < 0) + return err; + +- err = scarlett2_usb_get_config(mixer, SCARLETT2_CONFIG_POWER_STATUS, +- 1, &power_status); ++ err = scarlett2_usb_get_config(mixer, SCARLETT2_CONFIG_POWER_LOW, ++ 1, &power_low); + if (err < 0) + return err; + +- if (power_status > 1) ++ if (power_low) + private->power_status = SCARLETT2_POWER_STATUS_FAIL; + else if (power_ext) + private->power_status = SCARLETT2_POWER_STATUS_EXT; +diff --git a/sound/usb/stream.c b/sound/usb/stream.c +index 3d4add94e367d..d5409f3879455 100644 +--- a/sound/usb/stream.c ++++ b/sound/usb/stream.c +@@ -300,9 +300,12 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits, + c = 0; + + if (bits) { +- for (; bits && *maps; maps++, bits >>= 1) ++ for (; bits && *maps; maps++, bits >>= 1) { + if (bits & 1) + chmap->map[c++] = *maps; ++ if (c == chmap->channels) ++ break; ++ } + } else { + /* If we're missing wChannelConfig, then guess something + to make sure the channel map is not skipped entirely */ +diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c +index cb46667a6b2e7..35b6859dd7c3d 100644 +--- a/tools/bpf/bpftool/link.c ++++ b/tools/bpf/bpftool/link.c +@@ -977,7 +977,7 @@ static int do_show_link(int fd) + cookies = calloc(count, sizeof(__u64)); + if (!cookies) { + p_err("mem alloc failed"); +- free(cookies); ++ free(ref_ctr_offsets); + free(offsets); + close(fd); + return -ENOMEM; +diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c +index feb8e305804fc..9cb42a3366c07 100644 +--- a/tools/bpf/bpftool/prog.c ++++ b/tools/bpf/bpftool/prog.c +@@ -2298,7 +2298,7 @@ static int profile_open_perf_events(struct profiler_bpf *obj) + int map_fd; + + profile_perf_events = calloc( +- sizeof(int), obj->rodata->num_cpu * obj->rodata->num_metric); ++ obj->rodata->num_cpu * obj->rodata->num_metric, sizeof(int)); + if (!profile_perf_events) { + p_err("failed to allocate memory for perf_event array: %s", + strerror(errno)); +diff --git a/tools/bpf/resolve_btfids/main.c b/tools/bpf/resolve_btfids/main.c +index 27a23196d58e1..d9520cb826b31 100644 +--- a/tools/bpf/resolve_btfids/main.c ++++ b/tools/bpf/resolve_btfids/main.c +@@ -70,6 +70,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -78,7 +79,7 @@ + #include + + #define BTF_IDS_SECTION ".BTF_ids" +-#define BTF_ID "__BTF_ID__" ++#define BTF_ID_PREFIX "__BTF_ID__" + + #define BTF_STRUCT "struct" + #define BTF_UNION "union" +@@ -89,6 +90,14 @@ + + #define ADDR_CNT 100 + ++#if __BYTE_ORDER == __LITTLE_ENDIAN ++# define ELFDATANATIVE ELFDATA2LSB ++#elif __BYTE_ORDER == __BIG_ENDIAN ++# define ELFDATANATIVE ELFDATA2MSB ++#else ++# error "Unknown machine endianness!" ++#endif ++ + struct btf_id { + struct rb_node rb_node; + char *name; +@@ -116,6 +125,7 @@ struct object { + int idlist_shndx; + size_t strtabidx; + unsigned long idlist_addr; ++ int encoding; + } efile; + + struct rb_root sets; +@@ -161,7 +171,7 @@ static int eprintf(int level, int var, const char *fmt, ...) + + static bool is_btf_id(const char *name) + { +- return name && !strncmp(name, BTF_ID, sizeof(BTF_ID) - 1); ++ return name && !strncmp(name, BTF_ID_PREFIX, sizeof(BTF_ID_PREFIX) - 1); + } + + static struct btf_id *btf_id__find(struct rb_root *root, const char *name) +@@ -319,6 +329,7 @@ static int elf_collect(struct object *obj) + { + Elf_Scn *scn = NULL; + size_t shdrstrndx; ++ GElf_Ehdr ehdr; + int idx = 0; + Elf *elf; + int fd; +@@ -350,6 +361,13 @@ static int elf_collect(struct object *obj) + return -1; + } + ++ if (gelf_getehdr(obj->efile.elf, &ehdr) == NULL) { ++ pr_err("FAILED cannot get ELF header: %s\n", ++ elf_errmsg(-1)); ++ return -1; ++ } ++ obj->efile.encoding = ehdr.e_ident[EI_DATA]; ++ + /* + * Scan all the elf sections and look for save data + * from .BTF_ids section and symbols. +@@ -441,7 +459,7 @@ static int symbols_collect(struct object *obj) + * __BTF_ID__TYPE__vfs_truncate__0 + * prefix = ^ + */ +- prefix = name + sizeof(BTF_ID) - 1; ++ prefix = name + sizeof(BTF_ID_PREFIX) - 1; + + /* struct */ + if (!strncmp(prefix, BTF_STRUCT, sizeof(BTF_STRUCT) - 1)) { +@@ -649,19 +667,18 @@ static int cmp_id(const void *pa, const void *pb) + static int sets_patch(struct object *obj) + { + Elf_Data *data = obj->efile.idlist; +- int *ptr = data->d_buf; + struct rb_node *next; + + next = rb_first(&obj->sets); + while (next) { +- unsigned long addr, idx; ++ struct btf_id_set8 *set8; ++ struct btf_id_set *set; ++ unsigned long addr, off; + struct btf_id *id; +- int *base; +- int cnt; + + id = rb_entry(next, struct btf_id, rb_node); + addr = id->addr[0]; +- idx = addr - obj->efile.idlist_addr; ++ off = addr - obj->efile.idlist_addr; + + /* sets are unique */ + if (id->addr_cnt != 1) { +@@ -670,14 +687,39 @@ static int sets_patch(struct object *obj) + return -1; + } + +- idx = idx / sizeof(int); +- base = &ptr[idx] + (id->is_set8 ? 2 : 1); +- cnt = ptr[idx]; ++ if (id->is_set) { ++ set = data->d_buf + off; ++ qsort(set->ids, set->cnt, sizeof(set->ids[0]), cmp_id); ++ } else { ++ set8 = data->d_buf + off; ++ /* ++ * Make sure id is at the beginning of the pairs ++ * struct, otherwise the below qsort would not work. ++ */ ++ BUILD_BUG_ON(set8->pairs != &set8->pairs[0].id); ++ qsort(set8->pairs, set8->cnt, sizeof(set8->pairs[0]), cmp_id); + +- pr_debug("sorting addr %5lu: cnt %6d [%s]\n", +- (idx + 1) * sizeof(int), cnt, id->name); ++ /* ++ * When ELF endianness does not match endianness of the ++ * host, libelf will do the translation when updating ++ * the ELF. This, however, corrupts SET8 flags which are ++ * already in the target endianness. So, let's bswap ++ * them to the host endianness and libelf will then ++ * correctly translate everything. ++ */ ++ if (obj->efile.encoding != ELFDATANATIVE) { ++ int i; ++ ++ set8->flags = bswap_32(set8->flags); ++ for (i = 0; i < set8->cnt; i++) { ++ set8->pairs[i].flags = ++ bswap_32(set8->pairs[i].flags); ++ } ++ } ++ } + +- qsort(base, cnt, id->is_set8 ? sizeof(uint64_t) : sizeof(int), cmp_id); ++ pr_debug("sorting addr %5lu: cnt %6d [%s]\n", ++ off, id->is_set ? set->cnt : set8->cnt, id->name); + + next = rb_next(next); + } +diff --git a/tools/include/linux/btf_ids.h b/tools/include/linux/btf_ids.h +index 2f882d5cb30f5..72535f00572f6 100644 +--- a/tools/include/linux/btf_ids.h ++++ b/tools/include/linux/btf_ids.h +@@ -8,6 +8,15 @@ struct btf_id_set { + u32 ids[]; + }; + ++struct btf_id_set8 { ++ u32 cnt; ++ u32 flags; ++ struct { ++ u32 id; ++ u32 flags; ++ } pairs[]; ++}; ++ + #ifdef CONFIG_DEBUG_INFO_BTF + + #include /* for __PASTE */ +diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h +index d0f53772bdc02..dad7917903d19 100644 +--- a/tools/lib/bpf/bpf.h ++++ b/tools/lib/bpf/bpf.h +@@ -35,7 +35,7 @@ + extern "C" { + #endif + +-int libbpf_set_memlock_rlim(size_t memlock_bytes); ++LIBBPF_API int libbpf_set_memlock_rlim(size_t memlock_bytes); + + struct bpf_map_create_opts { + size_t sz; /* size of this struct for forward/backward compatibility */ +diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c +index afd09571c482b..92bca96587a4a 100644 +--- a/tools/lib/bpf/libbpf.c ++++ b/tools/lib/bpf/libbpf.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -70,6 +71,7 @@ + + static struct bpf_map *bpf_object__add_map(struct bpf_object *obj); + static bool prog_is_subprog(const struct bpf_object *obj, const struct bpf_program *prog); ++static int map_set_def_max_entries(struct bpf_map *map); + + static const char * const attach_type_name[] = { + [BPF_CGROUP_INET_INGRESS] = "cgroup_inet_ingress", +@@ -5172,6 +5174,9 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b + + if (bpf_map_type__is_map_in_map(def->type)) { + if (map->inner_map) { ++ err = map_set_def_max_entries(map->inner_map); ++ if (err) ++ return err; + err = bpf_object__create_map(obj, map->inner_map, true); + if (err) { + pr_warn("map '%s': failed to create inner map: %d\n", +@@ -6695,6 +6700,14 @@ static struct { + /* all other program types don't have "named" context structs */ + }; + ++/* forward declarations for arch-specific underlying types of bpf_user_pt_regs_t typedef, ++ * for below __builtin_types_compatible_p() checks; ++ * with this approach we don't need any extra arch-specific #ifdef guards ++ */ ++struct pt_regs; ++struct user_pt_regs; ++struct user_regs_struct; ++ + static bool need_func_arg_type_fixup(const struct btf *btf, const struct bpf_program *prog, + const char *subprog_name, int arg_idx, + int arg_type_id, const char *ctx_name) +@@ -6735,11 +6748,21 @@ static bool need_func_arg_type_fixup(const struct btf *btf, const struct bpf_pro + /* special cases */ + switch (prog->type) { + case BPF_PROG_TYPE_KPROBE: +- case BPF_PROG_TYPE_PERF_EVENT: + /* `struct pt_regs *` is expected, but we need to fix up */ + if (btf_is_struct(t) && strcmp(tname, "pt_regs") == 0) + return true; + break; ++ case BPF_PROG_TYPE_PERF_EVENT: ++ if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct pt_regs) && ++ btf_is_struct(t) && strcmp(tname, "pt_regs") == 0) ++ return true; ++ if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct user_pt_regs) && ++ btf_is_struct(t) && strcmp(tname, "user_pt_regs") == 0) ++ return true; ++ if (__builtin_types_compatible_p(bpf_user_pt_regs_t, struct user_regs_struct) && ++ btf_is_struct(t) && strcmp(tname, "user_regs_struct") == 0) ++ return true; ++ break; + case BPF_PROG_TYPE_RAW_TRACEPOINT: + case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE: + /* allow u64* as ctx */ +diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h +index 27e4e320e1a69..878a0d0b51f5c 100644 +--- a/tools/lib/bpf/libbpf_internal.h ++++ b/tools/lib/bpf/libbpf_internal.h +@@ -18,6 +18,20 @@ + #include + #include "relo_core.h" + ++/* Android's libc doesn't support AT_EACCESS in faccessat() implementation ++ * ([0]), and just returns -EINVAL even if file exists and is accessible. ++ * See [1] for issues caused by this. ++ * ++ * So just redefine it to 0 on Android. ++ * ++ * [0] https://android.googlesource.com/platform/bionic/+/refs/heads/android13-release/libc/bionic/faccessat.cpp#50 ++ * [1] https://github.com/libbpf/libbpf-bootstrap/issues/250#issuecomment-1911324250 ++ */ ++#ifdef __ANDROID__ ++#undef AT_EACCESS ++#define AT_EACCESS 0 ++#endif ++ + /* make sure libbpf doesn't use kernel-only integer typedefs */ + #pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64 + +diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c +index 090bcf6e3b3d5..68a2def171751 100644 +--- a/tools/lib/bpf/netlink.c ++++ b/tools/lib/bpf/netlink.c +@@ -496,8 +496,8 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) + if (err) + return libbpf_err(err); + +- opts->feature_flags = md.flags; +- opts->xdp_zc_max_segs = md.xdp_zc_max_segs; ++ OPTS_SET(opts, feature_flags, md.flags); ++ OPTS_SET(opts, xdp_zc_max_segs, md.xdp_zc_max_segs); + + skip_feature_flags: + return 0; +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index 548ec3cd7c00c..c4c2f75eadfd9 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -3620,6 +3620,18 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, + } + + if (!save_insn->visited) { ++ /* ++ * If the restore hint insn is at the ++ * beginning of a basic block and was ++ * branched to from elsewhere, and the ++ * save insn hasn't been visited yet, ++ * defer following this branch for now. ++ * It will be seen later via the ++ * straight-line path. ++ */ ++ if (!prev_insn) ++ return 0; ++ + WARN_INSN(insn, "objtool isn't smart enough to handle this CFI save/restore combo"); + return 1; + } +diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf +index f8774a9b1377a..116db7874412d 100644 +--- a/tools/perf/Makefile.perf ++++ b/tools/perf/Makefile.perf +@@ -1167,7 +1167,7 @@ bpf-skel: + endif # CONFIG_PERF_BPF_SKEL + + bpf-skel-clean: +- $(call QUIET_CLEAN, bpf-skel) $(RM) -r $(SKEL_TMP_OUT) $(SKELETONS) ++ $(call QUIET_CLEAN, bpf-skel) $(RM) -r $(SKEL_TMP_OUT) $(SKELETONS) $(SKEL_OUT)/vmlinux.h + + clean:: $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean $(LIBSYMBOL)-clean $(LIBPERF)-clean arm64-sysreg-defs-clean fixdep-clean python-clean bpf-skel-clean tests-coresight-targets-clean + $(call QUIET_CLEAN, core-objs) $(RM) $(LIBPERF_A) $(OUTPUT)perf-archive $(OUTPUT)perf-iostat $(LANG_BINDINGS) +diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c +index 86c9101251726..3ddd4381aebd2 100644 +--- a/tools/perf/builtin-record.c ++++ b/tools/perf/builtin-record.c +@@ -1830,8 +1830,8 @@ static int + record__switch_output(struct record *rec, bool at_exit) + { + struct perf_data *data = &rec->data; ++ char *new_filename = NULL; + int fd, err; +- char *new_filename; + + /* Same Size: "2015122520103046"*/ + char timestamp[] = "InvalidTimestamp"; +@@ -2472,6 +2472,11 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) + if (data->is_pipe && rec->evlist->core.nr_entries == 1) + rec->opts.sample_id = true; + ++ if (rec->timestamp_filename && perf_data__is_pipe(data)) { ++ rec->timestamp_filename = false; ++ pr_warning("WARNING: --timestamp-filename option is not available in pipe mode.\n"); ++ } ++ + evlist__uniquify_name(rec->evlist); + + /* Debug message used by test scripts */ +diff --git a/tools/perf/pmu-events/arch/x86/amdzen4/cache.json b/tools/perf/pmu-events/arch/x86/amdzen4/cache.json +index ecbe9660b2b31..e6d710cf3ce29 100644 +--- a/tools/perf/pmu-events/arch/x86/amdzen4/cache.json ++++ b/tools/perf/pmu-events/arch/x86/amdzen4/cache.json +@@ -676,6 +676,10 @@ + "EventCode": "0xac", + "BriefDescription": "Average sampled latency when data is sourced from DRAM in the same NUMA node.", + "UMask": "0x01", ++ "EnAllCores": "0x1", ++ "EnAllSlices": "0x1", ++ "SliceId": "0x3", ++ "ThreadMask": "0x3", + "Unit": "L3PMC" + }, + { +@@ -683,6 +687,10 @@ + "EventCode": "0xac", + "BriefDescription": "Average sampled latency when data is sourced from DRAM in a different NUMA node.", + "UMask": "0x02", ++ "EnAllCores": "0x1", ++ "EnAllSlices": "0x1", ++ "SliceId": "0x3", ++ "ThreadMask": "0x3", + "Unit": "L3PMC" + }, + { +@@ -690,6 +698,10 @@ + "EventCode": "0xac", + "BriefDescription": "Average sampled latency when data is sourced from another CCX's cache when the address was in the same NUMA node.", + "UMask": "0x04", ++ "EnAllCores": "0x1", ++ "EnAllSlices": "0x1", ++ "SliceId": "0x3", ++ "ThreadMask": "0x3", + "Unit": "L3PMC" + }, + { +@@ -697,6 +709,10 @@ + "EventCode": "0xac", + "BriefDescription": "Average sampled latency when data is sourced from another CCX's cache when the address was in a different NUMA node.", + "UMask": "0x08", ++ "EnAllCores": "0x1", ++ "EnAllSlices": "0x1", ++ "SliceId": "0x3", ++ "ThreadMask": "0x3", + "Unit": "L3PMC" + }, + { +@@ -704,6 +720,10 @@ + "EventCode": "0xac", + "BriefDescription": "Average sampled latency when data is sourced from extension memory (CXL) in the same NUMA node.", + "UMask": "0x10", ++ "EnAllCores": "0x1", ++ "EnAllSlices": "0x1", ++ "SliceId": "0x3", ++ "ThreadMask": "0x3", + "Unit": "L3PMC" + }, + { +@@ -711,6 +731,10 @@ + "EventCode": "0xac", + "BriefDescription": "Average sampled latency when data is sourced from extension memory (CXL) in a different NUMA node.", + "UMask": "0x20", ++ "EnAllCores": "0x1", ++ "EnAllSlices": "0x1", ++ "SliceId": "0x3", ++ "ThreadMask": "0x3", + "Unit": "L3PMC" + }, + { +@@ -718,6 +742,10 @@ + "EventCode": "0xac", + "BriefDescription": "Average sampled latency from all data sources.", + "UMask": "0x3f", ++ "EnAllCores": "0x1", ++ "EnAllSlices": "0x1", ++ "SliceId": "0x3", ++ "ThreadMask": "0x3", + "Unit": "L3PMC" + }, + { +@@ -725,6 +753,10 @@ + "EventCode": "0xad", + "BriefDescription": "L3 cache fill requests sourced from DRAM in the same NUMA node.", + "UMask": "0x01", ++ "EnAllCores": "0x1", ++ "EnAllSlices": "0x1", ++ "SliceId": "0x3", ++ "ThreadMask": "0x3", + "Unit": "L3PMC" + }, + { +@@ -732,6 +764,10 @@ + "EventCode": "0xad", + "BriefDescription": "L3 cache fill requests sourced from DRAM in a different NUMA node.", + "UMask": "0x02", ++ "EnAllCores": "0x1", ++ "EnAllSlices": "0x1", ++ "SliceId": "0x3", ++ "ThreadMask": "0x3", + "Unit": "L3PMC" + }, + { +@@ -739,6 +775,10 @@ + "EventCode": "0xad", + "BriefDescription": "L3 cache fill requests sourced from another CCX's cache when the address was in the same NUMA node.", + "UMask": "0x04", ++ "EnAllCores": "0x1", ++ "EnAllSlices": "0x1", ++ "SliceId": "0x3", ++ "ThreadMask": "0x3", + "Unit": "L3PMC" + }, + { +@@ -746,6 +786,10 @@ + "EventCode": "0xad", + "BriefDescription": "L3 cache fill requests sourced from another CCX's cache when the address was in a different NUMA node.", + "UMask": "0x08", ++ "EnAllCores": "0x1", ++ "EnAllSlices": "0x1", ++ "SliceId": "0x3", ++ "ThreadMask": "0x3", + "Unit": "L3PMC" + }, + { +@@ -753,6 +797,10 @@ + "EventCode": "0xad", + "BriefDescription": "L3 cache fill requests sourced from extension memory (CXL) in the same NUMA node.", + "UMask": "0x10", ++ "EnAllCores": "0x1", ++ "EnAllSlices": "0x1", ++ "SliceId": "0x3", ++ "ThreadMask": "0x3", + "Unit": "L3PMC" + }, + { +@@ -760,6 +808,10 @@ + "EventCode": "0xad", + "BriefDescription": "L3 cache fill requests sourced from extension memory (CXL) in a different NUMA node.", + "UMask": "0x20", ++ "EnAllCores": "0x1", ++ "EnAllSlices": "0x1", ++ "SliceId": "0x3", ++ "ThreadMask": "0x3", + "Unit": "L3PMC" + }, + { +@@ -767,6 +819,10 @@ + "EventCode": "0xad", + "BriefDescription": "L3 cache fill requests sourced from all data sources.", + "UMask": "0x3f", ++ "EnAllCores": "0x1", ++ "EnAllSlices": "0x1", ++ "SliceId": "0x3", ++ "ThreadMask": "0x3", + "Unit": "L3PMC" + } + ] +diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py +index 53ab050c8fa43..ce846f29c08d6 100755 +--- a/tools/perf/pmu-events/jevents.py ++++ b/tools/perf/pmu-events/jevents.py +@@ -356,6 +356,10 @@ class JsonEvent: + ('UMask', 'umask='), + ('NodeType', 'type='), + ('RdWrMask', 'rdwrmask='), ++ ('EnAllCores', 'enallcores='), ++ ('EnAllSlices', 'enallslices='), ++ ('SliceId', 'sliceid='), ++ ('ThreadMask', 'threadmask='), + ] + for key, value in event_fields: + if key in jd and jd[key] != '0': +diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c +index c29d8a382b196..550675ce0b787 100644 +--- a/tools/perf/util/data.c ++++ b/tools/perf/util/data.c +@@ -430,8 +430,6 @@ int perf_data__switch(struct perf_data *data, + { + int ret; + +- if (check_pipe(data)) +- return -EINVAL; + if (perf_data__is_read(data)) + return -EINVAL; + +diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c +index 6d7c9c58a9bcb..727dae445da9f 100644 +--- a/tools/perf/util/evsel.c ++++ b/tools/perf/util/evsel.c +@@ -2363,7 +2363,6 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event, + data->period = evsel->core.attr.sample_period; + data->cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + data->misc = event->header.misc; +- data->id = -1ULL; + data->data_src = PERF_MEM_DATA_SRC_NONE; + data->vcpu = -1; + +diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c +index 7be23b3ac0821..b8875aac8f870 100644 +--- a/tools/perf/util/expr.c ++++ b/tools/perf/util/expr.c +@@ -500,7 +500,25 @@ double expr__has_event(const struct expr_parse_ctx *ctx, bool compute_ids, const + tmp = evlist__new(); + if (!tmp) + return NAN; +- ret = parse_event(tmp, id) ? 0 : 1; ++ ++ if (strchr(id, '@')) { ++ char *tmp_id, *p; ++ ++ tmp_id = strdup(id); ++ if (!tmp_id) { ++ ret = NAN; ++ goto out; ++ } ++ p = strchr(tmp_id, '@'); ++ *p = '/'; ++ p = strrchr(tmp_id, '@'); ++ *p = '/'; ++ ret = parse_event(tmp, tmp_id) ? 0 : 1; ++ free(tmp_id); ++ } else { ++ ret = parse_event(tmp, id) ? 0 : 1; ++ } ++out: + evlist__delete(tmp); + return ret; + } +diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c +index 3c9609944a2f3..6b82f4759ce69 100644 +--- a/tools/perf/util/pmu.c ++++ b/tools/perf/util/pmu.c +@@ -1019,10 +1019,9 @@ struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char + * type value and format definitions. Load both right + * now. + */ +- if (pmu_format(pmu, dirfd, name)) { +- free(pmu); +- return NULL; +- } ++ if (pmu_format(pmu, dirfd, name)) ++ goto err; ++ + pmu->is_core = is_pmu_core(name); + pmu->cpus = pmu_cpumask(dirfd, name, pmu->is_core); + +@@ -1760,6 +1759,12 @@ bool pmu__name_match(const struct perf_pmu *pmu, const char *pmu_name) + + bool perf_pmu__is_software(const struct perf_pmu *pmu) + { ++ const char *known_sw_pmus[] = { ++ "kprobe", ++ "msr", ++ "uprobe", ++ }; ++ + if (pmu->is_core || pmu->is_uncore || pmu->auxtrace) + return false; + switch (pmu->type) { +@@ -1771,7 +1776,11 @@ bool perf_pmu__is_software(const struct perf_pmu *pmu) + case PERF_TYPE_BREAKPOINT: return true; + default: break; + } +- return !strcmp(pmu->name, "kprobe") || !strcmp(pmu->name, "uprobe"); ++ for (size_t i = 0; i < ARRAY_SIZE(known_sw_pmus); i++) { ++ if (!strcmp(pmu->name, known_sw_pmus[i])) ++ return true; ++ } ++ return false; + } + + FILE *perf_pmu__open_file(const struct perf_pmu *pmu, const char *name) +diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c +index 9e47712507cc2..b14d1a894abce 100644 +--- a/tools/perf/util/print-events.c ++++ b/tools/perf/util/print-events.c +@@ -232,7 +232,6 @@ void print_sdt_events(const struct print_callbacks *print_cb, void *print_state) + bool is_event_supported(u8 type, u64 config) + { + bool ret = true; +- int open_return; + struct evsel *evsel; + struct perf_event_attr attr = { + .type = type, +@@ -246,20 +245,32 @@ bool is_event_supported(u8 type, u64 config) + + evsel = evsel__new(&attr); + if (evsel) { +- open_return = evsel__open(evsel, NULL, tmap); +- ret = open_return >= 0; ++ ret = evsel__open(evsel, NULL, tmap) >= 0; + +- if (open_return == -EACCES) { ++ if (!ret) { + /* +- * This happens if the paranoid value ++ * The event may fail to open if the paranoid value + * /proc/sys/kernel/perf_event_paranoid is set to 2 +- * Re-run with exclude_kernel set; we don't do that +- * by default as some ARM machines do not support it. +- * ++ * Re-run with exclude_kernel set; we don't do that by ++ * default as some ARM machines do not support it. + */ + evsel->core.attr.exclude_kernel = 1; + ret = evsel__open(evsel, NULL, tmap) >= 0; + } ++ ++ if (!ret) { ++ /* ++ * The event may fail to open if the PMU requires ++ * exclude_guest to be set (e.g. as the Apple M1 PMU ++ * requires). ++ * Re-run with exclude_guest set; we don't do that by ++ * default as it's equally legitimate for another PMU ++ * driver to require that exclude_guest is clear. ++ */ ++ evsel->core.attr.exclude_guest = 1; ++ ret = evsel__open(evsel, NULL, tmap) >= 0; ++ } ++ + evsel__delete(evsel); + } + +diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c +index 034b496df2978..7addc34afcf5d 100644 +--- a/tools/perf/util/srcline.c ++++ b/tools/perf/util/srcline.c +@@ -399,6 +399,8 @@ static void addr2line_subprocess_cleanup(struct child_process *a2l) + kill(a2l->pid, SIGKILL); + finish_command(a2l); /* ignore result, we don't care */ + a2l->pid = -1; ++ close(a2l->in); ++ close(a2l->out); + } + + free(a2l); +diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c +index 8c61f8627ebc9..b7d00a538d703 100644 +--- a/tools/perf/util/stat-display.c ++++ b/tools/perf/util/stat-display.c +@@ -560,7 +560,7 @@ static void print_metric_only(struct perf_stat_config *config, + if (color) + mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1; + +- color_snprintf(str, sizeof(str), color ?: "", fmt, val); ++ color_snprintf(str, sizeof(str), color ?: "", fmt ?: "", val); + fprintf(out, "%*s ", mlen, str); + os->first = false; + } +diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c +index e31426167852a..cf573ff3fa84f 100644 +--- a/tools/perf/util/stat-shadow.c ++++ b/tools/perf/util/stat-shadow.c +@@ -414,12 +414,7 @@ static int prepare_metric(struct evsel **metric_events, + val = NAN; + source_count = 0; + } else { +- /* +- * If an event was scaled during stat gathering, +- * reverse the scale before computing the +- * metric. +- */ +- val = aggr->counts.val * (1.0 / metric_events[i]->scale); ++ val = aggr->counts.val; + source_count = evsel__source_count(metric_events[i]); + } + } +diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c +index e848579e61a86..ea3b431b97830 100644 +--- a/tools/perf/util/thread_map.c ++++ b/tools/perf/util/thread_map.c +@@ -280,13 +280,13 @@ struct perf_thread_map *thread_map__new_by_tid_str(const char *tid_str) + threads->nr = ntasks; + } + out: ++ strlist__delete(slist); + if (threads) + refcount_set(&threads->refcnt, 1); + return threads; + + out_free_threads: + zfree(&threads); +- strlist__delete(slist); + goto out; + } + +diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c +index 91907b321f913..e7c9e1c7fde04 100644 +--- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c ++++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c +@@ -2,6 +2,7 @@ + /* Copyright (c) 2020 Facebook */ + #include + #include ++#include + #include + #include + #include +@@ -544,6 +545,14 @@ static int bpf_testmod_init(void) + + static void bpf_testmod_exit(void) + { ++ /* Need to wait for all references to be dropped because ++ * bpf_kfunc_call_test_release() which currently resides in kernel can ++ * be called after bpf_testmod is unloaded. Once release function is ++ * moved into the module this wait can be removed. ++ */ ++ while (refcount_read(&prog_test_struct.cnt) > 1) ++ msleep(20); ++ + return sysfs_remove_bin_file(kernel_kobj, &bin_attr_bpf_testmod_file); + } + +diff --git a/tools/testing/selftests/bpf/prog_tests/lwt_redirect.c b/tools/testing/selftests/bpf/prog_tests/lwt_redirect.c +index 59b38569f310b..2bc932a18c17e 100644 +--- a/tools/testing/selftests/bpf/prog_tests/lwt_redirect.c ++++ b/tools/testing/selftests/bpf/prog_tests/lwt_redirect.c +@@ -203,6 +203,7 @@ static int setup_redirect_target(const char *target_dev, bool need_mac) + if (!ASSERT_GE(target_index, 0, "if_nametoindex")) + goto fail; + ++ SYS(fail, "sysctl -w net.ipv6.conf.all.disable_ipv6=1"); + SYS(fail, "ip link add link_err type dummy"); + SYS(fail, "ip link set lo up"); + SYS(fail, "ip addr add dev lo " LOCAL_SRC "/32"); +diff --git a/tools/testing/selftests/bpf/prog_tests/tc_redirect.c b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c +index 518f143c5b0fe..dbe06aeaa2b27 100644 +--- a/tools/testing/selftests/bpf/prog_tests/tc_redirect.c ++++ b/tools/testing/selftests/bpf/prog_tests/tc_redirect.c +@@ -188,6 +188,7 @@ static int netns_setup_links_and_routes(struct netns_setup_result *result) + { + struct nstoken *nstoken = NULL; + char src_fwd_addr[IFADDR_STR_LEN+1] = {}; ++ char src_addr[IFADDR_STR_LEN + 1] = {}; + int err; + + if (result->dev_mode == MODE_VETH) { +@@ -208,6 +209,9 @@ static int netns_setup_links_and_routes(struct netns_setup_result *result) + if (get_ifaddr("src_fwd", src_fwd_addr)) + goto fail; + ++ if (get_ifaddr("src", src_addr)) ++ goto fail; ++ + result->ifindex_src = if_nametoindex("src"); + if (!ASSERT_GT(result->ifindex_src, 0, "ifindex_src")) + goto fail; +@@ -270,6 +274,13 @@ static int netns_setup_links_and_routes(struct netns_setup_result *result) + SYS(fail, "ip route add " IP4_DST "/32 dev dst_fwd scope global"); + SYS(fail, "ip route add " IP6_DST "/128 dev dst_fwd scope global"); + ++ if (result->dev_mode == MODE_VETH) { ++ SYS(fail, "ip neigh add " IP4_SRC " dev src_fwd lladdr %s", src_addr); ++ SYS(fail, "ip neigh add " IP6_SRC " dev src_fwd lladdr %s", src_addr); ++ SYS(fail, "ip neigh add " IP4_DST " dev dst_fwd lladdr %s", MAC_DST); ++ SYS(fail, "ip neigh add " IP6_DST " dev dst_fwd lladdr %s", MAC_DST); ++ } ++ + close_netns(nstoken); + + /** setup in 'dst' namespace */ +@@ -280,6 +291,7 @@ static int netns_setup_links_and_routes(struct netns_setup_result *result) + SYS(fail, "ip addr add " IP4_DST "/32 dev dst"); + SYS(fail, "ip addr add " IP6_DST "/128 dev dst nodad"); + SYS(fail, "ip link set dev dst up"); ++ SYS(fail, "ip link set dev lo up"); + + SYS(fail, "ip route add " IP4_SRC "/32 dev dst scope global"); + SYS(fail, "ip route add " IP4_NET "/16 dev dst scope global"); +@@ -457,7 +469,7 @@ static int set_forwarding(bool enable) + return 0; + } + +-static void rcv_tstamp(int fd, const char *expected, size_t s) ++static int __rcv_tstamp(int fd, const char *expected, size_t s, __u64 *tstamp) + { + struct __kernel_timespec pkt_ts = {}; + char ctl[CMSG_SPACE(sizeof(pkt_ts))]; +@@ -478,7 +490,7 @@ static void rcv_tstamp(int fd, const char *expected, size_t s) + + ret = recvmsg(fd, &msg, 0); + if (!ASSERT_EQ(ret, s, "recvmsg")) +- return; ++ return -1; + ASSERT_STRNEQ(data, expected, s, "expected rcv data"); + + cmsg = CMSG_FIRSTHDR(&msg); +@@ -487,6 +499,12 @@ static void rcv_tstamp(int fd, const char *expected, size_t s) + memcpy(&pkt_ts, CMSG_DATA(cmsg), sizeof(pkt_ts)); + + pkt_ns = pkt_ts.tv_sec * NSEC_PER_SEC + pkt_ts.tv_nsec; ++ if (tstamp) { ++ /* caller will check the tstamp itself */ ++ *tstamp = pkt_ns; ++ return 0; ++ } ++ + ASSERT_NEQ(pkt_ns, 0, "pkt rcv tstamp"); + + ret = clock_gettime(CLOCK_REALTIME, &now_ts); +@@ -496,6 +514,60 @@ static void rcv_tstamp(int fd, const char *expected, size_t s) + if (ASSERT_GE(now_ns, pkt_ns, "check rcv tstamp")) + ASSERT_LT(now_ns - pkt_ns, 5 * NSEC_PER_SEC, + "check rcv tstamp"); ++ return 0; ++} ++ ++static void rcv_tstamp(int fd, const char *expected, size_t s) ++{ ++ __rcv_tstamp(fd, expected, s, NULL); ++} ++ ++static int wait_netstamp_needed_key(void) ++{ ++ int opt = 1, srv_fd = -1, cli_fd = -1, nretries = 0, err, n; ++ char buf[] = "testing testing"; ++ struct nstoken *nstoken; ++ __u64 tstamp = 0; ++ ++ nstoken = open_netns(NS_DST); ++ if (!nstoken) ++ return -1; ++ ++ srv_fd = start_server(AF_INET6, SOCK_DGRAM, "::1", 0, 0); ++ if (!ASSERT_GE(srv_fd, 0, "start_server")) ++ goto done; ++ ++ err = setsockopt(srv_fd, SOL_SOCKET, SO_TIMESTAMPNS_NEW, ++ &opt, sizeof(opt)); ++ if (!ASSERT_OK(err, "setsockopt(SO_TIMESTAMPNS_NEW)")) ++ goto done; ++ ++ cli_fd = connect_to_fd(srv_fd, TIMEOUT_MILLIS); ++ if (!ASSERT_GE(cli_fd, 0, "connect_to_fd")) ++ goto done; ++ ++again: ++ n = write(cli_fd, buf, sizeof(buf)); ++ if (!ASSERT_EQ(n, sizeof(buf), "send to server")) ++ goto done; ++ err = __rcv_tstamp(srv_fd, buf, sizeof(buf), &tstamp); ++ if (!ASSERT_OK(err, "__rcv_tstamp")) ++ goto done; ++ if (!tstamp && nretries++ < 5) { ++ sleep(1); ++ printf("netstamp_needed_key retry#%d\n", nretries); ++ goto again; ++ } ++ ++done: ++ if (!tstamp && srv_fd != -1) { ++ close(srv_fd); ++ srv_fd = -1; ++ } ++ if (cli_fd != -1) ++ close(cli_fd); ++ close_netns(nstoken); ++ return srv_fd; + } + + static void snd_tstamp(int fd, char *b, size_t s) +@@ -832,11 +904,20 @@ static void test_tc_redirect_dtime(struct netns_setup_result *setup_result) + { + struct test_tc_dtime *skel; + struct nstoken *nstoken; +- int err; ++ int hold_tstamp_fd, err; ++ ++ /* Hold a sk with the SOCK_TIMESTAMP set to ensure there ++ * is no delay in the kernel net_enable_timestamp(). ++ * This ensures the following tests must have ++ * non zero rcv tstamp in the recvmsg(). ++ */ ++ hold_tstamp_fd = wait_netstamp_needed_key(); ++ if (!ASSERT_GE(hold_tstamp_fd, 0, "wait_netstamp_needed_key")) ++ return; + + skel = test_tc_dtime__open(); + if (!ASSERT_OK_PTR(skel, "test_tc_dtime__open")) +- return; ++ goto done; + + skel->rodata->IFINDEX_SRC = setup_result->ifindex_src_fwd; + skel->rodata->IFINDEX_DST = setup_result->ifindex_dst_fwd; +@@ -881,6 +962,7 @@ static void test_tc_redirect_dtime(struct netns_setup_result *setup_result) + + done: + test_tc_dtime__destroy(skel); ++ close(hold_tstamp_fd); + } + + static void test_tc_redirect_neigh_fib(struct netns_setup_result *setup_result) +diff --git a/tools/testing/selftests/bpf/progs/test_map_in_map.c b/tools/testing/selftests/bpf/progs/test_map_in_map.c +index f416032ba858b..b295f9b721bf8 100644 +--- a/tools/testing/selftests/bpf/progs/test_map_in_map.c ++++ b/tools/testing/selftests/bpf/progs/test_map_in_map.c +@@ -21,6 +21,32 @@ struct { + __type(value, __u32); + } mim_hash SEC(".maps"); + ++/* The following three maps are used to test ++ * perf_event_array map can be an inner ++ * map of hash/array_of_maps. ++ */ ++struct perf_event_array { ++ __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); ++ __type(key, __u32); ++ __type(value, __u32); ++} inner_map0 SEC(".maps"); ++ ++struct { ++ __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); ++ __uint(max_entries, 1); ++ __type(key, __u32); ++ __array(values, struct perf_event_array); ++} mim_array_pe SEC(".maps") = { ++ .values = {&inner_map0}}; ++ ++struct { ++ __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS); ++ __uint(max_entries, 1); ++ __type(key, __u32); ++ __array(values, struct perf_event_array); ++} mim_hash_pe SEC(".maps") = { ++ .values = {&inner_map0}}; ++ + SEC("xdp") + int xdp_mimtest0(struct xdp_md *ctx) + { +diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c +index 767e0693df106..dfbab214f4d1c 100644 +--- a/tools/testing/selftests/bpf/test_maps.c ++++ b/tools/testing/selftests/bpf/test_maps.c +@@ -1190,7 +1190,11 @@ static void test_map_in_map(void) + goto out_map_in_map; + } + +- bpf_object__load(obj); ++ err = bpf_object__load(obj); ++ if (err) { ++ printf("Failed to load test prog\n"); ++ goto out_map_in_map; ++ } + + map = bpf_object__find_map_by_name(obj, "mim_array"); + if (!map) { +diff --git a/tools/testing/selftests/bpf/trace_helpers.c b/tools/testing/selftests/bpf/trace_helpers.c +index 4faa898ff7fc4..27fd7ed3e4b0c 100644 +--- a/tools/testing/selftests/bpf/trace_helpers.c ++++ b/tools/testing/selftests/bpf/trace_helpers.c +@@ -271,7 +271,7 @@ ssize_t get_uprobe_offset(const void *addr) + * addi r2,r2,XXXX + */ + { +- const u32 *insn = (const u32 *)(uintptr_t)addr; ++ const __u32 *insn = (const __u32 *)(uintptr_t)addr; + + if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) || + ((*insn & OP_RT_RA_MASK) == LIS_R2)) && +diff --git a/tools/testing/selftests/net/forwarding/config b/tools/testing/selftests/net/forwarding/config +index 697994a9278bb..8d7a1a004b7c3 100644 +--- a/tools/testing/selftests/net/forwarding/config ++++ b/tools/testing/selftests/net/forwarding/config +@@ -6,14 +6,49 @@ CONFIG_IPV6_MULTIPLE_TABLES=y + CONFIG_NET_VRF=m + CONFIG_BPF_SYSCALL=y + CONFIG_CGROUP_BPF=y ++CONFIG_DUMMY=m ++CONFIG_IPV6=y ++CONFIG_IPV6_GRE=m ++CONFIG_IPV6_MROUTE=y ++CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y ++CONFIG_IPV6_PIMSM_V2=y ++CONFIG_IP_MROUTE=y ++CONFIG_IP_MROUTE_MULTIPLE_TABLES=y ++CONFIG_IP_PIMSM_V1=y ++CONFIG_IP_PIMSM_V2=y ++CONFIG_MACVLAN=m + CONFIG_NET_ACT_CT=m + CONFIG_NET_ACT_MIRRED=m + CONFIG_NET_ACT_MPLS=m ++CONFIG_NET_ACT_PEDIT=m ++CONFIG_NET_ACT_POLICE=m ++CONFIG_NET_ACT_SAMPLE=m ++CONFIG_NET_ACT_SKBEDIT=m ++CONFIG_NET_ACT_TUNNEL_KEY=m + CONFIG_NET_ACT_VLAN=m + CONFIG_NET_CLS_FLOWER=m + CONFIG_NET_CLS_MATCHALL=m ++CONFIG_NET_CLS_BASIC=m ++CONFIG_NET_EMATCH=y ++CONFIG_NET_EMATCH_META=m ++CONFIG_NET_IPGRE=m ++CONFIG_NET_IPGRE_DEMUX=m ++CONFIG_NET_IPIP=m ++CONFIG_NET_SCH_ETS=m + CONFIG_NET_SCH_INGRESS=m + CONFIG_NET_ACT_GACT=m ++CONFIG_NET_SCH_PRIO=m ++CONFIG_NET_SCH_RED=m ++CONFIG_NET_SCH_TBF=m ++CONFIG_NET_TC_SKB_EXT=y ++CONFIG_NET_TEAM=y ++CONFIG_NET_TEAM_MODE_LOADBALANCE=y ++CONFIG_NETFILTER=y ++CONFIG_NF_CONNTRACK=m ++CONFIG_NF_FLOW_TABLE=m ++CONFIG_NF_TABLES=m + CONFIG_VETH=m + CONFIG_NAMESPACES=y + CONFIG_NET_NS=y ++CONFIG_VXLAN=m ++CONFIG_XFRM_USER=m +diff --git a/tools/testing/selftests/net/forwarding/vxlan_bridge_1d_ipv6.sh b/tools/testing/selftests/net/forwarding/vxlan_bridge_1d_ipv6.sh +index ac97f07e5ce82..bd3f7d492af2b 100755 +--- a/tools/testing/selftests/net/forwarding/vxlan_bridge_1d_ipv6.sh ++++ b/tools/testing/selftests/net/forwarding/vxlan_bridge_1d_ipv6.sh +@@ -354,7 +354,7 @@ __ping_ipv4() + + # Send 100 packets and verify that at least 100 packets hit the rule, + # to overcome ARP noise. +- PING_COUNT=100 PING_TIMEOUT=11 ping_do $dev $dst_ip ++ PING_COUNT=100 PING_TIMEOUT=20 ping_do $dev $dst_ip + check_err $? "Ping failed" + + tc_check_at_least_x_packets "dev $rp1 egress" 101 10 100 +@@ -410,7 +410,7 @@ __ping_ipv6() + + # Send 100 packets and verify that at least 100 packets hit the rule, + # to overcome neighbor discovery noise. +- PING_COUNT=100 PING_TIMEOUT=11 ping6_do $dev $dst_ip ++ PING_COUNT=100 PING_TIMEOUT=20 ping6_do $dev $dst_ip + check_err $? "Ping failed" + + tc_check_at_least_x_packets "dev $rp1 egress" 101 100 +diff --git a/tools/testing/selftests/net/forwarding/vxlan_bridge_1q_ipv6.sh b/tools/testing/selftests/net/forwarding/vxlan_bridge_1q_ipv6.sh +index d880df89bc8bd..e83fde79f40d0 100755 +--- a/tools/testing/selftests/net/forwarding/vxlan_bridge_1q_ipv6.sh ++++ b/tools/testing/selftests/net/forwarding/vxlan_bridge_1q_ipv6.sh +@@ -457,7 +457,7 @@ __ping_ipv4() + + # Send 100 packets and verify that at least 100 packets hit the rule, + # to overcome ARP noise. +- PING_COUNT=100 PING_TIMEOUT=11 ping_do $dev $dst_ip ++ PING_COUNT=100 PING_TIMEOUT=20 ping_do $dev $dst_ip + check_err $? "Ping failed" + + tc_check_at_least_x_packets "dev $rp1 egress" 101 10 100 +@@ -522,7 +522,7 @@ __ping_ipv6() + + # Send 100 packets and verify that at least 100 packets hit the rule, + # to overcome neighbor discovery noise. +- PING_COUNT=100 PING_TIMEOUT=11 ping6_do $dev $dst_ip ++ PING_COUNT=100 PING_TIMEOUT=20 ping6_do $dev $dst_ip + check_err $? "Ping failed" + + tc_check_at_least_x_packets "dev $rp1 egress" 101 100